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
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.
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.
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.
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.
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
Asigne el valor y la cartera deseados antes de iniciar la estrategia.
Ajuste los cuatro parámetros públicos para alinearlos con el instrumento negociado (volumen, stop-loss, take-profit y distancia de seguimiento).
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;
}
}
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, RelativeStrengthIndex
from StockSharp.Algo.Strategies import Strategy
class sample_trailingstop_mt5_strategy(Strategy):
def __init__(self):
super(sample_trailingstop_mt5_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(60)))
self._ema_period = self.Param("EmaPeriod", 50)
self._rsi_period = self.Param("RsiPeriod", 21)
self._prev_close = 0.0
self._prev_ema = 0.0
self._has_prev = False
@property
def CandleType(self):
return self._candle_type.Value
@CandleType.setter
def CandleType(self, value):
self._candle_type.Value = value
@property
def EmaPeriod(self):
return self._ema_period.Value
@EmaPeriod.setter
def EmaPeriod(self, value):
self._ema_period.Value = value
@property
def RsiPeriod(self):
return self._rsi_period.Value
@RsiPeriod.setter
def RsiPeriod(self, value):
self._rsi_period.Value = value
def OnReseted(self):
super(sample_trailingstop_mt5_strategy, self).OnReseted()
self._prev_close = 0.0
self._prev_ema = 0.0
self._has_prev = False
def OnStarted2(self, time):
super(sample_trailingstop_mt5_strategy, self).OnStarted2(time)
self._prev_close = 0.0
self._prev_ema = 0.0
self._has_prev = False
ema = ExponentialMovingAverage()
ema.Length = self.EmaPeriod
rsi = RelativeStrengthIndex()
rsi.Length = self.RsiPeriod
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(ema, rsi, self._process_candle).Start()
def _process_candle(self, candle, ema_value, rsi_value):
if candle.State != CandleStates.Finished:
return
close = float(candle.ClosePrice)
ema_val = float(ema_value)
rsi_val = float(rsi_value)
if self._has_prev:
if self._prev_close <= self._prev_ema and close > ema_val and rsi_val > 55 and self.Position <= 0:
self.BuyMarket()
elif self._prev_close >= self._prev_ema and close < ema_val and rsi_val < 45 and self.Position >= 0:
self.SellMarket()
self._prev_close = close
self._prev_ema = ema_val
self._has_prev = True
def CreateClone(self):
return sample_trailingstop_mt5_strategy()