O SampleTrailingStopStrategy é uma porta C# direta do consultor especialista MetaTrader SampleTrailingstop.mq4. A estratégia não gera entradas próprias; em vez disso, observa continuamente a posição atual e mantém ordens protetoras de stop-loss e take-profit. A lógica reflete o EA original, respeitando os níveis de stop e congelamento impostos pelo corretor ao aplicar um trailing stop medido em faixas de preço.
Sempre que uma posição longa se torna lucrativa e a melhor oferta se afasta o suficiente do preço de entrada, a estratégia primeiro move o stop-loss logo abaixo da oferta pela distância mínima permitida. As atualizações subsequentes acompanham o stop atrás do lance pelo número configurado de pontos mais os buffers do corretor. As posições curtas são processadas simetricamente, com o stop acima do pedido. As metas opcionais de lucro são recalculadas em cada evento final.
Fluxo de dados
Assina as atualizações do Level1 para receber as melhores cotações de compra/venda.
Rastreia o preço da posição atual por meio da base Strategy API.
Registra novamente ordens de stop e limite de proteção quando novos preços são calculados.
Parâmetros
Parâmetro
Padrão
Descrição
TrailingStopPoints
200
Distância entre o mercado e o trailing stop medido em pontos de preço. Este valor é adicionado aos buffers do corretor durante os cálculos finais.
TakeProfitPoints
1000
Distância opcional de take-profit em pontos. Defina como 0 para desativar o gerenciamento de lucro.
StopLevelPoints
0
Restrição de nível de stop da corretora expressa em pontos. É adicionado à distância final para manter as ordens de parada válidas.
FreezeLevelPoints
0
Restrição de nível de congelamento do corretor expressa em pontos. O trailing espera até que o mercado ultrapasse esse buffer em relação ao preço de entrada.
Todas as distâncias são traduzidas em valores de preço com o tamanho do tick do instrumento para emular o comportamento _Point de MetaTrader.
Algoritmo de trilha
Validação de posição – A estratégia ignora o trailing até que exista uma posição e a melhor oferta/venda seja conhecida.
Verificação de lucro – O trailing é ativado somente quando a posição é lucrativa (bid > entry para posições longas, ask < entry para posições curtas) e o buffer de congelamento foi limpo.
Colocação de stop inicial – Se nenhum trailing stop estiver ativo ainda, o stop é movido para a distância mínima permitida do mercado (oferta menos buffers para posições compradas, venda mais buffers para posições vendidas) assim que o preço percorrer pelo menos a distância final da entrada.
Atualizações de trailing – Enquanto a posição permanece lucrativa, o stop é aprofundado usando a distância de trailing configurada mais os buffers da corretora. Os níveis de lucro são recalculados em cada atualização quando ativados.
Manutenção de ordens – As ordens de proteção são criadas, atualizadas ou canceladas automaticamente por meio de métodos auxiliares de alto nível para que a corretora sempre veja os valores mais recentes de stop-loss e take-profit.
Notas de uso
Inicie a estratégia junto com outro componente que abre posições, ou utilize ordens manuais; este módulo gerencia apenas saídas.
Certifique-se de que os metadados do instrumento contenham etapas adequadas de preço e volume. A estratégia normaliza todos os preços e valores gerados para satisfazer as restrições cambiais.
Quando a direção da posição muda, quaisquer ordens de proteção herdadas são canceladas antes dos reinícios do novo lado.
namespace StockSharp.Samples.Strategies;
using System;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.Messages;
/// <summary>
/// Sample Trailing Stop strategy: Smoothed MA crossover.
/// Buys when close crosses above Smoothed MA, sells when crosses below.
/// </summary>
public class SampleTrailingStopStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _period;
private decimal _prevClose;
private decimal _prevSma;
private bool _hasPrev;
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public int Period { get => _period.Value; set => _period.Value = value; }
public SampleTrailingStopStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(60).TimeFrame())
.SetDisplay("Candle Type", "Candle timeframe", "General");
_period = Param(nameof(Period), 50)
.SetGreaterThanZero()
.SetDisplay("Period", "Smoothed MA period", "Indicators");
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevClose = 0;
_prevSma = 0;
_hasPrev = false;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevClose = 0;
_prevSma = 0;
_hasPrev = false;
var smma = new ExponentialMovingAverage { Length = Period };
var subscription = SubscribeCandles(CandleType);
subscription.Bind(smma, ProcessCandle).Start();
}
private void ProcessCandle(ICandleMessage candle, decimal smmaValue)
{
if (candle.State != CandleStates.Finished) return;
if (_hasPrev)
{
if (_prevClose <= _prevSma && candle.ClosePrice > smmaValue && Position <= 0)
BuyMarket();
else if (_prevClose >= _prevSma && candle.ClosePrice < smmaValue && Position >= 0)
SellMarket();
}
_prevClose = candle.ClosePrice;
_prevSma = smmaValue;
_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
from StockSharp.Algo.Strategies import Strategy
class sample_trailing_stop_strategy(Strategy):
def __init__(self):
super(sample_trailing_stop_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(60)))
self._period = self.Param("Period", 50)
self._prev_close = 0.0
self._prev_sma = 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 Period(self):
return self._period.Value
@Period.setter
def Period(self, value):
self._period.Value = value
def OnReseted(self):
super(sample_trailing_stop_strategy, self).OnReseted()
self._prev_close = 0.0
self._prev_sma = 0.0
self._has_prev = False
def OnStarted2(self, time):
super(sample_trailing_stop_strategy, self).OnStarted2(time)
self._prev_close = 0.0
self._prev_sma = 0.0
self._has_prev = False
smma = ExponentialMovingAverage()
smma.Length = self.Period
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(smma, self._process_candle).Start()
def _process_candle(self, candle, smma_value):
if candle.State != CandleStates.Finished:
return
close = float(candle.ClosePrice)
smma_val = float(smma_value)
if self._has_prev:
if self._prev_close <= self._prev_sma and close > smma_val and self.Position <= 0:
self.BuyMarket()
elif self._prev_close >= self._prev_sma and close < smma_val and self.Position >= 0:
self.SellMarket()
self._prev_close = close
self._prev_sma = smma_val
self._has_prev = True
def CreateClone(self):
return sample_trailing_stop_strategy()