Indicator · Pine Script v6 · Own pane

TTM Squeeze Pro

by TamTH-Dev· code credited to tamth_

This indicator identifies volatility compression and momentum direction in a separate pane.

View on GitHub

GitHub stars2on the repository
Pine versionv6current
Lines of code329
Settings12inputs
LicenceNone statedfile: MPL-2.0
Last update6 weeks ago18 Sep 2026

Add It to Your TradingView Chart

  1. 1Copy the scriptPress Copy script above, or the copy button on the code below.
  2. 2Open the Pine EditorOpen a TradingView chart and choose Pine Editor at the bottom of the screen.
  3. 3Paste over the templateCreate a new indicator, select all of the template text and paste. Press Save and give it a name.
  4. 4Add it to the chartPress Add to chart, then adjust the settings with the gear icon next to its name.

Source Code

329 lines of Pine Script v6 from TTM Squeeze Pro.pine, published under MPL-2.0 (file header). Keep the author's credit and licence lines when you reuse it.

TTM Squeeze Pro.pine
// This Pine Script® code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © tamth_

//@version=6
indicator('TTM Squeeze Pro', overlay = false, precision = 2)

//-----------------------------------------------------------------------------
// Constants
//-----------------------------------------------------------------------------
// Colors
AQUA_COLOR = color.aqua
BLUE_COLOR = #2962ff
RED_COLOR = color.red
YELLOW_COLOR = color.yellow
ORANGE_COLOR = color.orange
GREEN_COLOR = color.green
BLACK_COLOR = color.black

//-----------------------------------------------------------------------------


//-----------------------------------------------------------------------------
// Settings
//-----------------------------------------------------------------------------
sqzGroup        = "Squeeze"
length          = input.int(20, "TTM Squeeze Length", group = sqzGroup)

// Bollinger Bands
BB_mult         = input.float(2.0, "Bollinger Band STD Multiplier", group = sqzGroup)


// Keltner Channels
KC_mult_high    = input.float(1.0, "Keltner Channel #1", group = sqzGroup)
KC_mult_mid     = input.float(1.5, "Keltner Channel #2", group = sqzGroup)
KC_mult_low     = input.float(2.0, "Keltner Channel #3", group = sqzGroup)

//-----------------------------------------------------------------------------


//-----------------------------------------------------------------------------
// Calculations
//-----------------------------------------------------------------------------
BB_basis = ta.sma(close, length)
dev = BB_mult * ta.stdev(close, length)
BB_upper = BB_basis + dev
BB_lower = BB_basis - dev

KC_basis = ta.sma(close, length)
devKC = ta.sma(ta.tr, length)
KC_upper_high = KC_basis + devKC * KC_mult_high
KC_lower_high = KC_basis - devKC * KC_mult_high
KC_upper_mid = KC_basis + devKC * KC_mult_mid
KC_lower_mid = KC_basis - devKC * KC_mult_mid
KC_upper_low = KC_basis + devKC * KC_mult_low
KC_lower_low = KC_basis - devKC * KC_mult_low

// Squeeze Conditions
NoSqz = BB_lower < KC_lower_low or BB_upper > KC_upper_low //NO SQUEEZE: GREEN
LowSqz = BB_lower >= KC_lower_low or BB_upper <= KC_upper_low //LOW COMPRESSION: BLACK
MidSqz = BB_lower >= KC_lower_mid or BB_upper <= KC_upper_mid //MID COMPRESSION: RED
HighSqz = BB_lower >= KC_lower_high or BB_upper <= KC_upper_high //HIGH COMPRESSION: ORANGE

// Momentum Oscillator
mom = ta.linreg(close - math.avg(math.avg(ta.highest(high, length), ta.lowest(low, length)), ta.sma(close, length)), length, 0)

// Momentum Histogram Colors
iff_1 = mom > nz(mom[1]) ? AQUA_COLOR : BLUE_COLOR
iff_2 = mom < nz(mom[1]) ? RED_COLOR : YELLOW_COLOR
mom_color = mom > 0 ? iff_1 : iff_2

// Squeeze Dots Colors
sq_color = HighSqz ? ORANGE_COLOR : MidSqz ? RED_COLOR : LowSqz ? BLACK_COLOR : GREEN_COLOR

