Konvertierung des MetaTrader 5-Expertenberaters "Crossing Moving Average (barabashkakvn's edition)" aus dem Quellcode MQL/21515.
Implementiert die Logik auf der StockSharp-High-Level-API mit Kerzen-Abonnements und Indikator-Bindung.
Entwickelt für Instrumente, bei denen Momentum und gleitende Durchschnittskruzungen Trendumkehrungen erfassen.
Dieses Paket enthält nur die C#-Version. Eine Python-Übersetzung wird gemäß Anfrage absichtlich weggelassen.
Kernidee
Die Strategie überwacht zwei konfigurierbare gleitende Durchschnitte (schnell und langsam) mit optionalen Vorwärtsverschiebungen und kombiniert ihre Kreuzung mit einem Momentum-Bestätigungsfilter. Ein Trade wird nur geöffnet, wenn:
Der schnelle Durchschnitt den langsamen Durchschnitt um mindestens die konfigurierte Mindestdistanz (in Pips) über die zwei jüngsten abgeschlossenen Balken kreuzt.
Der Momentum-Indikator über (für Long) oder unter (für Short) den benutzerdefinierten Schwellenwert steigt und sich in Richtung des Trades verbessert.
Die Signalpreisquelle kann zwischen Eröffnung, Hoch, Tief, Schluss, Median, Typisch oder gewichteten Kerzenpreisen gewählt werden, um MetaTrader-Angewandte-Preis-Modi nachzuahmen.
Risiko- und Trade-Management
Das Ordervolumen ist pro Trade fest und wird sowohl beim Einsteigen in eine neue Position als auch beim Umkehren einer bestehenden Position angewendet.
Stop-Loss/Take-Profit-Abstände werden in Pips konfiguriert und automatisch in Preisoffsets unter Verwendung von Security.PriceStep umgewandelt. Für Instrumente mit 3 oder 5 Dezimalstellen multipliziert die Strategie den Schritt mit 10, um die MetaTrader-Pip-Größe zu reproduzieren.
Der Trailing-Stop aktiviert sich, nachdem sich der Preis um TrailingStop + TrailingStep (in Pips) vom Einstieg bewegt. Einmal ausgelöst, wird der Stop auf aktueller Preis - TrailingStop für Long-Positionen (oder aktueller Preis + TrailingStop für Shorts) bewegt, wann immer er um mindestens TrailingStep Pips vorrücken kann.
Schutzlevels werden bei jeder fertigen Kerze ausgewertet: Wenn der Kerzenbereich den Stop-Loss oder Take-Profit berührt, wird die Position zum Markt geschlossen, um die Orderausführung in MetaTrader nachzuahmen.
Indikatoren
Schneller Gleitender Durchschnitt – konfigurierbarer Zeitraum, Verschiebung und Glättungsmethode (SMA, EMA, SMMA, WMA).
Langsamer Gleitender Durchschnitt – gleiche Optionen wie der schnelle MA.
Momentum – Zeitraum und Preisquelle identisch mit den gleitenden Durchschnitten. Die Strategie erkennt automatisch, ob der Indikator Werte um 0 oder 100 ausgibt, und wendet den Filter entsprechend an.
Signallogik
Warten, bis alle Indikatoren vollständig gebildet sind. Der Algorithmus führt eine interne Geschichte der neuesten Werte, um verschobene Kreuzungen genau wie im ursprünglichen Expertenberater auszuwerten.
Die Preisdistanz zwischen dem schnellen und langsamen Durchschnitt auf den zwei vorherigen Balken (mit angewendeten Verschiebungen) berechnen. Die schnelle Linie muss die langsame Linie kreuzen und den Mindestdistanzfilter überschreiten.
Momentum-Werte auf denselben Balken abrufen. Für Long-Einstiege muss das aktuelle Momentum größer als sowohl der konfigurierte Schwellenwert als auch der vorherige Momentum-Wert sein; für Short-Einstiege ist das Gegenteil erforderlich.
Wenn ein neues Signal erscheint, während die Position entgegengesetzt ist, schließt die Strategie die bestehende Position und öffnet sofort eine in der neuen Richtung mit der konfigurierten Losgröße.
Parameterreferenz
Parameter
Beschreibung
Standard
OrderVolume
Basisvolumen für jede Marktorder.
1
StopLossPips
Stop-Loss-Abstand in Pips (0 deaktiviert den Stop).
50
TakeProfitPips
Take-Profit-Abstand in Pips (0 deaktiviert das Ziel).
50
TrailingStopPips
Trailing-Stop-Abstand in Pips (0 deaktiviert Trailing).
5
TrailingStepPips
Mindest-Pip-Verbesserung zum Bewegen des Trailing-Stops.
5
MinDistancePips
Mindestabstand zwischen MAs zur Validierung der Kreuzung.
0
MomentumFilter
Mindestmomentum-Differenz für Einstiege.
0.1
FastPeriod / FastShift
Länge des schnellen MA und horizontale Verschiebung (Balken).
13 / 1
SlowPeriod / SlowShift
Länge des langsamen MA und horizontale Verschiebung (Balken).
Immer sicherstellen, dass Security.PriceStep für das Instrument konfiguriert ist; andernfalls fällt das pip-basierte Risikomanagement auf rohe Preiseinheiten zurück.
Die Trailing-Logik erfordert ein positives TrailingStepPips, wenn TrailingStopPips aktiviert ist—spiegelt die ursprüngliche MetaTrader-Validierung wider.
Da Stop- und Take-Levels auf Kerzenbereichen ausgewertet werden, bietet die Verwendung hochauflösenderer Kerzen eine genauere Annäherung an tick-basierte Ausführung.
Protokollierungsmeldungen bei Einstiegen und Trailing-Anpassungen sind enthalten, um Debugging und Parameteroptimierung zu erleichtern.
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>
/// Moving average crossover strategy.
/// Enters long when fast EMA crosses above slow EMA, enters short on the opposite crossover.
/// </summary>
public class CrossingMovingAverageStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _fastPeriod;
private readonly StrategyParam<int> _slowPeriod;
private decimal? _prevFast;
private decimal? _prevSlow;
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 CrossingMovingAverageStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame())
.SetDisplay("Candle Type", "Timeframe", "General");
_fastPeriod = Param(nameof(FastPeriod), 13)
.SetGreaterThanZero()
.SetDisplay("Fast Period", "Fast EMA period", "Indicators");
_slowPeriod = Param(nameof(SlowPeriod), 34)
.SetGreaterThanZero()
.SetDisplay("Slow Period", "Slow EMA period", "Indicators");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevFast = null;
_prevSlow = null;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevFast = null;
_prevSlow = null;
var fastEma = new ExponentialMovingAverage { Length = FastPeriod };
var slowEma = new ExponentialMovingAverage { Length = SlowPeriod };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(fastEma, slowEma, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, fastEma);
DrawIndicator(area, slowEma);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal fast, decimal slow)
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
{
_prevFast = fast;
_prevSlow = slow;
return;
}
if (_prevFast == null || _prevSlow == null)
{
_prevFast = fast;
_prevSlow = slow;
return;
}
// Crossover detection
var prevAbove = _prevFast.Value > _prevSlow.Value;
var currAbove = fast > slow;
_prevFast = fast;
_prevSlow = slow;
// Golden cross: fast crosses above slow
if (!prevAbove && currAbove)
{
if (Position < 0)
BuyMarket();
if (Position <= 0)
BuyMarket();
}
// Death cross: fast crosses below slow
else if (prevAbove && !currAbove)
{
if (Position > 0)
SellMarket();
if (Position >= 0)
SellMarket();
}
}
}
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 crossing_moving_average_strategy(Strategy):
def __init__(self):
super(crossing_moving_average_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(1))) \
.SetDisplay("Candle Type", "Timeframe", "General")
self._fast_period = self.Param("FastPeriod", 13) \
.SetDisplay("Fast Period", "Fast EMA period", "Indicators")
self._slow_period = self.Param("SlowPeriod", 34) \
.SetDisplay("Slow Period", "Slow EMA period", "Indicators")
self._prev_fast = None
self._prev_slow = None
@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(crossing_moving_average_strategy, self).OnReseted()
self._prev_fast = None
self._prev_slow = None
def OnStarted2(self, time):
super(crossing_moving_average_strategy, self).OnStarted2(time)
self._prev_fast = None
self._prev_slow = None
fast_ema = ExponentialMovingAverage()
fast_ema.Length = self.FastPeriod
slow_ema = ExponentialMovingAverage()
slow_ema.Length = self.SlowPeriod
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(fast_ema, slow_ema, self._on_process).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, fast_ema)
self.DrawIndicator(area, slow_ema)
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 self._prev_fast is None or self._prev_slow is None:
self._prev_fast = fv
self._prev_slow = sv
return
prev_above = self._prev_fast > self._prev_slow
curr_above = fv > sv
self._prev_fast = fv
self._prev_slow = sv
# Golden cross: fast crosses above slow
if not prev_above and curr_above:
if self.Position < 0:
self.BuyMarket()
if self.Position <= 0:
self.BuyMarket()
# Death cross: fast crosses below slow
elif prev_above and not curr_above:
if self.Position > 0:
self.SellMarket()
if self.Position >= 0:
self.SellMarket()
def CreateClone(self):
return crossing_moving_average_strategy()