Estratégia convertida do especialista MetaTrader Exp_AverageChangeCandle. Recria a lógica original dentro do StockSharp suavizando ratios de velas relativos a uma média móvel de referência dinâmica e reagindo às transições de cor altista/baixista.
Ideia principal
Calcular uma média móvel de referência (MaMethod1, Length1) sobre o preço aplicado selecionado.
Expressar o preço de abertura e fechamento da vela atual como ratios em relação à referência e elevá-los à potência Power.
Suavizar os valores transformados de abertura e fechamento com uma segunda média móvel (MaMethod2, Length2).
Classificar a cor da vela: altista quando o fechamento suavizado > abertura suavizada, baixista quando o fechamento suavizado < abertura suavizada.
Gerar sinais de trading quando a cor muda após o atraso SignalBar configurado.
Apenas velas terminadas são processadas. A estratégia abre posições de mercado na direção da nova cor e opcionalmente fecha o lado oposto.
Parâmetros
Parâmetro
Padrão
Descrição
OrderVolume
1
Volume usado ao abrir uma nova posição.
MaMethod1
Lwma
Suavização aplicada ao ratio de referência (subconjunto de SMA/EMA/SMMA/LWMA/JJMA/AMA). Tipos não suportados usam EMA.
Length1
12
Período da média móvel de referência.
Phase1
15
Parâmetro de fase Jurik para a referência (mantido por compatibilidade).
PriceSource
Median
Preço aplicado antes de calcular a referência.
MaMethod2
Jjma
Suavização aplicada aos ratios transformados.
Length2
5
Período da média móvel de sinal.
Phase2
100
Parâmetro de fase Jurik para a suavização de sinal.
Power
5
Expoente usado ao elevar os ratios de abertura/fechamento.
SignalBar
1
Quantas velas fechadas esperar antes de agir em uma mudança de cor.
BuyOpenEnabled
true
Permitir abrir posições compradas.
SellOpenEnabled
true
Permitir abrir posições vendidas.
BuyCloseEnabled
true
Fechar comprados quando um sinal baixista aparece.
SellCloseEnabled
true
Fechar vendidos quando um sinal altista aparece.
StopLossPoints
0
Distância absoluta de stop-loss. 0 desativa o stop.
TakeProfitPoints
0
Distância absoluta de take-profit. 0 desativa o alvo.
CandleType
Período H4
Série de velas processada pela estratégia.
Regras de trading
Transição altista (color muda para 2): fechar vendidos ativos (se permitido) e abrir uma posição comprada quando Position <= 0 e BuyOpenEnabled é verdadeiro.
Transição baixista (color muda para 0): fechar comprados ativos (se permitido) e abrir uma posição vendida quando Position >= 0 e SellOpenEnabled é verdadeiro.
Cor 1 (neutra) não aciona operações.
Os sinais são avaliados usando a barra localizada SignalBar passos atrás da vela terminada mais recente para imitar o timing original do MetaTrader.
Gestão de risco
StopLossPoints e TakeProfitPoints configuram StartProtection com distâncias absolutas. Quando qualquer valor é zero, a proteção respectiva é desativada.
Notas
Apenas os métodos de suavização disponíveis no StockSharp são implementados diretamente. JurX, ParMA, T3 e VIDYA do código original são mapeados para EMA como alternativa funcional.
Os parâmetros de fase são mantidos por compatibilidade, mas afetam apenas médias baseadas em Jurik/Kaufman.
A estratégia usa ordens de mercado assim como o assessor especialista original. O gerenciamento de slippage da versão MQL não é reproduzido porque o StockSharp lida com a execução via conectores.
namespace StockSharp.Samples.Strategies;
using System;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.Messages;
/// <summary>
/// Average Change Candle strategy (simplified).
/// Compares smoothed open vs close ratios to detect bullish/bearish candle patterns.
/// Uses EMA of open and close to determine trend direction.
/// </summary>
public class AverageChangeCandleStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _emaPeriod;
private decimal _prevSmoothedOpen;
private decimal _prevSmoothedClose;
private bool _initialized;
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public int EmaPeriod
{
get => _emaPeriod.Value;
set => _emaPeriod.Value = value;
}
public AverageChangeCandleStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Source candles", "General");
_emaPeriod = Param(nameof(EmaPeriod), 12)
.SetGreaterThanZero()
.SetDisplay("EMA Period", "EMA smoothing period", "Indicators");
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevSmoothedOpen = 0m;
_prevSmoothedClose = 0m;
_initialized = false;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevSmoothedOpen = 0;
_prevSmoothedClose = 0;
_initialized = false;
var ema = new ExponentialMovingAverage { Length = EmaPeriod };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(ema, (ICandleMessage candle, decimal emaValue) =>
{
if (candle.State != CandleStates.Finished)
return;
// Simple exponential smoothing of open and close
var alpha = 2m / (EmaPeriod + 1m);
if (!_initialized)
{
_prevSmoothedOpen = candle.OpenPrice;
_prevSmoothedClose = candle.ClosePrice;
_initialized = true;
return;
}
var smoothedOpen = alpha * candle.OpenPrice + (1m - alpha) * _prevSmoothedOpen;
var smoothedClose = alpha * candle.ClosePrice + (1m - alpha) * _prevSmoothedClose;
var prevBullish = _prevSmoothedClose > _prevSmoothedOpen;
var currBullish = smoothedClose > smoothedOpen;
if (!IsFormedAndOnlineAndAllowTrading())
{
_prevSmoothedOpen = smoothedOpen;
_prevSmoothedClose = smoothedClose;
return;
}
// Buy on transition to bullish smoothed candle
if (currBullish && !prevBullish && candle.ClosePrice > emaValue && Position <= 0)
{
BuyMarket();
}
// Sell on transition to bearish smoothed candle
else if (!currBullish && prevBullish && candle.ClosePrice < emaValue && Position >= 0)
{
SellMarket();
}
_prevSmoothedOpen = smoothedOpen;
_prevSmoothedClose = smoothedClose;
})
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, ema);
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 average_change_candle_strategy(Strategy):
def __init__(self):
super(average_change_candle_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Source candles", "General")
self._ema_period = self.Param("EmaPeriod", 12) \
.SetDisplay("EMA Period", "EMA smoothing period", "Indicators")
self._prev_smoothed_open = 0.0
self._prev_smoothed_close = 0.0
self._initialized = False
@property
def CandleType(self):
return self._candle_type.Value
@property
def EmaPeriod(self):
return self._ema_period.Value
def OnReseted(self):
super(average_change_candle_strategy, self).OnReseted()
self._prev_smoothed_open = 0.0
self._prev_smoothed_close = 0.0
self._initialized = False
def OnStarted2(self, time):
super(average_change_candle_strategy, self).OnStarted2(time)
self._prev_smoothed_open = 0.0
self._prev_smoothed_close = 0.0
self._initialized = False
ema = ExponentialMovingAverage()
ema.Length = self.EmaPeriod
subscription = self.SubscribeCandles(self.CandleType)
subscription \
.Bind(ema, self._on_process) \
.Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, ema)
self.DrawOwnTrades(area)
def _on_process(self, candle, ema_value):
if candle.State != CandleStates.Finished:
return
ev = float(ema_value)
o = float(candle.OpenPrice)
c = float(candle.ClosePrice)
alpha = 2.0 / (self.EmaPeriod + 1.0)
if not self._initialized:
self._prev_smoothed_open = o
self._prev_smoothed_close = c
self._initialized = True
return
smoothed_open = alpha * o + (1.0 - alpha) * self._prev_smoothed_open
smoothed_close = alpha * c + (1.0 - alpha) * self._prev_smoothed_close
prev_bullish = self._prev_smoothed_close > self._prev_smoothed_open
curr_bullish = smoothed_close > smoothed_open
if curr_bullish and not prev_bullish and c > ev and self.Position <= 0:
self.BuyMarket()
elif not curr_bullish and prev_bullish and c < ev and self.Position >= 0:
self.SellMarket()
self._prev_smoothed_open = smoothed_open
self._prev_smoothed_close = smoothed_close
def CreateClone(self):
return average_change_candle_strategy()