//-----------------------------------------------------------------------------


//-----------------------------------------------------------------------------
// Render
//-----------------------------------------------------------------------------
plot(mom, title = 'Momentum', color = mom_color, style = plot.style_columns, linewidth = 2)
plot(0, title = 'Squeeze', color = sq_color, style = plot.style_circles, linewidth = 3)

//-----------------------------------------------------------------------------





//-----------------------------------------------------------------------------
// Signals
//-----------------------------------------------------------------------------
// Settings
//-----------------------------------------------------------------------------
string  sigGroup    = "Signals"
bool    sigarrows   = input.bool(true, title = "Show", group = sigGroup)
string  sigt        = input.string("+/-", title = "Signal Type", options = ["Current Momentum", "Sum of Change", "+/-", "Rising/Falling", "Crossed Zero", "Basis Line Momentum", "Divergence", "Combo"], group = sigGroup)
string  custsqz     = input.string("Default", title = "Squeeze Signal Length", options = ["Default", "End of Early Signal", "End of Squeeze", "Custom"], group = sigGroup)
int     sqzsig      = input.int(8, title = "Custom Squeeze Signal Duration", group = sigGroup)
int     sumofc      = input.int(20, title = "Sum of Change Length", group = sigGroup)
int     entrysmooth = input.int(7, title = "Early Entry Smoothing Period", group = sigGroup)
int     exitsmooth  = input.int(9, title = "Early Exit Smoothing Period", group = sigGroup)

