Estrategia de Gestión Drag SL/TP
Esta estrategia coloca automáticamente órdenes de stop-loss y take-profit a una distancia fija del precio de la operación ejecutada. Es útil cuando las posiciones manuales deben protegerse inmediatamente después de la entrada.
Parámetros
- Auto Set SL (
bool): habilitar la colocación automática de stop-loss. - SL Points (
decimal): distancia del stop-loss en pasos de precio. - Auto Set TP (
bool): habilitar la colocación automática de take-profit. - TP Points (
decimal): distancia del take-profit en pasos de precio.
Comportamiento
Cuando la estrategia se inicia, llama a StartProtection con las distancias seleccionadas. Cualquier posición abierta mientras la estrategia está en ejecución recibirá inmediatamente las órdenes de protección correspondientes. Las distancias se miden en pasos de precio (Security.PriceStep).
La estrategia en sí no genera señales de trading; simplemente gestiona órdenes de protección para posiciones abiertas manualmente o por otras estrategias.
Notas
- Diseñada para uso con la API de alto nivel.
- Solo el estado de vela finalizada debe activar acciones de trading en versiones extendidas.
- No se implementa la función de arrastre gráfico del script MQL original.
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;
/// <summary>
/// Strategy that uses EMA crossover for entries with stop-loss and take-profit.
/// </summary>
public class DragSlTpStrategy : Strategy
{
private readonly StrategyParam<decimal> _slPoints;
private readonly StrategyParam<decimal> _tpPoints;
private readonly StrategyParam<int> _fastPeriod;
private readonly StrategyParam<int> _slowPeriod;
private readonly StrategyParam<DataType> _candleType;
private decimal _prevFast;
private decimal _prevSlow;
private bool _isInitialized;
private decimal _entryPrice;
public decimal SlPoints { get => _slPoints.Value; set => _slPoints.Value = value; }
public decimal TpPoints { get => _tpPoints.Value; set => _tpPoints.Value = value; }
public int FastPeriod { get => _fastPeriod.Value; set => _fastPeriod.Value = value; }
public int SlowPeriod { get => _slowPeriod.Value; set => _slowPeriod.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public DragSlTpStrategy()
{
_slPoints = Param(nameof(SlPoints), 500m)
.SetGreaterThanZero()
.SetDisplay("SL Points", "Stop-loss distance", "Risk");
_tpPoints = Param(nameof(TpPoints), 1000m)
.SetGreaterThanZero()
.SetDisplay("TP Points", "Take-profit distance", "Risk");
_fastPeriod = Param(nameof(FastPeriod), 10)
.SetGreaterThanZero()
.SetDisplay("Fast Period", "Fast EMA period", "Indicators");
_slowPeriod = Param(nameof(SlowPeriod), 30)
.SetGreaterThanZero()
.SetDisplay("Slow Period", "Slow EMA period", "Indicators");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Type of candles", "General");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
=> [(Security, CandleType)];
protected override void OnReseted()
{
base.OnReseted();
_prevFast = 0;
_prevSlow = 0;
_isInitialized = false;
_entryPrice = 0;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var fastEma = new ExponentialMovingAverage { Length = FastPeriod };
var slowEma = new ExponentialMovingAverage { Length = SlowPeriod };
SubscribeCandles(CandleType)
.Bind(fastEma, slowEma, ProcessCandle)
.Start();
}
private void ProcessCandle(ICandleMessage candle, decimal fast, decimal slow)
{
if (candle.State != CandleStates.Finished) return;
if (!_isInitialized)
{
_prevFast = fast;
_prevSlow = slow;
_isInitialized = true;
return;
}
var crossUp = _prevFast <= _prevSlow && fast > slow;
var crossDown = _prevFast >= _prevSlow && fast < slow;
_prevFast = fast;
_prevSlow = slow;
if (Position == 0)
{
if (crossUp)
{
BuyMarket();
_entryPrice = candle.ClosePrice;
}
else if (crossDown)
{
SellMarket();
_entryPrice = candle.ClosePrice;
}
}
else if (Position > 0)
{
var price = candle.ClosePrice;
if (price - _entryPrice >= TpPoints || _entryPrice - price >= SlPoints || crossDown)
{
SellMarket();
if (crossDown)
{
SellMarket();
_entryPrice = candle.ClosePrice;
}
}
}
else if (Position < 0)
{
var price = candle.ClosePrice;
if (_entryPrice - price >= TpPoints || price - _entryPrice >= SlPoints || crossUp)
{
BuyMarket();
if (crossUp)
{
BuyMarket();
_entryPrice = candle.ClosePrice;
}
}
}
}
}
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 drag_sl_tp_strategy(Strategy):
def __init__(self):
super(drag_sl_tp_strategy, self).__init__()
self._sl_points = self.Param("SlPoints", 500.0) \
.SetDisplay("SL Points", "Stop-loss distance", "Risk")
self._tp_points = self.Param("TpPoints", 1000.0) \
.SetDisplay("TP Points", "Take-profit distance", "Risk")
self._fast_period = self.Param("FastPeriod", 10) \
.SetDisplay("Fast Period", "Fast EMA period", "Indicators")
self._slow_period = self.Param("SlowPeriod", 30) \
.SetDisplay("Slow Period", "Slow EMA period", "Indicators")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Type of candles", "General")
self._prev_fast = 0.0
self._prev_slow = 0.0
self._is_initialized = False
self._entry_price = 0.0
@property
def sl_points(self):
return self._sl_points.Value
@property
def tp_points(self):
return self._tp_points.Value
@property
def fast_period(self):
return self._fast_period.Value
@property
def slow_period(self):
return self._slow_period.Value
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(drag_sl_tp_strategy, self).OnReseted()
self._prev_fast = 0.0
self._prev_slow = 0.0
self._is_initialized = False
self._entry_price = 0.0
def OnStarted2(self, time):
super(drag_sl_tp_strategy, self).OnStarted2(time)
fast_ema = ExponentialMovingAverage()
fast_ema.Length = self.fast_period
slow_ema = ExponentialMovingAverage()
slow_ema.Length = self.slow_period
self.SubscribeCandles(self.candle_type).Bind(fast_ema, slow_ema, self.process_candle).Start()
def process_candle(self, candle, fast, slow):
if candle.State != CandleStates.Finished:
return
fv = float(fast)
sv = float(slow)
if not self._is_initialized:
self._prev_fast = fv
self._prev_slow = sv
self._is_initialized = True
return
cross_up = self._prev_fast <= self._prev_slow and fv > sv
cross_down = self._prev_fast >= self._prev_slow and fv < sv
self._prev_fast = fv
self._prev_slow = sv
tp = float(self.tp_points)
sl = float(self.sl_points)
price = float(candle.ClosePrice)
if self.Position == 0:
if cross_up:
self.BuyMarket()
self._entry_price = price
elif cross_down:
self.SellMarket()
self._entry_price = price
elif self.Position > 0:
if price - self._entry_price >= tp or self._entry_price - price >= sl or cross_down:
self.SellMarket()
if cross_down:
self.SellMarket()
self._entry_price = price
elif self.Position < 0:
if self._entry_price - price >= tp or price - self._entry_price >= sl or cross_up:
self.BuyMarket()
if cross_up:
self.BuyMarket()
self._entry_price = price
def CreateClone(self):
return drag_sl_tp_strategy()