Ver en GitHub

Estrategia Straddle Trail v2.40

La Estrategia Straddle Trail v2.40 es una versión StockSharp del asesor experto MetaTrader 4 "Straddle&Trail" (versión 2.40). El algoritmo prepara un par simétrico de órdenes stop antes de un evento de alto impacto, gestiona automáticamente la posición activada con lógica de punto de equilibrio y trailing-stop, y puede reaccionar a las operaciones manuales que ya existen en la cuenta.

Flujo de trabajo principal

  1. Preparación
    • La estrategia se suscribe a actualizaciones del libro de pedidos para realizar un seguimiento de la mejor oferta/demanda y a velas diminutas (configurables) para tomar decisiones de programación.
    • Los pips se calculan a partir de la configuración del instrumento para que todas las distancias definidas en pips se conviertan correctamente en precios.
  2. Colocación a horcajadas
    • En el tiempo de entrega configurado antes del evento (PreEventEntryMinutes), o inmediatamente si PlaceStraddleImmediately está habilitado, se colocan una orden de compra y venta a DistanceFromPrice pips por encima y por debajo del mercado.
    • Antes del evento, las órdenes pendientes se pueden volver a centrar cada minuto si AdjustPendingOrders está habilitado. Los ajustes se detienen StopAdjustMinutes antes del evento.
  3. Gestión de pedidos
    • Una vez que se activa un lado, la eliminación opcional de la orden pendiente opuesta (RemoveOppositeOrder) evita la doble exposición.
    • ShutdownNow junto con ShutdownOption permite aplanar posiciones abiertas y/o cancelar órdenes pendientes bajo demanda.
  4. Protección de posición
    • Los niveles iniciales de stop-loss y take-profit se derivan de los parámetros basados en pips.
    • Cuando el precio alcanza el punto de equilibrio, el stop se mueve para bloquear BreakevenLockPips de ganancia.
    • El seguimiento comienza inmediatamente o después del punto de equilibrio (dependiendo de TrailAfterBreakeven).
    • Si ManageManualTrades es verdadero, cualquier posición manual detectada por la estrategia se protegerá utilizando las mismas reglas.

Parámetros

Parámetro Descripción
ShutdownNow Fuerza la lógica de apagado a ejecutarse en el siguiente cierre de vela.
ShutdownOption Elige qué cerrar: todo, solo posiciones activadas, solo largas, solo cortas, todas las órdenes pendientes, solo paradas de compra o solo paradas de venta.
DistanceFromPrice Distancia en pips entre el precio actual y las órdenes stop pendientes.
StopLossPips Distancia inicial de stop-loss en pips.
TakeProfitPips Distancia inicial de toma de ganancias en pips. Establezca en 0 para desactivar el nivel de obtención de beneficios.
TrailPips Distancia del trailing-stop en pips. Establezca en 0 para desactivar el seguimiento.
TrailAfterBreakeven Si es verdadero, el seguimiento solo comenzará después de que se alcance el punto de equilibrio.
BreakevenLockPips Beneficio (en pips) bloqueado una vez que se activa el disparador del punto de equilibrio.
BreakevenTriggerPips Umbral de beneficio (en pips) que activa el movimiento de equilibrio.
EventHour / EventMinute Hora programada para el evento de noticias (hora del corredor). Establezca ambos en 0 para desactivar la programación y utilizar el modo manual/inmediato.
PreEventEntryMinutes Minutos antes del evento cuando se coloca el straddle.
StopAdjustMinutes Minutos antes del evento cuando cesan los ajustes de pedidos. El valor mínimo es 1 minuto.
RemoveOppositeOrder Elimina la orden pendiente opuesta después de que se llena un lado del straddle.
AdjustPendingOrders Vuelve a centrar las órdenes pendientes cada minuto hasta alcanzar la ventana de ajuste de parada.
PlaceStraddleImmediately Coloca el straddle tan pronto como comienza la estrategia, ignorando el calendario del evento.
ManageManualTrades Extiende la lógica de equilibrio y seguimiento a posiciones manuales.
CandleType Serie de velas utilizada para la lógica de sincronización y programación (el valor predeterminado es un período de tiempo de 1 minuto).

Notas de uso

  • Configure siempre el tamaño de pip correcto para el instrumento a través de la configuración de seguridad para que las distancias basadas en pips se traduzcan en precios con precisión.
  • La estrategia cierra posiciones utilizando órdenes de mercado cuando se cumple una condición de límite de pérdidas o toma de ganancias, lo que refleja cómo el EA original realizó ajustes de límite manuales.
  • Cuando PlaceStraddleImmediately está deshabilitado y el programa está activo, el straddle se coloca solo una vez por día de negociación. Restablezca la estrategia para prepararse para otro evento el mismo día.
  • Los controles de apagado se pueden utilizar como freno de emergencia para reducir rápidamente la exposición y eliminar órdenes pendientes en todos los escenarios.

