# Multi-Time Frame (MTF) Squeeze Indicator for ThinkorSwim

> Free MTF Squeeze indicator for ThinkorSwim: 18 labels, monthly to 1-minute, turn red when that timeframe is in a squeeze. Built from source code.

Page: https://tosindicators.com/indicators/mtf-squeeze  
Video: https://www.youtube.com/watch?v=64pDGTBxz_s  
Section: Indicators  
Skill: Beginner  
Access: free  
Updated: 2026-10-16

In this tutorial I build a multi-time frame (MTF) Squeeze indicator for ThinkorSwim that shows the default Squeeze on every timeframe at a glance. Each timeframe gets a label on the chart, from M for monthly down to 1m, red when that timeframe is in a squeeze and dark green when it isn't.

The indicator rebuilds the Squeeze from Bollinger Band and Keltner Channel source code, because the built-in function tends to give false squeeze signals inside multi-time frame code. It's for Squeeze traders who check several timeframes, and for anyone who wants a reusable multi-time frame template in thinkScript.

## Key Takeaways

- The MTF Squeeze indicator for ThinkorSwim plots 18 labels, from monthly (M) down to 1-minute (1m). A label is red when that timeframe is in a squeeze and dark green when it isn't.

- It uses ThinkorSwim's default Squeeze settings: length 20, nK 1.5, nBB 2 and an alert line of 1.

- A timeframe is in a squeeze when nBB times the standard deviation, divided by nK times the average true range, is below 1. That means the Bollinger Bands are inside the Keltner Channels.

- The indicator rebuilds the Squeeze from source code because the built-in Squeeze function tends to give false squeeze signals inside an if/else block that uses aggregation periods.

- ThinkorSwim can only read timeframes equal to or higher than your chart's, so on a 5-minute chart the 1m to 4m labels don't appear.

## What the MTF Squeeze Indicator Shows

The MTF Squeeze indicator is a row of chart labels, one per timeframe, that shows whether each timeframe is in a squeeze. It saves you from flipping through charts: one glance tells you which timeframes have the default squeeze.

Each label is red when that timeframe has a squeeze and dark green when it doesn't. The free download covers 18 timeframes. The table lists each label with the aggregation period and the `period` string the code uses for it.

| Label | Timeframe | Aggregation check | Price period |
| --- | --- | --- | --- |

| M | Monthly | `AggregationPeriod.Month` | `period="Month"` |

| W | Weekly | `AggregationPeriod.week` | `period="week"` |

| 4D | 4-day | `AggregationPeriod.four_days` | `period="4 days"` |

| 3D | 3-day | `AggregationPeriod.three_days` | `period="3 days"` |

| 2D | 2-day | `AggregationPeriod.two_days` | `period="2 days"` |

| D | Daily | `AggregationPeriod.day` | `period="day"` |

| 4h | 4-hour | `AggregationPeriod.four_hours` | `period="4 Hours"` |

| 2h | 2-hour | `AggregationPeriod.two_hours` | `period="2 Hours"` |

| 1h | 1-hour | `AggregationPeriod.hour` | `period="1 Hour"` |

| 30m | 30-minute | `AggregationPeriod.Thirty_Min` | `period="30 Min"` |

| 20m | 20-minute | `AggregationPeriod.Twenty_Min` | `period="20 Min"` |

| 15m | 15-minute | `AggregationPeriod.Fifteen_Min` | `period="15 Min"` |

| 10m | 10-minute | `AggregationPeriod.Ten_Min` | `period="10 Min"` |

| 5m | 5-minute | `AggregationPeriod.Five_Min` | `period="5 Min"` |

| 4m | 4-minute | `AggregationPeriod.Four_Min` | `period="4 Min"` |

| 3m | 3-minute | `AggregationPeriod.Three_Min` | `period="3 Min"` |

| 2m | 2-minute | `AggregationPeriod.Two_Min` | `period="2 Min"` |

| 1m | 1-minute | `AggregationPeriod.Min` | `period="1 Min"` |

Labels only appear for timeframes equal to or higher than your chart's. ThinkorSwim can read higher timeframes from the chart you're on, but nothing lower. On a 5-minute chart you'll see 5m and up, and you won't know whether the 1, 2, 3 or 4-minute charts have a squeeze. The higher labels also need enough candle data on your chart to calculate.

## Free Download vs the Member Version

