The Bollinger Band Squeeze is a volatility-based framework that looks for periods when price action is unusually quiet — Bollinger Bands narrow tightly, often contracting inside the Keltner Channels — and then watches for the directional move that can follow once volatility expands again. Traders use it to flag potential breakouts; it is not a signal that any trade will be profitable. This page explains how the setup is built and interpreted. Nothing here is predictive, and trading carries the risk of loss.
Bollinger Bands plot a moving average with an upper and lower band set a number of standard deviations away, so the band width expands and contracts with volatility. When a market consolidates, the standard deviation shrinks and the bands pull in tight — this narrowing is the "squeeze." A common, more formal definition (the TTM-style squeeze) is when the Bollinger Bands move entirely inside the Keltner Channels, which are built from Average True Range rather than standard deviation. While that condition holds, the market is described as being in a low-volatility, coiled state. The idea traders work with is that low-volatility phases are often followed by higher-volatility phases — but the squeeze itself says nothing about direction, and the expansion is not guaranteed to happen on any particular timeframe. So the squeeze is treated as a "get ready" condition, and a separate trigger (a band breakout, a close beyond a range, or a momentum reading) is used to define if and when a trader acts. The squeeze "firing" simply means the bands have widened back out past the Keltner Channels; the breakout that accompanies it can go either way, which is why direction must come from price or momentum, never from the squeeze alone.
//@version=6
strategy("Bollinger Band Squeeze (Illustrative)", overlay=true, margin_long=100, margin_short=100)
// --- Inputs ---
length = input.int(20, "Length")
bbMult = input.float(2.0, "Bollinger StdDev Mult", step=0.1)
kcMult = input.float(1.5, "Keltner ATR Mult", step=0.1)
// --- Shared basis (TTM-style: same SMA basis for BB and KC) ---
basis = ta.sma(close, length)
// --- Bollinger Bands (standard deviation based) ---
dev = bbMult * ta.stdev(close, length)
bbUpper = basis + dev
bbLower = basis - dev
// --- Keltner Channels (ATR based) ---
rangeMa = ta.atr(length)
kcUpper = basis + kcMult * rangeMa
kcLower = basis - kcMult * rangeMa
// --- Squeeze state: BBands fully inside Keltner Channels ---
squeezeOn = bbLower > kcLower and bbUpper < kcUpper
squeezeOff = bbLower < kcLower and bbUpper > kcUpper
// Squeeze "fires" when it was on last bar and is now off
fired = squeezeOff and squeezeOn[1]
// --- Directional trigger from price (not from the squeeze) ---
longTrigger = fired and close > bbUpper
shortTrigger = fired and close < bbLower
// --- Orders (illustrative only; past performance does not predict future results) ---
if longTrigger
strategy.entry("Long", strategy.long)
if shortTrigger
strategy.entry("Short", strategy.short)
// Volatility-based protective stop using ATR
atrStop = 2.0 * ta.atr(length)
strategy.exit("L-exit", from_entry="Long", stop=strategy.position_avg_price - atrStop)
strategy.exit("S-exit", from_entry="Short", stop=strategy.position_avg_price + atrStop)
// --- Plots ---
plot(bbUpper, "BB Upper", color.new(color.blue, 0))
plot(bbLower, "BB Lower", color.new(color.blue, 0))
plot(kcUpper, "KC Upper", color.new(color.orange, 50))
plot(kcLower, "KC Lower", color.new(color.orange, 50))
bgcolor(squeezeOn ? color.new(color.gray, 85) : na, title="Squeeze On")It is a period of unusually low volatility, seen when the Bollinger Bands narrow tightly. In the stricter TTM-style definition, the squeeze is "on" when the Bollinger Bands sit entirely inside the Keltner Channels. It describes current market conditions; it is not a buy or sell signal by itself.
No. The squeeze only indicates that volatility is compressed. The subsequent expansion can break either up or down, which is why traders pair it with a separate directional trigger such as a band breakout or a momentum filter — and why no setup can guarantee an outcome.
A common starting point is a 20-period Bollinger Band with a 2.0 standard-deviation multiplier and a Keltner Channel using a similar length with roughly a 1.5 ATR multiplier. There is no universally correct setting; changing the values changes how often a squeeze appears, so test changes carefully and avoid tuning purely to make a backtest look good.
Make sure signals are evaluated on confirmed (closed) bars and that you are not referencing future or not-yet-finished higher-timeframe data through request.security. ForexCodes' Strategy Validator is built to catch exactly these issues — look-ahead bias, repainting, and intent mismatches — and return validated Pine Script v6. You can try it free to validate your squeeze logic before you take it live.
Educational & software only — not financial advice, not a recommendation to trade. Backtests are illustrative; past performance does not predict future results. Trading involves substantial risk of loss.