Die Alli Heik-Strategie ist eine Konvertierung des MetaTrader 5-Expertenberaters "AlliHeik". Sie handelt den Heiken Ashi Smoothed Oscillator (HASO), der ursprünglich von mladen veröffentlicht wurde. Der Indikator erstellt eine benutzerdefinierte Heiken-Ashi-Kerze, indem er die rohen Eröffnungs-, Hoch-, Tief- und Schlusskurse mit einem wählbaren gleitenden Durchschnitt glättet, einen zusätzlichen Glättungsdurchgang auf den Heiken-Ashi-Mittelpunkt anwendet und dann die Bar-zu-Bar-Differenz dieses geglätteten Werts misst. Ein gleitender Durchschnitt der Differenz bildet die Signallinie.
Handelsentscheidungen werden auf dem Crossover des Oszillators und der Signallinie getroffen, bewertet auf vollständig geschlossenen Kerzen. Die Strategie bietet einen optionalen Umkehrmodus, die Möglichkeit, entgegengesetzte Positionen automatisch zu schließen, statische Stop-Loss/Take-Profit-Behandlung und einen Trailing-Stop, der die Schrittlogik der ursprünglichen MetaTrader-Version imitiert.
Handelsregeln
Indikatorvorbereitung
OHLC-Daten mit einer von SMA, EMA, SMMA oder LWMA vor-glätten.
Heiken-Ashi-Kerzen aus den geglätteten Daten erstellen und Eröffnung/Schluss mitteln, um einen Mittelpunkt zu erhalten.
Den Mittelpunkt nach-glätten und den Oszillator als Differenz zwischen aufeinanderfolgenden geglätteten Werten berechnen.
Den Oszillator mit einem konfigurierbaren gleitenden Durchschnitt glätten, um die Signallinie zu erstellen.
Einstiegsbedingungen
Normalmodus: Long öffnen, wenn der Oszillator unter die Signallinie kreuzt, Short öffnen, wenn er über die Signallinie kreuzt (exakte Reproduktion der MQL-Logik).
Umkehrmodus: Long- und Short-Bedingungen tauschen.
Signale werden nur auf abgeschlossenen Kerzen ausgewertet. Bestehende Positionen können optional geschlossen werden, bevor ein neuer Trade in die entgegengesetzte Richtung eingegangen wird.
Ausstiegsmanagement
Statische Stop-Loss- und Take-Profit-Abstände werden in Pips ausgedrückt und mithilfe der Tick-Größe und Dezimalstellen des Instruments in Preise umgerechnet.
Ein Trailing-Stop wird aktiv, wenn sich der Preis um TrailingStop + TrailingStep Pips im Gewinn bewegt. Der Stop wird dann auf aktueller Preis - TrailingStop für Longs (oder aktueller Preis + TrailingStop für Shorts) verschoben und bewegt sich nur, wenn der neue Stop mindestens TrailingStep Pips über dem vorherigen Level liegt.
Manuelle Ausstiege werden ausgelöst, wenn der Preis den konfigurierten Stop oder das Ziel berührt.
Parameter
Volume – Ordervolumen in Lots.
Stop Loss (pips) – Abstand für den Schutz-Stop; auf 0 setzen zum Deaktivieren.
Take Profit (pips) – Abstand für das Gewinnziel; auf 0 setzen zum Deaktivieren.
Trailing Stop (pips) – Trailing-Stop-Abstand; auf 0 setzen zum Deaktivieren des Trailings.
Trailing Step (pips) – Mindestfortschritt über den Trailing-Stop hinaus, bevor der Stop bewegt wird (muss positiv sein, wenn Trailing aktiviert ist).
Reverse Signals – Long/Short-Interpretation des Oszillator-Crossovers umkehren.
Close Opposite – Eine bestehende Position schließen, bevor ein neuer Trade in die entgegengesetzte Richtung eröffnet wird.
Pre Smooth Period / Method – Gleitender Durchschnittszeitraum und -typ zum Glätten der rohen OHLC-Daten.
Post Smooth Period / Method – Gleitende Durchschnittsparameter zum Glätten des Heiken-Ashi-Mittelpunkts.
Signal Period / Method – Gleitende Durchschnittsparameter für die Oszillator-Signallinie.
Candle Type – Für Berechnungen verwendete Kerzenquelle (Standard: 15-Minuten-Zeitrahmen).
Implementierungshinweise
Die Konvertierung reproduziert den ursprünglichen Heiken Ashi Smoothed Oscillator durch Verkettung von StockSharp-Gleitenden-Durchschnitts-Indikatoren (SMA, EMA, SMMA, LWMA) zum Vor-Glätten von Preisen, Erstellen der Heiken-Ashi-Reihe und Ableiten der Oszillatordifferenz.
Pip-Abstände werden mithilfe der Tick-Größe und Dezimalpräzision des Instruments in absolute Preisoffsets übersetzt, was der 3/5-Ziffern-Behandlung von MetaTrader entspricht.
Manuelle Stop/Ziel-Überprüfungen und der schrittbasierte Trailing-Stop werden bei jeder abgeschlossenen Kerze ausgeführt und spiegeln das Verhalten der MQL-Version eng wider.
Signale werden nur verarbeitet, wenn alle erforderlichen Werte verfügbar sind; partielle Indikatorzustände werden ignoriert, bis genügend Daten angesammelt wurden.
In diesem Verzeichnis wird keine Python-Übersetzung bereitgestellt.
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()