Bollinger Bands Automated
Strategy that places buy limit orders at the lower Bollinger Band and sell limit orders at the upper band. Positions close when the price touches the middle band. Pending orders are refreshed at the start of each candle.
Details
- Entry Criteria:
- Long: buy limit at lower Bollinger Band
- Short: sell limit at upper Bollinger Band
- Long/Short: Both
- Exit Criteria:
- Long: price crosses above middle Bollinger Band
- Short: price crosses below middle Bollinger Band
- Stops: None
- Default Values:
BbPeriod= 20BbDeviation= 2mCandleType= TimeSpan.FromMinutes(15).TimeFrame()
- Filters:
- Category: Mean Reversion
- Direction: Both
- Indicators: Bollinger Bands
- Stops: No
- Complexity: Basic
- Timeframe: Short-term
- Seasonality: No
- Neural Networks: No
- Divergence: No
- Risk Level: Medium
using System;
using System.Linq;
using System.Collections.Generic;
using Ecng.Common;
using Ecng.Collections;
using Ecng.Serialization;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Bollinger Bands mean reversion strategy.
/// Buys when price touches lower band, sells when price touches upper band.
/// Closes at middle band.
/// </summary>
public class BollingerBandsAutomatedStrategy : Strategy
{
private readonly StrategyParam<int> _bbPeriod;
private readonly StrategyParam<decimal> _bbDeviation;
private readonly StrategyParam<DataType> _candleType;
public int BbPeriod { get => _bbPeriod.Value; set => _bbPeriod.Value = value; }
public decimal BbDeviation { get => _bbDeviation.Value; set => _bbDeviation.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public BollingerBandsAutomatedStrategy()
{
_bbPeriod = Param(nameof(BbPeriod), 20)
.SetDisplay("BB Period", "Bollinger Bands period", "Indicators")
.SetGreaterThanZero();
_bbDeviation = Param(nameof(BbDeviation), 2m)
.SetDisplay("BB Deviation", "Bollinger Bands deviation", "Indicators")
.SetGreaterThanZero();
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Type of candles", "General");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
=> [(Security, CandleType)];
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var bb = new BollingerBands
{
Length = BbPeriod,
Width = BbDeviation
};
var subscription = SubscribeCandles(CandleType);
subscription
.BindEx(bb, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, bb);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, IIndicatorValue bbValue)
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
var bb = bbValue as BollingerBandsValue;
if (bb?.UpBand is not decimal upper || bb?.LowBand is not decimal lower)
return;
var middle = (upper + lower) / 2m;
var close = candle.ClosePrice;
// Close long at middle band
if (Position > 0 && close >= middle)
SellMarket();
// Close short at middle band
else if (Position < 0 && close <= middle)
BuyMarket();
// Open new positions at band extremes
if (close <= lower && Position <= 0)
BuyMarket();
else if (close >= upper && Position >= 0)
SellMarket();
}
}
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
from StockSharp.Algo.Indicators import BollingerBands
from StockSharp.Algo.Strategies import Strategy
class bollinger_bands_automated_strategy(Strategy):
def __init__(self):
super(bollinger_bands_automated_strategy, self).__init__()
self._bb_period = self.Param("BbPeriod", 20) \
.SetDisplay("BB Period", "Bollinger Bands period", "Indicators")
self._bb_deviation = self.Param("BbDeviation", 2.0) \
.SetDisplay("BB Deviation", "Bollinger Bands deviation", "Indicators")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Type of candles", "General")
@property
def bb_period(self):
return self._bb_period.Value
@property
def bb_deviation(self):
return self._bb_deviation.Value
@property
def candle_type(self):
return self._candle_type.Value
def OnStarted2(self, time):
super(bollinger_bands_automated_strategy, self).OnStarted2(time)
bb = BollingerBands()
bb.Length = self.bb_period
bb.Width = self.bb_deviation
subscription = self.SubscribeCandles(self.candle_type)
subscription.BindEx(bb, self.process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, bb)
self.DrawOwnTrades(area)
def process_candle(self, candle, bb_value):
if candle.State != CandleStates.Finished:
return
if not bb_value.IsFormed:
return
upper = bb_value.UpBand
lower = bb_value.LowBand
if upper is None or lower is None:
return
upper = float(upper)
lower = float(lower)
middle = (upper + lower) / 2.0
close = float(candle.ClosePrice)
if self.Position > 0 and close >= middle:
self.SellMarket()
elif self.Position < 0 and close <= middle:
self.BuyMarket()
if close <= lower and self.Position <= 0:
self.BuyMarket()
elif close >= upper and self.Position >= 0:
self.SellMarket()
def CreateClone(self):
return bollinger_bands_automated_strategy()