Parabolic SAR Stochastic Strategie
Implementierung der Strategie Parabolic SAR + Stochastic. Kaufen, wenn der Preis über dem SAR liegt und Stochastic %K unter 20 (überverkauft) ist. Verkaufen, wenn der Preis unter dem SAR liegt und Stochastic %K über 80 (überkauft) ist.
Tests zeigen eine durchschnittliche jährliche Rendite von etwa 61%. Am besten geeignet für den Kryptomarkt.
Der Parabolic SAR liefert den Trend und der Stochastic verfeinert den Einstieg bei Rücksetzern. Signale wechseln, wenn der SAR die Seite wechselt.
Eine unkomplizierte Trendstrategie mit eingebautem SAR-Stop. ATR-Einstellungen sorgen für zusätzliche Risikokontrolle.
Details
- Einstiegskriterien:
- Long:
Close > SAR && StochK < StochOversold - Short:
Close < SAR && StochK > StochOverbought
- Long:
- Long/Short: Beide
- Ausstiegskriterien:
- Parabolic SAR-Wechsel in entgegengesetzte Richtung
- Stops: Dynamisch, SAR-basiert
- Standardwerte:
AccelerationFactor= 0.02mMaxAccelerationFactor= 0.2mStochK= 3StochD= 3StochPeriod= 14StochOversold= 20mStochOverbought= 80mCandleType= TimeSpan.FromMinutes(5).TimeFrame()
- Filter:
- Kategorie: Mean Reversion
- Richtung: Beide
- Indikatoren: Parabolic SAR, Parabolic SAR, Stochastic Oscillator
- Stops: Ja
- Komplexität: Mittel
- Zeitrahmen: Mittelfristig
- Saisonalität: Nein
- Neuronale Netze: Nein
- Divergenz: Nein
- Risikolevel: Mittel
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;
/// <summary>
/// Strategy combining Parabolic SAR trend direction with Stochastic entry confirmation.
/// </summary>
public class ParabolicSarStochasticStrategy : Strategy
{
private readonly StrategyParam<decimal> _accelerationFactor;
private readonly StrategyParam<decimal> _maxAccelerationFactor;
private readonly StrategyParam<int> _stochK;
private readonly StrategyParam<int> _stochD;
private readonly StrategyParam<int> _stochPeriod;
private readonly StrategyParam<decimal> _stochOversold;
private readonly StrategyParam<decimal> _stochOverbought;
private readonly StrategyParam<int> _cooldownBars;
private readonly StrategyParam<DataType> _candleType;
private decimal _sarValue;
private decimal _lastStochK;
private bool _isAboveSar;
private bool _hasTrendState;
private int _cooldown;
/// <summary>
/// Parabolic SAR acceleration factor.
/// </summary>
public decimal AccelerationFactor
{
get => _accelerationFactor.Value;
set => _accelerationFactor.Value = value;
}
/// <summary>
/// Parabolic SAR max acceleration factor.
/// </summary>
public decimal MaxAccelerationFactor
{
get => _maxAccelerationFactor.Value;
set => _maxAccelerationFactor.Value = value;
}
/// <summary>
/// Stochastic K period.
/// </summary>
public int StochK
{
get => _stochK.Value;
set => _stochK.Value = value;
}
/// <summary>
/// Stochastic D period.
/// </summary>
public int StochD
{
get => _stochD.Value;
set => _stochD.Value = value;
}
/// <summary>
/// Stochastic main period.
/// </summary>
public int StochPeriod
{
get => _stochPeriod.Value;
set => _stochPeriod.Value = value;
}
/// <summary>
/// Stochastic oversold level.
/// </summary>
public decimal StochOversold
{
get => _stochOversold.Value;
set => _stochOversold.Value = value;
}
/// <summary>
/// Stochastic overbought level.
/// </summary>
public decimal StochOverbought
{
get => _stochOverbought.Value;
set => _stochOverbought.Value = value;
}
/// <summary>
/// Bars to wait between trades.
/// </summary>
public int CooldownBars
{
get => _cooldownBars.Value;
set => _cooldownBars.Value = value;
}
/// <summary>
/// Candle type used for strategy.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Strategy constructor.
/// </summary>
public ParabolicSarStochasticStrategy()
{
_accelerationFactor = Param(nameof(AccelerationFactor), 0.02m)
.SetRange(0.01m, 0.2m)
.SetDisplay("Acceleration Factor", "Initial acceleration factor for SAR", "SAR");
_maxAccelerationFactor = Param(nameof(MaxAccelerationFactor), 0.2m)
.SetRange(0.05m, 0.5m)
.SetDisplay("Max Acceleration Factor", "Maximum acceleration factor for SAR", "SAR");
_stochK = Param(nameof(StochK), 3)
.SetRange(1, 10)
.SetDisplay("Stochastic %K", "Stochastic %K smoothing period", "Stochastic");
_stochD = Param(nameof(StochD), 3)
.SetRange(1, 10)
.SetDisplay("Stochastic %D", "Stochastic %D smoothing period", "Stochastic");
_stochPeriod = Param(nameof(StochPeriod), 14)
.SetRange(5, 30)
.SetDisplay("Stochastic Period", "Main stochastic period", "Stochastic");
_stochOversold = Param(nameof(StochOversold), 20m)
.SetDisplay("Oversold Level", "Stochastic oversold level", "Stochastic");
_stochOverbought = Param(nameof(StochOverbought), 80m)
.SetDisplay("Overbought Level", "Stochastic overbought level", "Stochastic");
_cooldownBars = Param(nameof(CooldownBars), 160)
.SetRange(5, 500)
.SetDisplay("Cooldown Bars", "Bars between trades", "General");
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
.SetDisplay("Candle Type", "Candle type for strategy", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_sarValue = 0;
_lastStochK = 50m;
_isAboveSar = false;
_hasTrendState = false;
_cooldown = 0;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var parabolicSar = new ParabolicSar
{
AccelerationStep = AccelerationFactor,
AccelerationMax = MaxAccelerationFactor
};
var stochastic = new StochasticOscillator
{
K = { Length = StochK },
D = { Length = StochD },
};
var subscription = SubscribeCandles(CandleType);
subscription.BindEx(parabolicSar, OnSar);
subscription
.BindEx(stochastic, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, parabolicSar);
DrawOwnTrades(area);
var stochArea = CreateChartArea();
if (stochArea != null)
DrawIndicator(stochArea, stochastic);
}
}
private void OnSar(ICandleMessage candle, IIndicatorValue sarValue)
{
if (candle is null || sarValue is null)
return;
if (candle.State != CandleStates.Finished || !sarValue.IsFormed)
return;
_sarValue = sarValue.ToDecimal();
}
private void ProcessCandle(ICandleMessage candle, IIndicatorValue stochValue)
{
if (candle is null || stochValue is null)
return;
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
if (_sarValue == 0 || !stochValue.IsFormed)
return;
if (stochValue is not IStochasticOscillatorValue stochTyped || stochTyped.K is not decimal stochK)
return;
var close = candle.ClosePrice;
var priceAboveSar = close > _sarValue;
if (!_hasTrendState)
{
_isAboveSar = priceAboveSar;
_hasTrendState = true;
_lastStochK = stochK;
return;
}
var sarSignalChange = priceAboveSar != _isAboveSar;
if (_cooldown > 0)
{
_cooldown--;
_lastStochK = stochK;
_isAboveSar = priceAboveSar;
return;
}
var longEntry = Position == 0
&& priceAboveSar
&& _lastStochK <= StochOversold
&& stochK > _lastStochK;
var shortEntry = Position == 0
&& !priceAboveSar
&& _lastStochK >= StochOverbought
&& stochK < _lastStochK;
if (longEntry)
{
BuyMarket();
_cooldown = CooldownBars;
}
else if (shortEntry)
{
SellMarket();
_cooldown = CooldownBars;
}
else if (sarSignalChange && Position > 0 && !priceAboveSar)
{
SellMarket();
_cooldown = CooldownBars;
}
else if (sarSignalChange && Position < 0 && priceAboveSar)
{
BuyMarket();
_cooldown = CooldownBars;
}
_lastStochK = stochK;
_isAboveSar = priceAboveSar;
}
}
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 ParabolicSar, StochasticOscillator
from StockSharp.Algo.Strategies import Strategy
from datatype_extensions import *
class parabolic_sar_stochastic_strategy(Strategy):
"""
Strategy combining Parabolic SAR trend direction with Stochastic entry confirmation.
"""
def __init__(self):
super(parabolic_sar_stochastic_strategy, self).__init__()
self._acceleration_factor = self.Param("AccelerationFactor", 0.02) \
.SetRange(0.01, 0.2) \
.SetDisplay("Acceleration Factor", "Initial acceleration factor for SAR", "SAR")
self._max_acceleration_factor = self.Param("MaxAccelerationFactor", 0.2) \
.SetRange(0.05, 0.5) \
.SetDisplay("Max Acceleration Factor", "Maximum acceleration factor for SAR", "SAR")
self._stoch_k = self.Param("StochK", 3) \
.SetRange(1, 10) \
.SetDisplay("Stochastic %K", "Stochastic %K smoothing period", "Stochastic")
self._stoch_d = self.Param("StochD", 3) \
.SetRange(1, 10) \
.SetDisplay("Stochastic %D", "Stochastic %D smoothing period", "Stochastic")
self._stoch_oversold = self.Param("StochOversold", 20.0) \
.SetDisplay("Oversold Level", "Stochastic oversold level", "Stochastic")
self._stoch_overbought = self.Param("StochOverbought", 80.0) \
.SetDisplay("Overbought Level", "Stochastic overbought level", "Stochastic")
self._cooldown_bars = self.Param("CooldownBars", 160) \
.SetRange(5, 500) \
.SetDisplay("Cooldown Bars", "Bars between trades", "General")
self._candle_type = self.Param("CandleType", tf(5)) \
.SetDisplay("Candle Type", "Candle type for strategy", "General")
self._sar_value = 0.0
self._last_stoch_k = 50.0
self._is_above_sar = False
self._has_trend_state = False
self._cooldown = 0
@property
def candle_type(self):
return self._candle_type.Value
def OnStarted2(self, time):
super(parabolic_sar_stochastic_strategy, self).OnStarted2(time)
self._sar_value = 0.0
self._last_stoch_k = 50.0
self._is_above_sar = False
self._has_trend_state = False
self._cooldown = 0
sar = ParabolicSar()
sar.AccelerationStep = self._acceleration_factor.Value
sar.AccelerationMax = self._max_acceleration_factor.Value
stoch = StochasticOscillator()
stoch.K.Length = self._stoch_k.Value
stoch.D.Length = self._stoch_d.Value
subscription = self.SubscribeCandles(self.candle_type)
subscription.BindEx(sar, self.OnSar)
subscription.BindEx(stoch, self.ProcessCandle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, sar)
self.DrawOwnTrades(area)
stoch_area = self.CreateChartArea()
if stoch_area is not None:
self.DrawIndicator(stoch_area, stoch)
def OnSar(self, candle, sar_value):
if candle is None or sar_value is None:
return
if candle.State != CandleStates.Finished or not sar_value.IsFormed:
return
self._sar_value = float(sar_value)
def ProcessCandle(self, candle, stoch_value):
if candle is None or stoch_value is None:
return
if candle.State != CandleStates.Finished:
return
if self._sar_value == 0 or not stoch_value.IsFormed:
return
if not hasattr(stoch_value, 'K') or stoch_value.K is None:
return
stoch_k = float(stoch_value.K)
close = float(candle.ClosePrice)
price_above_sar = close > self._sar_value
if not self._has_trend_state:
self._is_above_sar = price_above_sar
self._has_trend_state = True
self._last_stoch_k = stoch_k
return
sar_signal_change = price_above_sar != self._is_above_sar
if self._cooldown > 0:
self._cooldown -= 1
self._last_stoch_k = stoch_k
self._is_above_sar = price_above_sar
return
cd = self._cooldown_bars.Value
os_level = self._stoch_oversold.Value
ob_level = self._stoch_overbought.Value
long_entry = (self.Position == 0 and price_above_sar
and self._last_stoch_k <= os_level and stoch_k > self._last_stoch_k)
short_entry = (self.Position == 0 and not price_above_sar
and self._last_stoch_k >= ob_level and stoch_k < self._last_stoch_k)
if long_entry:
self.BuyMarket()
self._cooldown = cd
elif short_entry:
self.SellMarket()
self._cooldown = cd
elif sar_signal_change and self.Position > 0 and not price_above_sar:
self.SellMarket()
self._cooldown = cd
elif sar_signal_change and self.Position < 0 and price_above_sar:
self.BuyMarket()
self._cooldown = cd
self._last_stoch_k = stoch_k
self._is_above_sar = price_above_sar
def OnReseted(self):
super(parabolic_sar_stochastic_strategy, self).OnReseted()
self._sar_value = 0.0
self._last_stoch_k = 50.0
self._is_above_sar = False
self._has_trend_state = False
self._cooldown = 0
def CreateClone(self):
return parabolic_sar_stochastic_strategy()