Ver en GitHub

Estrategia de cuadrícula de límites pendiente (MQL/8147 Conversión)

Descripción general

La Estrategia de cuadrícula de límites pendiente reproduce el comportamiento del experto MetaTrader almacenado en MQL/8147. La estrategia construye una cuadrícula simétrica de órdenes límite pendientes. alrededor de los precios actuales de oferta y demanda. Mantiene la red activa mientras las ganancias flotan. permanece dentro de un objetivo de ganancias configurado y un umbral de reducción. Cuando uno de los se superan los umbrales, se cancelan todas las órdenes, se aplanan las posiciones abiertas y la red se reconstruye utilizando el patrimonio de la nueva cuenta como base de referencia.

Lógica de trading

  1. Suscríbase a los datos de nivel uno para realizar un seguimiento de los mejores precios de oferta y demanda.
  2. Capture el capital de la cuenta la primera vez que se reciban datos en vivo y guárdelos como la línea base de la sesión.
  3. Coloque LevelsPerSide límites de venta por encima del mercado y la misma cantidad de compras límites por debajo del mercado. La distancia entre los niveles de la cuadrícula está controlada por GridStepPoints convertido al paso del precio del instrumento.
  4. Mantenga las órdenes pendientes sin volver a emitir nuevas cuando se ejecuten. el La cuadrícula se recrea solo después de un reinicio completo.
  5. Supervise continuamente el PnL flotante:
    • Si la ganancia alcanza ProfitTargetCurrency, cierre toda exposición y reiníciela.
    • Si la reducción excede MaxDrawdownCurrency, aplana el libro y reinícialo.
  6. Después de cada reinicio, la equidad de referencia se captura nuevamente y se reconstruye la red. utilizando la instantánea de oferta/demanda más reciente.

Parámetros

Parámetro Descripción
ProfitTargetCurrency Beneficio neto (en la moneda de la cuenta) que desencadena un reinicio completo de la red.
MaxDrawdownCurrency Pérdida flotante máxima tolerada antes de que se cierre toda exposición.
GridStepPoints Distancia entre niveles consecutivos de la grilla expresada en puntos de corredor.
LevelsPerSide Número de órdenes pendientes creadas por encima y por debajo del mercado.
OrderVolume Volumen asignado a cada orden límite pendiente.

Gestión del riesgo

La estrategia no adjunta paradas ni objetivos por orden. En cambio, supervisa el pérdidas y ganancias agregadas. El ayudante RequestFlatten cancela los pedidos pendientes y utiliza órdenes de mercado (a través de ClosePosition) para eliminar cualquier exposición abierta. Después del Cuando se completa el aplanamiento, el estado de la red y la equidad de referencia se restablecen antes de colocar nuevos pedidos.

Notas

  • Los precios están normalizados a través de Security.ShrinkPrice para respetar el cambio. paso de precio.
  • El valor "Punto" MetaTrader se emula analizando el instrumento PriceStep para hacer coincidir cotizaciones de cuatro y cinco dígitos.
  • La estrategia evita reenviar los pedidos de la grilla una vez realizados, imitando el experto original que se basaba en variables de bandera para mantener cada nivel único hasta se produce un reinicio manual o automático.
using System;

using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;

namespace StockSharp.Samples.Strategies;

public class PendingLimitGridStrategy : Strategy
{
	private readonly StrategyParam<int> _channelPeriod;
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _cooldownBars;

	private decimal _prevClose;
	private decimal _prevMid;
	private bool _hasPrev;
	private int _barsSinceLastTrade;

	public int ChannelPeriod { get => _channelPeriod.Value; set => _channelPeriod.Value = value; }
	public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
	public int CooldownBars { get => _cooldownBars.Value; set => _cooldownBars.Value = value; }

	public PendingLimitGridStrategy()
	{
		_channelPeriod = Param(nameof(ChannelPeriod), 24).SetDisplay("Channel Period", "Grid channel lookback", "Indicators");
		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame()).SetDisplay("Candle Type", "Candle timeframe", "General");
		_cooldownBars = Param(nameof(CooldownBars), 200).SetDisplay("Cooldown Bars", "Minimum bars between trades", "Risk");
	}

	protected override void OnReseted()
	{
		base.OnReseted();
		_prevClose = 0;
		_prevMid = 0;
		_hasPrev = false;
		_barsSinceLastTrade = 0;
	}

	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);
		_hasPrev = false;
		_barsSinceLastTrade = 0;
		var highest = new Highest { Length = ChannelPeriod };
		var lowest = new Lowest { Length = ChannelPeriod };
		var subscription = SubscribeCandles(CandleType);
		subscription.Bind(highest, lowest, ProcessCandle).Start();
	}

	private void ProcessCandle(ICandleMessage candle, decimal highest, decimal lowest)
	{
		if (candle.State != CandleStates.Finished) return;

		var close = candle.ClosePrice;
		var mid = (highest + lowest) / 2;

		if (!_hasPrev) { _prevClose = close; _prevMid = mid; _hasPrev = true; return; }

		_barsSinceLastTrade++;

		if (_barsSinceLastTrade >= CooldownBars)
		{
			if (_prevClose <= _prevMid && close > mid && Position <= 0)
			{
				if (Position < 0) BuyMarket();
				BuyMarket();
				_barsSinceLastTrade = 0;
			}
			else if (_prevClose >= _prevMid && close < mid && Position >= 0)
			{
				if (Position > 0) SellMarket();
				SellMarket();
				_barsSinceLastTrade = 0;
			}
		}

		_prevClose = close;
		_prevMid = mid;
	}
}