Bollinger BandWidth on TradingView: formula and limits
Bollinger BandWidth is the distance between the upper and lower Bollinger Bands divided by the middle band. Multiply by 100 to express it as a percentage. Narrowing bands describe lower price dispersion relative to the average; they do not tell you which way price will move.
BandWidth (%) = 100 × (Upper − Lower) / Middle
Upper 104, lower 96, middle 100 → width 8 → BandWidth 8%.
Calculate width with the same source and denominator
Let M be the SMA of N source values and σ their population standard deviation. Upper = M + kσ and lower = M − kσ, so BandWidth = 100 × 2kσ / M. Population variance divides the squared deviations by N. A spreadsheet sample-standard-deviation function divides by N − 1 and produces different bands.
For the five hypothetical closes 96, 98, 100, 102 and 104, M = 100. Squared deviations sum to 40, so σ = √(40 / 5) = 2.828427. With k = 2, the total band spread is 11.313708 and BandWidth is 11.313708%. Using sample standard deviation instead gives 12.649111%.
A contraction without a breakout
Demonstration only: use a five-bar window and a multiplier of 2. After bar 5, every new close is 100. Values below are rounded for display; calculations use unrounded values.
| Bar | Five closes | SMA | Population σ | Lower | Upper | BandWidth |
|---|---|---|---|---|---|---|
| 5 | 96, 98, 100, 102, 104 | 100.00 | 2.8284 | 94.3431 | 105.6569 | 11.3137% |
| 6 | 98, 100, 102, 104, 100 | 100.80 | 2.0396 | 96.7208 | 104.8792 | 8.0937% |
| 7 | 100, 102, 104, 100, 100 | 101.20 | 1.6000 | 98.0000 | 104.4000 | 6.3241% |
| 8 | 102, 104, 100, 100, 100 | 101.20 | 1.6000 | 98.0000 | 104.4000 | 6.3241% |
| 9 | 104, 100, 100, 100, 100 | 100.80 | 1.6000 | 97.6000 | 104.0000 | 6.3492% |
| 10 | 100, 100, 100, 100, 100 | 100.00 | 0.0000 | 100.0000 | 100.0000 | 0.0000% |
Width reaches 0% on bar 10 with no close outside the bands. At bar 9, σ stays at 1.6 but the middle band falls from 101.2 to 100.8, so percentage width rises slightly. The denominator matters even when the absolute spread is unchanged.
At a positive middle band, zero dispersion gives zero BandWidth. A zero middle band makes the ratio undefined; a negative middle band produces a negative result that defeats the usual interpretation of narrowness. The example code returns no value for either case. A small positive middle band can still create a very large ratio, so synthetic spreads near zero need a different normalization.
Separate BandWidth, %B and historical rank
BandWidth of 8% describes separation. With those same 96 and 104 bands, a current price of 102 gives %B = (102 − 96) / (104 − 96) = 0.75. %B is a location ratio: 0 at the lower band and 1 at the upper band. It can lie outside that interval. Neither its denominator nor its interpretation matches BandWidth.
Historical rank asks whether today's width is small relative to earlier widths. This page defines rank as 100 × the number of prior-window widths less than or equal to the current width / window size. The current bar is excluded from the reference window; ties are counted. Other percentile implementations can use different tie or window conventions.
Hypothetical prior widths: 4%, 6%, 8%, 10%, 12%. Current width: 4%. One of five prior values is at or below 4%, so rank = 20%.
If all five prior widths and the current width are 4%, the same rule returns 100%, not 0%. A flat low-volatility period can therefore have a high rank under this tie convention.
An orange marker in the code means the confirmed bar has rank at most 20%. That is an illustrative cutoff, not a calibrated entry rule. A rank of 20% is not a 20% probability of a breakout. Change the history length and the reference distribution changes, even when the current width does not.
A rolling high includes its current value
The plotted highest and lowest widths include the current bar. Width can equal these extrema, but cannot rise above its own current-inclusive maximum or fall below its own current-inclusive minimum. Test a new extreme against the previous N bars if that is the intended condition. An old extreme dropping out of the window can move a reference line without a new price event.
Bollinger BandWidth Pine Script v6 example
Paste the complete example into TradingView's Pine Editor and add it to a chart. It plots percentage width and its rolling extrema in a separate pane. The Data Window shows historical rank; orange dots mark confirmed low-rank bars. The script places no orders.
| Input | Example default | What changes |
|---|---|---|
| Source | Close | The same data feeds the SMA and standard deviation. |
| Band length | 20 bars | Changes both the average and dispersion window. |
| Standard deviation multiplier | 2 | Doubling it doubles width for the same source and length. |
| Highest / lowest lengths | 125 bars each | Independent windows, including the current bar. |
| Prior bars for rank | 125 bars | Excludes current; requires all prior widths to be valid. |
Copy Pine Script
//@version=6
indicator("Bollinger BandWidth: percentage and context", overlay=false, precision=4, max_bars_back=1001)
source = input.source(close, "Source")
length = input.int(20, "Band length", minval=2, maxval=500)
mult = input.float(2.0, "Standard deviation multiplier", minval=0.1)
highLength = input.int(125, "Highest expansion length", minval=2, maxval=500)
lowLength = input.int(125, "Lowest contraction length", minval=2, maxval=500)
rankLength = input.int(125, "Prior bars for rank", minval=2, maxval=500)
basis = ta.sma(source, length)
sigma = ta.stdev(source, length, true)
upper = basis + mult * sigma
lower = basis - mult * sigma
// Positive-price convention: reject zero and negative middle bands.
bbw = not na(basis) and basis > 0 ? 100 * (upper - lower) / basis : na
// Extrema include the current bar; require a full valid window.
highestRaw = ta.highest(bbw, highLength)
lowestRaw = ta.lowest(bbw, lowLength)
highReady = ta.sma(na(bbw) ? 0.0 : 1.0, highLength) == 1.0
lowReady = ta.sma(na(bbw) ? 0.0 : 1.0, lowLength) == 1.0
highestExpansion = highReady ? highestRaw : na
lowestContraction = lowReady ? lowestRaw : na
// Rank against the previous N bars only, counting ties as at-or-below.
int validCount = 0
int atOrBelow = 0
for i = 1 to rankLength
if not na(bbw[i])
validCount += 1
if bbw[i] <= bbw
atOrBelow += 1
rankReady = not na(bbw) and validCount == rankLength
rankPercent = rankReady ? 100.0 * atOrBelow / rankLength : na
lowRankClosed = barstate.isconfirmed and rankReady and rankPercent <= 20
plot(bbw, "BandWidth (%)", color.blue, 2)
plot(highestExpansion, "Highest expansion (includes current)", color.red)
plot(lowestContraction, "Lowest contraction (includes current)", color.teal)
plot(rankPercent, "Rank vs prior bars (%)", display=display.data_window)
plotshape(lowRankClosed, title="Closed bar: rank at most 20%", style=shape.circle, location=location.bottom, color=color.orange, size=size.tiny)
hline(0, "Zero", color.gray)Check the calculation before adding a trading rule
- Match the symbol, chart type, session, timeframe, price source, length and multiplier with the comparison indicator. A 20-bar window is not always 20 calendar days.
- Compare the middle band, standard deviation and final percentage on the same closed bar. Confirm that a raw ratio such as 0.08 has been converted to 8% exactly once.
- Allow the full history window. On valid uninterrupted data, width starts at bar 20, default extrema at bar 144 and default rank at bar 145. Missing source values and nonpositive middle bands need inspection.
- Inspect live updates separately. Width and rank can change while a bar is open; the orange marker waits for bar-close confirmation. It does not freeze the live width line.
- If adding entries, define direction and order timing explicitly, then add exits, sizing, commissions and slippage. A syntax check does not establish trading performance.
Educational calculation example, not investment advice. No backtest or expected return is claimed.
Turn a BandWidth specification into reviewable code
Give Pineify's Pine Script AI Coding Agent the source, length, deviation multiplier, percentage units and window rules. Ask for explicit handling of nonpositive middle bands and a marker that waits for the chart bar to close. Review the generated values bar by bar before requesting a separate strategy.
Build a Pine v6 BandWidth indicator with close, SMA 20 and population standard deviation × 2. Display width as a percentage. Return na when the middle band is nonpositive. Compare the current width with 125 prior valid widths, count ties, and mark rank ≤ 20 only on confirmed bars. Keep entry and exit rules separate.Open Pine Script AI Coding Agent
Bollinger BandWidth questions
Sources and related reading
Official sources reviewed October 17, 2026. The rolling calculation table and rank examples are hypothetical demonstrations created for this page.