Ver en GitHub

Estrategia MultiBreakout V001k

Descripción general

La estrategia MultiBreakout V001k reproduce el clásico asesor experto MT4 "Multibreakout_v001k". Opera con rupturas de la sesión horaria anterior acumulando órdenes de compra y venta una vez finalizada la hora de referencia. La gestión de posiciones sigue la lógica original de obtención de beneficios y equilibrio por etapas, incluido el equilibrio móvil opcional que rastrea las paradas utilizando los últimos máximos y mínimos horarios.

Reglas de trading

  1. Hora de referencia – Se pueden definir hasta cuatro sesiones de negociación. Después de que se cierra cada hora de sesión habilitada, la estrategia mide la vela horaria terminada y prepara órdenes para la siguiente hora.
  2. Ubicación de entrada
    • Las órdenes de stop de compra se colocan en el máximo de la hora anterior más el diferencial actual y un colchón de entrada adicional (PipsForEntry).
    • Las órdenes Sell-Stop se colocan en el mínimo de la hora anterior menos el colchón de entrada.
    • Cada lado coloca NumberOfOrdersPerSide órdenes pendientes con volumen idéntico.
  3. Escalera de obtención de beneficios: cada entrada recibe un objetivo de beneficio individual espaciado por TakeProfitIncrement puntos. Cuando el mercado toca cada nivel, la estrategia cierra un tramo en el mercado para imitar la cola de obtención de beneficios original de MT4.
  4. Gestión de stop-loss: se establece un stop inicial a StopLoss puntos del precio de entrada. Una vez que el precio se mueve BreakEven puntos a favor, el stop salta al punto de equilibrio. Si MovingBreakEven está habilitado y pasa el retraso configurado, la parada sigue utilizando los mínimos horarios más recientes (para largos) o máximos (para cortos) cuando esos niveles continúan apretándose.
  5. Salida de la sesión: a las ExitMinute dentro de la hora de la sesión configurada, la estrategia cierra por completo todas las posiciones y elimina todas las órdenes pendientes.

Parámetros

Parámetro Descripción
TradeVolume Volumen para cada orden de ruptura.
NumberOfOrdersPerSide Cantidad de órdenes pendientes apiladas para ambas direcciones.
TakeProfitIncrement Distancia (en puntos) entre objetivos de obtención de beneficios consecutivos.
PipsForEntry Se agregaron puntos adicionales al disparador de ruptura por encima/por debajo del rango de la sesión.
StopLoss Distancia de parada inicial desde el precio de entrada.
BreakEven Beneficio (en puntos) requerido antes de que el stop llegue al punto de equilibrio.
MovingBreakEven Habilita la lógica móvil de seguimiento del punto de equilibrio.
MovingBreakEvenHoursToStart Retraso (en horas) después de la sesión de referencia antes de que el punto de equilibrio móvil pueda retroceder.
BrokerOffsetToGmt Desfase horario entre la hora del corredor y el GMT utilizado por el programador de equilibrio móvil.
TradeSession1..4 Alterna para las cuatro sesiones de negociación independientes.
SessionHour1..4 Hora (0-23) que define cada sesión de referencia.
ExitMinute Minuto dentro de la hora de sesión para liquidar posiciones y cancelar órdenes.
CandleType Tipo de vela utilizado para medir la hora de referencia (el valor predeterminado es velas de 1 hora).

Notas de uso

  • Asegúrese de que el instrumento tenga un PriceStep válido para que los cálculos del valor en puntos coincidan con la versión MT4.
  • La estrategia supone que los tiempos de los corredores están alineados con las marcas de tiempo de las velas. Ajuste BrokerOffsetToGmt cuando históricamente se haya utilizado un desplazamiento de servidor MT4 diferente.
  • El punto de equilibrio móvil evalúa las dos últimas velas horarias terminadas antes de apretar el tope, igualando el comportamiento del asesor experto original.
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>
/// Multi-breakout strategy - Highest/Lowest channel breakout.
/// Buys when price breaks above the channel high, sells when below channel low.
/// Reverses position on opposite breakout.
/// </summary>
public class MultiBreakoutV001kStrategy : Strategy
{
	private readonly StrategyParam<int> _channelPeriod;
	private readonly StrategyParam<DataType> _candleType;

	private decimal _prevClose;
	private decimal _prevHigh;
	private decimal _prevLow;
	private bool _hasPrev;

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

	public MultiBreakoutV001kStrategy()
	{
		_channelPeriod = Param(nameof(ChannelPeriod), 20)
			.SetDisplay("Channel Period", "Lookback for breakout 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;
		_prevHigh = 0m;
		_prevLow = 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;
			_prevHigh = mid;
			_prevLow = mid;
			_hasPrev = true;
			return;
		}

		// Cross above midpoint - go long
		if (_prevClose <= _prevHigh && close > mid && Position <= 0)
		{
			if (Position < 0)
				BuyMarket();
			BuyMarket();
		}
		// Cross below midpoint - go short
		else if (_prevClose >= _prevLow && close < mid && Position >= 0)
		{
			if (Position > 0)
				SellMarket();
			SellMarket();
		}

		_prevClose = close;
		_prevHigh = mid;
		_prevLow = mid;
	}
}