Esta estratégia reproduz a lógica do assessor especialista original do MetaTrader "Exp_2XMA_Ichimoku_Oscillator" combinando dois envelopes de preço estilo Ichimoku suavizados com médias móveis configuráveis. A implementação no StockSharp usa a API de estratégia de alto nível e foca na geração de sinais baseada em velas, mantendo as regras de gerenciamento de posição do algoritmo fonte.
Ideia principal
Dois pontos médios tipo Donchian são calculados no timeframe selecionado:
O ponto médio rápido calcula a média do máximo mais alto e mínimo mais baixo em UpPeriod1 e DownPeriod1 barras.
O ponto médio lento realiza a mesma operação com UpPeriod2 e DownPeriod2 barras.
Cada ponto médio é suavizado por uma média móvel (Method1, Method2) de comprimentos XLength1 e XLength2. Os métodos de suavização disponíveis são Simples, Exponencial, Suavizado e Linear Ponderado.
O valor do oscilador é a diferença entre os dois pontos médios suavizados. Quatro estados de cor descrevem seu comportamento:
PositiveRising (0): oscilador acima de zero e subindo.
PositiveFalling (1): oscilador acima de zero e perdendo momentum.
NegativeRising (3): oscilador abaixo de zero mas subindo em direção ao zero.
NegativeFalling (4): oscilador abaixo de zero e caindo mais.
Neutral (2) é atribuído durante o aquecimento.
Os sinais são avaliados usando as cores da barra em SignalBar e a barra imediatamente anterior (SignalBar + 1), o que espelha o deslocamento de buffer na versão MQL.
Lógica de trading
Entrada comprada: permitida quando EnableBuyOpen é verdadeiro. Se a cor da barra mais antiga (SignalBar + 1) era ascendente (0 ou 3) e a barra mais recente (SignalBar) mudou para uma cor descendente (1 ou 4), a estratégia fecha qualquer posição vendida (EnableSellClose) e abre/estende uma posição comprada usando Volume + |Position| unidades.
Entrada vendida: permitida quando EnableSellOpen é verdadeiro. Se a cor da barra mais antiga era descendente (1 ou 4) e a barra mais recente mudou para uma cor ascendente (0 ou 3), a estratégia fecha os comprados existentes (EnableBuyClose) e abre/estende uma posição vendida com Volume + |Position| unidades.
Todas as execuções ocorrem no fechamento da vela que gera o gatilho. As ordens são sempre a mercado e a estratégia não aplica níveis adicionais de stop-loss ou take-profit; depende exclusivamente das transições de cor para as saídas.
StartProtection() é ativado na inicialização para usar as verificações de segurança integradas do framework para posições inesperadas.
Parâmetros
Nome
Descrição
Padrão
CandleType
Período usado para cálculos do indicador.
Velas de 4 horas
UpPeriod1, DownPeriod1
Janelas de retrospecto para o ponto médio rápido.
6, 6
UpPeriod2, DownPeriod2
Janelas de retrospecto para o ponto médio lento.
9, 9
XLength1, XLength2
Comprimentos de suavização para as duas médias móveis.
25, 80
Method1, Method2
Tipos de média móvel (Simples, Exponencial, Suavizado, Ponderado).
Simples
SignalBar
Deslocamento de barra histórica usado para ler cores do oscilador.
1
EnableBuyOpen, EnableSellOpen
Alternar entradas compradas/vendidas.
true
EnableBuyClose, EnableSellClose
Alternar saídas compradas/vendidas.
true
Volume
Tamanho base da operação; posições existentes são somadas a este valor ao reverter.
1
Notas de uso
Os tipos de média móvel cobrem os comportamentos de suavização mais comuns do especialista original. Opções avançadas como ajustes de fase XMA personalizados não estão disponíveis no StockSharp e foram substituídas por indicadores padrão.
Como o oscilador é calculado em velas fechadas, os sinais aparecem com o mesmo atraso de uma barra que a implementação MQL usava (SignalBar = 1). Aumente SignalBar se precisar de barras de confirmação adicionais.
Considere combinar a estratégia com gerenciamento de risco externo (gestor de portfólio, stops protetores) ao operar em mercados ao vivo, pois as saídas dependem exclusivamente das reversões de cor do oscilador.
namespace StockSharp.Samples.Strategies;
using System;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.Messages;
/// <summary>
/// Exp 2XMA Ichimoku Oscillator strategy (simplified).
/// Uses two SMAs of different periods as a crossover oscillator.
/// Buys when fast SMA crosses above slow SMA, sells when fast crosses below.
/// </summary>
public class Exp2XmaIchimokuOscillatorStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _fastPeriod;
private readonly StrategyParam<int> _slowPeriod;
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 Exp2XmaIchimokuOscillatorStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame())
.SetDisplay("Candle Type", "Source candles", "General");
_fastPeriod = Param(nameof(FastPeriod), 5)
.SetGreaterThanZero()
.SetDisplay("Fast Period", "Fast moving average length", "Indicators");
_slowPeriod = Param(nameof(SlowPeriod), 20)
.SetGreaterThanZero()
.SetDisplay("Slow Period", "Slow moving average length", "Indicators");
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var fastMa = new ExponentialMovingAverage { Length = FastPeriod };
var slowMa = new ExponentialMovingAverage { Length = SlowPeriod };
decimal prevFast = 0, prevSlow = 0;
bool prevInitialized = false;
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(fastMa, slowMa, (ICandleMessage candle, decimal fastValue, decimal slowValue) =>
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
{
prevFast = fastValue;
prevSlow = slowValue;
prevInitialized = true;
return;
}
if (!prevInitialized)
{
prevFast = fastValue;
prevSlow = slowValue;
prevInitialized = true;
return;
}
// Buy on bullish crossover
if (prevFast <= prevSlow && fastValue > slowValue && Position <= 0)
{
BuyMarket();
}
// Sell on bearish crossover
else if (prevFast >= prevSlow && fastValue < slowValue && Position >= 0)
{
SellMarket();
}
prevFast = fastValue;
prevSlow = slowValue;
})
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, fastMa);
DrawIndicator(area, slowMa);
DrawOwnTrades(area);
}
}
}
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 exp2_xma_ichimoku_oscillator_strategy(Strategy):
def __init__(self):
super(exp2_xma_ichimoku_oscillator_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(1))) \
.SetDisplay("Candle Type", "Source candles", "General")
self._fast_period = self.Param("FastPeriod", 5) \
.SetDisplay("Fast Period", "Fast moving average length", "Indicators")
self._slow_period = self.Param("SlowPeriod", 20) \
.SetDisplay("Slow Period", "Slow moving average length", "Indicators")
self._prev_fast = 0.0
self._prev_slow = 0.0
self._prev_initialized = False
@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(exp2_xma_ichimoku_oscillator_strategy, self).OnReseted()
self._prev_fast = 0.0
self._prev_slow = 0.0
self._prev_initialized = False
def OnStarted2(self, time):
super(exp2_xma_ichimoku_oscillator_strategy, self).OnStarted2(time)
self._prev_fast = 0.0
self._prev_slow = 0.0
self._prev_initialized = False
fast_ma = ExponentialMovingAverage()
fast_ma.Length = self.FastPeriod
slow_ma = ExponentialMovingAverage()
slow_ma.Length = self.SlowPeriod
subscription = self.SubscribeCandles(self.CandleType)
subscription \
.Bind(fast_ma, slow_ma, self._on_process) \
.Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, fast_ma)
self.DrawIndicator(area, slow_ma)
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 not self.IsFormedAndOnlineAndAllowTrading():
self._prev_fast = fv
self._prev_slow = sv
self._prev_initialized = True
return
if not self._prev_initialized:
self._prev_fast = fv
self._prev_slow = sv
self._prev_initialized = True
return
if self._prev_fast <= self._prev_slow and fv > sv and self.Position <= 0:
self.BuyMarket()
elif self._prev_fast >= self._prev_slow and fv < sv and self.Position >= 0:
self.SellMarket()
self._prev_fast = fv
self._prev_slow = sv
def CreateClone(self):
return exp2_xma_ichimoku_oscillator_strategy()