Double Supertrend-Strategie
Double Supertrend verwendet zwei ATR-basierte gleitende Durchschnitte mit unterschiedlichen Perioden und Multiplikatoren. Die erste Linie legt die Handelsrichtung fest, während die zweite als Ziel oder Trailing-Ausstieg fungieren kann. Diese Kombination ermöglicht flexibles Trendfolgen mit definierten Gewinn- und Risikoparametern.
Wenn der Preis über beide Linien steigt und die Strategie auf Long-Handel eingestellt ist, wird eine Position eröffnet. Für Short-Trades sind die Bedingungen gespiegelt. Ausstiege hängen vom gewählten Take-Profit-Typ oder einem prozentualen Stop-Loss ab.
Details
- Daten: Kurskerzen.
- Einstiegskriterien: Preis kreuzt Supertrend-Linien in der erlaubten
Direction. - Ausstiegskriterien: Gegenseitiger Linienbruch, Take-Profit (
TPType/TPPercent) oder Stop-Loss (SLPercent). - Stops: Prozentualer Stop basierend auf
SLPercent. - Standardwerte:
ATRPeriod1= 10Factor1= 3.0ATRPeriod2= 20Factor2= 5.0Direction= "Long"TPType= "Supertrend"TPPercent= 1.5SLPercent= 10.0
- Filter:
- Kategorie: Trendfolge
- Richtung: Konfigurierbar
- Indikatoren: ATR‑based Supertrend
- Komplexität: Fortgeschritten
- 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>
/// Double Supertrend strategy.
/// A position opens in the allowed Direction ("Long", "Short" or "Both") when the close moves above (below) both
/// Supertrend lines. A close back through the first line exits. With TPType "Supertrend" the second line also works as
/// a trailing exit; with TPType "Percent" a TPPercent take-profit is used instead. SLPercent is a percent stop-loss.
/// </summary>
public class DoubleSupertrendStrategy : Strategy
{
private readonly StrategyParam<int> _atrPeriod1;
private readonly StrategyParam<decimal> _factor1;
private readonly StrategyParam<int> _atrPeriod2;
private readonly StrategyParam<decimal> _factor2;
private readonly StrategyParam<string> _direction;
private readonly StrategyParam<string> _tpType;
private readonly StrategyParam<decimal> _tpPercent;
private readonly StrategyParam<decimal> _slPercent;
private readonly StrategyParam<DataType> _candleType;
private bool? _prevAboveBoth;
private bool? _prevBelowBoth;
/// <summary>
/// ATR period of the first Supertrend.
/// </summary>
public int ATRPeriod1
{
get => _atrPeriod1.Value;
set => _atrPeriod1.Value = value;
}
/// <summary>
/// Multiplier of the first Supertrend.
/// </summary>
public decimal Factor1
{
get => _factor1.Value;
set => _factor1.Value = value;
}
/// <summary>
/// ATR period of the second Supertrend.
/// </summary>
public int ATRPeriod2
{
get => _atrPeriod2.Value;
set => _atrPeriod2.Value = value;
}
/// <summary>
/// Multiplier of the second Supertrend.
/// </summary>
public decimal Factor2
{
get => _factor2.Value;
set => _factor2.Value = value;
}
/// <summary>
/// Allowed trade direction: "Long", "Short" or "Both".
/// </summary>
public string Direction
{
get => _direction.Value;
set => _direction.Value = value;
}
/// <summary>
/// Take-profit type: "Supertrend" or "Percent".
/// </summary>
public string TPType
{
get => _tpType.Value;
set => _tpType.Value = value;
}
/// <summary>
/// Take-profit percentage used when TPType is "Percent".
/// </summary>
public decimal TPPercent
{
get => _tpPercent.Value;
set => _tpPercent.Value = value;
}
/// <summary>
/// Stop-loss percentage. 0 disables it.
/// </summary>
public decimal SLPercent
{
get => _slPercent.Value;
set => _slPercent.Value = value;
}
/// <summary>
/// Candle type for strategy calculation.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Constructor.
/// </summary>
public DoubleSupertrendStrategy()
{
_atrPeriod1 = Param(nameof(ATRPeriod1), 10)
.SetGreaterThanZero()
.SetDisplay("ST1 Period", "ATR period of the first Supertrend", "Supertrend 1");
_factor1 = Param(nameof(Factor1), 3.0m)
.SetGreaterThanZero()
.SetDisplay("ST1 Factor", "Multiplier of the first Supertrend", "Supertrend 1");
_atrPeriod2 = Param(nameof(ATRPeriod2), 20)
.SetGreaterThanZero()
.SetDisplay("ST2 Period", "ATR period of the second Supertrend", "Supertrend 2");
_factor2 = Param(nameof(Factor2), 5.0m)
.SetGreaterThanZero()
.SetDisplay("ST2 Factor", "Multiplier of the second Supertrend", "Supertrend 2");
_direction = Param(nameof(Direction), "Long")
.SetDisplay("Direction", "Allowed trade direction: Long, Short or Both", "Trading");
_tpType = Param(nameof(TPType), "Supertrend")
.SetDisplay("TP Type", "Take-profit type: Supertrend or Percent", "Risk");
_tpPercent = Param(nameof(TPPercent), 1.5m)
.SetNotNegative()
.SetDisplay("TP %", "Take-profit percentage for the Percent type", "Risk");
_slPercent = Param(nameof(SLPercent), 10.0m)
.SetNotNegative()
.SetDisplay("SL %", "Stop-loss percentage", "Risk");
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(15).TimeFrame())
.SetDisplay("Candle type", "Candle type for strategy calculation", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
=> [(Security, CandleType)];
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevAboveBoth = null;
_prevBelowBoth = null;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevAboveBoth = null;
_prevBelowBoth = null;
var st1 = new SuperTrend { Length = ATRPeriod1, Multiplier = Factor1 };
var st2 = new SuperTrend { Length = ATRPeriod2, Multiplier = Factor2 };
var subscription = SubscribeCandles(CandleType);
subscription
.BindEx(st1, st2, ProcessCandle)
.Start();
var takeProfit = TPType.EqualsIgnoreCase("Percent") && TPPercent > 0
? new Unit(TPPercent, UnitTypes.Percent)
: new Unit();
var stopLoss = SLPercent > 0 ? new Unit(SLPercent, UnitTypes.Percent) : new Unit();
StartProtection(takeProfit, stopLoss, useMarketOrders: true);
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, st1);
DrawIndicator(area, st2);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, IIndicatorValue st1Value, IIndicatorValue st2Value)
{
if (candle.State != CandleStates.Finished)
return;
if (!st1Value.IsFormed || !st2Value.IsFormed)
return;
var line1 = st1Value.ToDecimal();
var line2 = st2Value.ToDecimal();
var close = candle.ClosePrice;
var aboveBoth = close > line1 && close > line2;
var belowBoth = close < line1 && close < line2;
var prevAbove = _prevAboveBoth;
var prevBelow = _prevBelowBoth;
_prevAboveBoth = aboveBoth;
_prevBelowBoth = belowBoth;
if (prevAbove is not bool wasAbove || prevBelow is not bool wasBelow)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
var allowLong = !Direction.EqualsIgnoreCase("Short");
var allowShort = !Direction.EqualsIgnoreCase("Long");
var trailOnSecond = TPType.EqualsIgnoreCase("Supertrend");
var longSignal = allowLong && aboveBoth && !wasAbove;
var shortSignal = allowShort && belowBoth && !wasBelow;
if (longSignal && Position <= 0)
BuyMarket(Volume + Math.Abs(Position));
else if (shortSignal && Position >= 0)
SellMarket(Volume + Math.Abs(Position));
else if (Position > 0 && (close < line1 || (trailOnSecond && close < line2)))
SellMarket(Position);
else if (Position < 0 && (close > line1 || (trailOnSecond && close > line2)))
BuyMarket(-Position);
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan, Decimal
from StockSharp.Messages import DataType, CandleStates, Unit, UnitTypes
from StockSharp.Algo.Indicators import SuperTrend
from StockSharp.Algo.Strategies import Strategy
class double_supertrend_strategy(Strategy):
"""
Double Supertrend strategy.
A position opens in the allowed Direction ("Long", "Short" or "Both") when the close moves above (below) both
Supertrend lines. A close back through the first line exits. With TPType "Supertrend" the second line also works as
a trailing exit; with TPType "Percent" a TPPercent take-profit is used instead. SLPercent is a percent stop-loss.
"""
def __init__(self):
super(double_supertrend_strategy, self).__init__()
self._atr_period1 = self.Param("ATRPeriod1", 10) \
.SetGreaterThanZero() \
.SetDisplay("ST1 Period", "ATR period of the first Supertrend", "Supertrend 1")
self._factor1 = self.Param("Factor1", 3.0) \
.SetGreaterThanZero() \
.SetDisplay("ST1 Factor", "Multiplier of the first Supertrend", "Supertrend 1")
self._atr_period2 = self.Param("ATRPeriod2", 20) \
.SetGreaterThanZero() \
.SetDisplay("ST2 Period", "ATR period of the second Supertrend", "Supertrend 2")
self._factor2 = self.Param("Factor2", 5.0) \
.SetGreaterThanZero() \
.SetDisplay("ST2 Factor", "Multiplier of the second Supertrend", "Supertrend 2")
self._direction = self.Param("Direction", "Long") \
.SetDisplay("Direction", "Allowed trade direction: Long, Short or Both", "Trading")
self._tp_type = self.Param("TPType", "Supertrend") \
.SetDisplay("TP Type", "Take-profit type: Supertrend or Percent", "Risk")
self._tp_percent = self.Param("TPPercent", 1.5) \
.SetNotNegative() \
.SetDisplay("TP %", "Take-profit percentage for the Percent type", "Risk")
self._sl_percent = self.Param("SLPercent", 10.0) \
.SetNotNegative() \
.SetDisplay("SL %", "Stop-loss percentage", "Risk")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(15))) \
.SetDisplay("Candle type", "Candle type for strategy calculation", "General")
self._prev_above_both = None
self._prev_below_both = None
@property
def CandleType(self):
return self._candle_type.Value
def GetWorkingSecurities(self):
return [(self.Security, self.CandleType)]
def OnReseted(self):
super(double_supertrend_strategy, self).OnReseted()
self._prev_above_both = None
self._prev_below_both = None
def OnStarted2(self, time):
super(double_supertrend_strategy, self).OnStarted2(time)
self._prev_above_both = None
self._prev_below_both = None
st1 = SuperTrend()
st1.Length = self._atr_period1.Value
st1.Multiplier = Decimal(self._factor1.Value)
st2 = SuperTrend()
st2.Length = self._atr_period2.Value
st2.Multiplier = Decimal(self._factor2.Value)
subscription = self.SubscribeCandles(self.CandleType)
subscription.BindEx(st1, st2, self._process_candle).Start()
tp_percent = float(self._tp_percent.Value)
sl_percent = float(self._sl_percent.Value)
take_profit = Unit(Decimal(tp_percent), UnitTypes.Percent) \
if str(self._tp_type.Value).lower() == "percent" and tp_percent > 0 else Unit()
stop_loss = Unit(Decimal(sl_percent), UnitTypes.Percent) if sl_percent > 0 else Unit()
self.StartProtection(take_profit, stop_loss, useMarketOrders=True)
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, st1)
self.DrawIndicator(area, st2)
self.DrawOwnTrades(area)
def _process_candle(self, candle, st1_value, st2_value):
if candle.State != CandleStates.Finished:
return
if not st1_value.IsFormed or not st2_value.IsFormed:
return
line1 = float(st1_value.GetValue[Decimal](None))
line2 = float(st2_value.GetValue[Decimal](None))
close = float(candle.ClosePrice)
above_both = close > line1 and close > line2
below_both = close < line1 and close < line2
prev_above = self._prev_above_both
prev_below = self._prev_below_both
self._prev_above_both = above_both
self._prev_below_both = below_both
if prev_above is None or prev_below is None:
return
if not self.IsFormedAndOnlineAndAllowTrading():
return
direction = str(self._direction.Value).lower()
allow_long = direction != "short"
allow_short = direction != "long"
trail_on_second = str(self._tp_type.Value).lower() == "supertrend"
long_signal = allow_long and above_both and not prev_above
short_signal = allow_short and below_both and not prev_below
if long_signal and self.Position <= 0:
self.BuyMarket(self.Volume + abs(self.Position))
elif short_signal and self.Position >= 0:
self.SellMarket(self.Volume + abs(self.Position))
elif self.Position > 0 and (close < line1 or (trail_on_second and close < line2)):
self.SellMarket(self.Position)
elif self.Position < 0 and (close > line1 or (trail_on_second and close > line2)):
self.BuyMarket(-self.Position)
def CreateClone(self):
return double_supertrend_strategy()