Estrategia Ilan14
Ilan14 es una estrategia de grilla de cobertura que abre posiciones largas y cortas simultáneamente. Cuando el mercado se mueve en contra de un lado una distancia definida en pips por el usuario, la estrategia añade una nueva orden en esa dirección con su volumen multiplicado por el Lot Exponent. Se rastrea el precio promedio de la posición y una vez que el precio revierte la distancia de Take Profit configurada, todas las órdenes de ese lado se cierran.
Parámetros:
- Pip Step – distancia en pips entre las órdenes de la grilla.
- Lot Exponent – multiplicador aplicado al volumen de cada orden adicional.
- Max Trades – número máximo de órdenes por dirección.
- Take Profit – objetivo de ganancia en pips desde el precio promedio ponderado.
- Initial Volume – volumen de la primera orden.
- Candle Type – marco temporal para la suscripción de velas.
La implementación utiliza la API de alto nivel de StockSharp con suscripciones a velas y evita colecciones de datos manuales. Ambos lados de la grilla se gestionan de forma independiente, lo que permite a la estrategia capturar rebotes después de movimientos adversos.
using System;
using System.Linq;
using System.Collections.Generic;
using Ecng.Common;
using Ecng.Collections;
using Ecng.Serialization;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
public class Ilan14Strategy : Strategy {
private readonly StrategyParam<decimal> _pipStep;
private readonly StrategyParam<decimal> _lotExponent;
private readonly StrategyParam<int> _maxTrades;
private readonly StrategyParam<decimal> _takeProfit;
private readonly StrategyParam<decimal> _initialVolume;
private readonly StrategyParam<DataType> _candleType;
private decimal _lastBuyPrice;
private decimal _lastSellPrice;
private decimal _lastBuyVolume;
private decimal _lastSellVolume;
private decimal _buyVolume;
private decimal _sellVolume;
private decimal _avgBuyPrice;
private decimal _avgSellPrice;
private int _buyCount;
private int _sellCount;
public decimal PipStep {
get => _pipStep.Value;
set => _pipStep.Value = value;
}
public decimal LotExponent {
get => _lotExponent.Value;
set => _lotExponent.Value = value;
}
public int MaxTrades {
get => _maxTrades.Value;
set => _maxTrades.Value = value;
}
public decimal TakeProfit {
get => _takeProfit.Value;
set => _takeProfit.Value = value;
}
public decimal InitialVolume {
get => _initialVolume.Value;
set => _initialVolume.Value = value;
}
public DataType CandleType {
get => _candleType.Value;
set => _candleType.Value = value;
}
public Ilan14Strategy() {
_pipStep =
Param(nameof(PipStep), 30m)
.SetGreaterThanZero()
.SetDisplay("Pip Step", "Distance in pips to add position",
"General")
;
_lotExponent =
Param(nameof(LotExponent), 1.667m)
.SetGreaterThanZero()
.SetDisplay("Lot Exponent",
"Volume multiplier for each additional order",
"General")
;
_maxTrades = Param(nameof(MaxTrades), 1)
.SetGreaterThanZero()
.SetDisplay("Max Trades",
"Maximum number of trades per direction",
"General");
_takeProfit =
Param(nameof(TakeProfit), 300m)
.SetGreaterThanZero()
.SetDisplay("Take Profit",
"Target profit in pips from average price",
"General")
;
_initialVolume = Param(nameof(InitialVolume), 0.1m)
.SetGreaterThanZero()
.SetDisplay("Initial Volume",
"Volume of first order", "General")
;
_candleType =
Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame())
.SetDisplay("Candle Type", "Type of candles to use", "General");
}
public override IEnumerable<(Security sec, DataType dt)>
GetWorkingSecurities() => [(Security, CandleType)];
protected override void OnReseted() {
base.OnReseted();
_lastBuyPrice = 0m;
_lastSellPrice = 0m;
_lastBuyVolume = 0m;
_lastSellVolume = 0m;
_buyVolume = 0m;
_sellVolume = 0m;
_avgBuyPrice = 0m;
_avgSellPrice = 0m;
_buyCount = 0;
_sellCount = 0;
}
protected override void OnStarted2(DateTime time) {
base.OnStarted2(time);
StartProtection(null, null);
var sub = SubscribeCandles(CandleType);
sub.Bind(Process).Start();
}
private void Process(ICandleMessage candle) {
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
var step = Security.PriceStep ?? 1m;
var price = candle.ClosePrice;
if (_buyCount == 0 && _sellCount == 0) {
// Open initial hedge positions
BuyMarket(InitialVolume);
SellMarket(InitialVolume);
_lastBuyPrice = price;
_lastSellPrice = price;
_lastBuyVolume = InitialVolume;
_lastSellVolume = InitialVolume;
_buyVolume = InitialVolume;
_sellVolume = InitialVolume;
_avgBuyPrice = price;
_avgSellPrice = price;
_buyCount = 1;
_sellCount = 1;
return;
}
// --- Buy side management ---
if (_buyCount > 0) {
if (_buyCount < MaxTrades &&
price <= _lastBuyPrice - PipStep * step) {
var vol = _lastBuyVolume * LotExponent;
BuyMarket(vol);
_lastBuyVolume = vol;
_lastBuyPrice = price;
_avgBuyPrice = (_avgBuyPrice * _buyVolume + price * vol) /
(_buyVolume + vol);
_buyVolume += vol;
_buyCount++;
}
if (_buyVolume > 0 && price >= _avgBuyPrice + TakeProfit * step) {
// Close all buy positions when profit target is reached
SellMarket(_buyVolume);
_buyVolume = 0m;
_lastBuyPrice = 0m;
_lastBuyVolume = 0m;
_avgBuyPrice = 0m;
_buyCount = 0;
}
}
// --- Sell side management ---
if (_sellCount > 0) {
if (_sellCount < MaxTrades &&
price >= _lastSellPrice + PipStep * step) {
var vol = _lastSellVolume * LotExponent;
SellMarket(vol);
_lastSellVolume = vol;
_lastSellPrice = price;
_avgSellPrice = (_avgSellPrice * _sellVolume + price * vol) /
(_sellVolume + vol);
_sellVolume += vol;
_sellCount++;
}
if (_sellVolume > 0 && price <= _avgSellPrice - TakeProfit * step) {
// Close all sell positions when profit target is reached
BuyMarket(_sellVolume);
_sellVolume = 0m;
_lastSellPrice = 0m;
_lastSellVolume = 0m;
_avgSellPrice = 0m;
_sellCount = 0;
}
}
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Strategies import Strategy
class ilan14_strategy(Strategy):
def __init__(self):
super(ilan14_strategy, self).__init__()
self._pip_step = self.Param("PipStep", 30.0)
self._lot_exponent = self.Param("LotExponent", 1.667)
self._max_trades = self.Param("MaxTrades", 1)
self._take_profit = self.Param("TakeProfit", 300.0)
self._initial_volume = self.Param("InitialVolume", 0.1)
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(1)))
self._last_buy_price = 0.0
self._last_sell_price = 0.0
self._last_buy_volume = 0.0
self._last_sell_volume = 0.0
self._buy_volume = 0.0
self._sell_volume = 0.0
self._avg_buy_price = 0.0
self._avg_sell_price = 0.0
self._buy_count = 0
self._sell_count = 0
@property
def PipStep(self):
return self._pip_step.Value
@PipStep.setter
def PipStep(self, value):
self._pip_step.Value = value
@property
def LotExponent(self):
return self._lot_exponent.Value
@LotExponent.setter
def LotExponent(self, value):
self._lot_exponent.Value = value
@property
def MaxTrades(self):
return self._max_trades.Value
@MaxTrades.setter
def MaxTrades(self, value):
self._max_trades.Value = value
@property
def TakeProfit(self):
return self._take_profit.Value
@TakeProfit.setter
def TakeProfit(self, value):
self._take_profit.Value = value
@property
def InitialVolume(self):
return self._initial_volume.Value
@InitialVolume.setter
def InitialVolume(self, value):
self._initial_volume.Value = value
@property
def CandleType(self):
return self._candle_type.Value
@CandleType.setter
def CandleType(self, value):
self._candle_type.Value = value
def OnStarted2(self, time):
super(ilan14_strategy, self).OnStarted2(time)
self._last_buy_price = 0.0
self._last_sell_price = 0.0
self._last_buy_volume = 0.0
self._last_sell_volume = 0.0
self._buy_volume = 0.0
self._sell_volume = 0.0
self._avg_buy_price = 0.0
self._avg_sell_price = 0.0
self._buy_count = 0
self._sell_count = 0
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(self.ProcessCandle).Start()
self.StartProtection(None, None)
def ProcessCandle(self, candle):
if candle.State != CandleStates.Finished:
return
if not self.IsFormedAndOnlineAndAllowTrading():
return
step = float(self.Security.PriceStep) if self.Security is not None and self.Security.PriceStep is not None else 1.0
price = float(candle.ClosePrice)
pip_step = float(self.PipStep)
lot_exp = float(self.LotExponent)
max_trades = int(self.MaxTrades)
tp = float(self.TakeProfit)
init_vol = float(self.InitialVolume)
if self._buy_count == 0 and self._sell_count == 0:
self.BuyMarket(init_vol)
self.SellMarket(init_vol)
self._last_buy_price = price
self._last_sell_price = price
self._last_buy_volume = init_vol
self._last_sell_volume = init_vol
self._buy_volume = init_vol
self._sell_volume = init_vol
self._avg_buy_price = price
self._avg_sell_price = price
self._buy_count = 1
self._sell_count = 1
return
if self._buy_count > 0:
if self._buy_count < max_trades and price <= self._last_buy_price - pip_step * step:
vol = self._last_buy_volume * lot_exp
self.BuyMarket(vol)
self._last_buy_volume = vol
self._last_buy_price = price
self._avg_buy_price = (self._avg_buy_price * self._buy_volume + price * vol) / (self._buy_volume + vol)
self._buy_volume += vol
self._buy_count += 1
if self._buy_volume > 0.0 and price >= self._avg_buy_price + tp * step:
self.SellMarket(self._buy_volume)
self._buy_volume = 0.0
self._last_buy_price = 0.0
self._last_buy_volume = 0.0
self._avg_buy_price = 0.0
self._buy_count = 0
if self._sell_count > 0:
if self._sell_count < max_trades and price >= self._last_sell_price + pip_step * step:
vol = self._last_sell_volume * lot_exp
self.SellMarket(vol)
self._last_sell_volume = vol
self._last_sell_price = price
self._avg_sell_price = (self._avg_sell_price * self._sell_volume + price * vol) / (self._sell_volume + vol)
self._sell_volume += vol
self._sell_count += 1
if self._sell_volume > 0.0 and price <= self._avg_sell_price - tp * step:
self.BuyMarket(self._sell_volume)
self._sell_volume = 0.0
self._last_sell_price = 0.0
self._last_sell_volume = 0.0
self._avg_sell_price = 0.0
self._sell_count = 0
def OnReseted(self):
super(ilan14_strategy, self).OnReseted()
self._last_buy_price = 0.0
self._last_sell_price = 0.0
self._last_buy_volume = 0.0
self._last_sell_volume = 0.0
self._buy_volume = 0.0
self._sell_volume = 0.0
self._avg_buy_price = 0.0
self._avg_sell_price = 0.0
self._buy_count = 0
self._sell_count = 0
def CreateClone(self):
return ilan14_strategy()