Ver en GitHub

Estrategia de Cuadrícula de Tres Niveles

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

  1. Al inicio, la estrategia se suscribe a velas y espera la primera vela completada.
  2. Usando el precio de cierre de esa vela, se construye la cuadrícula con el número de niveles configurado.
  3. Para cada nivel se colocan órdenes límite de compra y/o venta dependiendo de los lados permitidos.
  4. 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.
  5. 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();
		}
	}
}