Detalles de conversión

  • Todos los comentarios del código se han traducido al inglés y se han ampliado con explicaciones adicionales para mayor claridad.
  • Los métodos StockSharp API de alto nivel (BuyStop, SellStop, ClosePosition) se utilizan para mantener la implementación cerca de las mejores prácticas del marco.
  • El algoritmo evita las búsquedas directas de indicadores y, en cambio, se basa en las velas vinculadas y las suscripciones al libro de órdenes, como lo exigen las pautas del proyecto.
using System;
using System.Linq;
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>
/// Straddle breakout strategy converted from the MetaTrader 4 Straddle and Trail EA (v2.40).
/// Uses price channel breakouts with trailing stop management.
/// </summary>
public class StraddleTrailV240Strategy : Strategy
{
	private readonly StrategyParam<int> _channelPeriod;
	private readonly StrategyParam<decimal> _stopLoss;
	private readonly StrategyParam<decimal> _takeProfit;
	private readonly StrategyParam<DataType> _candleType;

	private readonly List<decimal> _highs = new();
	private readonly List<decimal> _lows = new();

	/// <summary>
	/// Channel lookback period for breakout detection.
	/// </summary>
	public int ChannelPeriod
	{
		get => _channelPeriod.Value;
		set => _channelPeriod.Value = value;
	}

	/// <summary>
	/// Stop loss distance in absolute price units.
	/// </summary>
	public decimal StopLoss
	{
		get => _stopLoss.Value;
		set => _stopLoss.Value = value;
	}

	/// <summary>
	/// Take profit distance in absolute price units.
	/// </summary>
	public decimal TakeProfit
	{
		get => _takeProfit.Value;
		set => _takeProfit.Value = value;
	}

	/// <summary>
	/// Candle type used by the strategy.
	/// </summary>
	public DataType CandleType
	{
		get => _candleType.Value;
		set => _candleType.Value = value;
	}

	/// <summary>
	/// Initializes a new instance.
	/// </summary>
	public StraddleTrailV240Strategy()
	{
		_channelPeriod = Param(nameof(ChannelPeriod), 20)
			.SetGreaterThanZero()
			.SetDisplay("Channel Period", "Lookback period for breakout levels", "Parameters");

		_stopLoss = Param(nameof(StopLoss), 500m)
			.SetNotNegative()
			.SetDisplay("Stop Loss", "Stop loss distance", "Risk");

		_takeProfit = Param(nameof(TakeProfit), 500m)
			.SetNotNegative()
			.SetDisplay("Take Profit", "Take profit distance", "Risk");

		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(2).TimeFrame())
			.SetDisplay("Candle Type", "Candle subscription used", "General");
	}

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

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();
		_highs.Clear();
		_lows.Clear();
	}

	/// <inheritdoc />
	protected override void OnStarted2(DateTime time)
	{
		var ema = new EMA { Length = 10 };

		var subscription = SubscribeCandles(CandleType);
		subscription
			.Bind(ema, ProcessCandle)
			.Start();

		var area = CreateChartArea();
		if (area != null)
		{
			DrawCandles(area, subscription);
			DrawIndicator(area, ema);
			DrawOwnTrades(area);
		}

		var tp = TakeProfit > 0 ? new Unit(TakeProfit, UnitTypes.Absolute) : null;
		var sl = StopLoss > 0 ? new Unit(StopLoss, UnitTypes.Absolute) : null;
		StartProtection(tp, sl);

		base.OnStarted2(time);
	}

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

		_highs.Add(candle.HighPrice);
		_lows.Add(candle.LowPrice);

		while (_highs.Count > ChannelPeriod)
			_highs.RemoveAt(0);
		while (_lows.Count > ChannelPeriod)
			_lows.RemoveAt(0);

		if (_highs.Count < ChannelPeriod)
			return;

		if (!IsFormedAndOnlineAndAllowTrading())
			return;

		var upper = _highs.Take(_highs.Count - 1).Max();
		var lower = _lows.Take(_lows.Count - 1).Min();

		// Breakout above channel -> buy
		if (candle.ClosePrice > upper && Position <= 0)
		{
			if (Position < 0)
				BuyMarket(Math.Abs(Position));
			BuyMarket(Volume);
		}
		// Breakout below channel -> sell
		else if (candle.ClosePrice < lower && Position >= 0)
		{
			if (Position > 0)
				SellMarket(Position);
			SellMarket(Volume);
		}
	}

	/// <summary>
	/// Shutdown modes enum (preserved from original).
	/// </summary>
	public enum ShutdownModes
	{
		All = 0,
		TriggeredPositions = 1,
		TriggeredLong = 2,
		TriggeredShort = 3,
		PendingOrders = 4,
		PendingLong = 5,
		PendingShort = 6
	}
}