Skip to content
Open RaamTrade

BollingerPercentB — Bollinger %B

Where the close sits inside the Bollinger bands: 0 at the lower band, 1 at the upper, 0.5 at the mean, outside [0, 1] beyond the bands. The band position as a portable number — comparable across instruments in a way raw band distance is not.

Signature

BollingerPercentB(period, multiplier, on=<source>)
Argument Type Required Notes
period int Param or literal Yes Bollinger window. Default 20, bounds 2–400.
multiplier float Param or literal Yes Band width in standard deviations. Default 2.0, bounds 0.1–10.0.
on= symbol, OHLCV field, or indicator No Source. Defaults to the trade symbol’s close.

Formula

$$ %B = \frac{C - \text{lower}}{\text{upper} - \text{lower}} $$

Warmup

period bars; 0.5 (the mean) until then, and 0.5 when the bands collapse on a flat window.

Reading the value

pb.value
pb < 0
pb.crossed_above(0.5)

Example

class PercentBReversion(Strategy):
"""Buy a close below the lower band, exit at the mean."""
trade = Symbol()
sizing = FixedCapital()
def execute(self):
pb = BollingerPercentB(20, 2.0, on=self.trade)
if pb.value < 0 and self.trade.is_flat:
self.buy(self.trade, reason=f"%B {pb.value:.2f}")
if pb.value > 0.5 and self.trade.is_long:
self.sell(self.trade, self.trade.position, reason="At the mean")

Notes

  • John Bollinger’s %B. Equivalent to a rescaled ZScore: %B = z/(2m) + 0.5.
  • Proven by an assert-via-trade run on SPY daily (matched a strategy-side reference to 1e-3 on every bar; zero alarm trades).
  • Flat-window sentinel is 0.5 — the neutral middle, not a band touch.