Library/Technical Indicators/Volatility and Channels

D07-F04-A06 / Complete engineering topic

Bollinger BandWidth

A production-minded guide to Bollinger BandWidth.

D07 · TECHNICAL INDICATORS
D07-F04-A06Canonical / Tested / Open
D07 / D07-F04

How wide are Bollinger Bands relative to their own middle level? That is the practical question behind Bollinger BandWidth. This tutorial builds the answer from finalized data, shows the exact arithmetic, and gives you a laboratory for breaking the indicator safely.

The mental model in one minute

This package reports percent units: 100 × (upper-lower)/middle. It requires a strictly positive middle band for the intended relative-width interpretation.

The output is a measurement. It is not an order, forecast, confidence interval, or promise that a familiar-looking market pattern will repeat.

Contract before chart

  • Variant: The package returns percent units. Some APIs return the raw ratio; divide these values by 100 before comparing.
  • Defaults: period=20, multiplier=2.
  • First publication: index 19 when bands exist and the middle band is nonzero.
  • Data: finalized, causal observations on one price basis.
  • Missing, malformed, or mixed-basis input: reject rather than repair silently.

Formula and symbols

BandWidtht=100UppertLowertMiddletBandWidth_t=100\frac{Upper_t-Lower_t}{Middle_t}

SymbolMeaningUnit
Ut,LtU_t, L_tBollinger upper and lower bandsprice units
MtM_tBollinger middle bandprice units
kkBollinger multiplierdimensionless
BBWtBBW_tnormalized full band widthpercent

Calculate it by hand

Suppose middle is 100, population deviation is 2.5, and k=2.

  1. Upper: 100 + 2 × 2.5 = 105.
  2. Lower: 100 - 2 × 2.5 = 95.
  3. Absolute width: 105 - 95 = 10.
  4. BandWidth: 100 × 10 / 100 = 10%.

Because upper-lower = 2kσ, BandWidth is also 100 × 2kσ/M. With k=2 it equals 400 times the coefficient-of-variation ratio σ/M. Multiplying all prices by ten preserves the result; adding a constant does not.

That calculation is deliberately small enough to audit without code. The 240-row fixtures then show how the same rule behaves through warm-up, regime changes, ties, gaps, shocks, and expiry.

The complete algorithm

  1. Build the selected population-standard-deviation Bollinger Bands.
  2. Withhold BandWidth until the bands exist.
  3. Require the middle band to be strictly positive for relative-width semantics.
  4. Divide full band width by the middle and multiply by 100.
  5. Interpret low or high only relative to the same instrument, timeframe, price basis, and lookback context.
Rendering system map…

The flow exposes the point where a result becomes unavailable, where recursive state begins, or where a rolling owner expires.

See the mechanism

Mechanism map for Bollinger BandWidth

The map connects formula terms to the exact data they consume.

Follow a complete causal trace

Canonical 240-row trace for Bollinger BandWidth

Only rows at or before the active observation may influence the displayed state. Warm-up is shown as unavailable rather than silently converted to zero.

Memory is part of the definition

Finite Bollinger window. A dispersion shock enters and later expires with the window; normalization also changes whenever the rolling middle changes.

BandWidth is invariant to positive multiplicative rescaling but not additive translation. It is directionless and has no universal squeeze threshold.

Memory and family comparison for Bollinger BandWidth

This is why two indicators can react differently to the same shock even when their plotted bands appear similar.

Six ways to try to break it

ScenarioTeaching jobExpected lesson
quote-scale-referenceQuote-scale referenceA reference path establishes the unscaled percentage.
scale-invarianceQuote-scale invarianceMultiplying every close by ten preserves BandWidth.
squeeze-expansionSqueeze then expansionThe percentage contracts and later expands.
additive-shiftAdditive-shift contrastAdding a constant changes the denominator and therefore the percentage.
zero-middleZero-middle unavailable stateA zero basis with zero width remains unavailable, not zero.
multiplier-identityMultiplier identityHalving the multiplier halves BandWidth for the same mean and dispersion.

Boundary atlas for Bollinger BandWidth

