MA + BB + SuperTrend-Strategie
Die Strategie kombiniert einen gleitenden Durchschnitt-Crossover mit der SuperTrend-Bestätigung und verwendet Bollinger Bands für Ausstiege. Eine Long-Position wird eröffnet, wenn die Signal-MA die Basis-MA von unten kreuzt und der Preis über der SuperTrend-Linie liegt. Short-Positionen werden beim umgekehrten Kreuzung unter einem bärischen SuperTrend eröffnet. Positionen werden geschlossen, wenn der Preis das entfernte Bollinger Band berührt oder wenn der Preis den SuperTrend in die entgegengesetzte Richtung kreuzt.
Details
- Einstiegskriterien:
- Signal-MA kreuzt die Basis-MA in Richtung des SuperTrend.
- Long/Short: Beide Richtungen.
- Ausstiegskriterien:
- Berührung des gegenüberliegenden Bollinger Bands oder SuperTrend-Wechsel.
- Stops: SuperTrend fungiert als Trailing-Stop.
- Standardwerte:
- MA-Signallänge = 89, MA-Verhältnis = 1.08.
- BB-Länge = 30, BB-Breite = 3.
- SuperTrend-Periode = 20, SuperTrend-Faktor = 4.
- Filter:
- Kategorie: Trendfolge
- Richtung: Beide
- Indikatoren: MA, Bollinger Bands, SuperTrend
- Stops: SuperTrend
- Komplexität: Moderat
- Zeitrahmen: Kurz/mittel
- Saisonalität: Nein
- Neuronale Netze: Nein
- Divergenz: Nein
- Risikolevel: Mittel
namespace StockSharp.Samples.Strategies;
using System;
using System.Collections.Generic;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
/// <summary>
/// Moving Average Crossover confirmed by SuperTrend with Bollinger Bands exits.
/// Buys on MA cross up + SuperTrend uptrend.
/// Sells on MA cross down + SuperTrend downtrend.
/// Exits at BB bands.
/// </summary>
public class MaBbSupertrendStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _fastMaLength;
private readonly StrategyParam<int> _slowMaLength;
private readonly StrategyParam<int> _bbLength;
private readonly StrategyParam<int> _supertrendPeriod;
private readonly StrategyParam<decimal> _supertrendFactor;
private readonly StrategyParam<int> _cooldownBars;
private SimpleMovingAverage _fastMa;
private SimpleMovingAverage _slowMa;
private BollingerBands _bb;
private SuperTrend _supertrend;
private decimal _prevFast;
private decimal _prevSlow;
private bool _hasPrev;
private int _cooldownRemaining;
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public int FastMaLength
{
get => _fastMaLength.Value;
set => _fastMaLength.Value = value;
}
public int SlowMaLength
{
get => _slowMaLength.Value;
set => _slowMaLength.Value = value;
}
public int BbLength
{
get => _bbLength.Value;
set => _bbLength.Value = value;
}
public int SupertrendPeriod
{
get => _supertrendPeriod.Value;
set => _supertrendPeriod.Value = value;
}
public decimal SupertrendFactor
{
get => _supertrendFactor.Value;
set => _supertrendFactor.Value = value;
}
public int CooldownBars
{
get => _cooldownBars.Value;
set => _cooldownBars.Value = value;
}
public MaBbSupertrendStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(30).TimeFrame())
.SetDisplay("Candle Type", "Type of candles to use", "General");
_fastMaLength = Param(nameof(FastMaLength), 20)
.SetGreaterThanZero()
.SetDisplay("Fast MA Length", "Fast SMA period", "MA");
_slowMaLength = Param(nameof(SlowMaLength), 50)
.SetGreaterThanZero()
.SetDisplay("Slow MA Length", "Slow SMA period", "MA");
_bbLength = Param(nameof(BbLength), 20)
.SetGreaterThanZero()
.SetDisplay("BB Length", "Bollinger Bands period", "Bollinger");
_supertrendPeriod = Param(nameof(SupertrendPeriod), 20)
.SetGreaterThanZero()
.SetDisplay("SuperTrend Period", "ATR period for SuperTrend", "SuperTrend");
_supertrendFactor = Param(nameof(SupertrendFactor), 4m)
.SetDisplay("SuperTrend Factor", "ATR multiplier for SuperTrend", "SuperTrend");
_cooldownBars = Param(nameof(CooldownBars), 10)
.SetDisplay("Cooldown Bars", "Bars between trades", "Risk");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
=> [(Security, CandleType)];
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_fastMa = null;
_slowMa = null;
_bb = null;
_supertrend = null;
_prevFast = 0;
_prevSlow = 0;
_hasPrev = false;
_cooldownRemaining = 0;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_fastMa = new SimpleMovingAverage { Length = FastMaLength };
_slowMa = new SimpleMovingAverage { Length = SlowMaLength };
_bb = new BollingerBands { Length = BbLength, Width = 2m };
_supertrend = new SuperTrend { Length = SupertrendPeriod, Multiplier = SupertrendFactor };
var subscription = SubscribeCandles(CandleType);
subscription
.BindEx(_fastMa, _slowMa, _bb, _supertrend, OnProcess)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, _fastMa);
DrawIndicator(area, _slowMa);
DrawIndicator(area, _bb);
DrawOwnTrades(area);
}
}
private void OnProcess(ICandleMessage candle, IIndicatorValue fastVal, IIndicatorValue slowVal, IIndicatorValue bbVal, IIndicatorValue stVal)
{
if (candle.State != CandleStates.Finished)
return;
if (!_fastMa.IsFormed || !_slowMa.IsFormed || !_bb.IsFormed || !_supertrend.IsFormed)
return;
if (fastVal.IsEmpty || slowVal.IsEmpty || bbVal.IsEmpty || stVal.IsEmpty)
return;
var fast = fastVal.ToDecimal();
var slow = slowVal.ToDecimal();
var bb = (BollingerBandsValue)bbVal;
if (bb.UpBand is not decimal upper || bb.LowBand is not decimal lower)
return;
var stTyped = (SuperTrendIndicatorValue)stVal;
var uptrend = stTyped.IsUpTrend;
if (!IsFormedAndOnlineAndAllowTrading())
{
_prevFast = fast;
_prevSlow = slow;
_hasPrev = true;
return;
}
if (!_hasPrev)
{
_prevFast = fast;
_prevSlow = slow;
_hasPrev = true;
return;
}
if (_cooldownRemaining > 0)
{
_cooldownRemaining--;
_prevFast = fast;
_prevSlow = slow;
return;
}
var crossUp = _prevFast <= _prevSlow && fast > slow;
var crossDown = _prevFast >= _prevSlow && fast < slow;
// Entry long: MA cross up + SuperTrend uptrend
if (crossUp && uptrend && Position <= 0)
{
if (Position < 0)
BuyMarket(Math.Abs(Position));
BuyMarket(Volume);
_cooldownRemaining = CooldownBars;
}
// Entry short: MA cross down + SuperTrend downtrend
else if (crossDown && !uptrend && Position >= 0)
{
if (Position > 0)
SellMarket(Math.Abs(Position));
SellMarket(Volume);
_cooldownRemaining = CooldownBars;
}
// Exit long: price reaches upper BB or SuperTrend flips
else if (Position > 0 && (candle.ClosePrice >= upper || !uptrend))
{
SellMarket(Math.Abs(Position));
_cooldownRemaining = CooldownBars;
}
// Exit short: price reaches lower BB or SuperTrend flips
else if (Position < 0 && (candle.ClosePrice <= lower || uptrend))
{
BuyMarket(Math.Abs(Position));
_cooldownRemaining = CooldownBars;
}
_prevFast = fast;
_prevSlow = slow;
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan, Math
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Indicators import SimpleMovingAverage, BollingerBands, SuperTrend, IndicatorHelper
from StockSharp.Algo.Strategies import Strategy
class ma_bb_supertrend_strategy(Strategy):
"""Moving Average Crossover confirmed by SuperTrend with Bollinger Bands exits."""
def __init__(self):
super(ma_bb_supertrend_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(30))) \
.SetDisplay("Candle Type", "Type of candles to use", "General")
self._fast_ma_length = self.Param("FastMaLength", 20) \
.SetDisplay("Fast MA Length", "Fast SMA period", "MA")
self._slow_ma_length = self.Param("SlowMaLength", 50) \
.SetDisplay("Slow MA Length", "Slow SMA period", "MA")
self._bb_length = self.Param("BbLength", 20) \
.SetDisplay("BB Length", "Bollinger Bands period", "Bollinger")
self._supertrend_period = self.Param("SupertrendPeriod", 20) \
.SetDisplay("SuperTrend Period", "ATR period for SuperTrend", "SuperTrend")
self._supertrend_factor = self.Param("SupertrendFactor", 4.0) \
.SetDisplay("SuperTrend Factor", "ATR multiplier for SuperTrend", "SuperTrend")
self._cooldown_bars = self.Param("CooldownBars", 10) \
.SetDisplay("Cooldown Bars", "Bars between trades", "Risk")
self._fast_ma = None
self._slow_ma = None
self._bb = None
self._supertrend = None
self._prev_fast = 0.0
self._prev_slow = 0.0
self._has_prev = False
self._cooldown_remaining = 0
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(ma_bb_supertrend_strategy, self).OnReseted()
self._fast_ma = None
self._slow_ma = None
self._bb = None
self._supertrend = None
self._prev_fast = 0.0
self._prev_slow = 0.0
self._has_prev = False
self._cooldown_remaining = 0
def OnStarted2(self, time):
super(ma_bb_supertrend_strategy, self).OnStarted2(time)
self._fast_ma = SimpleMovingAverage()
self._fast_ma.Length = int(self._fast_ma_length.Value)
self._slow_ma = SimpleMovingAverage()
self._slow_ma.Length = int(self._slow_ma_length.Value)
self._bb = BollingerBands()
self._bb.Length = int(self._bb_length.Value)
self._bb.Width = 2.0
self._supertrend = SuperTrend()
self._supertrend.Length = int(self._supertrend_period.Value)
self._supertrend.Multiplier = float(self._supertrend_factor.Value)
subscription = self.SubscribeCandles(self.candle_type)
subscription.BindEx(self._fast_ma, self._slow_ma, self._bb, self._supertrend, self._on_process).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, self._fast_ma)
self.DrawIndicator(area, self._slow_ma)
self.DrawIndicator(area, self._bb)
self.DrawOwnTrades(area)
def _on_process(self, candle, fast_val, slow_val, bb_val, st_val):
if candle.State != CandleStates.Finished:
return
if not self._fast_ma.IsFormed or not self._slow_ma.IsFormed or not self._bb.IsFormed or not self._supertrend.IsFormed:
return
if fast_val.IsEmpty or slow_val.IsEmpty or bb_val.IsEmpty or st_val.IsEmpty:
return
fast = float(IndicatorHelper.ToDecimal(fast_val))
slow = float(IndicatorHelper.ToDecimal(slow_val))
if bb_val.UpBand is None or bb_val.LowBand is None:
return
upper = float(bb_val.UpBand)
lower = float(bb_val.LowBand)
uptrend = st_val.IsUpTrend
if not self.IsFormedAndOnlineAndAllowTrading():
self._prev_fast = fast
self._prev_slow = slow
self._has_prev = True
return
if not self._has_prev:
self._prev_fast = fast
self._prev_slow = slow
self._has_prev = True
return
if self._cooldown_remaining > 0:
self._cooldown_remaining -= 1
self._prev_fast = fast
self._prev_slow = slow
return
cooldown = int(self._cooldown_bars.Value)
cross_up = self._prev_fast <= self._prev_slow and fast > slow
cross_down = self._prev_fast >= self._prev_slow and fast < slow
if cross_up and uptrend and self.Position <= 0:
if self.Position < 0:
self.BuyMarket(Math.Abs(self.Position))
self.BuyMarket(self.Volume)
self._cooldown_remaining = cooldown
elif cross_down and not uptrend and self.Position >= 0:
if self.Position > 0:
self.SellMarket(Math.Abs(self.Position))
self.SellMarket(self.Volume)
self._cooldown_remaining = cooldown
elif self.Position > 0 and (float(candle.ClosePrice) >= upper or not uptrend):
self.SellMarket(Math.Abs(self.Position))
self._cooldown_remaining = cooldown
elif self.Position < 0 and (float(candle.ClosePrice) <= lower or uptrend):
self.BuyMarket(Math.Abs(self.Position))
self._cooldown_remaining = cooldown
self._prev_fast = fast
self._prev_slow = slow
def CreateClone(self):
return ma_bb_supertrend_strategy()