Ver en GitHub

Estrategia TP SL Trailing

Descripción general

Esta estrategia es una conversión directa del asesor experto de MetaTrader 5 "TP SL Trailing". La estrategia no genera entradas por sí misma. En cambio, gestiona posiciones existentes instalando un stop-loss y take-profit de protección y arrastrando el stop una vez que la operación se vuelve rentable. La configuración basada en pips coincide con los parámetros del script original y permite que la lógica se adjunte a cualquier símbolo admitido por StockSharp.

Lógica de negociación

  • Cuando aparece una nueva posición, la estrategia puede opcionalmente establecer un stop-loss y take-profit inicial usando las distancias en pips configuradas. Este comportamiento está controlado por el flag Only Zero Values, igual que en el asesor experto original.
  • Para posiciones largas, la estrategia mueve el stop-loss hacia arriba una vez que la ganancia no realizada excede la suma del trailing stop y el trailing step. El stop se mueve a precio actual - trailing stop, garantizando que se asegure una porción mínima del beneficio.
  • Para posiciones cortas, la estrategia refleja la misma idea y mueve el stop hacia abajo una vez que el beneficio excede los umbrales de trailing.
  • Si tanto el trailing stop como el trailing step son cero, la estrategia deja el stop-loss sin tocar.
  • El nivel de take-profit nunca se arrastra. Solo se establece durante la fase de colocación inicial cuando Only Zero Values está habilitado, replicando completamente el comportamiento MQL.

Parámetros

Nombre Descripción
CandleType Marco temporal de las velas usadas para rastrear movimientos de precio. Un marco temporal más rápido mejora la precisión del trailing.
StopLossPips Distancia en pips entre el precio de entrada y el stop-loss inicial. Aplicado solo cuando Only Zero Values está habilitado.
TakeProfitPips Distancia en pips entre el precio de entrada y el take-profit inicial. Aplicado solo cuando Only Zero Values está habilitado.
TrailingStopPips Distancia de trailing core en pips. Define cuán lejos detrás del precio actual debe permanecer el stop después de la activación.
TrailingStepPips Buffer adicional de pips que debe superarse antes de que el stop se mueva de nuevo. Previene actualizaciones de stop demasiado frecuentes.
OnlyZeroValues Coincide con el flag EA original. Cuando está habilitado, las órdenes de protección iniciales se crean solo para posiciones que actualmente no tienen stop-loss o take-profit asignados.

Notas de conversión

  • Las distancias en pips se convierten a unidades de precio usando el PriceStep del instrumento. Esto mantiene la lógica agnóstica al instrumento y refleja el ajuste de 3/5 dígitos en la versión MQL.
  • Las órdenes de protección se re-registran cada vez que la lógica de trailing mueve el stop-loss. Las órdenes activas de una posición anterior se cancelan automáticamente cuando el tamaño de la posición vuelve a cero.
  • Todos los comentarios de código están escritos en inglés, mientras que esta documentación es intencionalmente detallada para ayudar a reproducir cada decisión tomada durante el proceso de porteo.
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>
/// TP SL Trailing strategy. Uses EMA with price crossover for entries.
/// </summary>
public class TpSlTrailingStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _emaPeriod;
	private decimal? _prevClose;
	private decimal? _prevEma;

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

	public TpSlTrailingStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame()).SetDisplay("Candle Type", "Timeframe", "General");
		_emaPeriod = Param(nameof(EmaPeriod), 20).SetGreaterThanZero().SetDisplay("EMA Period", "EMA lookback", "Indicators");
	}

	public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities() => [(Security, CandleType)];

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

	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);
		_prevClose = null; _prevEma = null;
		var ema = new ExponentialMovingAverage { Length = EmaPeriod };
		var subscription = SubscribeCandles(CandleType);
		subscription.Bind(ema, ProcessCandle).Start();
		var area = CreateChartArea();
		if (area != null) { DrawCandles(area, subscription); DrawIndicator(area, ema); DrawOwnTrades(area); }
	}

	private void ProcessCandle(ICandleMessage candle, decimal emaVal)
	{
		if (candle.State != CandleStates.Finished) return;
		var close = candle.ClosePrice;
		if (!IsFormedAndOnlineAndAllowTrading()) { _prevClose = close; _prevEma = emaVal; return; }
		if (_prevClose == null || _prevEma == null) { _prevClose = close; _prevEma = emaVal; return; }
		if (_prevClose.Value < _prevEma.Value && close >= emaVal && Position <= 0) { if (Position < 0) BuyMarket(); BuyMarket(); }
		else if (_prevClose.Value > _prevEma.Value && close <= emaVal && Position >= 0) { if (Position > 0) SellMarket(); SellMarket(); }
		_prevClose = close; _prevEma = emaVal;
	}
}