//-----------------------------------------------------------------------------
// Values
//-----------------------------------------------------------------------------
// Squeeze Variables
float   sqz         = ta.linreg(close - math.avg(math.avg(ta.highest(high, 20), ta.lowest(low, 20)), ta.ema(close, 20)), 20, 0)
float   momo        = ta.linreg((sqz - sqz[1]), exitsmooth, 0)
// Basis Line
float   basis       = ta.sma(close,20)
// Bollinger Bands
float   upperbb     = basis + dev
float   lowerbb     = basis - dev
// Keltner Channels Range
float   kcrange     = ta.sma(ta.tr, 20)
// Keltner Channels High
float   kcuph       = basis + kcrange * KC_mult_high
float   kcdnh       = basis - kcrange * KC_mult_high
// Keltner Channels Mid
float   kcupm       = basis + kcrange * KC_mult_mid
float   kcdnm       = basis - kcrange * KC_mult_mid
// Keltner Channels Low
float   kcupl       = basis + kcrange * KC_mult_low
float   kcdnl       = basis - kcrange * KC_mult_low
// Early Signal Variables
float   bkhigh      = upperbb - kcuph
float   bkmid       = upperbb - kcupm
float   bklow       = upperbb - kcupl
float   bkhema      = ta.ema(bkhigh,entrysmooth)
float   bkmema      = ta.ema(bkmid,entrysmooth)
float   bklema      = ta.ema(bklow,entrysmooth)
// Each Squeeze Type
bool    lowsqz      = upperbb < kcupl and lowerbb > kcdnl
bool    midsqz      = upperbb < kcupm and lowerbb > kcdnm
bool    highsqz     = upperbb < kcuph and lowerbb > kcdnh
// BB and KC Signal Formulas
bool    ksm         = close < kcdnm or close > kcupm
bool    ksh         = close < kcdnh or close > kcuph
bool    ksl         = close < kcdnl or close > kcupl
bool    bbsmh       = close < lowerbb or close > upperbb
// Early Entry Candle Conditions
bool    earlyentrymid   = bkmid > bkmema and bkmid <=0
bool    earlyentryhigh  = bkhigh > bkhema and bkhigh <=0
bool    earlyentrylow   = bklow > bklema and bklow <=0
bool    endofmid        = ta.barssince(earlyentrymid) == 1
bool    endofhigh       = ta.barssince(earlyentryhigh) == 1
bool    endoflow        = ta.barssince(earlyentrylow) == 1
// Individual KC Formulas
barssinceKsl = ta.barssince(ksl)
barssinceKsm = ta.barssince(ksm)
barssinceKsh = ta.barssince(ksh)
bool    kcllong     = ksl and lowsqz[1] and close > basis and (barssinceKsl[1] > 20)
bool    kclshort    = ksl and lowsqz[1] and close < basis and (barssinceKsl[1] > 20)
bool    kcmlong     = ksm and midsqz[1] and close > basis and (barssinceKsm[1] > 20)
bool    kcmshort    = ksm and midsqz[1] and close < basis and (barssinceKsm[1] > 20)
bool    kchlong     = ksh and highsqz[1] and close > basis and (barssinceKsh[1] > 20)
bool    kchshort    = ksh and highsqz[1] and close < basis and (barssinceKsh[1] > 20)
// Individual BB Formulas
barssinceBbSmh = ta.barssince(bbsmh)
bool    bbllong     = bbsmh and lowsqz[1] and close > basis and (barssinceBbSmh[1] > 20)
bool    bblshort    = bbsmh and lowsqz[1] and close < basis and (barssinceBbSmh[1] > 20)
bool    bbmlong     = bbsmh and midsqz[1] and close > basis and (barssinceBbSmh[1] > 20)
bool    bbmshort    = bbsmh and midsqz[1] and close < basis and (barssinceBbSmh[1] > 20)
bool    bbhlong     = bbsmh and highsqz[1] and close > basis and (barssinceBbSmh[1] > 20)
bool    bbhshort    = bbsmh and highsqz[1] and close < basis and (barssinceBbSmh[1] > 20)
// Signal Types
bool  cmom          = sigt == "Current Momentum"
bool  soc           = sigt == "Sum of Change"
bool  momom         = sigt == "+/-"
bool  rf            = sigt == "Rising/Falling"
bool  czero         = sigt == "Crossed Zero"
bool  blma          = sigt == "Basis Line Momentum"
bool  diverg        = sigt == "Divergence"
bool  combo         = sigt == "Combo"
// Signal Durations
bool  sigreg        = custsqz == "Default"
bool  sigeoe        = custsqz == "End of Early Signal"
bool  sigeos        = custsqz == "End of Squeeze"
bool  sigcus        = custsqz == "Custom"
// Sum of Change
float   change     = math.sum((sqz-sqz[1]),sumofc)
bool    changel    = change > 0
bool    changes    = change < 0
// Basis Line Filter
bool    bbmal       = close >= basis
bool    bbmas       = close < basis
// Basic Signal Conditions
bool    sc1         = sqz > 0
bool    sc2         = sqz < 0
// Rising/Falling Conditions
bool    sqzlongreg  = sqz > sqz[1] and sqz[1] > sqz[2] and sqz[2] > sqz[3] and sqz[3] > sqz[4] and sqz[4] > sqz[5] and sqz[5] > sqz[6]
bool    sqzshortreg = sqz < sqz[1] and sqz[1] < sqz[2] and sqz[2] < sqz[3] and sqz[3] < sqz[4] and sqz[4] < sqz[5] and sqz[5] < sqz[6]
// Zero Line Conditions
bool    sqzzerolong = sqz > 0 and sqz[6] < 0
bool    sqzzeroshort= sqz < 0 and sqz[6] > 0
// Divergence Formula
ftf(_src) => _src[4] < _src[2] and _src[3] < _src[2] and _src[2] > _src[1] and _src[2] > _src[0]
fbf(_src) => _src[4] > _src[2] and _src[3] > _src[2] and _src[2] < _src[1] and _src[2] < _src[0]
ffract(_src) => ftf(_src) ? 1 : fbf(_src) ? -1 : 0
// Divergence Variables
float   fractaltop = ffract(sqz) > 0 ? sqz[2] : na
float   fractalbot = ffract(sqz) < 0 ? sqz[2] : na
float   high_prev  = ta.valuewhen(not na(fractaltop), sqz[2], 1) 
float   high_price = ta.valuewhen(not na(fractaltop), high[2], 1)
float   low_prev   = ta.valuewhen(not na(fractalbot), sqz[2], 1) 
float   low_price  = ta.valuewhen(not na(fractalbot), low[2], 1)
bool    regbeardiv = not na(fractaltop) and high[2] > high_price and sqz[2] < high_prev
bool    regbulldiv = not na(fractalbot) and low[2] < low_price and sqz[2] > low_prev
// Current Momentum
bool    cmolong         = sqz > sqz[1]
bool    cmoshort        = sqz <= sqz[1]
// False Signals
bool    lsf             = lowsqz == false
bool    msf             = midsqz == false
bool    hsf             = highsqz == false
// End of Early Signal
bool    eoel            = sigeoe ? endoflow : false
bool    eoem            = sigeoe ? endofmid : false
bool    eoeh            = sigeoe ? endofhigh : false

