La Estrategia Trailing Stop Trigger Manager es una StockSharp adaptación del MetaTrader asesor experto Trailing Sl.mq5. El EA original
no abrió operaciones por sí solo. En lugar de ello, supervisó las posiciones ya abiertas con un número mágico coincidente y reforzó sus
niveles de stop-loss cuando el mercado se movía en la dirección deseada. Esta implementación de C# reproduce ese comportamiento usando
La estrategia de alto nivel de StockSharp API, que ofrece una gestión transparente de trailing-stop que funciona con cualquier instrumento compatible con
StockSharp.
Lógica final
Suscríbete al libro de pedidos para leer las últimas mejores ofertas y mejores cotizaciones.
Detecta si la estrategia mantiene actualmente una posición neta larga o corta.
Calcula el beneficio flotante utilizando el lado apropiado del mercado (mejor oferta para posiciones largas, mejor demanda para posiciones cortas).
Activa el modo de seguimiento una vez que la ganancia excede TriggerPoints (convertida a unidades de precio hasta PriceStep).
Establece el trailing stop a la distancia configurada TrailingPoints de la cotización de mercado actual.
Mueve el trailing stop solo hacia el mercado para seguir obteniendo ganancias adicionales.
Envía una orden de mercado para aplanar la posición tan pronto como la mejor cotización toque el nivel de trailing stop calculado.
Gestión de pedidos y riesgos.
La estrategia no envía órdenes de entrada iniciales. Solo gestiona una posición existente que puede haber sido abierta manualmente.
o por otra estrategia.
Las salidas de mercado se colocan con BuyMarket/SellMarket, reflejando las llamadas PositionModify del código MetaTrader original.
La distancia de parada escala automáticamente con el PriceStep del instrumento, lo que preserva la configuración basada en puntos de
el EA.
Una vez que se cierra la posición, el estado final se restablece para que las nuevas posiciones comiencen desde cero.
Parámetros
Nombre
Tipo
Predeterminado
Descripción
TrailingPoints
int
1000
Distancia entre el precio actual y el trailing stop, medida en incrementos de precio.
TriggerPoints
int
1500
Beneficio mínimo en los pasos de precio requeridos para comenzar a rastrear la posición.
Notas de uso
Adjunte la estrategia al valor cuya posición desea supervisar. Inmediatamente comenzará a rastrear los existentes.
exposición.
Configure el Volume inicial de la estrategia para que coincida con el tamaño de su posición abierta. StockSharp utiliza posiciones netas, por lo que el
La estrategia saldrá de todo el lote cuando se active el trailing stop.
Si el corredor ofrece incrementos de precios aproximados, ajuste TrailingPoints y TriggerPoints en consecuencia para evitar salidas prematuras.
La estrategia mantiene su estado completamente dentro de StockSharp, por lo que se puede combinar con cualquier sistema discrecional o automatizado que
deja la ejecución real de la orden en StockSharp.
Diferencias con el experto MetaTrader original
MetaTrader gestionó posiciones separadas por ticket y las filtró por número mágico. StockSharp trabaja con una posición neta por
seguridad, eliminando la necesidad de filtrar tickets.
Las entradas Setloss, TakeProfit y Lots no se usaron en el EA original. Por lo tanto, se omiten en el StockSharp
versión para mantener la configuración centrada en el comportamiento de seguimiento.
Las modificaciones de órdenes se reemplazan por salidas directas del mercado, que es el enfoque idiomático para compensar cuentas en StockSharp.
using System;
using System.Linq;
using System.Collections.Generic;
using Ecng.Common;
using Ecng.Collections;
using Ecng.Serialization;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Strategy that mirrors the MetaTrader "Trailing Sl" expert by managing trailing stops for existing positions.
/// Adds SMA crossover entries for backtesting.
/// </summary>
public class TrailingStopTriggerManagerStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _trailingPoints;
private readonly StrategyParam<int> _triggerPoints;
private decimal _lastEntryPrice;
private decimal? _activeStopPrice;
private bool _trailingEnabled;
private decimal _trailingDistance;
private decimal _triggerDistance;
private decimal _prevFast;
private decimal _prevSlow;
private bool _hasPrev;
/// <summary>
/// Candle type.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Trailing stop distance in price steps.
/// </summary>
public int TrailingPoints
{
get => _trailingPoints.Value;
set => _trailingPoints.Value = value;
}
/// <summary>
/// Profit distance that activates trailing stop.
/// </summary>
public int TriggerPoints
{
get => _triggerPoints.Value;
set => _triggerPoints.Value = value;
}
/// <summary>
/// Initializes a new instance of the strategy.
/// </summary>
public TrailingStopTriggerManagerStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame())
.SetDisplay("Candle Type", "Timeframe", "General");
_trailingPoints = Param(nameof(TrailingPoints), 1000)
.SetGreaterThanZero()
.SetDisplay("Trailing Points", "Trailing stop distance", "Trailing Management");
_triggerPoints = Param(nameof(TriggerPoints), 1500)
.SetGreaterThanZero()
.SetDisplay("Trigger Points", "Profit to activate trailing", "Trailing Management");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_lastEntryPrice = 0m;
_activeStopPrice = null;
_trailingEnabled = false;
_trailingDistance = 0m;
_triggerDistance = 0m;
_prevFast = 0m;
_prevSlow = 0m;
_hasPrev = false;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var step = Security?.PriceStep ?? 1m;
if (step <= 0m) step = 1m;
_trailingDistance = step * TrailingPoints;
_triggerDistance = step * TriggerPoints;
var smaFast = new SimpleMovingAverage { Length = 10 };
var smaSlow = new SimpleMovingAverage { Length = 30 };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(smaFast, smaSlow, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawOwnTrades(area);
}
}
/// <inheritdoc />
protected override void OnOwnTradeReceived(MyTrade trade)
{
base.OnOwnTradeReceived(trade);
_lastEntryPrice = trade.Trade.Price;
}
private void ProcessCandle(ICandleMessage candle, decimal fast, decimal slow)
{
if (candle.State != CandleStates.Finished)
return;
var price = candle.ClosePrice;
// Trailing stop management
if (Position > 0 && _lastEntryPrice > 0)
{
var profit = price - _lastEntryPrice;
if (!_trailingEnabled && profit >= _triggerDistance)
{
_trailingEnabled = true;
_activeStopPrice = price - _trailingDistance;
}
else if (_trailingEnabled)
{
var desiredStop = price - _trailingDistance;
if (!_activeStopPrice.HasValue || desiredStop > _activeStopPrice.Value)
_activeStopPrice = desiredStop;
}
if (_trailingEnabled && _activeStopPrice.HasValue && price <= _activeStopPrice.Value)
{
SellMarket();
ResetTrailingState();
return;
}
}
else if (Position < 0 && _lastEntryPrice > 0)
{
var profit = _lastEntryPrice - price;
if (!_trailingEnabled && profit >= _triggerDistance)
{
_trailingEnabled = true;
_activeStopPrice = price + _trailingDistance;
}
else if (_trailingEnabled)
{
var desiredStop = price + _trailingDistance;
if (!_activeStopPrice.HasValue || desiredStop < _activeStopPrice.Value)
_activeStopPrice = desiredStop;
}
if (_trailingEnabled && _activeStopPrice.HasValue && price >= _activeStopPrice.Value)
{
BuyMarket();
ResetTrailingState();
return;
}
}
// SMA crossover entries
if (_hasPrev)
{
var crossUp = _prevFast <= _prevSlow && fast > slow;
var crossDown = _prevFast >= _prevSlow && fast < slow;
if (crossUp && Position <= 0)
{
if (Position < 0)
BuyMarket();
BuyMarket();
ResetTrailingState();
}
else if (crossDown && Position >= 0)
{
if (Position > 0)
SellMarket();
SellMarket();
ResetTrailingState();
}
}
_prevFast = fast;
_prevSlow = slow;
_hasPrev = true;
}
private void ResetTrailingState()
{
_trailingEnabled = false;
_activeStopPrice = null;
}
}
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 SimpleMovingAverage
from StockSharp.Algo.Strategies import Strategy
class trailing_stop_trigger_manager_strategy(Strategy):
def __init__(self):
super(trailing_stop_trigger_manager_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(1))) \
.SetDisplay("Candle Type", "Timeframe", "General")
self._trailing_points = self.Param("TrailingPoints", 1000) \
.SetGreaterThanZero() \
.SetDisplay("Trailing Points", "Trailing stop distance", "Trailing Management")
self._trigger_points = self.Param("TriggerPoints", 1500) \
.SetGreaterThanZero() \
.SetDisplay("Trigger Points", "Profit to activate trailing", "Trailing Management")
self._last_entry_price = 0.0
self._active_stop_price = None
self._trailing_enabled = False
self._trailing_distance = 0.0
self._trigger_distance = 0.0
self._prev_fast = 0.0
self._prev_slow = 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 TrailingPoints(self):
return self._trailing_points.Value
@TrailingPoints.setter
def TrailingPoints(self, value):
self._trailing_points.Value = value
@property
def TriggerPoints(self):
return self._trigger_points.Value
@TriggerPoints.setter
def TriggerPoints(self, value):
self._trigger_points.Value = value
def OnReseted(self):
super(trailing_stop_trigger_manager_strategy, self).OnReseted()
self._last_entry_price = 0.0
self._active_stop_price = None
self._trailing_enabled = False
self._trailing_distance = 0.0
self._trigger_distance = 0.0
self._prev_fast = 0.0
self._prev_slow = 0.0
self._has_prev = False
def OnStarted2(self, time):
super(trailing_stop_trigger_manager_strategy, self).OnStarted2(time)
step = 1.0
if self.Security is not None and self.Security.PriceStep is not None:
s = float(self.Security.PriceStep)
if s > 0:
step = s
self._trailing_distance = step * self.TrailingPoints
self._trigger_distance = step * self.TriggerPoints
sma_fast = SimpleMovingAverage()
sma_fast.Length = 10
sma_slow = SimpleMovingAverage()
sma_slow.Length = 30
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(sma_fast, sma_slow, self._process_candle).Start()
def OnOwnTradeReceived(self, trade):
super(trailing_stop_trigger_manager_strategy, self).OnOwnTradeReceived(trade)
self._last_entry_price = float(trade.Trade.Price)
def _process_candle(self, candle, fast, slow):
if candle.State != CandleStates.Finished:
return
price = float(candle.ClosePrice)
fv = float(fast)
sv = float(slow)
# Trailing stop management for long
if self.Position > 0 and self._last_entry_price > 0:
profit = price - self._last_entry_price
if not self._trailing_enabled and profit >= self._trigger_distance:
self._trailing_enabled = True
self._active_stop_price = price - self._trailing_distance
elif self._trailing_enabled:
desired_stop = price - self._trailing_distance
if self._active_stop_price is None or desired_stop > self._active_stop_price:
self._active_stop_price = desired_stop
if self._trailing_enabled and self._active_stop_price is not None and price <= self._active_stop_price:
self.SellMarket()
self._reset_trailing_state()
return
# Trailing stop management for short
elif self.Position < 0 and self._last_entry_price > 0:
profit = self._last_entry_price - price
if not self._trailing_enabled and profit >= self._trigger_distance:
self._trailing_enabled = True
self._active_stop_price = price + self._trailing_distance
elif self._trailing_enabled:
desired_stop = price + self._trailing_distance
if self._active_stop_price is None or desired_stop < self._active_stop_price:
self._active_stop_price = desired_stop
if self._trailing_enabled and self._active_stop_price is not None and price >= self._active_stop_price:
self.BuyMarket()
self._reset_trailing_state()
return
# SMA crossover entries
if self._has_prev:
cross_up = self._prev_fast <= self._prev_slow and fv > sv
cross_down = self._prev_fast >= self._prev_slow and fv < sv
if cross_up and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
self._reset_trailing_state()
elif cross_down and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._reset_trailing_state()
self._prev_fast = fv
self._prev_slow = sv
self._has_prev = True
def _reset_trailing_state(self):
self._trailing_enabled = False
self._active_stop_price = None
def CreateClone(self):
return trailing_stop_trigger_manager_strategy()