On this page
Overview
In this tutorial I build a moving average indicator for ThinkOrSwim that plots averages from four different time frames on one chart: a 10-period simple moving average from the daily chart, and exponential moving averages from the 1-hour, 30-minute and 15-minute charts. On a 5-minute chart, you see all four lines at once.
It's for traders who want more information on one screen, such as traders working from a laptop or anyone tired of keeping five chart windows open. Along the way I explain aggregation periods, the ThinkOrSwim limit on which time frames a chart can read, and the if/else blocks that stop the indicator from breaking when you change time frames.
Key Takeaways
- The multiple time frame moving averages indicator plots a 10-period daily SMA, a 50-period 1-hour EMA, a 30-period 30-minute EMA and a 20-period 15-minute EMA on one ThinkOrSwim chart.
- ThinkOrSwim only lets a chart read data from time frames greater than or equal to its own, so a 30-minute chart can't plot the 15-minute EMA.
- Without if/else blocks, one line the chart can't access breaks the whole study: on a 30-minute chart, all 4 lines disappeared and ThinkOrSwim showed an error.
- The finished code checks
getAggregationPeriod()and plots 4 lines on 15-minute and smaller charts, 3 on a 30-minute chart, 2 on a 1-hour chart, and only the daily SMA above 1 hour up to the daily chart. - In the video, the daily SMA read 165.23 on a 30-minute Johnson & Johnson chart, the same value it showed on the daily chart.
What the Indicator Plots
The multiple time frame moving averages indicator puts four moving averages from four different time frames on the chart you're trading. My goal in the video was a 5-minute chart that shows a moving average from the 15-minute chart, one from the 30-minute chart, one from the 1-hour chart and one from the daily chart.
| Line | Time frame | Type | Default length | Input |
|---|---|---|---|---|
SMAOneDayChart | Daily | Simple | 10 | dailySMALength |
EMAOneHourChart | 1 hour | Exponential | 50 | oneHourEMALength |
EMAThirtyMinuteChart | 30 minutes | Exponential | 30 | thirtyMinuteEMALength |
EMAFifteenMinuteChart | 15 minutes | Exponential | 20 | fifteenMinuteEMALength |
Each length is an input, so you can change it from the study's settings window without opening the code. The indicator is for anyone who wants to fit more information on one screen instead of keeping several chart windows open.
Aggregation Periods and the Time Frame Limit
An aggregation period is ThinkOrSwim's term for a time frame. Every line in this indicator reads its prices from an aggregation period that can differ from the chart's. Our earlier tutorial on plotting a daily indicator on an intraday chart covers the same idea with a 50-day simple moving average.
There are three things to know before writing any code, and all three come from one ThinkOrSwim limit.
- A chart can only read time frames greater than or equal to its own. On a 5-minute chart you can't access 1-minute candles, so you can't plot a 1-minute moving average either. Nothing smaller than 5 minutes is available on a 5-minute chart.
- The code needs if/else blocks. On a 30-minute chart, I'd want to see the daily, 1-hour and 30-minute lines. Without if/else blocks, the 15-minute line triggers an error, and ThinkOrSwim plots none of the four, even the three that are allowed.
- Start with the largest time frame. If a chart can't access daily data, it can't access the 1-hour, 30-minute or 15-minute data either. Checking from the top down means the code doesn't test time frames it knows it can't read.
How to Build the Indicator in ThinkOrSwim
The multiple time frame moving averages indicator is a regular ThinkOrSwim study, built in the study editor.
- Click the Studies icon on your chart, then click Create.
- Give the study a name. I called mine TI_multiple time frame moving averages.
- Paste in the code from the Code tab on this page, click OK, then Apply.
- Load a 5-minute or 15-minute chart to see all four lines.
The download has the same code as a .ts file. If you'd rather import it, our guide on how to import a study into ThinkOrSwim covers the steps.
How the Code Works
The multiple time frame moving averages code has three parts: the inputs, the plot declarations, and a chain of if/else blocks that give each plot a value. I built it in the video in the order below, including the mistake that made the if/else blocks necessary.
Step 1: The Inputs
This step’s code is free with an account. Create one or sign in.
Each length is an input variable, so it shows up in the study's settings window.
Step 2: The First Version, Without If/Else Blocks
My first version defined the four averages directly, as plots. Here it is with the names and calls the download uses. The key piece is the period parameter on close, which tells ThinkOrSwim which time frame's closing prices to use.
This step’s code is free with an account. Create one or sign in.
The daily line is a 10-period simple moving average of daily closes. The other three use the exponential average function with the 1-hour, 30-minute and 15-minute closes.
On a 5-minute chart, all four lines plotted. On a 15-minute chart, all four still plotted, and the 15-minute line smoothed out a little because it was on its own time frame. On a 30-minute chart, every line disappeared.
The error in the top left of the chart said the secondary period cannot be less than the primary. The study was asking for 15-minute data, the secondary period, on a 30-minute chart, the primary period.
Step 3: Declare the Plots Without Values
This step’s code is free with an account. Create one or sign in.
Each plot is declared with a semicolon and no value. Each one gets its value inside the if/else blocks, depending on the chart's time frame. ThinkOrSwim flags the four variables as already used until you delete the four lines from Step 2.
Step 4: The If/Else Blocks
getAggregationPeriod() returns the time frame of the chart the study is on. The first block covers charts above 1 hour and below 2 days, where only the daily data is accessible.
This step’s code is free with an account. Create one or sign in.
Double.nan means "not a number", so a plot set to it draws nothing. The daily SMA gets a value, and the other three stay blank.
The next three blocks open with these checks. Each one adds one more line, and the fourth block, for 15-minute and smaller charts, is the only one that gives all four plots a value.
This step’s code is free with an account. Create one or sign in.
The last block is the fallback. If none of the checks match, all four plots are set to Double.nan, so the study shows nothing and no error icon appears. In the download's code, only a chart between 15 and 30 minutes, such as 20 minutes, reaches this block.
Weekly, 2-day and other charts larger than a day never reach the fallback. They pass the second check, greater than or equal to 1 hour, which asks for daily and 1-hour data. That data is smaller than the chart's own time frame, so those charts hit the secondary period limit and nothing plots.
Step 5: The Bug on the 5-Minute Chart
With the if/else blocks in place, the 30-minute, 15-minute and daily charts worked, but a 5-minute chart showed zero moving averages. At that point the fourth block checked for a time frame greater than or equal to 15 minutes.
A 5-minute chart failed every check: it isn't above 1 hour, it isn't 30 minutes or more, and it isn't 15 minutes or more. Changing the last check to less than or equal to 15 minutes fixed it, because 1, 2, 3 and 5-minute charts can all read 15-minute data. The download has the fixed version.
Which Lines Plot on Each Time Frame
The multiple time frame moving averages indicator shows a different number of lines depending on the chart's time frame. This table follows the if/else blocks in the download.
| Chart time frame | Daily SMA | 1-hour EMA | 30-minute EMA | 15-minute EMA |
|---|---|---|---|---|
| 15 minutes and smaller | Yes | Yes | Yes | Yes |
| 30 minutes | Yes | Yes | Yes | No |
| 1 hour | Yes | Yes | No | No |
| Above 1 hour, up to daily | Yes | No | No | No |
| 2 days and larger | No | No | No | No |
A time frame between 15 and 30 minutes, such as 20 minutes, matches none of the blocks in the download, so the fallback block runs and nothing plots. On 2-day and larger charts, the 1-hour block matches and asks for data smaller than the chart's own time frame, so nothing plots there either.
Checking the Values on Johnson & Johnson
The Johnson & Johnson chart in the video is how I checked the finished code. I removed my drawings so only the moving averages showed, then stepped through the time frames.
- 30-minute chart. Three moving averages plotted: the 30-minute, the 1-hour and the daily. That's what the code should do.
- Daily value. The daily SMA read 165.23, on its line and its price bubble. In the study settings, the daily line was the cyan one.
- Daily chart. Switching to a daily chart showed the same 165.23, so the daily line on the intraday chart was reading the right data.
- 15-minute chart. All four moving averages plotted.
- 5-minute chart. Zero moving averages plotted, which led to the bug fix in Step 5.
Run the same check on your own symbol. Load a daily chart next to your intraday chart and compare the daily SMA's value on both. If they match, the study is reading the daily closes correctly.
How I Use It
The multiple time frame moving averages indicator is about fitting more information on one screen. One intraday chart shows where price sits against the daily, 1-hour, 30-minute and 15-minute averages, so you don't need a window open for each time frame.
The lines show you where those averages are. They don't tell you where to enter or exit. Before you trade off any of them, decide where your stop goes and size the position so a stop-out costs a small, fixed share of your account.
For a different view of the same idea, our stacked moving averages indicator plots the 8, 21 and 34 EMAs with the 50 and 200 SMAs on one time frame and marks when they stack in order. To test how a pair of averages has traded, our moving average crossover backtester totals the profit and loss of every crossover on a chart.
Ways to Customize It
The multiple time frame moving averages code is a template you can change in a few places.
- Colors. Change each line's color in the Plots section of the study's settings.
- Lengths. Change the 4 inputs in the settings window.
- 20-minute charts. To get the daily, 1-hour and 30-minute lines on a 20-minute chart, change the third check to
getAggregationPeriod() > AggregationPeriod.Fifteen_Min. A 15-minute chart still reaches the fourth check, less than or equal to 15 minutes, and keeps all four lines. - Types. I started with an SMA and three EMAs. You could swap in a Hull or another moving average by replacing the average function in each block.
- Other indicators. The same if/else structure works for any study you want to read from a larger time frame. Our multi-time frame Squeeze indicator is another example of a multi-time frame tool.
- A shaded version. If you want two averages on one time frame with the space between them colored, see our moving average clouds indicator.
More examples of these thinkScript concepts are on our tutorials page. Most of the tutorials there are free.
Common Problems
The multiple time frame moving averages indicator has four problems people run into. The download fixes the first three, and the fourth is how the finished code handles some time frames.
- All the lines disappear and an exclamation icon shows in the top left. The code is reading a time frame smaller than the chart's. Use the if/else version from the download.
- An error that the variables are already used. You declared the plots with a semicolon but left the original four definitions in place. Delete them.
- No lines on a 5-minute chart. The fourth block checks for greater than or equal to 15 minutes. Change it to less than or equal to.
- No lines on a 20-minute, 2-day or weekly chart. A 20-minute chart matches none of the blocks, so the fallback plots nothing. Charts of 2 days or more match the 1-hour block, which asks for daily and 1-hour data those charts can't read. Use the indicator on charts from 1 minute to daily. Our guide on how to fix bugs in thinkScript code covers tracking down issues like these.
The four lines on real charts
Drawn from real intraday bars with the code on this page, through the Oct 20, 2026 close. The post's goal was one 5-minute chart that carries the daily 10 SMA, the 1-hour 50 EMA, the 30-minute 30 EMA and the 15-minute 20 EMA. On past bars ThinkOrSwim gives each 5-minute bar the value of the higher-timeframe bar it belongs to, so each line steps once per day, hour, half hour or 15 minutes. Hourly bars here are built from 30-minute bars starting at 9:30.
SPY over five sessions

