◆ New — Strategy Validator, Code Fixer & Prop Compliance Checker are live. Try one free →
Home / Indicators / TTM Squeeze (Squeeze Momentum)
Volatility indicator

TTM Squeeze (Squeeze Momentum)

A volatility-compression detector — Bollinger Bands inside Keltner Channels — paired with a linear-regression momentum histogram; it flags coiling, not direction.

Illustrative diagram — not live market data.

What it is

The TTM Squeeze, developed by John Carter (and widely known on TradingView through LazyBear's 'Squeeze Momentum' adaptation), is often treated as a black box of red and green dots. It is actually two ordinary, well-documented components bolted together. The first is a volatility-compression test: it checks whether the Bollinger Bands (a standard-deviation envelope) have contracted to fit entirely inside the Keltner Channels (an ATR envelope) around the same moving average. When they have, volatility is unusually low relative to its ATR baseline — the 'squeeze is on', shown as dots. The second component is a momentum histogram built from a linear regression of price's distance from a reference midline, which describes which way price has been leaning while volatility compresses and after it releases. The honest framing matters: periods of low volatility have historically tended to be followed by periods of higher volatility, so a squeeze describes conditions for a possible expansion — it says nothing about direction, and 'possible' is not a schedule. The indicator is descriptive, not predictive; this is educational material only, not financial advice, and trading involves risk of loss.

How it works

Both envelopes are centered on the same basis, typically a 20-period SMA of the close. The Bollinger Bands sit at basis ± 2.0 standard deviations of close over 20 bars; the Keltner Channels sit at basis ± 1.5 × ATR(20) (Carter's defaults — LazyBear's version exposes both multipliers). The squeeze condition is a direct comparison: squeeze on when the upper Bollinger Band is below the upper Keltner Channel and the lower Bollinger Band is above the lower Keltner Channel — i.e., the standard-deviation envelope fits inside the ATR envelope, meaning close-to-close dispersion is small relative to average true range. The squeeze 'fires' on the first bar where that stops being true. The momentum histogram is separate mathematics: take the midpoint of the highest high and lowest low over the length, average it with the SMA of close, subtract that reference from close, and run a linear regression (ta.linreg) over the same length on the result. The histogram's sign shows which side of the reference price has been on; growing bars describe strengthening displacement, shrinking bars describe fading displacement. Nothing in either component looks forward — both are computed entirely from past bars.

How traders read it

Common settings

Carter's defaults: length 20 for everything, Bollinger multiplier 2.0, Keltner multiplier 1.5, close as source. The Keltner multiplier sets the strictness of the squeeze test — 1.0 flags only extreme compression, 2.0 flags it frequently; some versions plot all three thresholds at once. Note that implementations differ: LazyBear's script offers True Range versus high-low range for the Keltner calculation, and different multiplier conventions across platforms mean 'the squeeze' can be on in one implementation and off in another on the same bar — worth checking before comparing results.

Strengths

Pitfalls to watch

Pine v6 example

//@version=6
indicator("TTM Squeeze Example", overlay = false)

length = input.int(20, "Length", minval = 1)
bbMult = input.float(2.0, "Bollinger Multiplier", step = 0.1)
kcMult = input.float(1.5, "Keltner Multiplier", step = 0.1)

basis   = ta.sma(close, length)
dev     = bbMult * ta.stdev(close, length)
kcRange = kcMult * ta.atr(length)

bbUpper = basis + dev
bbLower = basis - dev
kcUpper = basis + kcRange
kcLower = basis - kcRange

// Squeeze on: Bollinger Bands fit inside Keltner Channels
squeezeOn = bbUpper < kcUpper and bbLower > kcLower

// Momentum: linear regression of close minus a midline reference
mid = math.avg(math.avg(ta.highest(high, length), ta.lowest(low, length)), ta.sma(close, length))
mom = ta.linreg(close - mid, length, 0)

plot(mom, "Momentum", style = plot.style_histogram, color = mom >= 0 ? color.teal : color.red)
plotshape(squeezeOn and barstate.isconfirmed, "Squeeze On", style = shape.circle, location = location.bottom, color = color.orange, size = size.tiny)
hline(0, "Zero", color = color.gray)

Pro tip: De-mystify the tool by plotting its parts: put Bollinger Bands and Keltner Channels directly on your price chart with the squeeze's settings and watch the moments the bands slip inside the channels — that is the entire 'squeeze', nothing more. Doing this once makes the two most common misreadings obvious: the dots carry no directional information, and the histogram at the moment of firing is a regression over the previous 20 bars, not a forecast. Use the squeeze as a description of volatility state, decide direction and risk from price itself, and expect a share of squeezes to fire into nothing. Educational only — no indicator predicts price, and trading involves risk of loss.

Built an indicator from this? Run it through the Validator to catch look-ahead bias and repainting, or convert a strategy to Pine Script.

Educational only — not financial advice, not a recommendation to trade. No indicator is predictive; trading involves substantial risk of loss.

Catch the bug that compiles.Run auditGet Pro