Die MA Parabolic SAR Strategie versucht, anhaltende Trends zu erfassen, indem ein einfacher gleitender Durchschnitt die vorherrschende Richtung bestimmt und die Parabolic SAR-Punkte das Einstiegs-Timing und die Stop-Platzierung liefern. Wenn beide Indikatoren übereinstimmen, geht das System davon aus, dass das Momentum stark genug ist, um ihm zu folgen.
Tests zeigen eine durchschnittliche Jahresrendite von etwa 76%. Sie funktioniert am besten auf dem Devisenmarkt.
Eine Long-Position wird eröffnet, wenn der Schlusskurs über dem gleitenden Durchschnitt liegt und die Parabolic SAR-Punkte unter den Markt kippen. Eine Short-Position wird eingegangen, wenn der Preis unter dem Durchschnitt liegt und die SAR-Punkte über den Preis kippen, was Abwärtsdruck signalisiert. Die Strategie steigt aus, sobald der Preis in die entgegengesetzte Richtung über den SAR kreuzt, Gewinne sichert oder Verluste begrenzt.
Dieser Ansatz eignet sich am besten für Trader, die systematisches Trendfolgen mit klaren, mechanischen Stops bevorzugen. Der Parabolic SAR passt sich kontinuierlich an, wenn sich die Volatilität ändert, und hält das Engagement im Einklang mit den Marktbedingungen, während der gleitende Durchschnitt Trades gegen den übergeordneten Trend verhindert.
Details
Einstiegskriterien:
Long: Price > MA && Price > Parabolic SAR
Short: Price < MA && Price < Parabolic SAR
Long/Short: Beide Seiten.
Ausstiegskriterien:
Long: Ausstieg, wenn der Preis unter den Parabolic SAR fällt
Short: Ausstieg, wenn der Preis über den Parabolic SAR steigt
Stops: Ja, dynamisch über Parabolic SAR und optionaler fester Stop.
Standardwerte:
MaPeriod = 20
SarStep = 0.02m
SarMaxStep = 0.2m
CandleType = TimeSpan.FromMinutes(5)
TakeValue = new Unit(0, UnitTypes.Absolute)
StopValue = new Unit(2, UnitTypes.Percent)
Filter:
Kategorie: Trend
Richtung: Beide
Indikatoren: MA, Parabolic SAR
Stops: Ja
Komplexität: Mittel
Zeitrahmen: Intraday
Saisonalität: Nein
Neuronale Netze: Nein
Divergenz: Nein
Risikolevel: Mittel
using System;
using System.Linq;
using System.Collections.Generic;
using Ecng.Common;
using Ecng.Collections;
using Ecng.Serialization;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Strategy based on Moving Average and Parabolic SAR indicators.
/// Enters long when price is above MA and above SAR.
/// Enters short when price is below MA and below SAR.
/// Uses Parabolic SAR as dynamic stop-loss.
/// </summary>
public class MaParabolicSarStrategy : Strategy
{
private readonly StrategyParam<int> _maPeriod;
private readonly StrategyParam<decimal> _sarStep;
private readonly StrategyParam<decimal> _sarMaxStep;
private readonly StrategyParam<int> _cooldownBars;
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<Unit> _takeValue;
private readonly StrategyParam<Unit> _stopValue;
private SimpleMovingAverage _ma;
private ExponentialMovingAverage _sarProxy;
private decimal _lastSarValue;
private bool _hasPrevState;
private bool _prevAboveMa;
private bool _prevAboveSar;
private int _cooldown;
/// <summary>
/// Moving Average period.
/// </summary>
public int MaPeriod
{
get => _maPeriod.Value;
set => _maPeriod.Value = value;
}
/// <summary>
/// Parabolic SAR acceleration factor.
/// </summary>
public decimal SarStep
{
get => _sarStep.Value;
set => _sarStep.Value = value;
}
/// <summary>
/// Parabolic SAR maximum acceleration factor.
/// </summary>
public decimal SarMaxStep
{
get => _sarMaxStep.Value;
set => _sarMaxStep.Value = value;
}
/// <summary>
/// Bars to wait between trades.
/// </summary>
public int CooldownBars
{
get => _cooldownBars.Value;
set => _cooldownBars.Value = value;
}
/// <summary>
/// Candle type parameter.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Take profit value.
/// </summary>
public Unit TakeValue
{
get => _takeValue.Value;
set => _takeValue.Value = value;
}
/// <summary>
/// Stop loss value.
/// </summary>
public Unit StopValue
{
get => _stopValue.Value;
set => _stopValue.Value = value;
}
/// <summary>
/// Constructor.
/// </summary>
public MaParabolicSarStrategy()
{
_maPeriod = Param(nameof(MaPeriod), 20)
.SetGreaterThanZero()
.SetDisplay("MA Period", "Period for Moving Average calculation", "Indicators")
.SetOptimize(10, 50, 5);
_sarStep = Param(nameof(SarStep), 0.02m)
.SetGreaterThanZero()
.SetDisplay("SAR Step", "Acceleration factor for Parabolic SAR", "Indicators")
.SetOptimize(0.01m, 0.05m, 0.01m);
_sarMaxStep = Param(nameof(SarMaxStep), 0.2m)
.SetGreaterThanZero()
.SetDisplay("SAR Max Step", "Maximum acceleration factor for Parabolic SAR", "Indicators")
.SetOptimize(0.1m, 0.3m, 0.05m);
_cooldownBars = Param(nameof(CooldownBars), 20)
.SetRange(1, 200)
.SetDisplay("Cooldown Bars", "Bars between trades", "General");
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
.SetDisplay("Candle Type", "Type of candles to use", "General");
_takeValue = Param(nameof(TakeValue), new Unit(0, UnitTypes.Absolute))
.SetDisplay("Take Profit", "Take profit value", "Protection");
_stopValue = Param(nameof(StopValue), new Unit(2, UnitTypes.Percent))
.SetDisplay("Stop Loss", "Stop loss value", "Protection");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_ma = null;
_sarProxy = null;
_lastSarValue = default;
_hasPrevState = false;
_prevAboveMa = false;
_prevAboveSar = false;
_cooldown = 0;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
// Initialize indicators
_ma = new() { Length = MaPeriod };
_sarProxy = new ExponentialMovingAverage
{
Length = Math.Max(2, MaPeriod / 2)
};
// Create candles subscription
var subscription = SubscribeCandles(CandleType);
// Bind indicators to subscription
subscription
.Bind(_ma, _sarProxy, ProcessCandle)
.Start();
// Setup chart if available
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, _ma);
DrawIndicator(area, _sarProxy);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal maValue, decimal sarValue)
{
// Skip unfinished candles
if (candle.State != CandleStates.Finished)
return;
// Store current SAR value for stop-loss
_lastSarValue = sarValue;
// Trading logic
bool isPriceAboveMA = candle.ClosePrice > maValue;
bool isPriceAboveSAR = candle.ClosePrice > sarValue;
if (!_hasPrevState)
{
_hasPrevState = true;
_prevAboveMa = isPriceAboveMA;
_prevAboveSar = isPriceAboveSAR;
return;
}
var turnedBull = !_prevAboveSar && isPriceAboveSAR && isPriceAboveMA;
var turnedBear = _prevAboveSar && !isPriceAboveSAR && !isPriceAboveMA;
var sarFlipDown = _prevAboveSar && !isPriceAboveSAR;
var sarFlipUp = !_prevAboveSar && isPriceAboveSAR;
if (_cooldown > 0)
_cooldown--;
// Long signal: Price above MA and above SAR
if (_cooldown == 0 && turnedBull)
{
if (Position <= 0)
{
BuyMarket();
_cooldown = CooldownBars;
}
}
// Short signal: Price below MA and below SAR
else if (_cooldown == 0 && turnedBear)
{
if (Position >= 0)
{
SellMarket();
_cooldown = CooldownBars;
}
}
// Exit long position: Price falls below SAR
else if (Position > 0 && sarFlipDown)
{
SellMarket();
_cooldown = CooldownBars;
}
else if (Position < 0 && sarFlipUp)
{
BuyMarket();
_cooldown = CooldownBars;
}
_prevAboveMa = isPriceAboveMA;
_prevAboveSar = isPriceAboveSAR;
}
}
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 SimpleMovingAverage, ExponentialMovingAverage
from StockSharp.Algo.Strategies import Strategy
class ma_parabolic_sar_strategy(Strategy):
"""
MA + SAR proxy (EMA). Enters on combined MA/SAR flip signals.
"""
def __init__(self):
super(ma_parabolic_sar_strategy, self).__init__()
self._ma_period = self.Param("MaPeriod", 20).SetDisplay("MA Period", "SMA period", "Indicators")
self._cooldown_bars = self.Param("CooldownBars", 20).SetDisplay("Cooldown", "Bars between trades", "General")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5))).SetDisplay("Candle Type", "Timeframe", "General")
self._has_prev = False
self._prev_above_ma = False
self._prev_above_sar = False
self._cooldown = 0
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(ma_parabolic_sar_strategy, self).OnReseted()
self._has_prev = False
self._prev_above_ma = False
self._prev_above_sar = False
self._cooldown = 0
def OnStarted2(self, time):
super(ma_parabolic_sar_strategy, self).OnStarted2(time)
ma = SimpleMovingAverage()
ma.Length = self._ma_period.Value
sar_proxy = ExponentialMovingAverage()
sar_proxy.Length = max(2, self._ma_period.Value // 2)
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(ma, sar_proxy, self._process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, ma)
self.DrawIndicator(area, sar_proxy)
self.DrawOwnTrades(area)
def _process_candle(self, candle, ma_val, sar_val):
if candle.State != CandleStates.Finished:
return
close = float(candle.ClosePrice)
ma = float(ma_val)
sar = float(sar_val)
above_ma = close > ma
above_sar = close > sar
if not self._has_prev:
self._has_prev = True
self._prev_above_ma = above_ma
self._prev_above_sar = above_sar
return
turned_bull = not self._prev_above_sar and above_sar and above_ma
turned_bear = self._prev_above_sar and not above_sar and not above_ma
sar_flip_down = self._prev_above_sar and not above_sar
sar_flip_up = not self._prev_above_sar and above_sar
if self._cooldown > 0:
self._cooldown -= 1
if self._cooldown == 0 and turned_bull:
if self.Position <= 0:
self.BuyMarket()
self._cooldown = self._cooldown_bars.Value
elif self._cooldown == 0 and turned_bear:
if self.Position >= 0:
self.SellMarket()
self._cooldown = self._cooldown_bars.Value
elif self.Position > 0 and sar_flip_down:
self.SellMarket()
self._cooldown = self._cooldown_bars.Value
elif self.Position < 0 and sar_flip_up:
self.BuyMarket()
self._cooldown = self._cooldown_bars.Value
self._prev_above_ma = above_ma
self._prev_above_sar = above_sar
def CreateClone(self):
return ma_parabolic_sar_strategy()