At the Oct 20, 2026 close SPY was at $769.01: the daily 10 SMA sat at $772.59, the 1-hour 50 EMA at $770.22, the 30-minute 30 EMA at $768.71 and the 15-minute 20 EMA at $768.88. Price closed above the 30-minute 30 EMA and 15-minute 20 EMA, and below the daily 10 SMA and 1-hour 50 EMA.
Oct 14: a test of the daily line

At 9:35 on Oct 14, SPY's 5-minute low of $774.54 reached the daily 10 SMA at $774.90, and the bar closed back above it at $775.58. The day's lowest price after that bar was $766.71, and SPY closed the session at $769.62, below the line. Held or broken, the test was on the 5-minute chart where you trade it, with no second chart to check.
Full thinkScript code
Create a free account or sign in to copy all 46 lines and download the file.
Download
Download the Multiple Time Frame Moving Averages indicator for ThinkOrSwim. The download is a .zip with one study file, TI_MultipleTimeFrame_MovingAveragesSTUDY.ts, the same code as the Code tab on this page, including the fix for 5-minute and smaller charts. Import it as a study, then open its settings to change the 4 lengths. If you haven't imported a study before, here's how to import into your ThinkOrSwim platform.
Video: Multiple Time Frame Moving Averages, built line by line
22 minutes on YouTube.
Watch on YouTube
Questions
How do I plot a daily moving average on an intraday chart in ThinkOrSwim?
Pass the daily closes into the average with the period parameter. In this indicator, SimpleMovingAvg(close(period = "Day"), dailySMALength) calculates a 10-period simple moving average of daily closes, and it plots on intraday charts. The chart can only read time frames greater than or equal to its own, so a daily average works on any intraday chart.
What is an aggregation period in thinkScript?
Aggregation period is ThinkOrSwim's term for a time frame. getAggregationPeriod() returns the time frame of the chart a study is on, and constants such as AggregationPeriod.Hour and AggregationPeriod.Thirty_Min let you compare it to a fixed time frame. The period parameter on close, such as period = "Day", reads prices from another time frame.
Why did my moving averages disappear on a 30-minute chart?
The study is asking for data from a time frame smaller than the chart's, such as a 15-minute average on a 30-minute chart. ThinkOrSwim shows an error that the secondary period cannot be less than the primary, and it plots none of the lines. Wrap each line in if/else blocks so it only gets a value where its data is allowed.
Which moving averages does the multiple time frame indicator plot?
By default it plots a 10-period simple moving average from the daily chart, a 50-period EMA from the 1-hour chart, a 30-period EMA from the 30-minute chart and a 20-period EMA from the 15-minute chart. All four lengths are inputs you can change in the study's settings window.
How many lines will I see on each time frame?
All 4 lines plot on 15-minute and smaller charts. A 30-minute chart shows 3: the daily, 1-hour and 30-minute averages. A 1-hour chart shows the daily and 1-hour averages. Above 1 hour, up to the daily chart, only the daily SMA plots, and on 2-day and larger charts the study shows nothing.
What does Double.NaN do in thinkScript?
Double.NaN means not a number, and a plot set to it draws nothing. This indicator sets every line the chart can't access to Double.NaN, so those lines stay blank instead of breaking the study. The fallback block sets all four plots to Double.NaN when no time frame check matches.
Why does the indicator show no lines on my chart?
Check the time frame. On a 20-minute chart, none of the if/else blocks match, so the fallback plots nothing. On 2-day, weekly and larger charts, the 1-hour block asks for daily and 1-hour data those charts can't read, so nothing plots there either. If you typed the code yourself and see no lines on a 5-minute chart, change the last check to less than or equal to 15 minutes.
Can I change the moving average types or colors?
Yes. Change each line's color in the Plots section of the study's settings, and change the 4 lengths there too. To change a type, replace the average function in each block where that line is defined. In the video I suggest trying a Hull moving average or applying the same structure to a different indicator.
Get each new indicator by email
One email on Sundays with the week's new tool and its code. A free account also unlocks every .txt download.
No credit card. Unsubscribe anytime.
Fair Value Gap
False Breakout Scanner
Heiken Ashi Trend



Stock Volatility Box
Futures Volatility Box
ORB Setups
Squeeze Setups
Reversion to 50-Day Moving Average
Moving Average Crossover Backtester
Moving Average Pullback Backtester
Stacked Moving Averages
Moving Average Clouds
Price to Book Value Calculator