Esta estratégia é um porte do StockSharp do assessor especializado do MetaTrader Exp_AltrTrend_Signal_v2_2. Ela recria a
lógica de canal adaptativo do indicador AltrTrend Signal original e executa operações em barras atrasadas assim como a versão
MQL5. O valor ADX contrai ou expande o canal para que rompimentos só disparem quando a força de tendência os suporta.
Como funciona
Um canal dinâmico é calculado em cada vela completada do período configurado. A largura do canal é definida pelo preço
máximo e mínimo dentro de um lookback que se expande ou contrai de acordo com o valor ADX anterior (KPeriod / ADX).
Os limites internos (smin, smax) são puxados em direção ao centro em KPercent. O preço deve fechar fora desses limites
internos para estabelecer um estado de tendência direcional.
Quando a tendência muda de baixista para altista e o fechamento está acima do limite superior, um sinal de compra é gerado.
Uma reversão baixista abaixo do limite inferior emite um sinal de venda. Os sinais são executados na barra definida pelo
atraso SignalBar, correspondendo ao comportamento do assessor especializado original.
Níveis opcionais de stop-loss e take-profit são mapeados de pontos para passos de preço para que as saídas de proteção
imitem a colocação de ordem original com valores fixos de SL/TP.
Detalhes
Critérios de entrada:
Comprado: A tendência anterior era baixista ou neutra, o preço fecha acima do limite superior contraído e as entradas
compradas estão habilitadas. As posições vendidas podem ser fechadas automaticamente se permitido.
Vendido: A tendência anterior era altista ou neutra, o preço fecha abaixo do limite inferior contraído e as entradas
vendidas estão habilitadas. As posições compradas podem ser fechadas automaticamente se permitido.
Critérios de saída:
Sinal de rompimento oposto quando as saídas são permitidas para a direção atual.
Distâncias de stop-loss ou take-profit expressas em passos de preço.
Comprado/Vendido: Direção dupla com interruptores independentes de habilitação/desabilitação para entradas e saídas.
Gestão de risco:
StopLossPoints e TakeProfitPoints replicam o módulo MM original aplicando saídas baseadas em distância após ordens de
mercado serem preenchidas.
Configurações do indicador:
KPercent controla quanto as bordas do canal são contraídas em direção ao intervalo médio.
KStop mantém o valor de projeção de seta original para gráficos e logging.
KPeriod é o lookback base antes da modulação ADX.
AdxPeriod define o comprimento do Average Directional Index que adapta a largura do canal.
SignalBar atrasa a execução de ordens pelo número especificado de velas completadas.
Mercados recomendados:
Funciona melhor em instrumentos com fases de swing claras onde a força de tendência varia ao longo do tempo (principais pares
de forex, ouro e futuros de índices). O período padrão é H1 como no modelo MQL5.
Parâmetros
Parâmetro
Descrição
CandleType
Período usado para construir o canal adaptativo.
KPercent
Porcentagem que puxa os limites internos do canal para dentro.
KStop
Multiplicador para preços de seta projetados (mantido para compatibilidade).
KPeriod
Número base de velas examinadas antes do ajuste ADX.
AdxPeriod
Período do Average Directional Index que impulsiona a largura do canal.
SignalBar
Número de velas completadas para aguardar antes de executar um sinal.
AllowBuyEntries / AllowSellEntries
Habilitar ou desabilitar a abertura de posições em cada direção.
AllowBuyExits / AllowSellExits
Permitir o fechamento automático de posições em sinais opostos.
StopLossPoints
Distância do stop-loss medida em passos de preço (0 desabilita).
TakeProfitPoints
Distância do take-profit medida em passos de preço (0 desabilita).
Este porte mantém os interruptores discricionários e os parâmetros de risco do assessor especializado original, facilitando a
reprodução do mesmo comportamento dentro do StockSharp Designer, Shell ou Runner.
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>
/// AltrTrend signal strategy using EMA crossover for alternating trend detection.
/// </summary>
public class AltrTrendSignalStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _fastPeriod;
private readonly StrategyParam<int> _slowPeriod;
private decimal? _prevFast;
private decimal? _prevSlow;
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public int FastPeriod
{
get => _fastPeriod.Value;
set => _fastPeriod.Value = value;
}
public int SlowPeriod
{
get => _slowPeriod.Value;
set => _slowPeriod.Value = value;
}
public AltrTrendSignalStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame())
.SetDisplay("Candle Type", "Timeframe", "General");
_fastPeriod = Param(nameof(FastPeriod), 7)
.SetGreaterThanZero()
.SetDisplay("Fast Period", "Fast EMA period", "Indicators");
_slowPeriod = Param(nameof(SlowPeriod), 14)
.SetGreaterThanZero()
.SetDisplay("Slow Period", "Slow EMA period", "Indicators");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevFast = null;
_prevSlow = null;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevFast = null;
_prevSlow = null;
var fast = new ExponentialMovingAverage { Length = FastPeriod };
var slow = new ExponentialMovingAverage { Length = SlowPeriod };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(fast, slow, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, fast);
DrawIndicator(area, slow);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal fastVal, decimal slowVal)
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
{
_prevFast = fastVal;
_prevSlow = slowVal;
return;
}
if (_prevFast == null || _prevSlow == null)
{
_prevFast = fastVal;
_prevSlow = slowVal;
return;
}
var prevAbove = _prevFast.Value > _prevSlow.Value;
var currAbove = fastVal > slowVal;
_prevFast = fastVal;
_prevSlow = slowVal;
if (!prevAbove && currAbove)
{
if (Position < 0)
BuyMarket();
if (Position <= 0)
BuyMarket();
}
else if (prevAbove && !currAbove)
{
if (Position > 0)
SellMarket();
if (Position >= 0)
SellMarket();
}
}
}
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 altr_trend_signal_strategy(Strategy):
def __init__(self):
super(altr_trend_signal_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(1))) \
.SetDisplay("Candle Type", "Timeframe", "General")
self._fast_period = self.Param("FastPeriod", 7) \
.SetDisplay("Fast Period", "Fast EMA period", "Indicators")
self._slow_period = self.Param("SlowPeriod", 14) \
.SetDisplay("Slow Period", "Slow EMA period", "Indicators")
self._prev_fast = None
self._prev_slow = None
@property
def CandleType(self):
return self._candle_type.Value
@property
def FastPeriod(self):
return self._fast_period.Value
@property
def SlowPeriod(self):
return self._slow_period.Value
def OnReseted(self):
super(altr_trend_signal_strategy, self).OnReseted()
self._prev_fast = None
self._prev_slow = None
def OnStarted2(self, time):
super(altr_trend_signal_strategy, self).OnStarted2(time)
self._prev_fast = None
self._prev_slow = None
fast = ExponentialMovingAverage()
fast.Length = self.FastPeriod
slow = ExponentialMovingAverage()
slow.Length = self.SlowPeriod
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(fast, slow, self._on_process).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, fast)
self.DrawIndicator(area, slow)
self.DrawOwnTrades(area)
def _on_process(self, candle, fast_value, slow_value):
if candle.State != CandleStates.Finished:
return
fv = float(fast_value)
sv = float(slow_value)
if self._prev_fast is None or self._prev_slow is None:
self._prev_fast = fv
self._prev_slow = sv
return
prev_above = self._prev_fast > self._prev_slow
curr_above = fv > sv
self._prev_fast = fv
self._prev_slow = sv
if not prev_above and curr_above:
if self.Position < 0:
self.BuyMarket()
if self.Position <= 0:
self.BuyMarket()
elif prev_above and not curr_above:
if self.Position > 0:
self.SellMarket()
if self.Position >= 0:
self.SellMarket()
def CreateClone(self):
return altr_trend_signal_strategy()