Predict the active component before opening the lab. Then jump to the relevant checkpoint and inspect the formula trace rather than guessing from line shape.

Interactive laboratory

Open the Bollinger BandWidth guided lab. It contains six 240-row scenarios. Change the period or multiplier where the formula exposes one; the lab recomputes immediately, stops playback, resets to an informative state, and preserves the same calculation path used by Step. Use the checkpoint selector to compare first publication, mechanism, boundary, memory, platform reconciliation, and mature state.

Production implementation

The Python and TypeScript references are topic-scoped and intentionally readable. They validate before calculating, return aligned arrays, and use None/null for unavailable states. Shared fixtures establish parity; independent family checks establish properties without trusting either implementation as the oracle.

When production output disagrees with a chart, log:

  1. symbol and source ownership;
  2. timeframe, session, timestamp, and bar finality;
  3. adjustment basis;
  4. parameter values and first-ready index;
  5. the earliest divergent component;
  6. window inclusion, seed, denominator, multiplier, equality, and null policy;
  7. the earliest revised observation.

Compare, do not conflate

Nearby topicWhat changes
Bollinger Bandssupply the three levels from which BandWidth is derived.
ATRis a raw price-unit range scale and therefore not quote-scale invariant.
Donchian widthis an unnormalized distance between extrema.

Misuse boundary

  • Do not: Comparing a raw ratio from one API with percent units from another.
  • Do not: Using one fixed squeeze threshold across instruments and timeframes.
  • Do not: Inferring breakout direction from a low BandWidth value.

The synthetic examples establish implementation behavior only. No historical association, transaction cost, out-of-sample result, or investment suitability claim is made.

Historical example decision

No named historical episode is used. The mechanism is learned more cleanly from controlled synthetic paths, and a named case would require point-in-time, licensed, adjustment-consistent OHLC evidence before publication.

Summary

You can now state the precise question Bollinger BandWidth answers, calculate it, explain its memory, diagnose a platform mismatch, and separate a measurement from a trading claim. Use the family comparison rather than chart resemblance to choose the next concept.

Primary evidence

See the topic reference ledger for source roles, dates, and limitations.

Bollinger BandWidth calculation flow

Purpose: show the exact selected state, readiness branch, and output.

Rendering system map…

Takeaway: the formula, memory, and unavailable state are part of the contract, not chart formatting.

ReferencesPrimary sources and evidence notes

Expand the source trail, evidence role, and limitations behind the engineering choices.

Bollinger Bands Rules

  • Organization or authors: John Bollinger
  • Source type: Creator-maintained guidance
  • Publication, version, or access date: site current at access 2026-07-26
  • URL or identifier: Bollinger Bands Rules
  • Accessed: 2026-07-26
  • Jurisdiction: not jurisdiction-specific
  • Evidence role: sourced definition, maintained implementation, or bounded historical context
  • Supports: Supports default-versus-universal distinctions, band-tag warnings, traditional SMA consistency, non-normality warning, %b, and BandWidth relationships.
  • Limitations: Interpretive guidance is not evidence of prediction or profitability.

Bollinger BandWidth (BBW)

  • Organization or authors: TradingView
  • Source type: Maintained platform documentation
  • Publication, version, or access date: accessed 2026-07-26
  • URL or identifier: Bollinger BandWidth (BBW)
  • Accessed: 2026-07-26
  • Jurisdiction: not jurisdiction-specific
  • Evidence role: sourced definition, maintained implementation, or bounded historical context
  • Supports: Documents percent-unit BandWidth and the need for instrument/timeframe context.
  • Limitations: No universal squeeze threshold or directional forecast is adopted.

Bollinger Bands (BB)

  • Organization or authors: TradingView
  • Source type: Maintained platform documentation
  • Publication, version, or access date: accessed 2026-07-26
  • URL or identifier: Bollinger Bands (BB)
  • Accessed: 2026-07-26
  • Jurisdiction: not jurisdiction-specific
  • Evidence role: sourced definition, maintained implementation, or bounded historical context
  • Supports: Documents the common 20-period SMA and two-deviation presentation and configurable inputs.
  • Limitations: Platform behavior is not a universal mathematical standard.

