Ver en GitHub

Ejemplo de estrategia Trailingstop MT5

Descripción general

SampleTrailingstopMt5Strategy reproduce el comportamiento del MetaTrader5 asesor experto SampleTrailingstop-MT5.mq5 utilizando el nivel alto de StockSharp API. La estrategia mantiene constantemente órdenes stop de ruptura emparejadas, protege las posiciones ocupadas con órdenes de salida dedicadas y aplica un stop dinámico una vez que la operación se vuelve rentable. Todos los cálculos se basan en el paso del precio del instrumento para que la lógica coincida con la implementación original basada en "puntos".

Lógica comercial

  1. Fuente de datos. La estrategia se suscribe a cotizaciones de nivel 1 para recibir los mejores precios de oferta y demanda que impulsan la orden y las actualizaciones del trailing stop.
  2. Pedidos de entrada.
    • Se coloca una orden stop de compra por encima del mercado actual usando BuyStop. El pedido se actualiza solo cuando se completa la instancia anterior.
    • Una orden de venta stop refleja la entrada larga utilizando SellStop por debajo del mercado.
    • Ambas órdenes de entrada comparten el mismo volumen configurable, distancias de stop-loss y take-profit. Los pedidos también reciben una fecha de vencimiento con un día de anticipación, que coincide con la implementación de MQL.
  3. Protección de posición.
    • Después de la ejecución, la estrategia rastrea la posición neta firmada y el precio de entrada promedio.
    • Se crean órdenes de salida y toma de ganancias separadas (SellStop/BuyStop y SellLimit/BuyLimit) para que los niveles de protección permanezcan en el intercambio incluso si las órdenes de entrada se cancelan o vencen.
    • Las órdenes de salida se sincronizan continuamente con el tamaño de la posición actual y el precio de entrada promedio más reciente.
  4. Lógica final.
    • Cuando el beneficio flotante alcanza la distancia final configurada, el stop protector se ajusta para mantener esa distancia de la oferta actual (para largos) o demanda (para cortos).
    • El trailing stop nunca cruza el precio de entrada y respeta un incremento mínimo de actualización igual a un paso de precio.
  5. Seguimiento de posición. Cada operación propia actualiza el valor de la posición acumulada y recalcula el precio de entrada promedio ponderado para que las ejecuciones y reversiones parciales se procesen correctamente.

Parámetros

Parámetro Descripción
TradeVolume Volumen de orden fijo (lotes o contratos) utilizado para ambas órdenes stop de ruptura.
TakeProfitPoints Distancia en puntos del instrumento para el objetivo de ganancias. Establezca en cero para desactivar la obtención de beneficios.
StopLossPoints Distancia en puntos para el stop-loss protector.
TrailingStopPoints Distancia de seguimiento en puntos aplicada una vez que la posición es rentable. Zero desactiva el seguimiento.

Notas de comportamiento

  • Las órdenes de inscripción solo se vuelven a enviar después de que finaliza la instancia anterior (completada, cancelada o vencida). Esto refleja la lógica CheckPendingOrder del experto original.
  • Las distancias de stop-loss y take-profit siempre se convierten en valores de precio utilizando Security.PriceStep, lo que garantiza un comportamiento consistente entre diferentes instrumentos.
  • Si la posición está completamente cerrada, la estrategia cancela automáticamente todas las órdenes de salida restantes y restablece los promedios internos.
  • La estrategia se basa únicamente en datos de nivel 1 y no requiere velas ni indicadores, lo que mantiene la conversión cerca de la plantilla MQL.

Uso

  1. Asigne el valor y la cartera deseados antes de iniciar la estrategia.
  2. Ajuste los cuatro parámetros públicos para alinearlos con el instrumento negociado (volumen, stop-loss, take-profit y distancia de seguimiento).
  3. Lanzar la estrategia. Gestionará de forma autónoma las órdenes de ruptura y la protección de posiciones en tiempo real.
namespace StockSharp.Samples.Strategies;

using System;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.Messages;

/// <summary>
/// Sample Trailingstop MT5 strategy: EMA + RSI confirmation.
/// Buys when close above EMA and RSI above 50, sells when close below EMA and RSI below 50.
/// </summary>
public class SampleTrailingstopMt5Strategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _emaPeriod;
	private readonly StrategyParam<int> _rsiPeriod;

	private decimal _prevClose;
	private decimal _prevEma;
	private bool _hasPrev;

	public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
	public int EmaPeriod { get => _emaPeriod.Value; set => _emaPeriod.Value = value; }
	public int RsiPeriod { get => _rsiPeriod.Value; set => _rsiPeriod.Value = value; }

	public SampleTrailingstopMt5Strategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(60).TimeFrame())
			.SetDisplay("Candle Type", "Candle timeframe", "General");
		_emaPeriod = Param(nameof(EmaPeriod), 50)
			.SetGreaterThanZero()
			.SetDisplay("EMA Period", "EMA period", "Indicators");
		_rsiPeriod = Param(nameof(RsiPeriod), 21)
			.SetGreaterThanZero()
			.SetDisplay("RSI Period", "RSI period", "Indicators");
	}

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

	/// <inheritdoc />
	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);
		_prevClose = 0;
		_prevEma = 0;
		_hasPrev = false;
		var ema = new ExponentialMovingAverage { Length = EmaPeriod };
		var rsi = new RelativeStrengthIndex { Length = RsiPeriod };
		var subscription = SubscribeCandles(CandleType);
		subscription.Bind(ema, rsi, ProcessCandle).Start();
	}

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

		if (_hasPrev)
		{
			if (_prevClose <= _prevEma && candle.ClosePrice > emaValue && rsiValue > 55 && Position <= 0)
				BuyMarket();
			else if (_prevClose >= _prevEma && candle.ClosePrice < emaValue && rsiValue < 45 && Position >= 0)
				SellMarket();
		}

		_prevClose = candle.ClosePrice;
		_prevEma = emaValue;
		_hasPrev = true;
	}
}