Trend-Catcher-Strategie
Die Trend Catcher-Strategie kombiniert den Parabolic SAR mit mehreren einfachen gleitenden Durchschnitten, um Richtungsbewegungen zu erfassen. Sie wartet darauf, dass der Kurs den Parabolic SAR in Richtung der vorherrschenden schnellen Durchschnitte kreuzt, und verwaltet dann die Position mithilfe dynamischer Stop-Loss- und Trailing-Regeln.
Ein Trade wird eröffnet, wenn die neueste Kerze auf der gegenüberliegenden Seite des Parabolic SAR im Vergleich zur vorherigen Kerze schließt, während die schnellen Durchschnitte die Bewegung bestätigen. Der anfängliche Stop-Loss wird aus der Entfernung zum SAR-Punkt berechnet und durch Mindest- und Höchstgrenzen begrenzt. Gewinnziele werden als Vielfaches des Stop-Abstands definiert. Nachdem der Kurs um einen bestimmten Betrag vorgerückt ist, wird der Stop mit einem kleinen Versatz auf den Breakeven verschoben und verfolgt später den Kurs.
Details
- Einstiegskriterien:
- Long:
Close[0] > SAR && Close[1] < SAR_prev && FastMA > SlowMA && Close > FastMA2.
- Short:
Close[0] < SAR && Close[1] > SAR_prev && FastMA < SlowMA && Close < FastMA2.
- Ausstiegskriterien:
- Stop-Loss- oder Take-Profit-Level werden erreicht.
- Trailing Stop nach Erreichen der Gewinnschwelle aktiviert.
- Ein entgegengesetztes Signal schließt die bestehende Position.
- Stops: Dynamischer Stop-Loss basierend auf SAR mit optionalen Breakeven- und Trailing-Anpassungen.
- Standardwerte:
SlowMaPeriod = 200
FastMaPeriod = 50
FastMa2Period = 25
SarStep = 0.004
SarMax = 0.2
SlMultiplier = 1
TpMultiplier = 1
MinStopLoss = 10
MaxStopLoss = 200
ProfitLevel = 500
BreakevenOffset = 1
TrailingThreshold = 500
TrailingDistance = 10
- Filter:
- Kategorie: Trendfolge
- Richtung: Beide
- Indikatoren: Parabolic SAR, SMA
- Stops: Ja
- Komplexität: Moderat
- Zeitrahmen: Kurzfristig
- 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>
/// Parabolic SAR trend catching strategy.
/// Uses Parabolic SAR flip with MA trend filter for entries.
/// </summary>
public class TrendCatcherStrategy : Strategy
{
private readonly StrategyParam<int> _slowMaPeriod;
private readonly StrategyParam<int> _fastMaPeriod;
private readonly StrategyParam<decimal> _sarStep;
private readonly StrategyParam<decimal> _sarMax;
private readonly StrategyParam<DataType> _candleType;
private ExponentialMovingAverage _slowMa;
private bool _isInitialized;
private bool _isPriceAboveSarPrev;
public int SlowMaPeriod { get => _slowMaPeriod.Value; set => _slowMaPeriod.Value = value; }
public int FastMaPeriod { get => _fastMaPeriod.Value; set => _fastMaPeriod.Value = value; }
public decimal SarStep { get => _sarStep.Value; set => _sarStep.Value = value; }
public decimal SarMax { get => _sarMax.Value; set => _sarMax.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public TrendCatcherStrategy()
{
_slowMaPeriod = Param(nameof(SlowMaPeriod), 200)
.SetGreaterThanZero()
.SetDisplay("Slow MA Period", "Period of the slow moving average", "Moving Averages");
_fastMaPeriod = Param(nameof(FastMaPeriod), 50)
.SetGreaterThanZero()
.SetDisplay("Fast MA Period", "Period of the fast moving average", "Moving Averages");
_sarStep = Param(nameof(SarStep), 0.004m)
.SetDisplay("SAR Step", "Parabolic SAR acceleration step", "Parabolic SAR");
_sarMax = Param(nameof(SarMax), 0.2m)
.SetDisplay("SAR Max", "Parabolic SAR maximum acceleration", "Parabolic SAR");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame())
.SetDisplay("Candle Type", "Type of candles", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_slowMa = default;
_isInitialized = default;
_isPriceAboveSarPrev = default;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_isInitialized = false;
var sar = new ParabolicSar
{
Acceleration = SarStep,
AccelerationStep = SarStep,
AccelerationMax = SarMax
};
var fastMa = new ExponentialMovingAverage { Length = FastMaPeriod };
_slowMa = new ExponentialMovingAverage { Length = SlowMaPeriod };
Indicators.Add(_slowMa);
var subscription = SubscribeCandles(CandleType);
subscription
.BindEx(sar, fastMa, ProcessCandle)
.Start();
StartProtection(
takeProfit: new Unit(3, UnitTypes.Percent),
stopLoss: new Unit(2, UnitTypes.Percent),
isStopTrailing: true
);
}
private void ProcessCandle(ICandleMessage candle, IIndicatorValue sarValue, IIndicatorValue fastMaValue)
{
if (candle.State != CandleStates.Finished)
return;
if (!sarValue.IsFormed || !fastMaValue.IsFormed)
return;
var sar = sarValue.ToDecimal();
var fastValue = fastMaValue.ToDecimal();
var slowResult = _slowMa.Process(candle.ClosePrice, candle.OpenTime, true);
if (!slowResult.IsFormed)
return;
var slowValue = slowResult.ToDecimal();
var isPriceAboveSar = candle.ClosePrice > sar;
if (!_isInitialized)
{
_isPriceAboveSarPrev = isPriceAboveSar;
_isInitialized = true;
return;
}
if (!IsFormedAndOnlineAndAllowTrading())
return;
// Buy: SAR flips below price + fast MA above slow MA
var buySignal = isPriceAboveSar && !_isPriceAboveSarPrev && fastValue > slowValue;
// Sell: SAR flips above price + fast MA below slow MA
var sellSignal = !isPriceAboveSar && _isPriceAboveSarPrev && fastValue < slowValue;
if (buySignal && Position <= 0)
{
if (Position < 0) BuyMarket();
BuyMarket();
}
else if (sellSignal && Position >= 0)
{
if (Position > 0) SellMarket();
SellMarket();
}
_isPriceAboveSarPrev = 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, Unit, UnitTypes
from StockSharp.Algo.Indicators import ExponentialMovingAverage, ParabolicSar
from StockSharp.Algo.Strategies import Strategy
from indicator_extensions import *
class trend_catcher_strategy(Strategy):
def __init__(self):
super(trend_catcher_strategy, self).__init__()
self._slow_ma_period = self.Param("SlowMaPeriod", 200) \
.SetDisplay("Slow MA Period", "Period of the slow moving average", "Moving Averages")
self._fast_ma_period = self.Param("FastMaPeriod", 50) \
.SetDisplay("Fast MA Period", "Period of the fast moving average", "Moving Averages")
self._sar_step = self.Param("SarStep", 0.004) \
.SetDisplay("SAR Step", "Parabolic SAR acceleration step", "Parabolic SAR")
self._sar_max = self.Param("SarMax", 0.2) \
.SetDisplay("SAR Max", "Parabolic SAR maximum acceleration", "Parabolic SAR")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(1))) \
.SetDisplay("Candle Type", "Type of candles", "General")
self._slow_ma = None
self._is_initialized = False
self._is_price_above_sar_prev = False
@property
def SlowMaPeriod(self):
return self._slow_ma_period.Value
@SlowMaPeriod.setter
def SlowMaPeriod(self, value):
self._slow_ma_period.Value = value
@property
def FastMaPeriod(self):
return self._fast_ma_period.Value
@FastMaPeriod.setter
def FastMaPeriod(self, value):
self._fast_ma_period.Value = value
@property
def SarStep(self):
return self._sar_step.Value
@SarStep.setter
def SarStep(self, value):
self._sar_step.Value = value
@property
def SarMax(self):
return self._sar_max.Value
@SarMax.setter
def SarMax(self, value):
self._sar_max.Value = value
@property
def CandleType(self):
return self._candle_type.Value
@CandleType.setter
def CandleType(self, value):
self._candle_type.Value = value
def OnStarted2(self, time):
super(trend_catcher_strategy, self).OnStarted2(time)
self._is_initialized = False
sar = ParabolicSar()
sar.Acceleration = self.SarStep
sar.AccelerationStep = self.SarStep
sar.AccelerationMax = self.SarMax
fast_ma = ExponentialMovingAverage()
fast_ma.Length = self.FastMaPeriod
self._slow_ma = ExponentialMovingAverage()
self._slow_ma.Length = self.SlowMaPeriod
self.SubscribeCandles(self.CandleType) \
.BindEx(sar, fast_ma, self.ProcessCandle) \
.Start()
self.StartProtection(
takeProfit=Unit(3.0, UnitTypes.Percent),
stopLoss=Unit(2.0, UnitTypes.Percent),
isStopTrailing=True
)
def ProcessCandle(self, candle, sar_value, fast_ma_value):
if candle.State != CandleStates.Finished:
return
if not sar_value.IsFormed or not fast_ma_value.IsFormed:
return
sar = float(sar_value)
fast_val = float(fast_ma_value)
close = float(candle.ClosePrice)
t = candle.OpenTime
slow_result = process_float(self._slow_ma, close, t, True)
if not slow_result.IsFormed:
return
slow_val = float(slow_result)
is_price_above_sar = close > sar
if not self._is_initialized:
self._is_price_above_sar_prev = is_price_above_sar
self._is_initialized = True
return
buy_signal = is_price_above_sar and not self._is_price_above_sar_prev and fast_val > slow_val
sell_signal = not is_price_above_sar and self._is_price_above_sar_prev and fast_val < slow_val
if buy_signal and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
elif sell_signal and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._is_price_above_sar_prev = is_price_above_sar
def OnReseted(self):
super(trend_catcher_strategy, self).OnReseted()
self._slow_ma = None
self._is_initialized = False
self._is_price_above_sar_prev = False
def CreateClone(self):
return trend_catcher_strategy()