BBANDS — Bollinger Bands

  • Organization or authors: TA-Lib
  • Source type: Maintained official documentation
  • Publication, version, or access date: maintained; accessed 2026-07-26
  • URL or identifier: BBANDS — Bollinger Bands
  • Accessed: 2026-07-26
  • Jurisdiction: not jurisdiction-specific
  • Evidence role: sourced definition, maintained implementation, or bounded historical context
  • Supports: Supports the moving-average and standard-deviation band structure.
  • Limitations: TA-Lib supports middle-band variants beyond this package’s SMA.

e-Handbook: Measures of Scale

  • Organization or authors: NIST/SEMATECH
  • Source type: Government statistical reference
  • Publication, version, or access date: accessed 2026-07-26
  • URL or identifier: e-Handbook: Measures of Scale
  • Accessed: 2026-07-26
  • Jurisdiction: not jurisdiction-specific
  • Evidence role: sourced definition, maintained implementation, or bounded historical context
  • Supports: Distinguishes standard deviation as a scale measure and supplies statistical context.
  • Limitations: It does not define a financial indicator or validate trading interpretations.

Public evidence boundary

The fixture is author-generated synthetic teaching material. Every displayed number is an author-derived calculation from those inputs. No provider observation, historical return, causal claim, forecast, or profitability result is published. Platform documentation supports only the named platform convention; local seeds, nulls, equality, and scope remain implementation choices.

volatility_channels.ts
function finite(v:number[],n:string){if(!Array.isArray(v)||!v.length||v.some(x=>!Number.isFinite(x)))throw new Error(`${n} must contain finite numbers`)}
function hlc(h:number[],l:number[],c:number[]){finite(h,"high");finite(l,"low");finite(c,"close");if(h.length!==l.length||h.length!==c.length)throw new Error("high, low, and close lengths must match");if(h.some((x,i)=>x<l[i]||c[i]<l[i]||c[i]>x))throw new Error("each bar requires low <= close <= high")}


function period(v:number,n="period"){if(!Number.isInteger(v)||v<1)throw new Error(`${n} must be a positive integer`)}

function rolling(close:number[],p:number){period(p);finite(close,"close");const middle:(number|null)[]=Array(close.length).fill(null),stddev:(number|null)[]=Array(close.length).fill(null);for(let i=p-1;i<close.length;i++){const w=close.slice(i-p+1,i+1),m=w.reduce((a,b)=>a+b,0)/p;middle[i]=m;stddev[i]=Math.sqrt(w.reduce((a,b)=>a+(b-m)**2,0)/p)}return{middle,stddev}}
export function bollinger_bands(close:number[],p=20,multiplier=2){if(!Number.isFinite(multiplier)||multiplier<=0)throw new Error("multiplier must be finite and positive");const r=rolling(close,p),upper:(number|null)[]=Array(close.length).fill(null),lower:(number|null)[]=Array(close.length).fill(null),percent_b:(number|null)[]=Array(close.length).fill(null);for(let i=0;i<close.length;i++){if(r.middle[i]===null)continue;upper[i]=(r.middle[i] as number)+multiplier*(r.stddev[i] as number);lower[i]=(r.middle[i] as number)-multiplier*(r.stddev[i] as number);const width=(upper[i] as number)-(lower[i] as number);percent_b[i]=width===0?null:(close[i]-(lower[i] as number))/width}return{middle:r.middle,stddev:r.stddev,upper,lower,percent_b}}

export function bollinger_bandwidth(close:number[],p=20,multiplier=2){const b=bollinger_bands(close,p,multiplier),bandwidth:(number|null)[]=Array(close.length).fill(null);for(let i=0;i<close.length;i++)if(b.middle[i]!==null&&(b.middle[i] as number)>0)bandwidth[i]=100*((b.upper[i] as number)-(b.lower[i] as number))/(b.middle[i] as number);return{middle:b.middle,stddev:b.stddev,upper:b.upper,lower:b.lower,bandwidth}}
Full-height labbollinger bandwidth labOpen full screen