Diese Strategie ist der StockSharp-Port des MetaTrader 4-Expertenberaters pSAR_alert.mq4. Das ursprüngliche Skript gab nur dann einen Warnton aus, wenn der Indikator Parabolic SAR von einer Seite des Preises auf die andere wechselte. Die Konvertierung behält die gleiche Entscheidungslogik bei, wandelt die Warnungen jedoch in tatsächliche Marktaufträge um, sodass das Signal automatisch in StockSharp gehandelt werden kann.
Handelslogik
Die Strategie abonniert den konfigurierten Kerzentyp und führt standardmäßig einen Parabolic SAR-Indikator mit dem klassischen Beschleunigungsfaktor (0,02) und der maximalen Beschleunigung (0,2) aus.
Für jede abgeschlossene Kerze vergleicht die Strategie den Parabolic SAR-Wert mit dem Kerzenschluss und verfolgt auch den vorherigen Kerzenkontext.
Wenn die vorherige Kerze unter SAR schloss, der aktuelle Schluss jedoch darüber liegt, ist der Indikator nach unten gekippt und eine Long-Position wird eröffnet (oder eine bestehende Short-Position wird umgekehrt).
Wenn die vorherige Kerze über SAR schloss, der aktuelle Schluss jedoch darunter liegt, ist der Indikator nach oben gekippt und eine Short-Position wird eröffnet (oder eine bestehende Long-Position wird umgekehrt).
Das Handelsvolumen wird als Basisstrategievolumen plus der absoluten aktuellen Position berechnet, um sicherzustellen, dass Umkehrungen den vorherigen Handel vollständig verlassen, bevor sie in die neue Richtung eintreten.
StartProtection() wird beim Start ausgeführt, sodass StockSharp automatisch unerwartete Verbindungsabbrüche verwaltet, während Positionen offen sind.
Parameter
Parameter
Standard
Beschreibung
AccelerationFactor
0,02
Anfänglicher Beschleunigungsschritt, der steuert, wie schnell der Parabolic SAR Preisbewegungen folgt.
MaxAccelerationFactor
0,2
Obergrenze für den Beschleunigungsschritt, die begrenzt, wie aggressiv der SAR bei starken Trends beschleunigt.
CandleType
Zeitrahmen von 5 Minuten
Marktdatentyp, der für Indikatoraktualisierungen verwendet wird; Ändern Sie es, um zwischen Zeitrahmen oder anderen Kerzendarstellungen zu wechseln.
Alle Parameter werden über StrategyParam<T> verfügbar gemacht, sodass sie direkt im StockSharp-Designer optimiert werden können.
Indikator-Workflow
Abonnieren Sie den konfigurierten Kerzenstream über SubscribeCandles.
Binden Sie den Stream an einen ParabolicSar-Indikator, damit StockSharp ihn automatisch aktualisiert.
Vergleichen Sie innerhalb des Bindungsrückrufs den aktuellen SAR-Wert mit dem Schlusskurs und behalten Sie das vorherige SAR/Schlusspaar bei.
Erkennen Sie Überschneidungen, indem Sie auswerten, ob sich der SAR von oben nach unter dem Schlusskurs (bullischer Flip) oder von unten nach oben (bärischer Flip) bewegt hat.
Führen Sie BuyMarket oder SellMarket entsprechend aus und protokollieren Sie beschreibende Nachrichten für jeden Trade.
Praktische Hinweise
Da die Strategie nur auf bestätigte Kerzenschließungen reagiert, vermeidet sie vorzeitige Signale, die möglicherweise verschwinden, bevor der Balken endet.
Die Standardparameter reproduzieren das Verhalten des Skripts MQL, Sie können sie jedoch anpassen, um die Empfindlichkeit des Skripts Parabolic SAR anzupassen.
Hängen Sie die Strategie an Instrumente an, die eindeutig im Trend liegen. Die SAR-Flip-Logik funktioniert am besten, wenn Umkehrungen entscheidend und nicht laut sind.
Die Diagrammvisualisierung wird automatisch aktiviert, wenn ein Diagrammbereich verfügbar ist: Kerzen, der Indikator Parabolic SAR und eigene Trades werden zur schnellen Überprüfung gezeichnet.
Dateien
CS/ParabolicSarCrossoverAlertStrategy.cs – C#-Implementierung der Strategie.
README.md – Diese Dokumentation auf Englisch.
README_zh.md – Chinesische Übersetzung der Dokumentation.
README_ru.md – Russische Übersetzung der Dokumentation.
using System;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Parabolic SAR Crossover: EMA crossover with ATR stops.
/// </summary>
public class ParabolicSarCrossoverAlertStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _fastEmaLength;
private readonly StrategyParam<int> _slowEmaLength;
private readonly StrategyParam<int> _atrLength;
private decimal _prevFast;
private decimal _prevSlow;
private decimal _entryPrice;
public ParabolicSarCrossoverAlertStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
.SetDisplay("Candle Type", "Timeframe.", "General");
_fastEmaLength = Param(nameof(FastEmaLength), 10)
.SetDisplay("Fast EMA", "Fast EMA period.", "Indicators");
_slowEmaLength = Param(nameof(SlowEmaLength), 30)
.SetDisplay("Slow EMA", "Slow EMA period.", "Indicators");
_atrLength = Param(nameof(AtrLength), 14)
.SetDisplay("ATR Length", "ATR period.", "Indicators");
}
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public int FastEmaLength
{
get => _fastEmaLength.Value;
set => _fastEmaLength.Value = value;
}
public int SlowEmaLength
{
get => _slowEmaLength.Value;
set => _slowEmaLength.Value = value;
}
public int AtrLength
{
get => _atrLength.Value;
set => _atrLength.Value = value;
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevFast = 0;
_prevSlow = 0;
_entryPrice = 0;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevFast = 0;
_prevSlow = 0;
_entryPrice = 0;
var fastEma = new ExponentialMovingAverage { Length = FastEmaLength };
var slowEma = new ExponentialMovingAverage { Length = SlowEmaLength };
var atr = new AverageTrueRange { Length = AtrLength };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(fastEma, slowEma, atr, 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 fastVal, decimal slowVal, decimal atrVal)
{
if (candle.State != CandleStates.Finished)
return;
if (_prevFast == 0 || _prevSlow == 0 || atrVal <= 0)
{
_prevFast = fastVal;
_prevSlow = slowVal;
return;
}
var close = candle.ClosePrice;
if (Position > 0)
{
if (fastVal < slowVal && _prevFast >= _prevSlow)
{
SellMarket();
_entryPrice = 0;
}
else if (close <= _entryPrice - atrVal * 2m)
{
SellMarket();
_entryPrice = 0;
}
}
else if (Position < 0)
{
if (fastVal > slowVal && _prevFast <= _prevSlow)
{
BuyMarket();
_entryPrice = 0;
}
else if (close >= _entryPrice + atrVal * 2m)
{
BuyMarket();
_entryPrice = 0;
}
}
if (Position == 0)
{
if (fastVal > slowVal && _prevFast <= _prevSlow)
{
_entryPrice = close;
BuyMarket();
}
else if (fastVal < slowVal && _prevFast >= _prevSlow)
{
_entryPrice = close;
SellMarket();
}
}
_prevFast = fastVal;
_prevSlow = slowVal;
}
}
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_crossover_alert_strategy(Strategy):
def __init__(self):
super(parabolic_sar_crossover_alert_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5))).SetDisplay("Candle Type", "Timeframe", "General")
self._fast_ema_length = self.Param("FastEmaLength", 10).SetDisplay("Fast EMA", "Fast EMA period", "Indicators")
self._slow_ema_length = self.Param("SlowEmaLength", 30).SetDisplay("Slow EMA", "Slow EMA period", "Indicators")
self._atr_length = self.Param("AtrLength", 14).SetDisplay("ATR Length", "ATR period", "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_crossover_alert_strategy, self).OnReseted()
self._prev_fast = 0
self._prev_slow = 0
self._entry_price = 0
def OnStarted2(self, time):
super(parabolic_sar_crossover_alert_strategy, self).OnStarted2(time)
self._prev_fast = 0
self._prev_slow = 0
self._entry_price = 0
fast_ema = ExponentialMovingAverage()
fast_ema.Length = self._fast_ema_length.Value
slow_ema = ExponentialMovingAverage()
slow_ema.Length = self._slow_ema_length.Value
atr = AverageTrueRange()
atr.Length = self._atr_length.Value
sub = self.SubscribeCandles(self.CandleType)
sub.Bind(fast_ema, slow_ema, atr, self.OnProcess).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, sub)
self.DrawIndicator(area, fast_ema)
self.DrawIndicator(area, slow_ema)
self.DrawOwnTrades(area)
def OnProcess(self, candle, fast_val, slow_val, atr_val):
if candle.State != CandleStates.Finished:
return
if self._prev_fast == 0 or self._prev_slow == 0 or atr_val <= 0:
self._prev_fast = fast_val
self._prev_slow = slow_val
return
close = candle.ClosePrice
if self.Position > 0:
if (fast_val < slow_val and self._prev_fast >= self._prev_slow) or close <= self._entry_price - atr_val * 2:
self.SellMarket()
self._entry_price = 0
elif self.Position < 0:
if (fast_val > slow_val and self._prev_fast <= self._prev_slow) or close >= self._entry_price + atr_val * 2:
self.BuyMarket()
self._entry_price = 0
if self.Position == 0:
if fast_val > slow_val and self._prev_fast <= self._prev_slow:
self._entry_price = close
self.BuyMarket()
elif fast_val < slow_val and self._prev_fast >= self._prev_slow:
self._entry_price = close
self.SellMarket()
self._prev_fast = fast_val
self._prev_slow = slow_val
def CreateClone(self):
return parabolic_sar_crossover_alert_strategy()