The free MTF Squeeze indicator tracks one compression, the default mid compression that the built-in Squeeze uses. Volatility Box members have a second version in [Module 9 of the Squeeze Course](https://tosindicators.com/squeeze-course/module-9) that takes the code one step further.

| Feature | Free download (built in this tutorial) | Member version (Module 9) |
| --- | --- | --- |

| Compressions | 1, the default mid compression | 3, fast, mid and slow |

| Squeeze colors | Red | Gray for fast, red for mid, yellow for slow |

| No squeeze | Dark green | Black in the video |

| Changing colors | Edit the `AddLabel` lines | Pick colors in the studies menu |

In the video, I changed the member version's no-squeeze color from black to dark green in the studies menu, clicked Apply, and every label without a squeeze turned dark green. Colors you can set from the menu also help if you're colorblind.

## Why the Indicator Rebuilds the Squeeze From Source Code

The built-in Squeeze function in ThinkorSwim tends to give false squeeze signals inside multi-time frame code. That happens when you reference it inside an if/else block that also uses aggregation periods. It doesn't return the squeeze alert value you'd expect, so the indicator doesn't work the way you want.

ThinkorSwim's own documentation describes the Squeeze as a measure of two indicators and their relationship: the Bollinger Bands and the Keltner Channels. The squeeze is on when the Bollinger Bands fall inside the Keltner Channels. The Squeeze's source code is hidden, but the Bollinger Band and Keltner Channel source code isn't, so you can rebuild it from those pieces.

To speed things along, I used code that a member sent us from another thinkScript author's Blogspot, which recreates the Squeeze. If you use that code, leave the author's credit and Blogspot link in your header. Our download keeps it on the first lines.

The math comes down to one ratio. Bollinger Band width is a multiple of the standard deviation (nBB), and Keltner Channel width is a multiple of the average true range (nK). The code divides the first by the second and compares the result with the alert line of 1. Below 1, the Bollinger Bands are inside the Keltner Channels, and that timeframe is in a squeeze.

## The Multi-Time Frame Framework

The MTF Squeeze is built on the drag-and-drop multi-time frame module from our [MTF DMI indicator](https://tosindicators.com/indicators/mtf-dmi). Because that code was written to be reusable, I could lift the same framework and drop in the squeeze math. You could do the same for EMA crossovers or your own set of indicators.

- **Declare first.** Each timeframe's variables are declared above its if/else block.

- **Check the timeframe.** The if tests whether the chart's aggregation period is less than or equal to the timeframe you want to measure, then assigns the values.

- **Default to 0.** The else sets every variable to 0 to keep things simple.

- **Prefix every name.** Each variable starts with its timeframe, like `monthPrice`, so a find-and-replace turns the monthly block into the weekly one.

If you only need one higher timeframe, such as a daily level on an intraday chart, our tutorial on [plotting higher time frame indicators with aggregation periods](https://tosindicators.com/thinkscript/aggregation-periods) covers that simpler case.

## How to Build It in ThinkorSwim

Building the MTF Squeeze takes one monthly block of code, then a copy of that block for every other timeframe.

- Click the **Studies** icon, click **Create**, and give the study a name.

- Add a header comment that credits the Blogspot source code with its link.

- Define the global variables: length, alert line, nK, nBB and the rest.

- Write the monthly block: the declarations, the if/else, and 2 labels.

- Click **Apply**, then check the M label against the built-in Squeeze on a monthly chart.

- Copy the block into a text editor, replace `month` with the next timeframe, fix the label text and the period string, and paste it back. Repeat down to 1 minute.

If you'd rather start from the finished file, download it and follow our guide on [how to import a study into ThinkorSwim](https://tosindicators.com/thinkscript/how-to-import-thinkorswim).

## How the Code Works

The MTF Squeeze code is a short global section followed by 18 blocks that each follow the same pattern. Once you understand the monthly block, you understand all of them.

### Step 1: Global Variables

Global variables are the settings that don't change from one timeframe to the next. These are the default values of the built-in Squeeze.

```
##Global Variables
def length = 20;
def AlertLine = 1;
def nk = 1.5;
def nBB = 2;
def averageTpype = AverageType.SIMPLE;
def displace = 0;
def trueRangeAverageType = AverageType.SIMPLE;
```

To change the compression, change `nk` here. To set a value from the studies menu, change its `def` to `input`.

I renamed the source's nBB factor to `nBB` so the code is easier to copy and paste later.

### Step 2: Declare the Monthly Variables

Each monthly variable is declared once, above the if/else, so both branches can assign it.

```
def monthPrice;
def monthATR;
def monthSDev;
def monthDenom;
def monthBBSInd;
def monthSqueeze;
def monthAggregationPeriod;
```

The download adds `monthAggregationPeriod`, a flag that hides the label on charts that can't read the monthly timeframe.

### Step 3: The Monthly If Block

The if block checks that the chart is monthly or lower, then calculates the squeeze on monthly bars. Inside it, you assign values without `def`, because the variables already exist.

```
if GetAggregationPeriod()

## thinkScript code

```
#TOS Indicators
#Home of the Volatility Box
#Indicator Name: Multi-Time Frame Squeeze 
#Full Tutorial Available Here: www.tosindicators.com/indicators/mtf-squeeze
#Contains TTM_Squeeze Source Code, found here (http://freethinkscript.blogspot.com/2009/05/ttm-like-squeeze-indicator-with.html)

##Global Variables
def length = 20;
def AlertLine = 1;
def nk = 1.5;
def nBB = 2;
def averageTpype = AverageType.SIMPLE;
def displace = 0;
def trueRangeAverageType = AverageType.SIMPLE;

## Month Aggregation Period Variables

def monthPrice;
def monthATR;
def monthSDev;
def monthDenom;
def monthBBSInd;
def monthSqueeze;
def monthAggregationPeriod;
if GetAggregationPeriod() <= AggregationPeriod.Month {
    monthPrice = close(period="Month");
    monthATR = Average(TrueRange(high (period="Month"), close(period="Month"), low(period="Month")), Length);
    monthSDev = stdev(monthPrice, Length);
    monthDenom = (nK*monthATR);
    monthBBSInd = if (monthDenom <> 0, ((nBB * monthSDev) /monthDenom), 0);
    monthSqueeze = if monthBBSInd < AlertLine then 1 else 0;
    monthAggregationPeriod = 1;
}
else {
    monthPrice = 0;
    monthATR = 0;
    monthSDev = 0;
    monthDenom = 0;
    monthBBSInd = 0;
    monthSqueeze = 0;
    monthAggregationPeriod = 0;
}
AddLabel(monthSqueeze and monthAggregationPeriod, "M", color.red);
AddLabel(!monthSqueeze and monthAggregationPeriod,"M", color.dark_green);

def weekPrice;
def weekATR;
def weekSDev;
def weekDenom;
def weekBBSInd;
def weekSqueeze;
def WeekAggregationPeriod;
if GetAggregationPeriod() <= AggregationPeriod.week {
    weekPrice = close(period="week");
    weekATR = Average(TrueRange(high (period="week"), close(period="week"), low(period="week")), Length);
    weekSDev = stdev(weekPrice, Length);
    weekDenom = (nK*weekATR);
    weekBBSInd = if (weekDenom <> 0, ((nBB * weekSDev) /weekDenom), 0);
    weekSqueeze = if weekBBSInd < AlertLine then 1 else 0;
    WeekAggregationPeriod = 1;
}
else {
    weekPrice = 0;
    weekATR = 0;
    weekSDev = 0;
    weekDenom = 0;
    weekBBSInd = 0;
    weekSqueeze = 0;
    WeekAggregationPeriod = 0;
}
AddLabel(weekSqueeze and WeekAggregationPeriod, "W", color.red);
AddLabel(!weekSqueeze and WeekAggregationPeriod,"W", color.dark_green);

def four_daysPrice;
def four_daysATR;
def four_daysSDev;
def four_daysDenom;
def four_daysBBSInd;
def four_daysSqueeze;
def FourDayAggregationPeriod;
if GetAggregationPeriod() <= AggregationPeriod.four_days {
    four_daysPrice = close(period="4 days");
    four_daysATR = Average(TrueRange(high (period="4 days"), close(period="4 days"), low(period="4 days")), Length);
    four_daysSDev = stdev(four_daysPrice, Length);
    four_daysDenom = (nK*four_daysATR);
    four_daysBBSInd = if (four_daysDenom <> 0, ((nBB * four_daysSDev) /four_daysDenom), 0);
    four_daysSqueeze = if four_daysBBSInd < AlertLine then 1 else 0;
    FourDayAggregationPeriod = 1;
}
else {
    four_daysPrice = 0;
    four_daysATR = 0;
    four_daysSDev = 0;
    four_daysDenom = 0;
    four_daysBBSInd = 0;
    four_daysSqueeze = 0;
    FourDayAggregationPeriod = 0;
}
AddLabel(four_daysSqueeze and FourDayAggregationPeriod, "4D", color.red);
AddLabel(!four_daysSqueeze and FourDayAggregationPeriod,"4D", color.dark_green);

def three_daysPrice;
def three_daysATR;
def three_daysSDev;
def three_daysDenom;
def three_daysBBSInd;
def three_daysSqueeze;
def ThreeDayMinAggregationPeriod;
if GetAggregationPeriod() <= AggregationPeriod.three_days {
    three_daysPrice = close(period="3 days");
    three_daysATR = Average(TrueRange(high (period="3 days"), close(period="3 days"), low(period="3 days")), Length);
    three_daysSDev = stdev(three_daysPrice, Length);
    three_daysDenom = (nK*three_daysATR);
    three_daysBBSInd = if (three_daysDenom <> 0, ((nBB * three_daysSDev) /three_daysDenom), 0);
    three_daysSqueeze = if three_daysBBSInd < AlertLine then 1 else 0;
    ThreeDayMinAggregationPeriod = 1;
}
else {
    three_daysPrice = 0;
    three_daysATR = 0;
    three_daysSDev = 0;
    three_daysDenom = 0;
    three_daysBBSInd = 0;
    three_daysSqueeze = 0;
    ThreeDayMinAggregationPeriod = 0;
}
AddLabel(three_daysSqueeze and ThreeDayMinAggregationPeriod, "3D", color.red);
AddLabel(!three_daysSqueeze and ThreeDayMinAggregationPeriod,"3D", color.dark_green);

def two_daysPrice;
def two_daysATR;
def two_daysSDev;
def two_daysDenom;
def two_daysBBSInd;
def two_daysSqueeze;
def TwoDayMinAggregationPeriod;
if GetAggregationPeriod() <= AggregationPeriod.two_days {
    two_daysPrice = close(period="2 days");
    two_daysATR = Average(TrueRange(high (period="2 days"), close(period="2 days"), low(period="2 days")), Length);
    two_daysSDev = stdev(two_daysPrice, Length);
    two_daysDenom = (nK*two_daysATR);
    two_daysBBSInd = if (two_daysDenom <> 0, ((nBB * two_daysSDev) /two_daysDenom), 0);
    two_daysSqueeze = if two_daysBBSInd < AlertLine then 1 else 0;
    TwoDayMinAggregationPeriod = 1;
}
else {
    two_daysPrice = 0;
    two_daysATR = 0;
    two_daysSDev = 0;
    two_daysDenom = 0;
    two_daysBBSInd = 0;
    two_daysSqueeze = 0;
    TwoDayMinAggregationPeriod = 0;
}
AddLabel(two_daysSqueeze and TwoDayMinAggregationPeriod, "2D", color.red);
AddLabel(!two_daysSqueeze and TwoDayMinAggregationPeriod,"2D", color.dark_green);

def dayPrice;
def dayATR;
def daySDev;
def dayDenom;
def dayBBSInd;
def daySqueeze;
def DayMinAggregationPeriod;
if GetAggregationPeriod() <= AggregationPeriod.day {
    dayPrice = close(period="day");
    dayATR = Average(TrueRange(high (period="day"), close(period="day"), low(period="day")), Length);
    daySDev = stdev(dayPrice, Length);
    dayDenom = (nK*dayATR);
    dayBBSInd = if (dayDenom <> 0, ((nBB * daySDev) /dayDenom), 0);
    daySqueeze = if dayBBSInd < AlertLine then 1 else 0;
    DayMinAggregationPeriod = 1;
}
else {
    dayPrice = 0;
    dayATR = 0;
    daySDev = 0;
    dayDenom = 0;
    dayBBSInd = 0;
    daySqueeze = 0;
    DayMinAggregationPeriod = 0;
}
AddLabel(daySqueeze and DayMinAggregationPeriod, "D", color.red);
AddLabel(!daySqueeze and DayMinAggregationPeriod,"D", color.dark_green);

def four_hoursPrice;
def four_hoursATR;
def four_hoursSDev;
def four_hoursDenom;
def four_hoursBBSInd;
def four_hoursSqueeze;
def FourHourMinAggregationPeriod;
if GetAggregationPeriod() <= AggregationPeriod.four_hours {
    four_hoursPrice = close(period="4 Hours");
    four_hoursATR = Average(TrueRange(high (period="4 Hours"), close(period="4 Hours"), low(period="4 Hours")), Length);
    four_hoursSDev = stdev(four_hoursPrice, Length);
    four_hoursDenom = (nK*four_hoursATR);
    four_hoursBBSInd = if (four_hoursDenom <> 0, ((nBB * four_hoursSDev) /four_hoursDenom), 0);
    four_hoursSqueeze = if four_hoursBBSInd < AlertLine then 1 else 0;
    FourHourMinAggregationPeriod = 1;
}
else {
    four_hoursPrice = 0;
    four_hoursATR = 0;
    four_hoursSDev = 0;
    four_hoursDenom = 0;
    four_hoursBBSInd = 0;
    four_hoursSqueeze = 0;
    FourHourMinAggregationPeriod = 0;
}
AddLabel(four_hoursSqueeze and FourHourMinAggregationPeriod, "4h", color.red);
AddLabel(!four_hoursSqueeze and FourHourMinAggregationPeriod,"4h", color.dark_green);

def two_hoursPrice;
def two_hoursATR;
def two_hoursSDev;
def two_hoursDenom;
def two_hoursBBSInd;
def two_hoursSqueeze;
def TwoHourMinAggregationPeriod;
if GetAggregationPeriod() <= AggregationPeriod.two_hours {
    two_hoursPrice = close(period="2 Hours");
    two_hoursATR = Average(TrueRange(high (period="2 Hours"), close(period="2 Hours"), low(period="2 Hours")), Length);
    two_hoursSDev = stdev(two_hoursPrice, Length);
    two_hoursDenom = (nK*two_hoursATR);
    two_hoursBBSInd = if (two_hoursDenom <> 0, ((nBB * two_hoursSDev) /two_hoursDenom), 0);
    two_hoursSqueeze = if two_hoursBBSInd < AlertLine then 1 else 0;
    TwoHourMinAggregationPeriod = 1;
}
else {
    two_hoursPrice = 0;
    two_hoursATR = 0;
    two_hoursSDev = 0;
    two_hoursDenom = 0;
    two_hoursBBSInd = 0;
    two_hoursSqueeze = 0;
    TwoHourMinAggregationPeriod = 0;
}
AddLabel(two_hoursSqueeze and TwoHourMinAggregationPeriod, "2h", color.red);
AddLabel(!two_hoursSqueeze and TwoHourMinAggregationPeriod,"2h", color.dark_green);

def hourPrice;
def hourATR;
def hourSDev;
def hourDenom;
def hourBBSInd;
def hourSqueeze;
def HourMinAggregationPeriod;
if GetAggregationPeriod() <= AggregationPeriod.hour {
    hourPrice = close(period="1 Hour");
    hourATR = Average(TrueRange(high (period="1 Hour"), close(period="1 Hour"), low(period="1 Hour")), Length);
    hourSDev = stdev(hourPrice, Length);
    hourDenom = (nK*hourATR);
    hourBBSInd = if (hourDenom <> 0, ((nBB * hourSDev) /hourDenom), 0);
    hourSqueeze = if hourBBSInd < AlertLine then 1 else 0;
    HourMinAggregationPeriod = 1;
}
else {
    hourPrice = 0;
    hourATR = 0;
    hourSDev = 0;
    hourDenom = 0;
    hourBBSInd = 0;
    hourSqueeze = 0;
    HourMinAggregationPeriod = 0;
}
AddLabel(hourSqueeze and HourMinAggregationPeriod, "1h", color.red);
AddLabel(!hourSqueeze and HourMinAggregationPeriod,"1h", color.dark_green);

def Thirty_MinPrice;
def Thirty_MinATR;
def Thirty_MinSDev;
def Thirty_MinDenom;
def Thirty_MinBBSInd;
def Thirty_MinSqueeze;
def ThirtyMinAggregationPeriod;
if GetAggregationPeriod() <= AggregationPeriod.Thirty_Min {
    Thirty_MinPrice = close(period="30 Min");
    Thirty_MinATR = Average(TrueRange(high (period="30 Min"), close(period="30 Min"), low(period="30 Min")), Length);
    Thirty_MinSDev = stdev(Thirty_MinPrice, Length);
    Thirty_MinDenom = (nK*Thirty_MinATR);
    Thirty_MinBBSInd = if (Thirty_MinDenom <> 0, ((nBB * Thirty_MinSDev) /Thirty_MinDenom), 0);
    Thirty_MinSqueeze = if Thirty_MinBBSInd < AlertLine then 1 else 0;
    ThirtyMinAggregationPeriod = 1;
}
else {
    Thirty_MinPrice = 0;
    Thirty_MinATR = 0;
    Thirty_MinSDev = 0;
    Thirty_MinDenom = 0;
    Thirty_MinBBSInd = 0;
    Thirty_MinSqueeze = 0;
    ThirtyMinAggregationPeriod = 0;
}
AddLabel(Thirty_MinSqueeze and ThirtyMinAggregationPeriod, "30m", color.red);
AddLabel(!Thirty_MinSqueeze and ThirtyMinAggregationPeriod,"30m", color.dark_green);

def Twenty_MinPrice;
def Twenty_MinATR;
def Twenty_MinSDev;
def Twenty_MinDenom;
def Twenty_MinBBSInd;
def Twenty_MinSqueeze;
def TwentyMinAggregationPeriod;
if GetAggregationPeriod() <= AggregationPeriod.Twenty_Min {
    Twenty_MinPrice = close(period="20 Min");
    Twenty_MinATR = Average(TrueRange(high (period="20 Min"), close(period="20 Min"), low(period="20 Min")), Length);
    Twenty_MinSDev = stdev(Twenty_MinPrice, Length);
    Twenty_MinDenom = (nK*Twenty_MinATR);
    Twenty_MinBBSInd = if (Twenty_MinDenom <> 0, ((nBB * Twenty_MinSDev) /Twenty_MinDenom), 0);
    Twenty_MinSqueeze = if Twenty_MinBBSInd < AlertLine then 1 else 0;
    TwentyMinAggregationPeriod = 1;
}
else {
    Twenty_MinPrice = 0;
    Twenty_MinATR = 0;
    Twenty_MinSDev = 0;
    Twenty_MinDenom = 0;
    Twenty_MinBBSInd = 0;
    Twenty_MinSqueeze = 0;
    TwentyMinAggregationPeriod = 0;
}
AddLabel(Twenty_MinSqueeze and TwentyMinAggregationPeriod, "20m", color.red);
AddLabel(!Twenty_MinSqueeze and TwentyMinAggregationPeriod,"20m", color.dark_green);

def Fifteen_MinPrice;
def Fifteen_MinATR;
def Fifteen_MinSDev;
def Fifteen_MinDenom;
def Fifteen_MinBBSInd;
def Fifteen_MinSqueeze;
def FifteenMinAggregationPeriod;
if GetAggregationPeriod() <= AggregationPeriod.Fifteen_Min {
    Fifteen_MinPrice = close(period="15 Min");
    Fifteen_MinATR = Average(TrueRange(high (period="15 Min"), close(period="15 Min"), low(period="15 Min")), Length);
    Fifteen_MinSDev = stdev(Fifteen_MinPrice, Length);
    Fifteen_MinDenom = (nK*Fifteen_MinATR);
    Fifteen_MinBBSInd = if (Fifteen_MinDenom <> 0, ((nBB * Fifteen_MinSDev) /Fifteen_MinDenom), 0);
    Fifteen_MinSqueeze = if Fifteen_MinBBSInd < AlertLine then 1 else 0;
    FifteenMinAggregationPeriod = 1;
}
else {
    Fifteen_MinPrice = 0;
    Fifteen_MinATR = 0;
    Fifteen_MinSDev = 0;
    Fifteen_MinDenom = 0;
    Fifteen_MinBBSInd = 0;
    Fifteen_MinSqueeze = 0;
    FifteenMinAggregationPeriod = 0;
}
AddLabel(Fifteen_MinSqueeze and FifteenMinAggregationPeriod, "15m", color.red);
AddLabel(!Fifteen_MinSqueeze and FifteenMinAggregationPeriod,"15m", color.dark_green);

def Ten_MinPrice;
def Ten_MinATR;
def Ten_MinSDev;
def Ten_MinDenom;
def Ten_MinBBSInd;
def Ten_MinSqueeze;
def TenMinAggregationPeriod;
if GetAggregationPeriod() <= AggregationPeriod.Ten_Min {
    Ten_MinPrice = close(period="10 Min");
    Ten_MinATR = Average(TrueRange(high (period="10 Min"), close(period="10 Min"), low(period="10 Min")), Length);
    Ten_MinSDev = stdev(Ten_MinPrice, Length);
    Ten_MinDenom = (nK*Ten_MinATR);
    Ten_MinBBSInd = if (Ten_MinDenom <> 0, ((nBB * Ten_MinSDev) /Ten_MinDenom), 0);
    Ten_MinSqueeze = if Ten_MinBBSInd < AlertLine then 1 else 0;
    TenMinAggregationPeriod = 1;
}
else {
    Ten_MinPrice = 0;
    Ten_MinATR = 0;
    Ten_MinSDev = 0;
    Ten_MinDenom = 0;
    Ten_MinBBSInd = 0;
    Ten_MinSqueeze = 0;
    TenMinAggregationPeriod = 0;
}
AddLabel(Ten_MinSqueeze and TenMinAggregationPeriod, "10m", color.red);
AddLabel(!Ten_MinSqueeze and TenMinAggregationPeriod,"10m", color.dark_green);

def Five_MinPrice;
def Five_MinATR;
def Five_MinSDev;
def Five_MinDenom;
def Five_MinBBSInd;
def Five_MinSqueeze;
def FiveMinAggregationPeriod;
if GetAggregationPeriod() <= AggregationPeriod.Five_Min {
    Five_MinPrice = close(period="5 Min");
    Five_MinATR = Average(TrueRange(high (period="5 Min"), close(period="5 Min"), low(period="5 Min")), Length);
    Five_MinSDev = stdev(Five_MinPrice, Length);
    Five_MinDenom = (nK*Five_MinATR);
    Five_MinBBSInd = if (Five_MinDenom <> 0, ((nBB * Five_MinSDev) /Five_MinDenom), 0);
    Five_MinSqueeze = if Five_MinBBSInd < AlertLine then 1 else 0;
    FiveMinAggregationPeriod = 1;
}
else {
    Five_MinPrice = 0;
    Five_MinATR = 0;
    Five_MinSDev = 0;
    Five_MinDenom = 0;
    Five_MinBBSInd = 0;
    Five_MinSqueeze = 0;
    FiveMinAggregationPeriod = 0;
}
AddLabel(Five_MinSqueeze and FiveMinAggregationPeriod, "5m", color.red);
AddLabel(!Five_MinSqueeze and FiveMinAggregationPeriod,"5m", color.dark_green);

def Four_MinPrice;
def Four_MinATR;
def Four_MinSDev;
def Four_MinDenom;
def Four_MinBBSInd;
def Four_MinSqueeze;
def FourMinAggregationPeriod;
if GetAggregationPeriod() <= AggregationPeriod.Four_Min {
    Four_MinPrice = close(period="4 Min");
    Four_MinATR = Average(TrueRange(high (period="4 Min"), close(period="4 Min"), low(period="4 Min")), Length);
    Four_MinSDev = stdev(Four_MinPrice, Length);
    Four_MinDenom = (nK*Four_MinATR);
    Four_MinBBSInd = if (Four_MinDenom <> 0, ((nBB * Four_MinSDev) /Four_MinDenom), 0);
    Four_MinSqueeze = if Four_MinBBSInd < AlertLine then 1 else 0;
    FourMinAggregationPeriod = 1;
}
else {
    Four_MinPrice = 0;
    Four_MinATR = 0;
    Four_MinSDev = 0;
    Four_MinDenom = 0;
    Four_MinBBSInd = 0;
    Four_MinSqueeze = 0;
    FourMinAggregationPeriod = 0;
}
AddLabel(Four_MinSqueeze and FourMinAggregationPeriod, "4m", color.red);
AddLabel(!Four_MinSqueeze and FourMinAggregationPeriod,"4m", color.dark_green);

def Three_MinPrice;
def Three_MinATR;
def Three_MinSDev;
def Three_MinDenom;
def Three_MinBBSInd;
def Three_MinSqueeze;
def ThreeMinAggregationPeriod;
if GetAggregationPeriod() <= AggregationPeriod.Three_Min {
    Three_MinPrice = close(period="3 Min");
    Three_MinATR = Average(TrueRange(high (period="3 Min"), close(period="3 Min"), low(period="3 Min")), Length);
    Three_MinSDev = stdev(Three_MinPrice, Length);
    Three_MinDenom = (nK*Three_MinATR);
    Three_MinBBSInd = if (Three_MinDenom <> 0, ((nBB * Three_MinSDev) /Three_MinDenom), 0);
    Three_MinSqueeze = if Three_MinBBSInd < AlertLine then 1 else 0;
    ThreeMinAggregationPeriod = 1;
}
else {
    Three_MinPrice = 0;
    Three_MinATR = 0;
    Three_MinSDev = 0;
    Three_MinDenom = 0;
    Three_MinBBSInd = 0;
    Three_MinSqueeze = 0;
    ThreeMinAggregationPeriod = 0;
}
AddLabel(Three_MinSqueeze and ThreeMinAggregationPeriod, "3m", color.red);
AddLabel(!Three_MinSqueeze and ThreeMinAggregationPeriod,"3m", color.dark_green);

def Two_MinPrice;
def Two_MinATR;
def Two_MinSDev;
def Two_MinDenom;
def Two_MinBBSInd;
def Two_MinSqueeze;
def twoMinAggregationPeriod;
if GetAggregationPeriod() <= AggregationPeriod.Two_Min {
    Two_MinPrice = close(period="2 Min");
    Two_MinATR = Average(TrueRange(high (period="2 Min"), close(period="2 Min"), low(period="2 Min")), Length);
    Two_MinSDev = stdev(Two_MinPrice, Length);
    Two_MinDenom = (nK*Two_MinATR);
    Two_MinBBSInd = if (Two_MinDenom <> 0, ((nBB * Two_MinSDev) /Two_MinDenom), 0);
    Two_MinSqueeze = if Two_MinBBSInd < AlertLine then 1 else 0;
    twoMinAggregationPeriod = 1;
}
else {
    Two_MinPrice = 0;
    Two_MinATR = 0;
    Two_MinSDev = 0;
    Two_MinDenom = 0;
    Two_MinBBSInd = 0;
    Two_MinSqueeze = 0;
    twoMinAggregationPeriod = 0;
}
AddLabel(Two_MinSqueeze and twoMinAggregationPeriod, "2m", color.red);
AddLabel(!Two_MinSqueeze and twoMinAggregationPeriod,"2m", color.dark_green);

def One_MinPrice;
def One_MinATR;
def One_MinSDev;
def One_MinDenom;
def One_MinBBSInd;
def One_MinSqueeze;
def minAggregationPeriod;

if GetAggregationPeriod() <= AggregationPeriod.Min {
    One_MinPrice = close(period="1 Min");
    One_MinATR = Average(TrueRange(high (period="1 Min"), close(period="1 Min"), low(period="1 Min")), Length);
    One_MinSDev = stdev(One_MinPrice, Length);
    One_MinDenom = (nK*One_MinATR);
    One_MinBBSInd = if (One_MinDenom <> 0, ((nBB * One_MinSDev) /One_MinDenom), 0);
    One_MinSqueeze = if One_MinBBSInd < AlertLine then 1 else 0;
    minAggregationPeriod = 1;
}
else {
    One_MinPrice = 0;
    One_MinATR = 0;
    One_MinSDev = 0;
    One_MinDenom = 0;
    One_MinBBSInd = 0;
    One_MinSqueeze = 0;
    minAggregationPeriod = 0;
}
AddLabel(One_MinSqueeze and minAggregationPeriod, "1m", color.red);
AddLabel(!One_MinSqueeze and minAggregationPeriod,"1m", color.dark_green);
```

## Questions

### What is a multi-time frame Squeeze indicator?

It shows whether the Squeeze is on for several timeframes at once, so you don't have to flip through charts. Our free MTF Squeeze indicator plots 18 labels on a ThinkorSwim chart, from monthly down to 1-minute. Each label is red when that timeframe is in a squeeze and dark green when it isn't.

### How do I add the MTF Squeeze indicator to ThinkorSwim?

Download the study file or copy the code from the Code tab. In ThinkorSwim, click the Studies icon, click Create, paste in the code, name the study, and click OK, then Apply. The labels appear on the chart. Use a 1-minute chart to see all 18 timeframes, with enough candle data loaded for the higher ones to calculate.

### Why don't I see the lower timeframe labels on my chart?

ThinkorSwim can only read timeframes equal to or higher than the chart you're on. On a 5-minute chart, the indicator shows 5m and every higher timeframe, and it hides the 1, 2, 3 and 4-minute labels. Higher timeframes also need enough candle data on the chart to calculate.

### Why not use the built-in Squeeze function for multiple timeframes?

When you reference the built-in Squeeze function inside an if/else block that uses aggregation periods, it tends to give false squeeze signals because it doesn't return the squeeze alert you'd expect. The MTF Squeeze rebuilds the squeeze from standard deviation and average true range instead, which works the way you'd expect.

### What settings does the MTF Squeeze indicator use?

It uses the built-in Squeeze defaults: a length of 20, an nK factor of 1.5, an nBB factor of 2 and an alert line of 1. They're global variables at the top of the code. Change def to input on any of them if you want to set it from the studies menu.

### How does the indicator decide a timeframe is in a squeeze?

For each timeframe it multiplies the standard deviation of the close by nBB and the average true range by nK, then divides the first by the second. If the result is below the alert line of 1, the Bollinger Bands are inside the Keltner Channels, and that timeframe's label turns red.

### How do I add the fast and slow compressions?

Add an nK factor 2 and an nK factor 3 to the global variables, then repeat the squeeze code with a 2 and a 3 version of each variable. Volatility Box members have a finished version in Module 9 of the Squeeze Course, with all 3 compressions and label colors you can change in the studies menu.

### Can I use this code for other multi-time frame indicators?

Yes. The framework comes from our MTF DMI indicator and works for things like EMA crossovers or your own indicators. Declare the variables above an if/else, check the aggregation period in the if, set everything to 0 in the else, and prefix each name with its timeframe so find-and-replace builds the next block.

## Related

- [Aggregation Periods in thinkScript: Plot a Daily Indicator on an Intraday Chart](https://tosindicators.com/thinkscript/aggregation-periods)
- [How to Build a Fair Value Gap Indicator in ThinkorSwim](https://tosindicators.com/indicators/fair-value-gap)
- [How to Build a Heiken Ashi Trend Dots Indicator in ThinkorSwim](https://tosindicators.com/indicators/heiken-ashi)
- [How to Build a Commodities Tracker in ThinkorSwim](https://tosindicators.com/indicators/commodities-tracker)
- [Trend Squeeze Indicator for ThinkorSwim](https://tosindicators.com/indicators/trend-squeeze)
- [Volume Intensity Indicator for ThinkorSwim](https://tosindicators.com/indicators/volume-intensity)

