Parabolic SAR Limit ist eine direkte Portierung des MT4 Expert Advisors ytg_Parabolic_exp.mq4. Das System hält kontinuierlich Kauf- und Verkaufs-Limit-Orders an den Parabolic SAR-Wert gebunden und lässt den Markt die Order in einen Handel ziehen. Sobald sie gefüllt ist, überwacht die Strategie die offene Position und führt Stop-Loss- oder Take-Profit-Exits mithilfe von Candle-Extremen durch, was das ursprüngliche MQL-Verhalten widerspiegelt.
Strategielogik
Die Strategie abonniert eine konfigurierbare Kerzenserie (standardmäßig 4-Stunden-Zeitrahmen) und berechnet den Indikator Parabolic SAR mit der gleichen Schrittweite und den gleichen Maximalwerten wie das MT4-Skript.
Auf jeder fertigen Kerze:
Wenn der SAR-Punkt unter dem Tiefststand des Balkens liegt und das beste Gebot mindestens MinOrderDistancePoints über dem SAR-Preis liegt, wird eine Kauf-Limit-Order genau auf den SAR-Wert platziert (oder neu ausgerichtet).
Wenn der SAR-Punkt über dem Hoch des Balkens liegt und der beste Brief mindestens MinOrderDistancePoints unter dem SAR-Preis liegt, wird eine Verkaufslimitorder zu diesem SAR-Preis platziert (oder neu ausgerichtet).
Es wird nur eine ausstehende Bestellung pro Seite verwaltet. Wenn sich der SAR verschiebt, wird die aktive ausstehende Bestellung storniert und eine neue auf der aktualisierten Ebene übermittelt.
Wenn eine ausstehende Order ausgeführt wird, werden die Stop-Loss- und Take-Profit-Distanzen (ausgedrückt in Punkten) mithilfe der Sicherheitspreisstufe in absolute Preise umgewandelt. Diese Ebenen werden als virtuelle Schutzgrenzen gespeichert.
Jede neue Kerze überprüft die aufgezeichneten Grenzen. Wenn die Kerzenspanne das Stop- oder Take-Level berührt, schließt die Strategie die entsprechende Position sofort und setzt den Schutzzustand zurück.
Parameter
CandleType – Zeitrahmen für Signalkerzen. Standardmäßig werden 4-Stunden-Kerzen verwendet, um dem MT4-Eingabeparameter timeframe zu entsprechen.
SarStep – Parabolic SAR Beschleunigungsfaktor (step in MT4). Steuert, wie schnell der SAR mit dem Preis mithalten kann.
SarMaximum – maximale Beschleunigung (maximum in MT4). Begrenzt die SAR-Geschwindigkeit.
StopLossPoints – Abstand in Punkten zwischen dem Einstiegspreis und dem Stop-Level. Zum Deaktivieren auf 0 setzen.
TakeProfitPoints – Abstand in Punkten zwischen dem Einstiegspreis und dem Take-Profit-Level. Zum Deaktivieren auf 0 setzen.
MinOrderDistancePoints – ahmt MODE_STOPLEVEL in MT4 nach. Ausstehende Aufträge werden nur übermittelt, wenn der Marktpreis weiter als dieser Abstand vom SAR-Wert entfernt ist.
OrderVolume – Lose (Volumen) für jede ausstehende Bestellung. Richten Sie es am VolumeStep des Instruments aus.
Alle punktbasierten Entfernungen werden mithilfe des Instruments PriceStep in Preise umgewandelt, sodass das Verhalten auf allen Märkten konsistent bleibt.
Handelsverhalten
Funktioniert in beide Richtungen gleichzeitig: Eine Kauf- und eine Verkaufs-Limit-Order können nebeneinander bestehen, wenn der SAR den Preis umkehrt.
Ausstehende Bestellungen werden immer auf den letzten SAR-Wert ausgerichtet; Veraltete Bestellungen werden storniert, bevor eine neue registriert wird.
Stop-Loss- und Take-Profit-Ausstiege werden praktisch über Kerzenhochs und -tiefs abgewickelt, da hochrangige StockSharp-Strategien SL/TP nicht direkt an ausstehende Aufträge anhängen.
Die Strategie basiert auf den besten Geld-/Briefdaten, sofern verfügbar; andernfalls wird der Schlusskurs der Kerze als Fallback zur Bewertung der Distanzbedingungen verwendet.
Portierungshinweise
MinOrderDistancePoints ist standardmäßig 0, aber Sie können es auf das Stop-Level des Brokers setzen, wenn der Handelsplatz einen Mindestabstand vorschreibt.
Die Schutzniveaus werden automatisch zurückgesetzt, wenn die Position geschlossen oder die ausstehende Order storniert wird, wobei die Logik mit der des MT4-Experten identisch bleibt.
Kommentare im C#-Code erläutern die Verwendung von API auf hoher Ebene, die Indikatorbindung und den Bestelllebenszyklus für eine einfachere Wartung.
Nutzungstipps
Bereitstellung von Angeboten der Stufe 1 für eine präzise Entfernungsprüfung; Andernfalls stellen Sie sicher, dass der Schlusskurs der Kerze ein guter Indikator für den aktuellen Marktpreis ist.
Überprüfen Sie die PriceStep und VolumeStep Ihres Symbols, damit die Punktabstände und das Bestellvolumen in gültige Preise und Mengen umgewandelt werden können.
Da Exits anhand abgeschlossener Kerzen bewertet werden, sollten Sie kürzere Zeitrahmen verwenden, wenn Sie eine feinere Granularität für die Stop-Loss-Überwachung benötigen.
using System;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Parabolic SAR strategy: enters on SAR flip (price crosses SAR level).
/// Buys when price moves above SAR, sells when price drops below SAR.
/// </summary>
public class ParabolicSarLimitStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _emaLength;
private readonly StrategyParam<int> _atrLength;
private decimal _prevEma;
private decimal _prevClose;
private decimal _entryPrice;
private bool _wasBullish;
private bool _hasPrev;
public ParabolicSarLimitStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
.SetDisplay("Candle Type", "Timeframe.", "General");
_emaLength = Param(nameof(EmaLength), 14)
.SetDisplay("EMA Length", "EMA period acting as dynamic SAR proxy.", "Indicators");
_atrLength = Param(nameof(AtrLength), 14)
.SetDisplay("ATR Length", "ATR for volatility.", "Indicators");
}
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public int EmaLength
{
get => _emaLength.Value;
set => _emaLength.Value = value;
}
public int AtrLength
{
get => _atrLength.Value;
set => _atrLength.Value = value;
}
/// <inheritdoc />
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevEma = 0;
_prevClose = 0;
_entryPrice = 0;
_wasBullish = false;
_hasPrev = false;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevEma = 0;
_prevClose = 0;
_entryPrice = 0;
_wasBullish = false;
_hasPrev = false;
var ema = new ExponentialMovingAverage { Length = EmaLength };
var atr = new AverageTrueRange { Length = AtrLength };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(ema, atr, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, ema);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal emaVal, decimal atrVal)
{
if (candle.State != CandleStates.Finished)
return;
var close = candle.ClosePrice;
if (!_hasPrev)
{
_prevEma = emaVal;
_prevClose = close;
_wasBullish = close > emaVal;
_hasPrev = true;
return;
}
var isBullish = close > emaVal;
var flip = isBullish != _wasBullish;
// Exit on SAR flip
if (Position > 0 && flip && !isBullish)
{
SellMarket();
_entryPrice = 0;
}
else if (Position < 0 && flip && isBullish)
{
BuyMarket();
_entryPrice = 0;
}
// Entry on flip
if (Position == 0 && flip)
{
if (isBullish)
{
_entryPrice = close;
BuyMarket();
}
else
{
_entryPrice = close;
SellMarket();
}
}
_prevEma = emaVal;
_prevClose = close;
_wasBullish = isBullish;
}
}
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, AverageTrueRange
from StockSharp.Algo.Strategies import Strategy
class parabolic_sar_limit_strategy(Strategy):
def __init__(self):
super(parabolic_sar_limit_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5))).SetDisplay("Candle Type", "Timeframe", "General")
self._ema_length = self.Param("EmaLength", 14).SetDisplay("EMA Length", "EMA period acting as dynamic SAR proxy", "Indicators")
self._atr_length = self.Param("AtrLength", 14).SetDisplay("ATR Length", "ATR for volatility", "Indicators")
@property
def CandleType(self): return self._candle_type.Value
@CandleType.setter
def CandleType(self, value): self._candle_type.Value = value
def OnReseted(self):
super(parabolic_sar_limit_strategy, self).OnReseted()
self._prev_ema = 0
self._prev_close = 0
self._entry_price = 0
self._was_bullish = False
self._has_prev = False
def OnStarted2(self, time):
super(parabolic_sar_limit_strategy, self).OnStarted2(time)
self._prev_ema = 0
self._prev_close = 0
self._entry_price = 0
self._was_bullish = False
self._has_prev = False
ema = ExponentialMovingAverage()
ema.Length = self._ema_length.Value
atr = AverageTrueRange()
atr.Length = self._atr_length.Value
sub = self.SubscribeCandles(self.CandleType)
sub.Bind(ema, atr, self.OnProcess).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, sub)
self.DrawIndicator(area, ema)
self.DrawOwnTrades(area)
def OnProcess(self, candle, ema_val, atr_val):
if candle.State != CandleStates.Finished:
return
close = candle.ClosePrice
if not self._has_prev:
self._prev_ema = ema_val
self._prev_close = close
self._was_bullish = close > ema_val
self._has_prev = True
return
is_bullish = close > ema_val
flip = is_bullish != self._was_bullish
if self.Position > 0 and flip and not is_bullish:
self.SellMarket()
self._entry_price = 0
elif self.Position < 0 and flip and is_bullish:
self.BuyMarket()
self._entry_price = 0
if self.Position == 0 and flip:
if is_bullish:
self._entry_price = close
self.BuyMarket()
else:
self._entry_price = close
self.SellMarket()
self._prev_ema = ema_val
self._prev_close = close
self._was_bullish = is_bullish
def CreateClone(self):
return parabolic_sar_limit_strategy()