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;
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Indicators import ExponentialMovingAverage
from StockSharp.Algo.Strategies import Strategy
from datatype_extensions import *
from indicator_extensions import *
class tp_sl_trailing_strategy(Strategy):
"""EMA price crossover for entries."""
def __init__(self):
super(tp_sl_trailing_strategy, self).__init__()
self._ema_period = self.Param("EmaPeriod", 20).SetGreaterThanZero().SetDisplay("EMA Period", "EMA lookback", "Indicators")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(1))).SetDisplay("Candle Type", "Timeframe", "General")
@property
def CandleType(self): return self._candle_type.Value
@CandleType.setter
def CandleType(self, value): self._candle_type.Value = value
def OnReseted(self):
super(tp_sl_trailing_strategy, self).OnReseted()
self._prev_close = 0
self._prev_ema = 0
def OnStarted2(self, time):
super(tp_sl_trailing_strategy, self).OnStarted2(time)
self._prev_close = 0
self._prev_ema = 0
ema = ExponentialMovingAverage()
ema.Length = self._ema_period.Value
sub = self.SubscribeCandles(self.CandleType)
sub.Bind(ema, self.OnProcess).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, sub)
self.DrawIndicator(area, ema)
self.DrawOwnTrades(area)
def OnProcess(self, candle, ema_val):
if candle.State != CandleStates.Finished:
return
close = float(candle.ClosePrice)
if self._prev_close == 0 or self._prev_ema == 0:
self._prev_close = close
self._prev_ema = float(ema_val)
return
ema_f = float(ema_val)
if self._prev_close < self._prev_ema and close >= ema_f and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
elif self._prev_close > self._prev_ema and close <= ema_f and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._prev_close = close
self._prev_ema = ema_f
def CreateClone(self):
return tp_sl_trailing_strategy()