ProfitLossTrailStrategy es un ayudante de gestión de riesgos convertido desde el asesor experto de MetaTrader ProfitLossTrailEA v2.30. La estrategia no genera entradas por sí misma. En su lugar, supervisa la posición actualmente abierta en el valor configurado y aplica automáticamente salidas de protección:
niveles iniciales de stop-loss y take-profit;
gestión de trailing stop con distancia de activación opcional y control de paso trailing;
protección break-even con disparador de ganancia y desplazamiento configurables;
capacidad de eliminar niveles de protección existentes cuando el trader quiere gestionarlos manualmente.
El comportamiento coincide estrechamente con el modo de gestión de "cesta" del EA original: todas las órdenes de la misma dirección se tratan como una sola posición y los niveles de protección se recalculan cuando cambia la exposición.
Referencia de parámetros
Parámetro
Descripción
Manage As Basket
Cuando está habilitado (predeterminado), cada ejecución en la misma dirección recalcula el precio medio de entrada y refresca niveles de stop-loss/take-profit. Desactive el flag para conservar los niveles iniciales después de la primera ejecución.
Enable Take Profit
Activa o desactiva la gestión automática de take-profit.
Take Profit (pips)
Distancia en pips entre el precio de entrada y el objetivo de take-profit.
Enable Stop Loss
Activa o desactiva la gestión automática de stop-loss.
Stop Loss (pips)
Distancia en pips entre el precio de entrada y el stop de protección inicial.
Enable Trailing Stop
Activa la gestión dinámica del stop cuando la posición está en ganancia.
Trailing Activation (pips)
Ganancia mínima en pips requerida antes de que el trailing stop pueda moverse. Use 0 para activar inmediatamente.
Trailing Stop (pips)
Distancia trailing base expresada en pips.
Trailing Step (pips)
Ganancia adicional que debe obtenerse antes de ajustar más el trailing stop.
Enable Break-Even
Habilita la rutina break-even que mueve el stop a ganancia después de una distancia disparadora.
Break-Even Trigger (pips)
Distancia de ganancia que activa el movimiento a break-even.
Break-Even Offset (pips)
Desplazamiento extra añadido por encima (largo) o por debajo (corto) del precio de entrada cuando break-even se activa.
Remove Take Profit
Cuando se establece en true, se limpia cualquier valor actual de take-profit y no se emiten salidas take-profit.
Remove Stop Loss
Cuando se establece en true, se limpia cualquier valor actual de stop-loss y no se emiten salidas stop-loss ni trailing.
Candle Type
Serie de velas usada para monitorizar la acción del precio. Las comprobaciones de trailing, break-even y salida se evalúan en velas finalizadas.
Notas de uso
Adjunte la estrategia a un valor y asegúrese de que las órdenes se coloquen externamente o por otra estrategia. ProfitLossTrailStrategy se centra exclusivamente en gestionar la exposición abierta.
Configure los parámetros basados en pips para que coincidan con la cotización del instrumento. El tamaño de pip se deriva automáticamente de Security.PriceStep.
Cuando tanto break-even como trailing stop están habilitados, el ajuste de break-even ocurre primero. Los pasos trailing posteriores solo ajustarán el stop si el nuevo nivel mejora el precio de protección actual al menos por la distancia de paso trailing especificada.
Establecer Remove Stop Loss desactiva simultáneamente stop-loss, trailing y lógica break-even, reflejando el comportamiento del EA original.
La estrategia usa órdenes de mercado (BuyMarket/SellMarket) para cerrar posiciones cuando se alcanzan niveles de protección.
Notas de conversión
Los modos "Order_By_Order" y "Same_Type_As_One" de MetaTrader se representan mediante el flag Manage As Basket. Gestionar niveles de stop por ticket no está soportado en StockSharp, por lo que el modo cesta se aplica por defecto.
Los filtros de magic number y comentario del EA original no son necesarios; la estrategia actúa solo sobre Strategy.Security configurado.
El dibujo en pantalla, las alertas sonoras y las actualizaciones de UI basadas en temporizador se omitieron porque StockSharp ya expone diagnósticos mediante logs y vinculaciones de gráfico.
using System;
using System.Collections.Generic;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
public class ProfitLossTrailStrategy : Strategy
{
private readonly StrategyParam<int> _fastPeriod;
private readonly StrategyParam<int> _slowPeriod;
private readonly StrategyParam<int> _stopLossPoints;
private readonly StrategyParam<int> _takeProfitPoints;
private ExponentialMovingAverage _fast;
private ExponentialMovingAverage _slow;
private decimal _prevFast;
private decimal _prevSlow;
private decimal _entryPrice;
private int _cooldown;
public int FastPeriod { get => _fastPeriod.Value; set => _fastPeriod.Value = value; }
public int SlowPeriod { get => _slowPeriod.Value; set => _slowPeriod.Value = value; }
public int StopLossPoints { get => _stopLossPoints.Value; set => _stopLossPoints.Value = value; }
public int TakeProfitPoints { get => _takeProfitPoints.Value; set => _takeProfitPoints.Value = value; }
public ProfitLossTrailStrategy()
{
_fastPeriod = Param(nameof(FastPeriod), 14).SetGreaterThanZero().SetDisplay("Fast Period", "Fast EMA period", "Indicator");
_slowPeriod = Param(nameof(SlowPeriod), 50).SetGreaterThanZero().SetDisplay("Slow Period", "Slow EMA period", "Indicator");
_stopLossPoints = Param(nameof(StopLossPoints), 200).SetNotNegative().SetDisplay("Stop Loss", "Stop-loss in price steps", "Risk");
_takeProfitPoints = Param(nameof(TakeProfitPoints), 400).SetNotNegative().SetDisplay("Take Profit", "Take-profit in price steps", "Risk");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
yield return (Security, TimeSpan.FromMinutes(5).TimeFrame());
}
protected override void OnReseted()
{
base.OnReseted();
_fast = null; _slow = null;
_prevFast = 0; _prevSlow = 0; _entryPrice = 0; _cooldown = 0;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_fast = new ExponentialMovingAverage { Length = FastPeriod };
_slow = new ExponentialMovingAverage { Length = SlowPeriod };
var subscription = SubscribeCandles(TimeSpan.FromMinutes(5).TimeFrame());
subscription.Bind(_fast, _slow, ProcessCandle);
subscription.Start();
}
private void ProcessCandle(ICandleMessage candle, decimal fastValue, decimal slowValue)
{
if (candle.State != CandleStates.Finished) return;
if (!_fast.IsFormed || !_slow.IsFormed) { _prevFast = fastValue; _prevSlow = slowValue; return; }
if (_cooldown > 0) { _cooldown--; _prevFast = fastValue; _prevSlow = slowValue; return; }
var close = candle.ClosePrice;
var step = Security?.PriceStep ?? 1m;
if (Position > 0 && _entryPrice > 0)
{
if (StopLossPoints > 0 && close <= _entryPrice - StopLossPoints * step) { SellMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
if (TakeProfitPoints > 0 && close >= _entryPrice + TakeProfitPoints * step) { SellMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
}
else if (Position < 0 && _entryPrice > 0)
{
if (StopLossPoints > 0 && close >= _entryPrice + StopLossPoints * step) { BuyMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
if (TakeProfitPoints > 0 && close <= _entryPrice - TakeProfitPoints * step) { BuyMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
}
if (_prevFast <= _prevSlow && fastValue > slowValue && Position <= 0)
{ if (Position < 0) BuyMarket(); BuyMarket(); _entryPrice = close; _cooldown = 100; }
else if (_prevFast >= _prevSlow && fastValue < slowValue && Position >= 0)
{ if (Position > 0) SellMarket(); SellMarket(); _entryPrice = close; _cooldown = 100; }
_prevFast = fastValue; _prevSlow = slowValue;
}
}
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
class profit_loss_trail_strategy(Strategy):
def __init__(self):
super(profit_loss_trail_strategy, self).__init__()
self._fast_period = self.Param("FastPeriod", 14) \
.SetDisplay("Fast Period", "Fast MA period", "Indicator")
self._slow_period = self.Param("SlowPeriod", 50) \
.SetDisplay("Slow Period", "Slow MA period", "Indicator")
self._stop_loss_points = self.Param("StopLossPoints", 200) \
.SetDisplay("Stop Loss", "Stop-loss in price steps", "Risk")
self._take_profit_points = self.Param("TakeProfitPoints", 400) \
.SetDisplay("Take Profit", "Take-profit in price steps", "Risk")
self._fast = None
self._slow = None
self._prev_fast = 0.0
self._prev_slow = 0.0
self._entry_price = 0.0
self._cooldown = 0
@property
def fast_period(self):
return self._fast_period.Value
@property
def slow_period(self):
return self._slow_period.Value
@property
def stop_loss_points(self):
return self._stop_loss_points.Value
@property
def take_profit_points(self):
return self._take_profit_points.Value
def OnReseted(self):
super(profit_loss_trail_strategy, self).OnReseted()
self._fast = None
self._slow = None
self._prev_fast = 0.0
self._prev_slow = 0.0
self._entry_price = 0.0
self._cooldown = 0
def OnStarted2(self, time):
super(profit_loss_trail_strategy, self).OnStarted2(time)
self._fast = ExponentialMovingAverage()
self._fast.Length = self.fast_period
self._slow = ExponentialMovingAverage()
self._slow.Length = self.slow_period
subscription = self.SubscribeCandles(DataType.TimeFrame(TimeSpan.FromMinutes(5)))
subscription.Bind(self._fast, self._slow, self._process_candle)
subscription.Start()
def _process_candle(self, candle, fast_value, slow_value):
if candle.State != CandleStates.Finished:
return
fast_val = float(fast_value)
slow_val = float(slow_value)
if not self._fast.IsFormed or not self._slow.IsFormed:
self._prev_fast = fast_val
self._prev_slow = slow_val
return
if self._cooldown > 0:
self._cooldown -= 1
self._prev_fast = fast_val
self._prev_slow = slow_val
return
close = float(candle.ClosePrice)
step = float(self.Security.PriceStep) if self.Security is not None and self.Security.PriceStep is not None else 1.0
if self.Position > 0 and self._entry_price > 0:
if self.stop_loss_points > 0 and close <= self._entry_price - self.stop_loss_points * step:
self.SellMarket()
self._entry_price = 0.0
self._cooldown = 100
self._prev_fast = fast_val
self._prev_slow = slow_val
return
if self.take_profit_points > 0 and close >= self._entry_price + self.take_profit_points * step:
self.SellMarket()
self._entry_price = 0.0
self._cooldown = 100
self._prev_fast = fast_val
self._prev_slow = slow_val
return
elif self.Position < 0 and self._entry_price > 0:
if self.stop_loss_points > 0 and close >= self._entry_price + self.stop_loss_points * step:
self.BuyMarket()
self._entry_price = 0.0
self._cooldown = 100
self._prev_fast = fast_val
self._prev_slow = slow_val
return
if self.take_profit_points > 0 and close <= self._entry_price - self.take_profit_points * step:
self.BuyMarket()
self._entry_price = 0.0
self._cooldown = 100
self._prev_fast = fast_val
self._prev_slow = slow_val
return
if self._prev_fast <= self._prev_slow and fast_val > slow_val and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
self._entry_price = close
self._cooldown = 100
elif self._prev_fast >= self._prev_slow and fast_val < slow_val and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._entry_price = close
self._cooldown = 100
self._prev_fast = fast_val
self._prev_slow = slow_val
def CreateClone(self):
return profit_loss_trail_strategy()