Diese Strategie erkennt Trendumkehrungen mithilfe des Parabolic SAR Indikators. Sie wartet auf eine konfigurierbare Anzahl negativer Umkehrungen, bevor sie in die neue Trendrichtung eintritt. Die Abstände für Stop-Loss und Take-Profit werden entweder in Pips oder als Prozentsatz des Einstiegspreises gemessen.
Parameter
Reversal Mode – Wahl zwischen pip-basierten oder prozentbasierten Abstandsberechnungen.
Delta – minimale Preisbewegung, die zwischen Umkehrungen erforderlich ist.
Negative Signals – wie viele fehlgeschlagene Umkehrungen auftreten müssen, bevor ein Trade eröffnet werden kann.
Stop Loss – Verlustschutzabstand vom Einstiegspreis.
Take Profit – Gewinnzielabstand vom Einstiegspreis.
Candle Type – Kerzenserie, die für Indikatorberechnungen verwendet wird.
Logik
Kerzendaten abonnieren und Parabolic SAR berechnen.
Wenn der Parabolic SAR die Richtung wechselt und der Preis sich um mindestens Delta bewegt, den Umkehrpreis speichern.
Negative Umkehrungen zählen, bei denen sich der Preis gegen den vorherigen Trend bewegte.
Sobald der Zähler den Wert Negative Signals erreicht, eine Position in der neuen Trendrichtung eröffnen.
Jede Kerze prüft Stop-Loss- und Take-Profit-Niveaus anhand des gewählten Reversal Mode.
Positionen werden bei entgegengesetzter Trendänderung oder bei Erreichen der Risikolimits geschlossen.
Die Strategie eignet sich für trendfolgende Ausbruchssysteme und kann durch Anpassen von Delta, Stop-Loss und Take-Profit-Abständen optimiert werden.
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>
/// Trend-following breakout strategy based on Parabolic SAR reversals.
/// Opens trades after negative reversals and uses percentage-based SL/TP.
/// </summary>
public class BreakoutBarsTrendStrategy : Strategy
{
private readonly StrategyParam<int> _negatives;
private readonly StrategyParam<decimal> _stopLossPct;
private readonly StrategyParam<decimal> _takeProfitPct;
private readonly StrategyParam<DataType> _candleType;
private ParabolicSar _parabolic;
private int _lastTrend; // -1, 0, 1
private int _negativeCounter;
public int Negatives
{
get => _negatives.Value;
set => _negatives.Value = value;
}
public decimal StopLossPct
{
get => _stopLossPct.Value;
set => _stopLossPct.Value = value;
}
public decimal TakeProfitPct
{
get => _takeProfitPct.Value;
set => _takeProfitPct.Value = value;
}
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public BreakoutBarsTrendStrategy()
{
_negatives = Param(nameof(Negatives), 1)
.SetNotNegative()
.SetDisplay("Negative Signals", "Negative reversals before entry", "General");
_stopLossPct = Param(nameof(StopLossPct), 2m)
.SetGreaterThanZero()
.SetDisplay("Stop Loss %", "Stop loss percentage", "Risk");
_takeProfitPct = Param(nameof(TakeProfitPct), 4m)
.SetGreaterThanZero()
.SetDisplay("Take Profit %", "Take profit percentage", "Risk");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).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();
_parabolic = default;
_lastTrend = 0;
_negativeCounter = 0;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_parabolic = new ParabolicSar();
Indicators.Add(_parabolic);
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(ProcessCandle)
.Start();
StartProtection(
takeProfit: new Unit(TakeProfitPct, UnitTypes.Percent),
stopLoss: new Unit(StopLossPct, UnitTypes.Percent),
useMarketOrders: true);
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle)
{
if (candle.State != CandleStates.Finished)
return;
var sarResult = _parabolic.Process(candle);
if (!sarResult.IsFormed)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
var sarValue = sarResult.ToDecimal();
var trend = sarValue < candle.ClosePrice ? 1 : -1;
if (_lastTrend != 0 && _lastTrend != trend)
{
// Reversal detected
if (trend == 1 && Position < 0)
BuyMarket();
else if (trend == -1 && Position > 0)
SellMarket();
_negativeCounter++;
if (_negativeCounter > Negatives)
{
if (trend == 1 && Position <= 0)
{
BuyMarket();
}
else if (trend == -1 && Position >= 0)
{
SellMarket();
}
_negativeCounter = 0;
}
}
_lastTrend = trend;
}
}
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 ParabolicSar, CandleIndicatorValue
from StockSharp.Algo.Strategies import Strategy
class breakout_bars_trend_strategy(Strategy):
def __init__(self):
super(breakout_bars_trend_strategy, self).__init__()
self._negatives = self.Param("Negatives", 1) \
.SetDisplay("Negative Signals", "Negative reversals before entry", "General")
self._stop_loss_pct = self.Param("StopLossPct", 2.0) \
.SetDisplay("Stop Loss %", "Stop loss percentage", "Risk")
self._take_profit_pct = self.Param("TakeProfitPct", 4.0) \
.SetDisplay("Take Profit %", "Take profit percentage", "Risk")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Type of candles", "General")
self._parabolic = None
self._last_trend = 0
self._negative_counter = 0
@property
def negatives(self):
return self._negatives.Value
@property
def stop_loss_pct(self):
return self._stop_loss_pct.Value
@property
def take_profit_pct(self):
return self._take_profit_pct.Value
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(breakout_bars_trend_strategy, self).OnReseted()
self._parabolic = None
self._last_trend = 0
self._negative_counter = 0
def OnStarted2(self, time):
super(breakout_bars_trend_strategy, self).OnStarted2(time)
self._parabolic = ParabolicSar()
self.Indicators.Add(self._parabolic)
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(self.process_candle).Start()
self.StartProtection(
takeProfit=Unit(self.take_profit_pct, UnitTypes.Percent),
stopLoss=Unit(self.stop_loss_pct, UnitTypes.Percent),
useMarketOrders=True)
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawOwnTrades(area)
def process_candle(self, candle):
if candle.State != CandleStates.Finished:
return
cv = CandleIndicatorValue(self._parabolic, candle)
sar_result = self._parabolic.Process(cv)
if not sar_result.IsFormed:
return
if not self.IsFormedAndOnlineAndAllowTrading():
return
sar_value = float(sar_result)
trend = 1 if sar_value < float(candle.ClosePrice) else -1
if self._last_trend != 0 and self._last_trend != trend:
if trend == 1 and self.Position < 0:
self.BuyMarket()
elif trend == -1 and self.Position > 0:
self.SellMarket()
self._negative_counter += 1
if self._negative_counter > int(self.negatives):
if trend == 1 and self.Position <= 0:
self.BuyMarket()
elif trend == -1 and self.Position >= 0:
self.SellMarket()
self._negative_counter = 0
self._last_trend = trend
def CreateClone(self):
return breakout_bars_trend_strategy()