Die MultiTimeframeEmaAlignmentStrategy ist ein StockSharp-Port des MetaTrader 4 Expert Advisors 1h-4h-1d.mq4 aus dem Ordner MQL/7713. Der ursprüngliche Roboter gleicht schnelle und langsame exponentielle gleitende Durchschnitte über drei Zeitrahmen an und wendet ein schützendes Geldmanagement über feste Stop-Loss-, Take-Profit- und Trailing-Stop-Levels an. Diese C#-Version folgt der gleichen Grundidee und nutzt dabei die Indikatorbindungen und Ordnungshelfer von StockSharp.
Handelslogik
Die Strategie abonniert gleichzeitig drei Kerzenserien: M1 (Signalzeitrahmen), M5 (Mittelfristfilter) und M30 (Trendbestätigung mit höherem Zeitrahmen).
Jede Serie speist ein Paar exponentieller gleitender Durchschnitte (EMA) mit konfigurierbaren Längen (Standard 8 und 64).
Ein bullisches Setup erfordert, dass der schnelle EMA in allen drei Zeitrahmen über dem langsamen EMA bleibt. Außerdem darf der schnelle EMA nicht an Schwung verlieren (aktueller Wert größer oder gleich dem vorherigen Wert und auch über dem Wert vor ShiftDepth Balken).
Ein bärisches Setup erfordert, dass der schnelle EMA in allen drei Zeitrahmen unter dem langsamen EMA bleibt, wobei der schnelle EMA an Dynamik verliert.
Aufträge werden beim Schließen der M1-Kerze ausgelöst, wenn die Ausrichtungs- und Momentumprüfungen erfüllt sind. Long-Signale sind nur zulässig, wenn keine Long-Position offen ist (oder ein bestehender Short zuerst geschlossen wird) und umgekehrt.
Diese Interpretation stellt die Absicht der MT4-Bedingungen mit dem übergeordneten API von StockSharp wieder her. Die MQL „MA-Shift“-Vergleiche werden durch den ShiftDepth-Puffer emuliert, der EMA-Werte ein paar Kerzen zurückverfolgt und sicherstellt, dass die Dynamik mit der Einstiegsrichtung übereinstimmt.
Risikomanagement
Die Positionsgröße wird durch den Parameter TradeVolume gesteuert (standardmäßig 3 Lots wie beim Original EA).
Optionale Stop-Loss- und Take-Profit-Abstände werden in Pips angegeben. Sie werden über den PriceStep des Instruments in Preise umgewandelt (fällt bei Fehlen auf 0.0001 zurück).
Der Trailing-Stop reproduziert das Verhalten von EA, indem er den Stop-Preis immer dann näher an den Markt verschiebt, wenn der Handel weit genug voranschreitet.
Risikoparameter können unabhängig voneinander umgeschaltet werden und entsprechen den Flags StopLossMode, TakeProfitMode und TrailingStopMode aus dem Skript MQL.
Parameter
Parameter
Beschreibung
Standard
TradeVolume
Bestellvolumen, das von BuyMarket / SellMarket verwendet wird. Spiegelt die Eingabe Lots.
3
FastLength
EMA Zeitraum für die Schnellleitung.
8
SlowLength
EMA Zeitraum für die langsame Leitung.
64
ShiftDepth
Anzahl der historischen Kerzen, die zur Emulation der MQL gleitenden Durchschnittsverschiebungsvergleiche verwendet werden.
3
UseStopLoss
Ermöglicht einen festen Stop-Loss.
true
StopLossPips
Stop-Loss-Distanz, ausgedrückt in Pips.
75
UseTakeProfit
Ermöglicht Take-Profit.
true
TakeProfitPips
Take-Profit-Distanz, ausgedrückt in Pips.
150
UseTrailingStop
Aktiviert die Trailing-Stop-Verwaltung.
true
TrailingStopPips
Nachlaufdistanz in Pips.
30
M1CandleType
Kerzentyp für den Signalzeitrahmen (Standard 1 Minute).
1m
M5CandleType
Kerzentyp für den Halbzeitfilter (Standard 5 Minuten).
5m
M30CandleType
Kerzentyp für den höheren Zeitrahmen (Standard 30 Minuten).
30m
Nutzungshinweise
Hängen Sie die Strategie an ein Instrument an und stellen Sie sicher, dass historische Daten für alle drei Zeitrahmen verfügbar sind, damit die EMA-Puffer gefüllt werden können.
Der Parameter ShiftDepth sollte mindestens 2 betragen, damit die Strategie die kurzfristige Dynamik validieren kann.
Wenn UseTrailingStop ohne UseStopLoss aktiv ist, initialisiert die abschließende Logik immer noch einen Stoppwert, sobald sich der Handel positiv entwickelt.
Da StockSharp bei Kerzenschluss ausgeführt wird, können die Ergebnisse leicht von der Tick-für-Tick-Ausführung der MT4-Version abweichen, insbesondere auf volatilen Märkten. Das zentrale Trendausrichtungsverhalten bleibt erhalten.
Konvertierungshinweise
Indikatorberechnungen basieren ausschließlich auf dem Bind-Mechanismus von StockSharp; Es werden keine manuellen Indikatorverlaufssammlungen verwendet.
Die Auftragsverwaltung wird mit High-Level-Helfern (BuyMarket, SellMarket) und interner Preisverfolgung anstelle direkter OrderSend-Aufrufe implementiert.
E-Mail-Benachrichtigungen und Slippage-Kontrollen aus dem MQL-Skript werden weggelassen, da sie außerhalb des Geltungsbereichs von StockSharp liegen.
Dateien
CS/MultiTimeframeEmaAlignmentStrategy.cs – Hauptimplementierung der C#-Strategie.
README_ru.md – Russische Dokumentation.
README_zh.md – Chinesische Dokumentation.
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>
/// Multi-Timeframe EMA Alignment strategy - fast/slow EMA crossover with trend EMA filter.
/// Buys when fast EMA crosses above slow EMA while close is above trend EMA.
/// Sells when fast EMA crosses below slow EMA while close is below trend EMA.
/// </summary>
public class MultiTimeframeEmaAlignmentStrategy : Strategy
{
private readonly StrategyParam<int> _fastPeriod;
private readonly StrategyParam<int> _slowPeriod;
private readonly StrategyParam<int> _trendPeriod;
private readonly StrategyParam<DataType> _candleType;
private decimal _prevFast;
private decimal _prevSlow;
private bool _hasPrev;
public int FastPeriod { get => _fastPeriod.Value; set => _fastPeriod.Value = value; }
public int SlowPeriod { get => _slowPeriod.Value; set => _slowPeriod.Value = value; }
public int TrendPeriod { get => _trendPeriod.Value; set => _trendPeriod.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public MultiTimeframeEmaAlignmentStrategy()
{
_fastPeriod = Param(nameof(FastPeriod), 10)
.SetDisplay("Fast EMA", "Fast EMA period", "Indicators");
_slowPeriod = Param(nameof(SlowPeriod), 30)
.SetDisplay("Slow EMA", "Slow EMA period", "Indicators");
_trendPeriod = Param(nameof(TrendPeriod), 100)
.SetDisplay("Trend EMA", "Trend EMA period", "Indicators");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame())
.SetDisplay("Candle Type", "Candle timeframe", "General");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities() => [(Security, CandleType)];
protected override void OnReseted() { base.OnReseted(); _prevFast = 0m; _prevSlow = 0m; _hasPrev = false; }
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_hasPrev = false;
var fast = new ExponentialMovingAverage { Length = FastPeriod };
var slow = new ExponentialMovingAverage { Length = SlowPeriod };
var trend = new ExponentialMovingAverage { Length = TrendPeriod };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(fast, slow, trend, ProcessCandle)
.Start();
}
private void ProcessCandle(ICandleMessage candle, decimal fast, decimal slow, decimal trend)
{
if (candle.State != CandleStates.Finished)
return;
var close = candle.ClosePrice;
if (!_hasPrev)
{
_prevFast = fast;
_prevSlow = slow;
_hasPrev = true;
return;
}
if (_prevFast <= _prevSlow && fast > slow && close > trend && Position <= 0)
{
if (Position < 0)
BuyMarket();
BuyMarket();
}
else if (_prevFast >= _prevSlow && fast < slow && close < trend && Position >= 0)
{
if (Position > 0)
SellMarket();
SellMarket();
}
_prevFast = fast;
_prevSlow = slow;
}
}
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 multi_timeframe_ema_alignment_strategy(Strategy):
def __init__(self):
super(multi_timeframe_ema_alignment_strategy, self).__init__()
self._fast_period = self.Param("FastPeriod", 10).SetDisplay("Fast EMA", "Fast EMA period", "Indicators")
self._slow_period = self.Param("SlowPeriod", 30).SetDisplay("Slow EMA", "Slow EMA period", "Indicators")
self._trend_period = self.Param("TrendPeriod", 100).SetDisplay("Trend EMA", "Trend EMA period", "Indicators")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(1))).SetDisplay("Candle Type", "Candle timeframe", "General")
self._prev_fast = 0.0; self._prev_slow = 0.0; self._has_prev = False
@property
def fast_period(self): return self._fast_period.Value
@property
def slow_period(self): return self._slow_period.Value
@property
def trend_period(self): return self._trend_period.Value
@property
def candle_type(self): return self._candle_type.Value
def OnReseted(self):
super(multi_timeframe_ema_alignment_strategy, self).OnReseted()
self._prev_fast = 0.0; self._prev_slow = 0.0; self._has_prev = False
def OnStarted2(self, time):
super(multi_timeframe_ema_alignment_strategy, self).OnStarted2(time)
self._has_prev = False
fast = ExponentialMovingAverage()
fast.Length = self.fast_period
slow = ExponentialMovingAverage()
slow.Length = self.slow_period
trend = ExponentialMovingAverage()
trend.Length = self.trend_period
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(fast, slow, trend, self.process_candle).Start()
def process_candle(self, candle, fast, slow, trend):
if candle.State != CandleStates.Finished: return
close = float(candle.ClosePrice)
f = float(fast); s = float(slow); t = float(trend)
if not self._has_prev:
self._prev_fast = f; self._prev_slow = s; self._has_prev = True; return
if self._prev_fast <= self._prev_slow and f > s and close > t and self.Position <= 0:
if self.Position < 0: self.BuyMarket()
self.BuyMarket()
elif self._prev_fast >= self._prev_slow and f < s and close < t and self.Position >= 0:
if self.Position > 0: self.SellMarket()
self.SellMarket()
self._prev_fast = f; self._prev_slow = s
def CreateClone(self): return multi_timeframe_ema_alignment_strategy()