barssinceLsf = ta.barssince(lsf)
barssinceMsf = ta.barssince(msf)
barssinceHsf = ta.barssince(hsf)
barssinceLowSqz = ta.barssince(lowsqz)
barssinceMidSqz = ta.barssince(midsqz)
barssinceHighSqz = ta.barssince(highsqz)

// Dot Count Regular
bool    llDef             = sigreg ? lowsqz and (barssinceLsf == 6) : false
bool    mlDef             = sigreg ? midsqz and (barssinceMsf == 6) : false
bool    hlDef             = sigreg ? highsqz and (barssinceHsf == 6) : false
// End Of Squeeze
bool    eol             = sigeos ? lsf and (barssinceLowSqz == 1) : false
bool    eom             = sigeos ? msf and (barssinceMidSqz == 1) : false
bool    eoh             = sigeos ? hsf and (barssinceHighSqz == 1) : false
// Custom Squeeze
bool    custl           = sigcus ? lowsqz and (barssinceLsf == sqzsig) : false
bool    custm           = sigcus ? midsqz and (barssinceMsf == sqzsig) : false
bool    custh           = sigcus ? highsqz and (barssinceHsf == sqzsig) : false
// Dot Count Signals
bool    squeezesignall  = eoel or llDef or eol or custl
bool    squeezesignalm  = eoem or mlDef or eom or custm
bool    squeezesignalh  = eoeh or hlDef or eoh or custh
// Sum of Change Formulas
bool    llchg           = squeezesignall and changel
bool    lschg           = squeezesignall and changes
bool    mlchg           = squeezesignalm and changel
bool    mschg           = squeezesignalm and changes
bool    hlchg           = squeezesignalh and changel
bool    hschg           = squeezesignalh and changes
// Basic Signal Formulas
bool    llbsc           = squeezesignall and sc1
bool    lsbsc           = squeezesignall and sc2
bool    mlbsc           = squeezesignalm and sc1
bool    msbsc           = squeezesignalm and sc2
bool    hlbsc           = squeezesignalh and sc1
bool    hsbsc           = squeezesignalh and sc2
// Rising/Falling Signal Formulas
bool    llrf            = squeezesignall and sqzlongreg
bool    lsrf            = squeezesignall and sqzshortreg
bool    mlrf            = squeezesignalm and sqzlongreg
bool    msrf            = squeezesignalm and sqzshortreg
bool    hlrf            = squeezesignalh and sqzlongreg
bool    hsrf            = squeezesignalh and sqzshortreg
// Zero Line Signal Formulas
bool    llz             = squeezesignall and sqzzerolong
bool    lsz             = squeezesignall and sqzzeroshort
bool    mlz             = squeezesignalm and sqzzerolong
bool    msz             = squeezesignalm and sqzzeroshort
bool    hlz             = squeezesignalh and sqzzerolong
bool    hsz             = squeezesignalh and sqzzeroshort
// Basis Line Signal Formulas
bool    llbl            = squeezesignall and bbmal
bool    lsbl            = squeezesignall and bbmas
bool    mlbl            = squeezesignalm and bbmal
bool    msbl            = squeezesignalm and bbmas
bool    hlbl            = squeezesignalh and bbmal
bool    hsbl            = squeezesignalh and bbmas
// Divergence Signal Formulas
bool    lldv            = squeezesignall and regbulldiv
bool    lsdv            = squeezesignall and regbeardiv
bool    mldv            = squeezesignalm and regbulldiv
bool    msdv            = squeezesignalm and regbeardiv
bool    hldv            = squeezesignalh and regbulldiv
bool    hsdv            = squeezesignalh and regbeardiv
// Current Momentum Signal Formulas
bool    llcm            = squeezesignall and cmolong
bool    lscm            = squeezesignall and cmoshort
bool    mlcm            = squeezesignalm and cmolong
bool    mscm            = squeezesignalm and cmoshort
bool    hlcm            = squeezesignalh and cmolong
bool    hscm            = squeezesignalh and cmoshort
// Combo Scoring
int     basicscore      = sc1 ? 6 : -6
int     rfscore         = sqzlongreg ? 3 : sqzshortreg ? -3 : 0
int     zlscore         = sqzzerolong ? 4 : sqzzeroshort ? -4 : 0
int     bbmascore       = bbmal ? 3 : bbmas ? -3 : 0
int     divscore        = regbulldiv ? 3 : regbeardiv ? -3 : 0
int     sumscore        = changel ? 4 : -4
int     currentmo       = cmolong ? 3 : -3
int     comboscore      = basicscore + rfscore + zlscore + bbmascore + divscore + sumscore + currentmo
bool    longcombo       = comboscore > 0
bool    shortcombo      = comboscore < 0
// Combo Signal Formulas
bool    llcombo         = squeezesignall and longcombo
bool    lscombo         = squeezesignall and shortcombo
bool    mlcombo         = squeezesignalm and longcombo
bool    mscombo         = squeezesignalm and shortcombo
bool    hlcombo         = squeezesignalh and longcombo
bool    hscombo         = squeezesignalh and shortcombo
// Final Signals
bool    longlow         = (soc and llchg) or (momom and llbsc) or (rf and llrf) or (czero and llz) or (blma and llbl) or (diverg and lldv) or (llcm and cmom) or (combo and llcombo)
bool    shortlow        = (soc and lschg) or (momom and lsbsc) or (rf and lsrf) or (czero and lsz) or (blma and lsbl) or (diverg and lsdv) or (lscm and cmom) or (combo and lscombo)
bool    longmid         = (soc and mlchg) or (momom and mlbsc) or (rf and mlrf) or (czero and mlz) or (blma and mlbl) or (diverg and mldv) or (mlcm and cmom) or (combo and mlcombo)
bool    shortmid        = (soc and mschg) or (momom and msbsc) or (rf and msrf) or (czero and msz) or (blma and msbl) or (diverg and msdv) or (mscm and cmom) or (combo and mscombo)
bool    longhigh        = (soc and hlchg) or (momom and hlbsc) or (rf and hlrf) or (czero and hlz) or (blma and hlbl) or (diverg and hldv) or (hlcm and cmom) or (combo and hlcombo)
bool    shorthigh       = (soc and hschg) or (momom and hsbsc) or (rf and hsrf) or (czero and hsz) or (blma and hsbl) or (diverg and hsdv) or (hscm and cmom) or (combo and hscombo)

