TradingView indicators

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.

Hypothetical rolling Bollinger BandWidth calculation
BarFive closesSMAPopulation σLowerUpperBandWidth
596, 98, 100, 102, 104100.002.828494.3431105.656911.3137%
698, 100, 102, 104, 100100.802.039696.7208104.87928.0937%
7100, 102, 104, 100, 100101.201.600098.0000104.40006.3241%
8102, 104, 100, 100, 100101.201.600098.0000104.40006.3241%
9104, 100, 100, 100, 100100.801.600097.6000104.00006.3492%
10100, 100, 100, 100, 100100.000.0000100.0000100.00000.0000%
Hypothetical five-bar Bollinger BandWidth falls from 11.3137% to 0% while each new close after bar 5 stays at 100.

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.

InputExample defaultWhat changes
SourceCloseThe same data feeds the SMA and standard deviation.
Band length20 barsChanges both the average and dispersion window.
Standard deviation multiplier2Doubling it doubles width for the same source and length.
Highest / lowest lengths125 bars eachIndependent windows, including the current bar.
Prior bars for rank125 barsExcludes current; requires all prior widths to be valid.
Pine Script v6 · percentage output

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

  1. 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.
  2. 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.
  3. 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.
  4. 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.
  5. 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

See the coding workflow

Bollinger BandWidth questions

Bollinger BandWidth measures the upper-to-lower band distance relative to the middle band. This page expresses the result as a percentage: 100 × (upper − lower) / middle. It describes the dispersion of the selected price source around its average. It does not identify a future price direction, estimate annualized return volatility or give a breakout deadline.

BandWidth measures band separation; %B measures price location within those bands. With lower 96, upper 104 and middle 100, BandWidth is 8%. At a price of 102, %B is 0.75. The same band width can accompany prices near either band. When upper equals lower, %B has a zero denominator even though BandWidth can be zero with a positive middle band.

There is no universally best setting established by this page. Close, a 20-bar SMA and a 2-standard-deviation multiplier are conventional starting inputs. The code also uses 125 bars for historical context. Compare settings on the same symbol, timeframe, session and source before interpreting differences. A lower BandWidth threshold can identify a different set of observations without proving better trade results.

The scripts may use different units. A raw width ratio of 0.08 and a displayed percentage of 8 describe the same bands. Check whether the expression already multiplies by 100 before applying thresholds or comparing outputs. Also match the middle-band average, standard-deviation convention, source and length. A ratio threshold of 0.04 corresponds to a percentage threshold of 4.

BandWidth cannot be strictly greater than a rolling maximum that includes its own current value. It can equal that maximum. To test a new high against earlier observations, compare the current width with the maximum of the previous N bars, excluding the current bar. A new width high describes dispersion and does not by itself establish a long or short entry.

A squeeze identifies relatively narrow bands; it does not guarantee a breakout. The worked example contracts to zero while the close stays at 100. A subsequent rise in width could accompany a move in either direction. Any directional rule, confirmation time, exit, position size and cost model must be defined separately before a trading strategy can be evaluated.

The calculation needs enough source observations for its moving average and standard deviation. This example also waits for complete valid windows before plotting the extrema or historical rank. On uninterrupted valid data with defaults, width first appears on bar 20, the 125-bar extrema on bar 144, and the rank against 125 prior widths on bar 145. Nonpositive middle bands can delay or interrupt these outputs.

Sources and related reading

Official sources reviewed October 17, 2026. The rolling calculation table and rank examples are hypothetical demonstrations created for this page.