Diese Strategie ist die StockSharp-Umstellung des MetaTrader 4-Expertenberaters mit Sitz in MQL/8606/EMA_CROSS_2.mq4. Es behält die ursprüngliche Idee bei, die Beziehung zwischen einem langsamen und einem schnellen exponentiellen gleitenden Durchschnitt zu verfolgen und eine einzelne Marktposition zu eröffnen, wenn ein Crossover auftritt. Schutzexits (Take-Profit, Stop-Loss und Trailing-Stop) werden über den übergeordneten StartProtection-Helfer abgewickelt, sodass das Verhalten die MetaTrader-Implementierung unter Verwendung der Best Practices von StockSharp widerspiegelt.
Handelslogik
Erstellen Sie Kerzen mit den konfigurierbaren CandleType (standardmäßig 15-Minuten-Balken) und füttern Sie zwei EMA-Indikatoren: Der langsame EMA verwendet SlowEmaLength und der schnelle EMA verwendet FastEmaLength.
Behalten Sie die aktuelle Richtung des langsamen EMA relativ zum schnellen EMA bei. Die erste abgeschlossene Kerze, nachdem beide Indikatoren gebildet wurden, wird nur zur Initialisierung dieser Richtung verwendet, genau wie der first_time-Schutz im ursprünglichen Berater.
Wenn sich der langsame EMA über den schnellen EMA bewegt (die neue Richtung wird zu 1) und die Strategie flach ist, senden Sie eine Marktkauforder. Wenn der langsame EMA unter den schnellen EMA fällt (die neue Richtung wird zu 2) und die Strategie flach ist, senden Sie einen Marktverkaufsauftrag. Dies reproduziert die genaue Auf-/Ab-Zuordnung der MQL-Funktion Crossed(LEma, SEma).
Es kann jeweils nur eine Position aktiv sein. Während ein Trade offen ist (oder die Einstiegsorder noch aussteht), werden zusätzliche Crossovers ignoriert.
Handels- und Risikomanagement
StartProtection konfiguriert Take-Profit-, Stop-Loss- und Trailing-Stop-Abstände in Preiseinheiten, die aus dem Instrument PriceStep berechnet werden. Trailing Stops sind optional: Setzen Sie TrailingStopPips auf Null, um sie zu deaktivieren.
Aufträge werden mit BuyMarket/SellMarket aufgegeben und vom Markt geschlossen, wenn ein Schutzniveau ausgelöst wird, genau wie die OrderSend- und Nachfolgelogik des ursprünglichen Beraters.
Die Basislosgröße wird durch OrderVolume gesteuert. Vor jeder Eingabe wird auf die Lautstärkestufe, das Minimum und das Maximum des Instruments abgeglichen, um eine Ablehnung zu vermeiden.
Parameter
Parameter
Beschreibung
TakeProfitPips
Abstand in Pips (Preisschritten), der für den schützenden Take-Profit verwendet wird. Standard: 20.
StopLossPips
Abstand in Pips, der für den schützenden Stop-Loss verwendet wird. Standard: 30.
TrailingStopPips
Nachlaufdistanz in Pips. Auf 0 setzen, um das Nachstellen zu deaktivieren. Standard: 50.
OrderVolume
Losgröße der Markteintritte vor der Ausrichtung. Standard: 2.
FastEmaLength
Periode des schnellen EMA, der auf die Schlusskurse angewendet wird. Standard: 5.
SlowEmaLength
Zeitraum der langsamen EMA, angewendet auf die Schlusskurse. Standard: 60.
CandleType
Zeitrahmen für den Kerzenbau. Standard: 15 Minuten.
Notizen
Die Strategie wartet, bis beide EMAs vollständig gebildet sind, bevor sie auf einen Crossover reagiert. Dabei wird die Bars < 100-Prüfung aus dem MQL-Skript entfernt und gleichzeitig die gleiche Stabilität erreicht.
Da nur Marktaufträge verwendet werden, gibt es keine einzelnen OrderModify-Aufrufe. Das integrierte Schutzmodul positioniert den Trailing Stop automatisch auf die gleiche Weise neu, wie die MetaTrader-Schleife OrderStopLoss aktualisiert hat.
Es wird kein Python-Port bereitgestellt (auf Anfrage); Es ist nur die C#-Implementierung enthalten.
using System;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// EMA crossover strategy with trailing stop.
/// Buys when fast EMA crosses above slow EMA, sells on the opposite crossover.
/// </summary>
public class EmaCrossTrailingStrategy : Strategy
{
private readonly StrategyParam<int> _fastEmaLength;
private readonly StrategyParam<int> _slowEmaLength;
private readonly StrategyParam<DataType> _candleType;
private int _currentDirection;
private bool _hasInitialDirection;
public EmaCrossTrailingStrategy()
{
_fastEmaLength = Param(nameof(FastEmaLength), 5)
.SetDisplay("Fast EMA", "Length of the fast exponential moving average.", "Indicator");
_slowEmaLength = Param(nameof(SlowEmaLength), 60)
.SetDisplay("Slow EMA", "Length of the slow exponential moving average.", "Indicator");
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(15).TimeFrame())
.SetDisplay("Candle Type", "Time frame used to build candles and EMAs.", "General");
}
public int FastEmaLength
{
get => _fastEmaLength.Value;
set => _fastEmaLength.Value = value;
}
public int SlowEmaLength
{
get => _slowEmaLength.Value;
set => _slowEmaLength.Value = value;
}
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_currentDirection = 0;
_hasInitialDirection = false;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var fastEma = new ExponentialMovingAverage { Length = FastEmaLength };
var slowEma = new ExponentialMovingAverage { Length = SlowEmaLength };
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 fastValue, decimal slowValue)
{
if (candle.State != CandleStates.Finished)
return;
// Determine direction: 1 = fast above slow (bullish), -1 = fast below slow (bearish)
var newDirection = fastValue > slowValue ? 1 : fastValue < slowValue ? -1 : 0;
if (newDirection == 0)
return;
if (!_hasInitialDirection)
{
_currentDirection = newDirection;
_hasInitialDirection = true;
return;
}
if (newDirection == _currentDirection)
return;
var prevDirection = _currentDirection;
_currentDirection = newDirection;
// Crossover detected
if (newDirection == 1 && prevDirection == -1)
{
// Bullish crossover
if (Position < 0)
BuyMarket(); // Close short
if (Position <= 0)
BuyMarket(); // Open long
}
else if (newDirection == -1 && prevDirection == 1)
{
// Bearish crossover
if (Position > 0)
SellMarket(); // Close long
if (Position >= 0)
SellMarket(); // Open short
}
}
}
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 ema_cross_trailing_strategy(Strategy):
"""
EMA crossover strategy with trailing stop.
Buys when fast EMA crosses above slow EMA, sells on opposite crossover.
"""
def __init__(self):
super(ema_cross_trailing_strategy, self).__init__()
self._fast_ema_length = self.Param("FastEmaLength", 5) \
.SetDisplay("Fast EMA", "Length of the fast EMA", "Indicator")
self._slow_ema_length = self.Param("SlowEmaLength", 60) \
.SetDisplay("Slow EMA", "Length of the slow EMA", "Indicator")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(15))) \
.SetDisplay("Candle Type", "Time frame for candles and EMAs", "General")
self._current_direction = 0
self._has_initial_direction = False
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(ema_cross_trailing_strategy, self).OnReseted()
self._current_direction = 0
self._has_initial_direction = False
def OnStarted2(self, time):
super(ema_cross_trailing_strategy, self).OnStarted2(time)
fast_ema = ExponentialMovingAverage()
fast_ema.Length = self._fast_ema_length.Value
slow_ema = ExponentialMovingAverage()
slow_ema.Length = self._slow_ema_length.Value
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(fast_ema, slow_ema, self._process_candle).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 _process_candle(self, candle, fast_val, slow_val):
if candle.State != CandleStates.Finished:
return
fast_val = float(fast_val)
slow_val = float(slow_val)
if fast_val > slow_val:
new_direction = 1
elif fast_val < slow_val:
new_direction = -1
else:
return
if not self._has_initial_direction:
self._current_direction = new_direction
self._has_initial_direction = True
return
if new_direction == self._current_direction:
return
prev_direction = self._current_direction
self._current_direction = new_direction
if new_direction == 1 and prev_direction == -1:
if self.Position < 0:
self.BuyMarket()
if self.Position <= 0:
self.BuyMarket()
elif new_direction == -1 and prev_direction == 1:
if self.Position > 0:
self.SellMarket()
if self.Position >= 0:
self.SellMarket()
def CreateClone(self):
return ema_cross_trailing_strategy()