This strategy blends Bollinger Bands with the Supertrend indicator to pinpoint entries during strong directional moves. Bollinger Bands gauge volatility expansion while the Supertrend line tracks the overall trend and acts as a trailing stop.
Testing indicates an average annual return of about 79%. It performs best in the stocks market.
A long trade triggers when price closes above the upper Bollinger Band and remains above the Supertrend line, confirming momentum and trend alignment. A short trade occurs when price closes below the lower band while staying under the Supertrend level. Trades are exited once price crosses back through the Supertrend, indicating momentum has faded.
Because the system waits for breakouts beyond normal volatility, it suits traders looking to capture sustained runs rather than quick reversals. The Supertrend stop dynamically adjusts to market swings, helping manage risk without manual intervention.
Details
Entry Criteria:
Long: Close > upper Bollinger Band && Close > Supertrend
Short: Close < lower Bollinger Band && Close < Supertrend
Long/Short: Both sides.
Exit Criteria:
Long: Exit when price crosses below Supertrend
Short: Exit when price crosses above Supertrend
Stops: Yes, via Supertrend trailing stop.
Default Values:
BollingerPeriod = 20
BollingerDeviation = 2
SupertrendPeriod = 10
SupertrendMultiplier = 3
CandleType = TimeSpan.FromMinutes(15)
A long closes when price closes below the Supertrend line and a short when it closes above it. An entry signal against an open position reverses it.
Filters:
Category: Trend
Direction: Both
Indicators: Bollinger Bands, Supertrend
Stops: Yes
Complexity: Intermediate
Timeframe: Intraday
Seasonality: No
Neural networks: No
Divergence: No
Risk Level: Medium
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>
/// Bollinger Supertrend strategy.
/// A close above the upper Bollinger band that is also above the Supertrend line goes long and a close below the lower band that is also
/// below the Supertrend goes short, reversing an opposite position. The Supertrend is the trailing stop: a long closes when price closes
/// below the line and a short when it closes above it.
/// </summary>
public class BollingerSupertrendStrategy : Strategy
{
private readonly StrategyParam<int> _bollingerPeriod;
private readonly StrategyParam<decimal> _bollingerDeviation;
private readonly StrategyParam<int> _supertrendPeriod;
private readonly StrategyParam<decimal> _supertrendMultiplier;
private readonly StrategyParam<DataType> _candleType;
/// <summary>
/// Period of the Bollinger Bands.
/// </summary>
public int BollingerPeriod
{
get => _bollingerPeriod.Value;
set => _bollingerPeriod.Value = value;
}
/// <summary>
/// Standard deviation multiplier of the bands.
/// </summary>
public decimal BollingerDeviation
{
get => _bollingerDeviation.Value;
set => _bollingerDeviation.Value = value;
}
/// <summary>
/// ATR period of Supertrend.
/// </summary>
public int SupertrendPeriod
{
get => _supertrendPeriod.Value;
set => _supertrendPeriod.Value = value;
}
/// <summary>
/// ATR multiplier of Supertrend.
/// </summary>
public decimal SupertrendMultiplier
{
get => _supertrendMultiplier.Value;
set => _supertrendMultiplier.Value = value;
}
/// <summary>
/// Candle type.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Constructor.
/// </summary>
public BollingerSupertrendStrategy()
{
_bollingerPeriod = Param(nameof(BollingerPeriod), 20)
.SetGreaterThanZero()
.SetDisplay("BB Period", "Period of the Bollinger Bands", "Bollinger");
_bollingerDeviation = Param(nameof(BollingerDeviation), 2m)
.SetGreaterThanZero()
.SetDisplay("BB Deviation", "Standard deviation multiplier of the bands", "Bollinger");
_supertrendPeriod = Param(nameof(SupertrendPeriod), 10)
.SetGreaterThanZero()
.SetDisplay("Supertrend Period", "ATR period of Supertrend", "Supertrend");
_supertrendMultiplier = Param(nameof(SupertrendMultiplier), 3m)
.SetGreaterThanZero()
.SetDisplay("Supertrend Multiplier", "ATR multiplier of Supertrend", "Supertrend");
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(15).TimeFrame())
.SetDisplay("Candle Type", "Type of candles to use", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var bollinger = new BollingerBands { Length = BollingerPeriod, Width = BollingerDeviation };
var supertrend = new SuperTrend { Length = SupertrendPeriod, Multiplier = SupertrendMultiplier };
var subscription = SubscribeCandles(CandleType);
subscription
.BindEx(bollinger, supertrend, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, bollinger);
DrawIndicator(area, supertrend);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, IIndicatorValue bollingerValue, IIndicatorValue supertrendValue)
{
if (candle.State != CandleStates.Finished)
return;
if (!bollingerValue.IsFormed || !supertrendValue.IsFormed)
return;
var bands = (BollingerBandsValue)bollingerValue;
if (bands.UpBand is not decimal upper || bands.LowBand is not decimal lower || supertrendValue is not SuperTrendIndicatorValue trend)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
var line = trend.Value;
var close = candle.ClosePrice;
if (close > upper && close > line && Position <= 0)
BuyMarket(Volume + Math.Abs(Position));
else if (close < lower && close < line && Position >= 0)
SellMarket(Volume + Math.Abs(Position));
else if (Position > 0 && close < line)
SellMarket(Position);
else if (Position < 0 && close > line)
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
from StockSharp.Algo.Indicators import BollingerBands, SuperTrend
from StockSharp.Algo.Strategies import Strategy
class bollinger_supertrend_strategy(Strategy):
"""
Bollinger Supertrend strategy.
A close above the upper Bollinger band that is also above the Supertrend line goes long and a close below the lower band that is also
below the Supertrend goes short, reversing an opposite position. The Supertrend is the trailing stop: a long closes when price closes
below the line and a short when it closes above it.
"""
def __init__(self):
super(bollinger_supertrend_strategy, self).__init__()
self._bollinger_period = self.Param("BollingerPeriod", 20).SetGreaterThanZero().SetDisplay("BB Period", "Period of the Bollinger Bands", "Bollinger")
self._bollinger_deviation = self.Param("BollingerDeviation", 2.0).SetGreaterThanZero().SetDisplay("BB Deviation", "Standard deviation multiplier of the bands", "Bollinger")
self._supertrend_period = self.Param("SupertrendPeriod", 10).SetGreaterThanZero().SetDisplay("Supertrend Period", "ATR period of Supertrend", "Supertrend")
self._supertrend_multiplier = self.Param("SupertrendMultiplier", 3.0).SetGreaterThanZero().SetDisplay("Supertrend Multiplier", "ATR multiplier of Supertrend", "Supertrend")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(15))).SetDisplay("Candle Type", "Type of candles to use", "General")
@property
def candle_type(self):
return self._candle_type.Value
def OnStarted2(self, time):
super(bollinger_supertrend_strategy, self).OnStarted2(time)
bollinger = BollingerBands()
bollinger.Length = self._bollinger_period.Value
bollinger.Width = Decimal(self._bollinger_deviation.Value)
supertrend = SuperTrend()
supertrend.Length = self._supertrend_period.Value
supertrend.Multiplier = Decimal(self._supertrend_multiplier.Value)
subscription = self.SubscribeCandles(self.candle_type)
subscription.BindEx(bollinger, supertrend, self._process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, bollinger)
self.DrawIndicator(area, supertrend)
self.DrawOwnTrades(area)
def _process_candle(self, candle, bollinger_value, supertrend_value):
if candle.State != CandleStates.Finished:
return
if not bollinger_value.IsFormed or not supertrend_value.IsFormed:
return
if bollinger_value.UpBand is None or bollinger_value.LowBand is None:
return
if not self.IsFormedAndOnlineAndAllowTrading():
return
upper = bollinger_value.UpBand
lower = bollinger_value.LowBand
line = supertrend_value.Value
close = candle.ClosePrice
if close > upper and close > line and self.Position <= 0:
self.BuyMarket(self.Volume + abs(self.Position))
elif close < lower and close < line and self.Position >= 0:
self.SellMarket(self.Volume + abs(self.Position))
elif self.Position > 0 and close < line:
self.SellMarket(self.Position)
elif self.Position < 0 and close > line:
self.BuyMarket(-self.Position)
def CreateClone(self):
return bollinger_supertrend_strategy()