A estratégia Alli Heik é uma conversão do assessor especialista MetaTrader 5 "AlliHeik". Ela opera o Heiken Ashi Smoothed Oscillator (HASO) originalmente publicado por mladen. O indicador constrói uma vela Heiken Ashi personalizada suavizando os preços brutos de abertura, máxima, mínima e fechamento com uma média móvel selecionável, aplica um passo de suavização adicional ao ponto médio de Heiken Ashi e, em seguida, mede a diferença barra a barra desse valor suavizado. Uma média móvel da diferença forma a linha de sinal.
As decisões de trading são tomadas no cruzamento do oscilador e da linha de sinal avaliada em velas completamente fechadas. A estratégia oferece um modo inverso opcional, a capacidade de fechar automaticamente posições opostas, tratamento estático de stop-loss/take-profit e um trailing stop que imita a lógica de passos da versão original do MetaTrader.
Regras de trading
Preparação do indicador
Pré-suavizar dados OHLC com uma de SMA, EMA, SMMA ou LWMA.
Construir velas Heiken Ashi a partir dos dados suavizados e calcular a média de abertura/fechamento para obter um ponto médio.
Pós-suavizar o ponto médio e calcular o oscilador como a diferença entre valores suavizados consecutivos.
Suavizar o oscilador com uma média móvel configurável para criar a linha de sinal.
Condições de entrada
Modo normal: abrir uma posição comprada quando o oscilador cruza abaixo da linha de sinal, abrir uma posição vendida quando cruza acima da linha de sinal (reproduzindo exatamente a lógica MQL).
Modo inverso: trocar as condições de comprado e vendido.
Os sinais são avaliados apenas em velas terminadas. As posições existentes podem opcionalmente ser fechadas antes de entrar em uma nova operação na direção oposta.
Gerenciamento de saídas
As distâncias estáticas de stop-loss e take-profit são expressas em pips e convertidas para preço usando o tamanho de tick e os decimais do instrumento.
Um trailing stop torna-se ativo assim que o preço avança TrailingStop + TrailingStep pips em lucro. O stop é então deslocado para preço atual - TrailingStop para posições compradas (ou preço atual + TrailingStop para posições vendidas) e só se move se o novo stop estiver pelo menos TrailingStep pips além do nível anterior.
Saídas manuais são emitidas se o preço tocar o stop ou o alvo configurados.
Parâmetros
Volume – volume de ordem em lotes.
Stop Loss (pips) – distância para o stop de proteção; definir como 0 para desabilitar.
Take Profit (pips) – distância para o alvo de lucro; definir como 0 para desabilitar.
Trailing Stop (pips) – distância do trailing stop; definir como 0 para desabilitar o trailing.
Trailing Step (pips) – avanço mínimo além do trailing stop antes que o stop se mova (deve ser positivo quando o trailing está habilitado).
Reverse Signals – inverter a interpretação comprado/vendido do cruzamento do oscilador.
Close Opposite – fechar uma posição existente antes de abrir uma nova operação na direção oposta.
Pre Smooth Period / Method – período e tipo de média móvel usado para suavizar os dados OHLC brutos.
Post Smooth Period / Method – parâmetros de média móvel para suavizar o ponto médio de Heiken Ashi.
Signal Period / Method – parâmetros de média móvel para a linha de sinal do oscilador.
Candle Type – fonte de velas usada para cálculos (período padrão de 15 minutos).
Notas de implementação
A conversão reproduz o Heiken Ashi Smoothed Oscillator original encadeando indicadores de média móvel do StockSharp (SMA, EMA, SMMA, LWMA) para pré-suavizar preços, construir a série Heiken Ashi e derivar a diferença do oscilador.
As distâncias em pips são traduzidas para deslocamentos de preço absolutos usando o tamanho de tick e a precisão decimal do instrumento, correspondendo ao tratamento de 3/5 dígitos do MetaTrader.
As verificações manuais de stop/alvo e o trailing stop baseado em passos são executados em cada vela terminada, refletindo de perto o comportamento da versão MQL.
Os sinais são processados apenas quando todos os valores necessários estão disponíveis; estados parciais do indicador são ignorados até que dados suficientes tenham se acumulado.
Nenhuma tradução Python é fornecida neste diretório.
namespace StockSharp.Samples.Strategies;
using System;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.Messages;
/// <summary>
/// Alli Heik strategy.
/// Uses Heikin Ashi candle patterns with EMA filter for trend following.
/// Buys on bullish HA candles when above EMA, sells on bearish HA candles when below EMA.
/// </summary>
public class AlliHeikStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _emaPeriod;
private decimal _prevHaOpen;
private decimal _prevHaClose;
private bool _initialized;
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public int EmaPeriod
{
get => _emaPeriod.Value;
set => _emaPeriod.Value = value;
}
public AlliHeikStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Source candles for the strategy", "General");
_emaPeriod = Param(nameof(EmaPeriod), 20)
.SetGreaterThanZero()
.SetDisplay("EMA Period", "Trend filter EMA period", "Indicators");
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevHaOpen = 0m;
_prevHaClose = 0m;
_initialized = false;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevHaOpen = 0;
_prevHaClose = 0;
_initialized = false;
var ema = new ExponentialMovingAverage { Length = EmaPeriod };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(ema, OnProcess)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, ema);
DrawOwnTrades(area);
}
}
private void OnProcess(ICandleMessage candle, decimal emaValue)
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
// Calculate Heikin Ashi values
decimal haClose = (candle.OpenPrice + candle.HighPrice + candle.LowPrice + candle.ClosePrice) / 4m;
decimal haOpen;
if (!_initialized)
{
haOpen = (candle.OpenPrice + candle.ClosePrice) / 2m;
_initialized = true;
}
else
{
haOpen = (_prevHaOpen + _prevHaClose) / 2m;
}
var haBullish = haClose > haOpen;
var haBearish = haClose < haOpen;
var prevHaBullish = _prevHaClose > _prevHaOpen;
var prevHaBearish = _prevHaClose < _prevHaOpen;
// Buy only on a bearish-to-bullish HA flip confirmed by the EMA filter.
if (haBullish && prevHaBearish && candle.ClosePrice > emaValue && Position <= 0)
{
BuyMarket();
}
// Sell only on a bullish-to-bearish HA flip confirmed by the EMA filter.
else if (haBearish && prevHaBullish && candle.ClosePrice < emaValue && Position >= 0)
{
SellMarket();
}
_prevHaOpen = haOpen;
_prevHaClose = haClose;
}
}
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 alli_heik_strategy(Strategy):
def __init__(self):
super(alli_heik_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Source candles for the strategy", "General")
self._ema_period = self.Param("EmaPeriod", 20) \
.SetDisplay("EMA Period", "Trend filter EMA period", "Indicators")
self._prev_ha_open = 0.0
self._prev_ha_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(alli_heik_strategy, self).OnReseted()
self._prev_ha_open = 0.0
self._prev_ha_close = 0.0
self._initialized = False
def OnStarted2(self, time):
super(alli_heik_strategy, self).OnStarted2(time)
self._prev_ha_open = 0.0
self._prev_ha_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)
h = float(candle.HighPrice)
l = float(candle.LowPrice)
c = float(candle.ClosePrice)
ha_close = (o + h + l + c) / 4.0
if not self._initialized:
ha_open = (o + c) / 2.0
self._initialized = True
else:
ha_open = (self._prev_ha_open + self._prev_ha_close) / 2.0
ha_bullish = ha_close > ha_open
ha_bearish = ha_close < ha_open
prev_ha_bullish = self._prev_ha_close > self._prev_ha_open
prev_ha_bearish = self._prev_ha_close < self._prev_ha_open
if ha_bullish and prev_ha_bearish and c > ev and self.Position <= 0:
self.BuyMarket()
elif ha_bearish and prev_ha_bullish and c < ev and self.Position >= 0:
self.SellMarket()
self._prev_ha_open = ha_open
self._prev_ha_close = ha_close
def CreateClone(self):
return alli_heik_strategy()