A volatility reading in percent of price, and the quantity Bollinger's
"squeeze" is defined on: a bbWidth at a multi-month low means the bands
have contracted, which is the setup the pattern names. Appends one column,
default 'bbWidth'.
×100, and why
John Bollinger's own statement of BandWidth is the bare ratio
(upper − lower)/middle; StockCharts, ChartIQ and TradingView all draw it
×100 so it reads as a percentage. The ×100 form ships, because it
is the one a caller comparing against a chart will see, and dividing by
100 to recover the ratio is a great deal more discoverable than
multiplying by it after wondering why the numbers are a hundredth of the
chart's. Stated here rather than left to be found.
It is bollinger's σ, not a second one — with one deliberate delta
The rolling pass is the samerollingColumns call bollinger
makes (avg + stdev, population ddof=0, one window scan), so on every
bar where bollinger emits bands, bbWidth is exactly
100·(bbUpper − bbLower)/bbMiddle — pinned by a test against the shipped
study rather than asserted here.
A flat window is worth reading. bollinger collapses its bands onto
the middle when σ = 0 (upper = lower = middle, [PND-BBFLAT]), and
BandWidth answers 0 there by the same arithmetic: the numerator is
2·stdDev·σ, which is forced to zero, and the denominator is the
flat window's own price level, which is not zero — so the value is 0, a
real reading ("the bands have no width", which is what a squeeze is). That
is the #699 rule applied rather than copied, and it means bbWidth is
recoverable from the bollinger columns on every bar the bands are
set, the flat stretch included.
A zero centre reads undefined, and the guard is at the output and
therefore live. Two windows get there: one flat at zero (every value
exactly 0, a genuine 0/0), and one zero-mean but not flat (values
summing to zero with a positive σ — an oscillator column crossing its
axis), where the ratio is ±∞ and has no finite reading either. Both are
pinned by tests (Layer-2 review of #711 asked for the second to be named).
Edges
Warm-up is period − 1 rows, the rolling window's own, and it does
not compose with the source's. Over another study's output the first
value still lands at bar period − 1, computed from however many
contributors that window holds — core's count-window counts rows for
minSamples and its reducers skip a missing cell. That is inherited
from bollinger, which does the same, and matching it is what
keeps this study arithmetic on that one's columns. Length-preserving.
Scale-INVARIANT and NOT shift-invariant. Scaling every price scales
the numerator and the denominator together, so the reading does not
move; adding a constant moves the denominator only, so it does. Both
pinned by property tests — this is the rsi side of the scale
pair, and the second half is the one that would be missed.
A negative centre flips the sign. Reachable only over a column that
can go negative (another study's output). Nothing takes an absolute
value; the sign is the centre's, honestly.
A gap costs it nothing at all. BandWidth reads only the window's
avg and stdev, and core's count-window reducers compute those over
the contributors that are present — minSamples counts rows, a missing
cell is skipped — so the line is drawn straight through a hole, over one
fewer sample on the windows containing it. That is the opposite of
bollingerPercentB, which additionally reads the bar's own price
and therefore loses exactly that bar. Measured and pinned in
study-missing-cells.test.ts; a caller who wants a gap to blank the
reading has to fill or drop the row.
Bollinger BandWidth — how wide the bollinger channel is, relative to its own centre:
A volatility reading in percent of price, and the quantity Bollinger's "squeeze" is defined on: a bbWidth at a multi-month low means the bands have contracted, which is the setup the pattern names. Appends one column, default
'bbWidth'.×100, and why
John Bollinger's own statement of BandWidth is the bare ratio
(upper − lower)/middle; StockCharts, ChartIQ and TradingView all draw it ×100 so it reads as a percentage. The ×100 form ships, because it is the one a caller comparing against a chart will see, and dividing by 100 to recover the ratio is a great deal more discoverable than multiplying by it after wondering why the numbers are a hundredth of the chart's. Stated here rather than left to be found.It is
bollinger's σ, not a second one — with one deliberate deltaThe rolling pass is the same
rollingColumnscall bollinger makes (avg+stdev, populationddof=0, one window scan), so on every bar wherebollingeremits bands,bbWidthis exactly100·(bbUpper − bbLower)/bbMiddle— pinned by a test against the shipped study rather than asserted here.A flat window is worth reading.
bollingercollapses its bands onto the middle whenσ = 0(upper = lower = middle, [PND-BBFLAT]), and BandWidth answers0there by the same arithmetic: the numerator is2·stdDev·σ, which is forced to zero, and the denominator is the flat window's own price level, which is not zero — so the value is0, a real reading ("the bands have no width", which is what a squeeze is). That is the #699 rule applied rather than copied, and it meansbbWidthis recoverable from thebollingercolumns on every bar the bands are set, the flat stretch included.A zero centre reads
undefined, and the guard is at the output and therefore live. Two windows get there: one flat at zero (every value exactly0, a genuine0/0), and one zero-mean but not flat (values summing to zero with a positive σ — an oscillator column crossing its axis), where the ratio is±∞and has no finite reading either. Both are pinned by tests (Layer-2 review of #711 asked for the second to be named).Edges
period − 1rows, the rolling window's own, and it does not compose with the source's. Over another study's output the first value still lands at barperiod − 1, computed from however many contributors that window holds — core's count-window counts rows forminSamplesand its reducers skip a missing cell. That is inherited from bollinger, which does the same, and matching it is what keeps this study arithmetic on that one's columns. Length-preserving.avgandstdev, and core's count-window reducers compute those over the contributors that are present —minSamplescounts rows, a missing cell is skipped — so the line is drawn straight through a hole, over one fewer sample on the windows containing it. That is the opposite of bollingerPercentB, which additionally reads the bar's own price and therefore loses exactly that bar. Measured and pinned instudy-missing-cells.test.ts; a caller who wants a gap to blank the reading has to fill or drop the row.