Files
wickra/docs/wiki/indicators/volatility-bands/Indicator-BollingerBandwidth.md
T

156 lines
4.8 KiB
Markdown
Raw Normal View History

2026-05-22 18:30:49 +02:00
# BollingerBandwidth
> Bollinger Bandwidth — the width of the Bollinger Bands relative to the
> middle band: a normalised volatility reading.
## Quick reference
| Field | Value |
|-------|-------|
| Family | Volatility & Bands |
2026-05-22 18:30:49 +02:00
| Input type | `f64` (single close) |
| Output type | `f64` |
| Output range | `[0, ∞)` |
| Default parameters | `(period = 20, multiplier = 2.0)` (Python) |
| Warmup period | `period` |
| Interpretation | Band width as a fraction of price; lows flag a "squeeze". |
## Formula
```
Bandwidth = (upper lower) / middle
```
where `upper`, `middle` and `lower` come from
[`BollingerBands`](../volatility-bands/Indicator-BollingerBands.md). Since the bands are
2026-05-22 18:30:49 +02:00
`middle ± multiplier · stddev`, the bandwidth simplifies to
`2 · multiplier · stddev / middle` — volatility normalised by price level.
Its extremes name two classic patterns: the **squeeze** (bandwidth at a
multi-month low — a coiled, quiet market that often precedes a sharp
move) and the **bulge** (bandwidth at an extreme high — an exhausted,
over-extended move).
## Parameters
| Name | Type | Default | Valid range | Description |
|--------------|---------|----------------|-------------|-------------|
| `period` | `usize` | `20` (Python) | `>= 1` | Bollinger Bands period. `0` errors with `Error::PeriodZero`. |
| `multiplier` | `f64` | `2.0` (Python) | `> 0` | Band standard-deviation multiplier. `<= 0` errors with `Error::NonPositiveMultiplier`. |
The Python binding defaults the pair to `(20, 2.0)`.
## Inputs / Outputs
From `crates/wickra-core/src/indicators/bollinger_bandwidth.rs`:
```rust
impl Indicator for BollingerBandwidth {
type Input = f64;
type Output = f64;
// update(&mut self, input: f64) -> Option<f64>
}
```
A single `f64` close in, an `Option<f64>` out. Python maps this to
`float | None` / `numpy.ndarray` (NaN warmup); Node to `number | null` /
`Array<number>` (NaN warmup).
## Warmup
`warmup_period() == period` — identical to the underlying `BollingerBands`.
## Edge cases
- **Constant series.** Flat prices collapse the bands onto the middle, so
the width — and bandwidth — is `0.0` (`constant_series_yields_zero`
pins this).
- **Zero middle band.** Bandwidth is undefined against a `0.0` middle
band; the indicator reports `0.0` for that bar.
- **Non-negative.** Bandwidth is `(upper lower) / middle` with
`upper >= lower` and a positive middle band, so it is never negative
(`output_is_non_negative` pins this).
- **Reset.** `bbw.reset()` clears the underlying bands.
## Examples
### Rust
```rust
use wickra::{BatchExt, Indicator, BollingerBandwidth};
fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut bbw = BollingerBandwidth::new(20, 2.0)?;
// A flat stretch then a volatile stretch: bandwidth rises.
let mut prices: Vec<f64> = vec![100.0; 30];
prices.extend((0..30).map(|i| 100.0 + (f64::from(i)).sin() * 10.0));
let out = bbw.batch(&prices);
println!("flat-window bandwidth: {:?}", out[25]);
Ok(())
}
```
Output:
```
flat-window bandwidth: Some(0.0)
```
While prices are flat the bands sit on top of each other, so bandwidth is
`0`; once volatility arrives it climbs.
### Python
```python
import numpy as np
import wickra as ta
bbw = ta.BollingerBandwidth(20, 2.0)
prices = np.full(40, 100.0) # flat series
print(bbw.batch(prices)[-1]) # 0.0
```
Output:
```
0.0
```
### Node
```javascript
const ta = require('wickra');
const bbw = new ta.BollingerBandwidth(20, 2.0);
const prices = Array.from({ length: 60 }, (_, i) => 100 + Math.sin(i * 0.3) * 6);
console.log('warmupPeriod:', bbw.warmupPeriod());
```
## Interpretation
`BollingerBandwidth` is the standard way to quantify the Bollinger
"squeeze". Volatility is mean-reverting and cyclical: extended periods of
low bandwidth tend to be followed by expansion, and vice versa. Traders
watch for bandwidth dropping to a multi-month low (the squeeze) as a
heads-up that a directional move is loading — then take the direction
from price breaking the band, or from a separate trend indicator.
## Common pitfalls
- **Treating the squeeze as directional.** Low bandwidth says a move is
*coming*, not which way. Confirm direction separately.
- **Comparing raw bandwidth across instruments without context.** It is
normalised by price, which helps, but "low" is relative to each
instrument's own history — compare against its own range.
## References
John Bollinger, *Bollinger on Bollinger Bands* (2001). Bandwidth is one
of Bollinger's two derived indicators (with %b).
## See also
- [Indicator-BollingerBands.md](../volatility-bands/Indicator-BollingerBands.md) — the bands
2026-05-22 18:30:49 +02:00
this measures.
- [Indicator-PercentB.md](../volatility-bands/Indicator-PercentB.md) — the companion derived
2026-05-22 18:30:49 +02:00
indicator: price *position* within the bands.
- [Indicators-Overview.md](../../Indicators-Overview.md) — the full taxonomy.