//-----------------------------------------------------------------------------
// Render
//-----------------------------------------------------------------------------
plotshape(sigarrows ? (longhigh ? false : longmid ? false : longlow ? longlow : false) : false, color = BLACK_COLOR, style = shape.arrowup, location = location.belowbar, size = size.small, title = "Low Squeeze Signal - Long", force_overlay = true)
plotshape(sigarrows ? (shorthigh ? false : shortmid ? false : shortlow ? shortlow : false) : false, color = BLACK_COLOR, style = shape.arrowdown, location = location.abovebar, size = size.small, title = "Low Squeeze Signal - Short", force_overlay = true)
plotshape(sigarrows ? (longhigh ? false : longmid ? longmid : false) : false, color = RED_COLOR, style = shape.arrowup, location = location.belowbar, size = size.small, title = "Mid Squeeze Signal - Long", force_overlay = true)
plotshape(sigarrows ? (shorthigh ? false : shortmid ? shortmid : false) : false, color = RED_COLOR, style = shape.arrowdown, location = location.abovebar, size = size.small, title = "Mid Squeeze Signal - Short", force_overlay = true)
plotshape(sigarrows ? (longhigh ? longhigh : false) : false, color = ORANGE_COLOR, style = shape.arrowup, location = location.belowbar, size = size.small, title = "High Squeeze Signal - Long", force_overlay = true)
plotshape(sigarrows ? (shorthigh ? shorthigh : false) : false, color = ORANGE_COLOR, style = shape.arrowdown, location = location.abovebar, size = size.small, title = "High Squeeze Signal - Short", force_overlay = true)

//------------------------------------------------------------------------------

Overview

