Ver en GitHub

Estrategia de pivote L3H3

Descripción general

La Estrategia de pivote L3H3 es una adaptación StockSharp del experto MetaTrader "L3_H3_Expert". El guión original construye una estructura de pivote diaria y despliega dos órdenes pendientes para negociar posibles rupturas o retrocesos alrededor de los máximos y mínimos de la sesión anterior. La versión StockSharp mantiene la misma idea: recalcula los niveles de pivote después de cada vela completa de período de tiempo más alto (diariamente de forma predeterminada) y decide entre detener o limitar las entradas en función de dónde cotiza actualmente el mercado en relación con el rango de ayer.

Lógica de trading

  1. Estadísticas de la sesión

    • Después de cada vela pivote completada (predeterminado: diariamente), la estrategia captura los valores de apertura, máximo, mínimo y cierre de la sesión anterior.
    • El nivel de pivote clásico se calcula como (High + Low + Close) / 3.
    • Estos niveles permanecen activos durante toda la siguiente sesión.
  2. Configuración de entrada

    • Un precio de entrada de compra está anclado ligeramente por encima del mínimo anterior. El desplazamiento es igual al parámetro EntryOffsetPips expresado en múltiplos de tamaño de pip.
    • Un precio de entrada de venta está anclado en el máximo anterior (reflejando al experto original que utilizó el máximo bruto sin ningún amortiguador adicional).
    • Para cada nuevo día de negociación (detectado a través de la suscripción de vela principal), la estrategia coloca nuevas órdenes pendientes:
      • Si el mercado cotiza por debajo del mínimo de ayer, se coloca un parada de compra para capturar una ruptura alcista.
      • Si el mercado cotiza por encima del máximo de ayer, se coloca un stop-de venta para negociar una reversión a la baja.
      • De lo contrario, el algoritmo prefiere órdenes limitadas en los mismos niveles de precios para comprar caídas o vender repuntes nuevamente dentro del rango.
    • Las órdenes de stop-loss se colocan StopLossPips lejos del mínimo/máximo de referencia, exactamente como la versión MQL fijó un stop buffer de 16 puntos.
    • La toma de ganancias de ambas órdenes pendientes está alineada con el nivel de pivote, replicando la ubicación objetivo que se encuentra en el código fuente.
  3. Gestión de pedidos

    • Cada vez que se calcula un nuevo pivote, cualquier orden pendiente en funcionamiento se cancela y se recalcula con los nuevos niveles.
    • La estrategia también cancela órdenes pendientes obsoletas cuando comienza una nueva sesión, evitando la acumulación de órdenes inactivas.
    • Cuando se completa una orden, su referencia interna se borra automáticamente para evitar cancelaciones duplicadas.

Parámetros

Nombre Descripción Predeterminado
EntryCandleType Serie de velas utilizadas para monitorear la sesión actual y activar la colocación de órdenes. marco de tiempo de 5 minutos
PivotCandleType Vela de marco temporal más alto utilizada para medir las estadísticas de la sesión anterior. Marco de tiempo diario
EntryOffsetPips Distancia (en pips) agregada por encima del mínimo anterior para entradas largas. 2
StopLossPips Distancia (en pips) aplicada más allá del mínimo/máximo de referencia para posicionar el stop loss. 16

Diferencias con el experto MQL

  • El script MetaTrader seleccionó diferentes sesiones de negociación (Asiática, Londres, Nueva York) mediante números mágicos y ventanas de tiempo. La versión StockSharp consolida el comportamiento mediante el uso de una vela de período de tiempo más alto configurable (diaria de forma predeterminada) para derivar los niveles de pivote, lo que hace que la lógica sea más fácil de auditar y adaptar entre corredores.
  • MetaTrader se basó en la oferta/demanda actual para decidir entre órdenes stop y límite. La implementación StockSharp utiliza la vela terminada más reciente de la serie EntryCandleType para esa comparación a fin de mantener el flujo de trabajo basado en eventos.
  • Los comentarios de pedidos y los números mágicos eran específicos de la plataforma en MT4. Se omiten aquí intencionadamente; en cambio, la estrategia mantiene referencias directas a sus órdenes pendientes.

Notas de uso

  • Asegúrese de que la seguridad subyacente exponga un PriceStep válido. La estrategia genera una excepción al inicio si la conexión del corredor no proporciona información sobre el tamaño del pip.
  • Para replicar el comportamiento original más fielmente, configure PivotCandleType en una serie de velas horarias agregadas durante la sesión deseada y ajuste los parámetros de compensación/detención en consecuencia.
  • Al igual que con cualquier estrategia de órdenes pendientes, considere la distancia mínima del corredor y las políticas de vencimiento de las órdenes pendientes al implementar en vivo.
using System;
using System.Collections.Generic;

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

namespace StockSharp.Samples.Strategies;

/// <summary>
/// L3/H3 Pivot strategy - trades around Highest/Lowest channel midpoint.
/// Buys when close crosses above the midpoint, sells when below.
/// Uses a longer lookback to simulate daily pivot levels.
/// </summary>
public class L3H3PivotStrategy : Strategy
{
	private readonly StrategyParam<int> _channelPeriod;
	private readonly StrategyParam<DataType> _candleType;

	private decimal _prevClose;
	private decimal _prevMid;
	private bool _hasPrev;

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

	public L3H3PivotStrategy()
	{
		_channelPeriod = Param(nameof(ChannelPeriod), 48)
			.SetDisplay("Channel Period", "Lookback for pivot channel", "Indicators");

		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
			.SetDisplay("Candle Type", "Candle timeframe", "General");
	}

	/// <inheritdoc />
	public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
	{
		return [(Security, CandleType)];
	}

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();
		_prevClose = 0m;
		_prevMid = 0m;
		_hasPrev = false;
	}

	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);

		_hasPrev = false;

		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 high, decimal low)
	{
		if (candle.State != CandleStates.Finished)
			return;

		var close = candle.ClosePrice;
		var mid = (high + low) / 2m;

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

		// Cross above midpoint
		if (_prevClose <= _prevMid && close > mid && Position <= 0)
		{
			if (Position < 0)
				BuyMarket();
			BuyMarket();
		}
		// Cross below midpoint
		else if (_prevClose >= _prevMid && close < mid && Position >= 0)
		{
			if (Position > 0)
				SellMarket();
			SellMarket();
		}

		_prevClose = close;
		_prevMid = mid;
	}
}