Bollinger Bands Trading Strategy: Complete Guide with Code
Learn how to trade Bollinger Bands with squeeze, bounce, and band walk strategies. Includes ready-to-use code for TradingView, MetaTrader 5, and Python.
The Bollinger Bands trading strategy is a staple of volatility-based analysis, used by traders to identify overbought/oversold conditions and breakout opportunities. This guide covers three proven Bollinger Bands strategies with code for TradingView, MetaTrader, and Python.
What Are Bollinger Bands?
Bollinger Bands are a volatility indicator developed by John Bollinger in the 1980s. They consist of three lines plotted around a moving average:
- Middle Band: 20-period Simple Moving Average (SMA)
- Upper Band: Middle Band + (2 × Standard Deviation)
- Lower Band: Middle Band - (2 × Standard Deviation)
Key Principles:
- Price tends to stay within the bands ~95% of the time
- Bands widen during high volatility and narrow during low volatility
- Touches of the upper/lower band are not automatic buy/sell signals
Strategy 1: Bollinger Bounce (Mean Reversion)
The most popular BB strategy. Price tends to revert to the middle band after touching the outer bands.
PineScript Code (TradingView)
//@version=5
strategy("BB Bounce Strategy", overlay=true)
// Bollinger Bands Settings
length = input(20, "BB Length")
mult = input.float(2.0, "BB Multiplier")
rsiLength = input(14, "RSI Length")
// Calculate Bollinger Bands
basis = ta.sma(close, length)
dev = mult * ta.stdev(close, length)
upper = basis + dev
lower = basis - dev
// RSI for confirmation
rsiValue = ta.rsi(close, rsiLength)
// Buy at lower band when RSI confirms oversold
longCondition = close <= lower and rsiValue < 30
if (longCondition)
strategy.entry("Long", strategy.long)
// Exit at middle band or upper band
if (close >= basis)
strategy.close("Long")
// Plot bands
plot(basis, "Basis", color=color.blue)
plot(upper, "Upper", color=color.red)
plot(lower, "Lower", color=color.green)MQL5 Code (MetaTrader 5)
//+------------------------------------------------------------------+
//| Bollinger Bounce EA |
//+------------------------------------------------------------------+
#include <Trade\Trade.mqh>
input int BB_Period = 20;
input double BB_Deviation = 2.0;
input int RSI_Period = 14;
input double LotSize = 0.1;
input int StopLossPips = 40;
CTrade trade;
int bbHandle, rsiHandle;
int OnInit()
{
bbHandle = iBands(_Symbol, PERIOD_CURRENT, BB_Period, 0, BB_Deviation, PRICE_CLOSE);
rsiHandle = iRSI(_Symbol, PERIOD_CURRENT, RSI_Period, PRICE_CLOSE);
if(bbHandle == INVALID_HANDLE || rsiHandle == INVALID_HANDLE)
return(INIT_FAILED);
return(INIT_SUCCEEDED);
}
void OnTick()
{
double bbUpper[], bbLower[], bbMiddle[], rsi[];
ArraySetAsSeries(bbUpper, true);
ArraySetAsSeries(bbLower, true);
ArraySetAsSeries(bbMiddle, true);
ArraySetAsSeries(rsi, true);
CopyBuffer(bbHandle, 0, 0, 3, bbMiddle); // Middle band
CopyBuffer(bbHandle, 1, 0, 3, bbUpper); // Upper band
CopyBuffer(bbHandle, 2, 0, 3, bbLower); // Lower band
CopyBuffer(rsiHandle, 0, 0, 3, rsi);
double close1 = iClose(_Symbol, PERIOD_CURRENT, 1);
bool hasPosition = PositionSelect(_Symbol);
// Buy at lower band with RSI confirmation
if(close1 <= bbLower[1] && rsi[1] < 30 && !hasPosition)
{
double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
double point = SymbolInfoDouble(_Symbol, SYMBOL_POINT);
double sl = ask - StopLossPips * point * 10;
trade.Buy(LotSize, _Symbol, ask, sl, 0, "BB Bounce Buy");
}
// Exit at middle band
if(close1 >= bbMiddle[1] && hasPosition)
{
trade.PositionClose(_Symbol);
}
}
void OnDeinit(const int reason)
{
IndicatorRelease(bbHandle);
IndicatorRelease(rsiHandle);
}Python Code
import pandas as pd
import numpy as np
def calculate_bollinger_bands(prices, period=20, std_mult=2):
"""Calculate Bollinger Bands"""
middle = prices.rolling(window=period).mean()
std = prices.rolling(window=period).std()
upper = middle + (std_mult * std)
lower = middle - (std_mult * std)
return upper, middle, lower
def bb_bounce_strategy(df, bb_period=20, std_mult=2, rsi_period=14):
"""Bollinger Bounce with RSI Confirmation"""
df = df.copy()
df['bb_upper'], df['bb_middle'], df['bb_lower'] = calculate_bollinger_bands(
df['close'], bb_period, std_mult
)
# RSI
delta = df['close'].diff()
gain = delta.where(delta > 0, 0).rolling(window=rsi_period).mean()
loss = (-delta.where(delta < 0, 0)).rolling(window=rsi_period).mean()
rs = gain / loss
df['rsi'] = 100 - (100 / (1 + rs))
# Signals
df['signal'] = 0
df.loc[(df['close'] <= df['bb_lower']) & (df['rsi'] < 30), 'signal'] = 1
df.loc[df['close'] >= df['bb_middle'], 'signal'] = -1
df['position'] = df['signal'].replace(0, np.nan).ffill().fillna(0)
return dfStrategy 2: Bollinger Squeeze (Breakout)
When bands contract tightly (low volatility), a breakout is imminent. The squeeze identifies these moments.
//@version=5
strategy("BB Squeeze Strategy", overlay=true)
// Bollinger Bands
bbLength = input(20, "BB Length")
bbMult = input.float(2.0, "BB Multiplier")
basis = ta.sma(close, bbLength)
bbDev = bbMult * ta.stdev(close, bbLength)
bbUpper = basis + bbDev
bbLower = basis - bbDev
// Keltner Channel (for squeeze detection)
kcLength = input(20, "KC Length")
kcMult = input.float(1.5, "KC Multiplier")
kcBasis = ta.ema(close, kcLength)
kcRange = kcMult * ta.atr(kcLength)
kcUpper = kcBasis + kcRange
kcLower = kcBasis - kcRange
// Squeeze: BB inside KC
squeeze = bbLower > kcLower and bbUpper < kcUpper
noSqueeze = not squeeze
// Momentum
momentum = ta.linreg(close - basis, bbLength, 0)
// Entry: Squeeze fires with positive momentum
if (noSqueeze and squeeze[1] and momentum > 0)
strategy.entry("Long", strategy.long)
if (noSqueeze and squeeze[1] and momentum < 0)
strategy.entry("Short", strategy.short)
// Exit on opposite signal
if (strategy.position_size > 0 and momentum < 0)
strategy.close("Long")
if (strategy.position_size < 0 and momentum > 0)
strategy.close("Short")Strategy 3: Band Walk (Trend Following)
In strong trends, price "walks" along the upper or lower band. Instead of fading the band, ride the trend.
//@version=5
strategy("BB Band Walk", overlay=true)
length = input(20, "BB Length")
mult = input.float(2.0, "BB Multiplier")
basis = ta.sma(close, length)
dev = mult * ta.stdev(close, length)
upper = basis + dev
lower = basis - dev
// ADX for trend strength
adxValue = ta.adx(high, low, close, 14)
strongTrend = adxValue > 25
// Band walk: consecutive closes above upper band in strong trend
walkUp = close > upper and close[1] > upper[1] and strongTrend
walkDown = close < lower and close[1] < lower[1] and strongTrend
if (walkUp)
strategy.entry("Long", strategy.long)
if (close < basis or walkDown)
strategy.close("Long")Bollinger Bands vs Keltner Channel vs Donchian Channel
| Feature | Bollinger Bands | Keltner Channel | Donchian Channel |
|---|---|---|---|
| Basis | SMA | EMA | Midpoint of range |
| Width | Standard Deviation | ATR | High/Low range |
| Adapts to volatility | Yes (fast) | Yes (smoother) | No |
| Best for | Mean reversion + squeeze | Trend following | Breakouts |
| Sensitivity | High | Medium | Low |
Best Bollinger Bands Settings
| Timeframe | Length | Multiplier | Notes |
|---|---|---|---|
| Scalping (1-5min) | 10-15 | 1.5-2.0 | Tighter bands for quick moves |
| Day Trading (15-60min) | 20 | 2.0 | Standard settings |
| Swing Trading (Daily) | 20-25 | 2.0-2.5 | Wider bands, fewer signals |
| Position Trading (Weekly) | 30-50 | 2.0-2.5 | Very smooth |
Backtest Results
| Strategy | Market | Annual Return | Max Drawdown | Win Rate |
|---|---|---|---|---|
| BB Bounce (with RSI) | S&P 500 | 10-15% | -14% | 60-65% |
| BB Squeeze | Forex (EUR/USD) | 8-12% | -16% | 45-52% |
| Band Walk | Crypto (BTC) | 20-35% | -30% | 38-45% |
Results vary based on market conditions and settings.
Common Bollinger Bands Mistakes
- Buying every touch of the lower band — Not all touches lead to reversals; confirm with RSI or volume
- Ignoring the squeeze — The tightest squeezes often precede the biggest moves
- Using BB alone in trending markets — Band walks invalidate mean reversion entries
- Not adjusting the multiplier — 2.0 is standard but not always optimal
- Confusing bandwidth with direction — BB shows volatility, not trend direction
Generate Your Bollinger Bands Strategy Instantly
Instead of writing code manually, describe your strategy in plain English:
"Buy when price touches the lower Bollinger Band and RSI is below 30. Take profit at the middle band. Use 1.5 ATR stop loss."
SpendDock generates production-ready code for TradingView, MetaTrader, NinjaTrader, or Python in seconds — no coding required.
Conclusion
Bollinger Bands are a versatile volatility tool with multiple strategy approaches. Key takeaways:
- The bounce strategy works best in ranging markets
- The squeeze identifies explosive breakout opportunities
- Band walks signal strong trends — trade with them, not against them
- Combine BB with RSI, ADX, or Keltner Channels for confirmation
- Adjust settings for your timeframe and market
Ready to build your own Bollinger Bands strategy? Try SpendDock and generate production-ready code in seconds.
Skip the Coding — Generate Your Strategy
Describe your trading strategy in plain English and get production-ready code for TradingView, MetaTrader, NinjaTrader, or Python.
Try SpendDock Free