What it measures
Bollinger Bands wrap a moving average in an envelope whose width follows volatility. When price swings widely the bands spread apart; when it goes quiet they contract. The bands therefore describe two things at once: where price sits relative to its recent average, and how volatile the market has been.
John Bollinger developed them in the 1980s. Two derived values are worth knowing: %B, which tells you where price is inside the bands, and bandwidth, which measures how wide the bands are relative to the average.
The formula in words
- Middle band: a 20-period simple moving average of the close.
- Compute the standard deviation of the same 20 closes: a measure of how far they typically sit from their average.
- Upper band = middle band + 2 × standard deviation. Lower band = middle band − 2 × standard deviation.
- %B = (close − lower band) ÷ (upper band − lower band). It is 1 at the upper band, 0 at the lower band, and goes above 1 or below 0 when price closes outside.
- Bandwidth = (upper band − lower band) ÷ middle band.
Pine Script's ta.bb() returns the three bands in one call, as the script below shows.
How traders read it
- Band touches are not signals by themselves. A close outside the upper band says price moved further than usual relative to the last 20 bars. In a range that can mean stretched; in a breakout it means strong.
- Mean reversion. Range traders look for a close back inside the bands after a move outside, often combined with an oscillator.
- Walking the band. In strong trends price can ride along the upper or lower band for many bars. Fading those moves is how band-based strategies take their worst losses.
- The squeeze. When bandwidth drops to its lowest level in a long time, volatility is compressed. Squeezes don't say which way the expansion will go, only that quiet periods tend not to last forever.
- %B for rules. Because %B is normalised, it is handy in code: "%B above 1" means a close above the upper band on any symbol.
Common settings
| Setting | Typical value | Notes |
|---|---|---|
| Length | 20 | Bollinger's default. 10 for short-term, 50 for long-term views. |
| Width | 2 standard deviations | Common pairings: 1.9 with length 10, 2.1 with length 50. |
| Basis | Simple moving average | Some variants use an EMA; band touches then behave differently. |
| Squeeze lookback | 120 bars or so | How far back "lowest bandwidth" is measured. |
Pine Script v6 code
The complete, self-contained script is below. Copy it into a new indicator in TradingView's Pine Editor, or download the .pine file.
//@version=6
indicator("Bollinger Bands with %B and squeeze", shorttitle = "BB", overlay = true)
src = input.source(close, "Source")
len = input.int(20, "Length", minval = 2)
mult = input.float(2.0, "Standard deviations", minval = 0.1, step = 0.1)
squeezeLen = input.int(120, "Squeeze lookback (bars)", minval = 10)
[basis, upper, lower] = ta.bb(src, len, mult)
bandwidth = (upper - lower) / basis
percentB = (src - lower) / (upper - lower)
// A squeeze: bandwidth at its lowest level of the lookback window.
squeeze = bandwidth <= ta.lowest(bandwidth, squeezeLen)
squeezeStart = squeeze and not squeeze[1]
plot(basis, "Basis", color = color.new(color.gray, 0))
upperPlot = plot(upper, "Upper", color = color.new(color.blue, 0))
lowerPlot = plot(lower, "Lower", color = color.new(color.blue, 0))
fill(upperPlot, lowerPlot, color = squeeze ? color.new(color.orange, 85) : color.new(color.blue, 92), title = "Band fill")
// %B and bandwidth appear in the data window.
plot(percentB, "%B", display = display.data_window)
plot(bandwidth, "Bandwidth", display = display.data_window)
closeAbove = ta.crossover(close, upper)
closeBelow = ta.crossunder(close, lower)
alertcondition(closeAbove, "Close above upper band", "{{ticker}} closed above the upper Bollinger Band ({{interval}})")
alertcondition(closeBelow, "Close below lower band", "{{ticker}} closed below the lower Bollinger Band ({{interval}})")
alertcondition(squeezeStart, "Squeeze starts", "Bollinger bandwidth hit a new low for the lookback on {{ticker}} ({{interval}})")The bands are drawn on the price chart and the fill turns orange while a squeeze is active, so quiet periods stand out. %B and bandwidth are plotted to the data window only: hover over a bar to read them without cluttering the chart.
Three alert conditions are included: a close above the upper band, a close below the lower band, and the start of a squeeze.
Add it to your chart
- Open any chart on TradingView and open the Pine Editor.
- Create a new indicator, delete the template code and paste the script.
- Click Save, then Add to chart. Change lengths and levels from the indicator's settings.
Stuck on an error? See how to add a Pine Script indicator to TradingView.
Pitfalls
- Fading every touch. In trends, closes outside the bands can continue for many bars. Decide in advance whether you are trading ranges or breakouts.
- Treating a squeeze as directional. It only says volatility is low. The break can go either way, and false breaks are common.
- Assuming a normal distribution. "Two standard deviations" suggests most closes stay inside the bands, but market returns have fat tails. Closes outside happen more often than textbook statistics imply.
- Copying settings across timeframes without checking. A 20-bar window is a month on daily bars and under two hours on 5-minute bars. The bands describe different things.
Related reading
- 8 backtesting mistakes that make a strategy look better than it is
- Pine Script alerts: alertcondition() vs alert(), messages, webhooks and frequency
- ATR Stop-Loss Calculator (free tool)
- Risk/Reward Calculator (free tool)
The script is an educational example: test it on your own markets before relying on it. Indicators describe the past; they don't predict the future. Trading involves substantial risk of loss and is not suitable for every investor. Edgoro is a software tool, not a broker or financial adviser: nothing it produces is investment advice, and past or backtested performance does not guarantee future results.