Diese Strategie repliziert den MetaTrader 5 Expert Advisor „iMA iSAR EA" unter Verwendung der StockSharp High-Level-API. Sie kombiniert einen dreifachen gewichteten gleitenden Durchschnittsfilter mit zwei Parabolic-SAR-Trails, um Momentum-Ausbrüche zu identifizieren. Eine Long-Position wird eröffnet, wenn der schnellste gewichtete gleitende Durchschnitt über den anderen beiden Durchschnitten bleibt und beide SAR-Trails unterhalb des Kerzen-Schlusskurses liegen. Eine gespiegelte Bedingung erzeugt Short-Einstiege. Schutzstops, Gewinnziele und ein optionaler Trailing-Stop werden in Preispunkten (Pips) verwaltet.
Die Implementierung arbeitet auf einer einzigen Kerzenserie, die über den Parameter CandleType konfigurierbar ist. Alle Indikatoren werden auf diesem Zeitrahmen ausgewertet. Der ursprüngliche MetaTrader Expert verwendete mehrere Zeitrahmen für seine Indikatoren; in StockSharp wird dieses Verhalten durch individuelle Gleitdurchschnitts-Shifts approximiert, die jedes Signal um eine Anzahl abgeschlossener Bars verzögern können.
Handelsregeln
Indikatoren
Drei gewichtete gleitende Durchschnitte (Fast, Normal, Slow) berechnet auf dem konfigurierten Kerzenstream. Optionale Bar-Shifts emulieren die verzögerten Puffer aus dem originalen MQ5-Code.
Zwei Parabolic-SAR-Indikatoren (FastSAR, NormalSAR) teilen denselben Kerzenstream, haben aber unabhängige Beschleunigungs- und Maximalschrittparameter.
Einstiegsbedingungen
Long: Fast MA liegt über Normal und Slow, während beide SAR-Werte unter dem Kerzen-Schlusskurs liegen.
Short: Fast MA liegt unter Normal und Slow, während beide SAR-Werte über dem Kerzen-Schlusskurs liegen.
Wenn ein Umkehrsignal erscheint, schließt die Strategie jedes entgegengesetzte Exposure und wechselt die Richtung in einer einzigen Marktorder.
Risikokontrollen
Feste Stop-Loss- und Take-Profit-Niveaus werden in Pips ausgedrückt (Vielfache des Wertpapier-Preisschritts). Sie werden auf abgeschlossenen Kerzen ausgewertet.
Optionaler Trailing-Stop: Einmal aktiviert folgt der Stop dem Schlusskurs in konfigurierbarem Abstand und rückt nur vor, nachdem er sich um den angegebenen Trailing-Schritt bewegt hat.
Volumina werden an die Einstellungen VolumeStep, MinVolume und MaxVolume des Wertpapiers angepasst, bevor Orders gesendet werden.
Parameter
Name
Typ
Standard
Beschreibung
Volume
decimal
0.1
Basis-Ordergröße. Wird automatisch erhöht, um eine entgegengesetzte Position beim Richtungswechsel zu decken.
StopLossPips
decimal
50
Schutzstop-Abstand in Pips. Auf 0 setzen zum Deaktivieren.
TakeProfitPips
decimal
50
Gewinnziel-Abstand in Pips. Auf 0 setzen zum Deaktivieren.
UseTrailing
bool
true
Aktiviert das dynamische Trailing-Stop-Management.
TrailingStopPips
decimal
25
Abstand zwischen Preis und Trailing-Stop, in Pips.
TrailingStepPips
decimal
5
Minimale günstige Bewegung (Pips) bevor der Trailing-Stop vorrückt.
CandleType
DataType
TimeFrameCandle 15m
Kerzenserie für alle Berechnungen.
FastMaPeriod
int
10
Periode des schnellen gewichteten gleitenden Durchschnitts.
FastMaShift
int
0
Anzahl abgeschlossener Bars zur Rückverschiebung des schnellen MA.
NormalMaPeriod
int
30
Periode des normalen gewichteten gleitenden Durchschnitts.
NormalMaShift
int
3
Anzahl abgeschlossener Bars zur Rückverschiebung des normalen MA.
SlowMaPeriod
int
60
Periode des langsamen gewichteten gleitenden Durchschnitts.
SlowMaShift
int
6
Anzahl abgeschlossener Bars zur Rückverschiebung des langsamen MA.
FastSarStep
decimal
0.02
Beschleunigungsfaktor für den schnellen Parabolic SAR.
FastSarMax
decimal
0.2
Maximale Beschleunigung für den schnellen Parabolic SAR.
NormalSarStep
decimal
0.02
Beschleunigungsfaktor für den normalen Parabolic SAR.
NormalSarMax
decimal
0.2
Maximale Beschleunigung für den normalen Parabolic SAR.
Hinweise
Trailing-Stop-Prüfungen erfolgen beim Kerzen-Schluss. Wenn Intrabar-Präzision erforderlich ist, kombinieren Sie die Strategie mit einer tick-basierten Schutzkomponente.
Die Pip-Größe entspricht dem Wertpapier-Preisschritt, wenn verfügbar. Andernfalls wird ein Standard-Tick von 0.0001 für FX-Paare angenommen.
Für Konsistenz mit der MetaTrader-Version arbeiten alle Indikatorsignale auf geschlossenen Kerzen. Ausstehende Transaktionen werden nicht vorbereitet; jedes Signal sendet sofort eine Marktorder.
using System;
using System.Collections.Generic;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
public class ImaIsarEaStrategy : Strategy
{
private readonly StrategyParam<int> _fastPeriod;
private readonly StrategyParam<int> _slowPeriod;
private readonly StrategyParam<int> _stopLossPoints;
private readonly StrategyParam<int> _takeProfitPoints;
private ExponentialMovingAverage _fast;
private ExponentialMovingAverage _slow;
private decimal _prevFast;
private decimal _prevSlow;
private decimal _entryPrice;
private int _cooldown;
public int FastPeriod { get => _fastPeriod.Value; set => _fastPeriod.Value = value; }
public int SlowPeriod { get => _slowPeriod.Value; set => _slowPeriod.Value = value; }
public int StopLossPoints { get => _stopLossPoints.Value; set => _stopLossPoints.Value = value; }
public int TakeProfitPoints { get => _takeProfitPoints.Value; set => _takeProfitPoints.Value = value; }
public ImaIsarEaStrategy()
{
_fastPeriod = Param(nameof(FastPeriod), 14).SetGreaterThanZero().SetDisplay("Fast Period", "Fast EMA period", "Indicator");
_slowPeriod = Param(nameof(SlowPeriod), 50).SetGreaterThanZero().SetDisplay("Slow Period", "Slow EMA period", "Indicator");
_stopLossPoints = Param(nameof(StopLossPoints), 200).SetNotNegative().SetDisplay("Stop Loss", "Stop-loss in price steps", "Risk");
_takeProfitPoints = Param(nameof(TakeProfitPoints), 400).SetNotNegative().SetDisplay("Take Profit", "Take-profit in price steps", "Risk");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
yield return (Security, TimeSpan.FromMinutes(5).TimeFrame());
}
protected override void OnReseted()
{
base.OnReseted();
_fast = null; _slow = null;
_prevFast = 0; _prevSlow = 0; _entryPrice = 0; _cooldown = 0;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_fast = new ExponentialMovingAverage { Length = FastPeriod };
_slow = new ExponentialMovingAverage { Length = SlowPeriod };
var subscription = SubscribeCandles(TimeSpan.FromMinutes(5).TimeFrame());
subscription.Bind(_fast, _slow, ProcessCandle);
subscription.Start();
}
private void ProcessCandle(ICandleMessage candle, decimal fastValue, decimal slowValue)
{
if (candle.State != CandleStates.Finished) return;
if (!_fast.IsFormed || !_slow.IsFormed) { _prevFast = fastValue; _prevSlow = slowValue; return; }
if (_cooldown > 0) { _cooldown--; _prevFast = fastValue; _prevSlow = slowValue; return; }
var close = candle.ClosePrice;
var step = Security?.PriceStep ?? 1m;
if (Position > 0 && _entryPrice > 0)
{
if (StopLossPoints > 0 && close <= _entryPrice - StopLossPoints * step) { SellMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
if (TakeProfitPoints > 0 && close >= _entryPrice + TakeProfitPoints * step) { SellMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
}
else if (Position < 0 && _entryPrice > 0)
{
if (StopLossPoints > 0 && close >= _entryPrice + StopLossPoints * step) { BuyMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
if (TakeProfitPoints > 0 && close <= _entryPrice - TakeProfitPoints * step) { BuyMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
}
if (_prevFast <= _prevSlow && fastValue > slowValue && Position <= 0)
{ if (Position < 0) BuyMarket(); BuyMarket(); _entryPrice = close; _cooldown = 100; }
else if (_prevFast >= _prevSlow && fastValue < slowValue && Position >= 0)
{ if (Position > 0) SellMarket(); SellMarket(); _entryPrice = close; _cooldown = 100; }
_prevFast = fastValue; _prevSlow = slowValue;
}
}
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 ima_isar_ea_strategy(Strategy):
def __init__(self):
super(ima_isar_ea_strategy, self).__init__()
self._fast_period = self.Param("FastPeriod", 14) \
.SetDisplay("Fast Period", "Fast MA period", "Indicator")
self._slow_period = self.Param("SlowPeriod", 50) \
.SetDisplay("Slow Period", "Slow MA period", "Indicator")
self._stop_loss_points = self.Param("StopLossPoints", 200) \
.SetDisplay("Stop Loss", "Stop-loss in price steps", "Risk")
self._take_profit_points = self.Param("TakeProfitPoints", 400) \
.SetDisplay("Take Profit", "Take-profit in price steps", "Risk")
self._fast = None
self._slow = None
self._prev_fast = 0.0
self._prev_slow = 0.0
self._entry_price = 0.0
self._cooldown = 0
@property
def fast_period(self):
return self._fast_period.Value
@property
def slow_period(self):
return self._slow_period.Value
@property
def stop_loss_points(self):
return self._stop_loss_points.Value
@property
def take_profit_points(self):
return self._take_profit_points.Value
def OnReseted(self):
super(ima_isar_ea_strategy, self).OnReseted()
self._fast = None
self._slow = None
self._prev_fast = 0.0
self._prev_slow = 0.0
self._entry_price = 0.0
self._cooldown = 0
def OnStarted2(self, time):
super(ima_isar_ea_strategy, self).OnStarted2(time)
self._fast = ExponentialMovingAverage()
self._fast.Length = self.fast_period
self._slow = ExponentialMovingAverage()
self._slow.Length = self.slow_period
subscription = self.SubscribeCandles(DataType.TimeFrame(TimeSpan.FromMinutes(5)))
subscription.Bind(self._fast, self._slow, self._process_candle)
subscription.Start()
def _process_candle(self, candle, fast_value, slow_value):
if candle.State != CandleStates.Finished:
return
fast_val = float(fast_value)
slow_val = float(slow_value)
if not self._fast.IsFormed or not self._slow.IsFormed:
self._prev_fast = fast_val
self._prev_slow = slow_val
return
if self._cooldown > 0:
self._cooldown -= 1
self._prev_fast = fast_val
self._prev_slow = slow_val
return
close = float(candle.ClosePrice)
step = float(self.Security.PriceStep) if self.Security is not None and self.Security.PriceStep is not None else 1.0
if self.Position > 0 and self._entry_price > 0:
if self.stop_loss_points > 0 and close <= self._entry_price - self.stop_loss_points * step:
self.SellMarket()
self._entry_price = 0.0
self._cooldown = 100
self._prev_fast = fast_val
self._prev_slow = slow_val
return
if self.take_profit_points > 0 and close >= self._entry_price + self.take_profit_points * step:
self.SellMarket()
self._entry_price = 0.0
self._cooldown = 100
self._prev_fast = fast_val
self._prev_slow = slow_val
return
elif self.Position < 0 and self._entry_price > 0:
if self.stop_loss_points > 0 and close >= self._entry_price + self.stop_loss_points * step:
self.BuyMarket()
self._entry_price = 0.0
self._cooldown = 100
self._prev_fast = fast_val
self._prev_slow = slow_val
return
if self.take_profit_points > 0 and close <= self._entry_price - self.take_profit_points * step:
self.BuyMarket()
self._entry_price = 0.0
self._cooldown = 100
self._prev_fast = fast_val
self._prev_slow = slow_val
return
if self._prev_fast <= self._prev_slow and fast_val > slow_val and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
self._entry_price = close
self._cooldown = 100
elif self._prev_fast >= self._prev_slow and fast_val < slow_val and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._entry_price = close
self._cooldown = 100
self._prev_fast = fast_val
self._prev_slow = slow_val
def CreateClone(self):
return ima_isar_ea_strategy()