Esta estratégia é uma conversão direta do consultor especialista MetaTrader 5 "TP SL Trailing". A estratégia não gera entradas por si mesma. Em vez disso, gerencia posições existentes instalando um stop-loss e take-profit de proteção e arrastando o stop assim que a operação se torna lucrativa. A configuração baseada em pips corresponde aos parâmetros do script original e permite que a lógica seja anexada a qualquer símbolo suportado pelo StockSharp.
Lógica de negociação
Quando uma nova posição aparece, a estratégia pode opcionalmente definir um stop-loss e take-profit inicial usando as distâncias em pips configuradas. Este comportamento é controlado pelo flag Only Zero Values, assim como no consultor especialista original.
Para posições compradas, a estratégia move o stop-loss para cima assim que o lucro não realizado excede a soma do trailing stop e o trailing step. O stop é movido para preço atual - trailing stop, garantindo que uma porção mínima do lucro seja assegurada.
Para posições vendidas, a estratégia reflete a mesma ideia e move o stop para baixo assim que o lucro excede os limiares de trailing.
Se tanto o trailing stop quanto o trailing step forem zero, a estratégia deixa o stop-loss intocado.
O nível de take-profit nunca é arrastado. É definido apenas durante a fase de colocação inicial quando Only Zero Values está habilitado, replicando completamente o comportamento MQL.
Parâmetros
Nome
Descrição
CandleType
Período das velas usadas para rastrear movimentos de preço. Um período mais rápido melhora a precisão do trailing.
StopLossPips
Distância em pips entre o preço de entrada e o stop-loss inicial. Aplicado apenas quando Only Zero Values está habilitado.
TakeProfitPips
Distância em pips entre o preço de entrada e o take-profit inicial. Aplicado apenas quando Only Zero Values está habilitado.
TrailingStopPips
Distância de trailing core em pips. Define o quão longe atrás do preço atual o stop deve permanecer após a ativação.
TrailingStepPips
Buffer adicional de pips que deve ser excedido antes que o stop se mova novamente. Previne atualizações de stop muito frequentes.
OnlyZeroValues
Corresponde ao flag EA original. Quando habilitado, as ordens de proteção iniciais são criadas apenas para posições que atualmente não têm stop-loss ou take-profit atribuídos.
Notas de conversão
As distâncias em pips são convertidas para unidades de preço usando o PriceStep do instrumento. Isso mantém a lógica agnóstica ao instrumento e reflete o ajuste de 3/5 dígitos na versão MQL.
As ordens de proteção são re-registradas sempre que a lógica de trailing move o stop-loss. As ordens ativas de uma posição anterior são canceladas automaticamente quando o tamanho da posição retorna a zero.
Todos os comentários de código estão escritos em inglês, enquanto esta documentação é intencionalmente detalhada para ajudar a reproduzir cada decisão tomada durante o processo de portabilidade.
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()