Auto Trade With Bollinger Bands Strategy
This strategy uses Bollinger Bands, RSI and Stochastic oscillator to automatically open trades during a specified GMT time window. A short position is opened when the previous candle closes above the upper Bollinger Band while RSI is above 75 and Stochastic %K is above 85. A long position is opened when the candle closes below the lower Bollinger Band with RSI below 25 and Stochastic %K below 155. Only one position per direction is allowed. A trailing stop in points protects open positions.
Parameters
OpenBuy– enable opening long positions.OpenSell– enable opening short positions.GmtTradeStart– trading start hour in GMT (exclusive).GmtTradeStop– trading stop hour in GMT (exclusive).BbPeriod– period for Bollinger Bands.RsiPeriod– period for RSI indicator.StochKPeriod– %K period for Stochastic oscillator.StochDPeriod– %D period for Stochastic oscillator.StochSlowing– smoothing factor for Stochastic oscillator.TrailingStop– trailing stop distance in points.CandleType– candle timeframe used for calculations.
using System;
using System.Collections.Generic;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Bollinger Bands auto trade strategy with RSI confirmation.
/// Sells when price touches upper band and RSI is overbought.
/// Buys when price touches lower band and RSI is oversold.
/// </summary>
public class AutoTradeWithBollingerBandsStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _bbPeriod;
private readonly StrategyParam<int> _rsiPeriod;
private readonly StrategyParam<decimal> _rsiOverbought;
private readonly StrategyParam<decimal> _rsiOversold;
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public int BbPeriod
{
get => _bbPeriod.Value;
set => _bbPeriod.Value = value;
}
public int RsiPeriod
{
get => _rsiPeriod.Value;
set => _rsiPeriod.Value = value;
}
public decimal RsiOverbought
{
get => _rsiOverbought.Value;
set => _rsiOverbought.Value = value;
}
public decimal RsiOversold
{
get => _rsiOversold.Value;
set => _rsiOversold.Value = value;
}
public AutoTradeWithBollingerBandsStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Candle timeframe", "General");
_bbPeriod = Param(nameof(BbPeriod), 20)
.SetDisplay("BB Period", "Bollinger Bands period", "Indicators");
_rsiPeriod = Param(nameof(RsiPeriod), 6)
.SetDisplay("RSI Period", "RSI period", "Indicators");
_rsiOverbought = Param(nameof(RsiOverbought), 70m)
.SetDisplay("RSI Overbought", "RSI overbought level", "Indicators");
_rsiOversold = Param(nameof(RsiOversold), 30m)
.SetDisplay("RSI Oversold", "RSI oversold level", "Indicators");
}
/// <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 = BbPeriod, Width = 2m };
var rsi = new RelativeStrengthIndex { Length = RsiPeriod };
var subscription = SubscribeCandles(CandleType);
subscription
.BindEx(bollinger, rsi, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, bollinger);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, IIndicatorValue bbValue, IIndicatorValue rsiValue)
{
if (candle.State != CandleStates.Finished)
return;
var bb = (BollingerBandsValue)bbValue;
if (bb.UpBand is not decimal upper ||
bb.LowBand is not decimal lower ||
bb.MovingAverage is not decimal middle)
return;
var rsi = rsiValue.ToDecimal();
var price = candle.ClosePrice;
// Sell when price above upper band and RSI overbought
if (price > upper && rsi > RsiOverbought && Position >= 0)
{
SellMarket();
}
// Buy when price below lower band and RSI oversold
else if (price < lower && rsi < RsiOversold && Position <= 0)
{
BuyMarket();
}
// Exit long when price returns to middle
else if (Position > 0 && price >= middle)
{
SellMarket();
}
// Exit short when price returns to middle
else if (Position < 0 && price <= middle)
{
BuyMarket();
}
}
}
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, RelativeStrengthIndex
from StockSharp.Algo.Strategies import Strategy
class auto_trade_with_bollinger_bands_strategy(Strategy):
def __init__(self):
super(auto_trade_with_bollinger_bands_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Candle timeframe", "General")
self._bb_period = self.Param("BbPeriod", 20) \
.SetDisplay("BB Period", "Bollinger Bands period", "Indicators")
self._rsi_period = self.Param("RsiPeriod", 6) \
.SetDisplay("RSI Period", "RSI period", "Indicators")
self._rsi_overbought = self.Param("RsiOverbought", 70.0) \
.SetDisplay("RSI Overbought", "RSI overbought level", "Indicators")
self._rsi_oversold = self.Param("RsiOversold", 30.0) \
.SetDisplay("RSI Oversold", "RSI oversold level", "Indicators")
@property
def candle_type(self):
return self._candle_type.Value
@property
def bb_period(self):
return self._bb_period.Value
@property
def rsi_period(self):
return self._rsi_period.Value
@property
def rsi_overbought(self):
return self._rsi_overbought.Value
@property
def rsi_oversold(self):
return self._rsi_oversold.Value
def OnStarted2(self, time):
super(auto_trade_with_bollinger_bands_strategy, self).OnStarted2(time)
bollinger = BollingerBands()
bollinger.Length = self.bb_period
bollinger.Width = 2.0
rsi = RelativeStrengthIndex()
rsi.Length = self.rsi_period
subscription = self.SubscribeCandles(self.candle_type)
subscription.BindEx(bollinger, rsi, self.process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, bollinger)
self.DrawOwnTrades(area)
def process_candle(self, candle, bb_value, rsi_value):
if candle.State != CandleStates.Finished:
return
if bb_value.UpBand is None or bb_value.LowBand is None or bb_value.MovingAverage is None:
return
upper = float(bb_value.UpBand)
lower = float(bb_value.LowBand)
middle = float(bb_value.MovingAverage)
rsi = float(rsi_value)
price = float(candle.ClosePrice)
ob = float(self.rsi_overbought)
os_level = float(self.rsi_oversold)
# Sell when price above upper band and RSI overbought
if price > upper and rsi > ob and self.Position >= 0:
self.SellMarket()
# Buy when price below lower band and RSI oversold
elif price < lower and rsi < os_level and self.Position <= 0:
self.BuyMarket()
# Exit long when price returns to middle
elif self.Position > 0 and price >= middle:
self.SellMarket()
# Exit short when price returns to middle
elif self.Position < 0 and price <= middle:
self.BuyMarket()
def CreateClone(self):
return auto_trade_with_bollinger_bands_strategy()