TTM Squeeze Pro calculates Bollinger Bands against three tiers of Keltner Channels to detect low, medium, and high squeeze states, displaying them as color-coded dots along the zero line. A linear regression momentum oscillator plots as a colored histogram to reflect trending strength and directional changes. Users can customize calculation lengths, Bollinger Band standard deviations, and channel multipliers. The tool functions purely as a visual indicator without automated execution rules.

Details

Published by

TamTH-Dev on GitHub

Code credit

tamth_, as written in the script's header

Draws

Separate pane below the chart

Markets

Any symbol

Timeframes

Any timeframe

Risk Notes

No repainting, lookahead or stacked entries were found in its code or README. That says nothing about how well it works: test it first.

Settings

The inputs you can change from the gear icon on the chart. Defaults are the author's.

SettingTypeDefaultVariable
TTM Squeeze Lengthint20length
Bollinger Band STD Multiplierfloat2.0BB_mult
Keltner Channel #1float1.0KC_mult_high
Keltner Channel #2float1.5KC_mult_mid
Keltner Channel #3float2.0KC_mult_low
Showbooltruesigarrows
Signal Typestring+/-sigt
Squeeze Signal LengthstringDefaultcustsqz
Custom Squeeze Signal Durationint8sqzsig
Sum of Change Lengthint20sumofc
Early Entry Smoothing Periodint7entrysmooth
Early Exit Smoothing Periodint9exitsmooth
Third-party code. ForexR did not write, test or endorse this script, and the summary above was generated automatically from its code and README. Indicators describe the past, and a strategy's backtest can look better than live trading, especially when a script repaints. Check it in the Strategy Tester and on a demo account before you rely on it.

Similar Pine Scripts

TTM Squeeze

by Alorse
330 stars

This indicator plots a TTM Squeeze momentum oscillator in a separate pane. It compares a Bollinger Band offset to a Keltner Channel offset and marks the zero line white when the difference is non-negative and black when the bands are inside the channel. A line

Indicator v5 Oscillators & momentumVolatility & bands
Updated 2 months ago · None stated GitHub repository of TTM Squeeze

Function - Logistic Equation

by ricardosantos79
261 stars

Calculates dynamic modeling values by applying a mathematical logistic differential equation to price change over a specified lookback length. It measures price momentum relative to the recent high-low price range. The script plots positive and negative logist

Indicator v5 Oscillators & momentumVolatility & bands
Updated 4 years ago · None stated GitHub repository of Function - Logistic Equation
228 stars

This indicator detects a Bollinger Band squeeze when the bands sit inside Keltner Channels, marking low volatility. It plots red dots during a squeeze and green dots when the bands are outside, in a separate pane. An optional histogram shows momentum as the cl

Indicator v6 Volatility & bandsOscillators & momentum
Updated 3 months ago · None stated GitHub repository of Bollinger Band Squeeze Detector

MACD-V

by harryguiacorn
220 stars

MACD-V is a volatility-normalized momentum indicator based on research by Alex Spiroglou. It calculates the standard MACD histogram and normalizes it by dividing by the Average True Range (ATR). Plotted in a separate pane as a colored histogram, it includes us

Indicator v5 Oscillators & momentumVolatility & bands
Updated 1 year ago · None stated GitHub repository of MACD-V
147 stars

This indicator generates trade entry signals and target levels optimized for 1-hour timeframes, designed for external signal extraction. It calculates 7-period and 16-period EMAs alongside 10-period RSI and ATR filters. Long signals occur when the fast EMA cro

Indicator v5 TrendOscillators & momentum
Updated 6 weeks ago · MIT GitHub repository of Signal Strategy 100 Candles of 1H Timeframe

Bubbles Indicator

by capissimo
114 stars

The Bubbles Indicator measures volatility squeezes and expansion bursts using Bollinger Bands combined with a sinusoid oscillator and RSI divergence. It processes price data through scaled Bollinger Bands to highlight volatility changes while confirming trend

Indicator v4 Volatility & bandsOscillators & momentum Repaints
Updated 1 year ago · None stated GitHub repository of Bubbles Indicator

More Volatility & bands scripts

Related on ForexR

Trade Your Charts With a Regulated Broker

Compare brokers that connect to TradingView, with spreads, minimum deposits and leverage side by side.

Compare brokers