Esta estrategia implementa un sistema de trading en cuadrícula simétrica con hasta tres rangos de take-profit.
Las órdenes límite se colocan por encima y por debajo del precio actual a intervalos fijos. Cuando una
orden de entrada se ejecuta, se envía una orden límite opuesta para capturar ganancias a una distancia
configurable. El método es adecuado para mercados laterales donde el precio oscila dentro de una banda.
Parámetros
Grid Size – distancia entre niveles de la cuadrícula.
Levels – número de niveles de cuadrícula en cada lado del precio actual.
Base Take Profit – distancia de ganancia base para el primer rango.
Order Volume – volumen utilizado para cada orden de cuadrícula.
Enable Rank1 – colocar órdenes con take-profit base.
Enable Rank2 – colocar órdenes con take-profit base más un tamaño de cuadrícula.
Enable Rank3 – colocar órdenes con take-profit base más dos tamaños de cuadrícula.
Allow Longs – habilitar el lado largo de la cuadrícula.
Allow Shorts – habilitar el lado corto de la cuadrícula.
Candle Type – tipo de vela usado para obtener el precio de referencia inicial.
Lógica de Trading
Al inicio, la estrategia se suscribe a velas y espera la primera vela completada.
Usando el precio de cierre de esa vela, se construye la cuadrícula con el número de niveles configurado.
Para cada nivel se colocan órdenes límite de compra y/o venta dependiendo de los lados permitidos.
Cuando una orden de entrada se ejecuta, se registra una orden límite opuesta al precio de take-profit
calculado según el rango seleccionado.
Las órdenes permanecen en el mercado hasta que se ejecutan o se cancelan manualmente.
Esta implementación es una conversión simplificada del sistema de cuadrícula MQL original y tiene como
objetivo destacar la mecánica central en la API de alto nivel de StockSharp.
using System;
using System.Collections.Generic;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Three-level grid strategy using EMA as center line.
/// Buys on dips below EMA at different levels, sells on rises above EMA.
/// </summary>
public class ThreeLevelGridStrategy : Strategy
{
private readonly StrategyParam<int> _emaLength;
private readonly StrategyParam<DataType> _candleType;
public int EmaLength { get => _emaLength.Value; set => _emaLength.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public ThreeLevelGridStrategy()
{
_emaLength = Param(nameof(EmaLength), 30)
.SetGreaterThanZero()
.SetDisplay("EMA Length", "EMA period for center line", "Indicators");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Type of candles", "General");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
=> [(Security, CandleType)];
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var ema = new ExponentialMovingAverage { Length = EmaLength };
var atr = new StandardDeviation { Length = 14 };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(ema, atr, ProcessCandle)
.Start();
}
private void ProcessCandle(ICandleMessage candle, decimal emaVal, decimal atrVal)
{
if (candle.State != CandleStates.Finished)
return;
if (atrVal <= 0)
return;
var close = candle.ClosePrice;
var diff = close - emaVal;
// Buy at different grid levels below EMA
if (diff < -1.5m * atrVal && Position <= 0)
{
if (Position < 0)
BuyMarket();
BuyMarket();
}
// Sell at different grid levels above EMA
else if (diff > 1.5m * atrVal && Position >= 0)
{
if (Position > 0)
SellMarket();
SellMarket();
}
// Mean reversion exit
else if (Position > 0 && close > emaVal + 0.5m * atrVal)
{
SellMarket();
}
else if (Position < 0 && close < emaVal - 0.5m * atrVal)
{
BuyMarket();
}
}
}
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.Indicators import ExponentialMovingAverage, StandardDeviation
from StockSharp.Algo.Strategies import Strategy
class three_level_grid_strategy(Strategy):
def __init__(self):
super(three_level_grid_strategy, self).__init__()
self._ema_length = self.Param("EmaLength", 30) \
.SetDisplay("EMA Length", "EMA period for center line", "Indicators")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Type of candles", "General")
@property
def ema_length(self):
return self._ema_length.Value
@property
def candle_type(self):
return self._candle_type.Value
def OnStarted2(self, time):
super(three_level_grid_strategy, self).OnStarted2(time)
ema = ExponentialMovingAverage()
ema.Length = self.ema_length
atr = StandardDeviation()
atr.Length = 14
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(ema, atr, self.on_process).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawOwnTrades(area)
def on_process(self, candle, ema_val, atr_val):
if candle.State != CandleStates.Finished:
return
if atr_val <= 0:
return
close = candle.ClosePrice
diff = close - ema_val
# Buy at different grid levels below EMA
if diff < -1.5 * atr_val and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
# Sell at different grid levels above EMA
elif diff > 1.5 * atr_val and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
# Mean reversion exit
elif self.Position > 0 and close > ema_val + 0.5 * atr_val:
self.SellMarket()
elif self.Position < 0 and close < ema_val - 0.5 * atr_val:
self.BuyMarket()
def CreateClone(self):
return three_level_grid_strategy()