On this page
Overview
In this tutorial I build a multi-timeframe DMI indicator for ThinkOrSwim, starting from the built-in DMI study. It reads DI+, DI- and ADX on 17 timeframes, from 1 minute to monthly, and shows each one as a green, red or yellow label on your chart. The candles take the same colors for the timeframe you are on.
I made it for momentum and breakout traders who want to catch fast, directional moves. The video is the raw build with the typos and bugs left in, so you can see how I read the ThinkOrSwim documentation, debug the code and copy one timeframe's block to every other timeframe.
Key Takeaways
- The MTF DMI indicator for ThinkOrSwim shows the DMI zone of 17 timeframes on one chart, as labels from M (monthly) down to 1m (1 minute).
- A timeframe is bullish (green) when DI+ is above DI- and ADX is at or above 20, bearish (red) when DI+ is below DI- and ADX is at or above 20, and neutral (yellow) otherwise.
- ThinkOrSwim's DMI documentation uses an ADX above 50 as confirmation, but in the video ADX didn't reach 50 on the SPY chart and capped out at 42 on Home Depot. The download's ADXLevels input defaults to 20, the middle of the 15 to 25 range members suggested.
- The built-in DMI() function has no price input, so it can't read another timeframe. The code rebuilds DI+, DI- and ADX from each timeframe's highs and lows, using code credited to Hubert Senters and Pete Hahn.
- The download is version 2 of the study, updated in November 2019, with 4 inputs: coloredCandlesOn (yes), length (14), ADXLevels (20) and averageType (Wilder's).
What Is the DMI Indicator?
The DMI (Directional Movement Index) is a trend-following study built into ThinkOrSwim with three plots: DI+, DI- and ADX. I started the build by reading ThinkOrSwim's documentation for it, which sums up the signals in one paragraph:
- DI+ crossing above DI- suggests uptrend conditions.
- DI+ crossing below DI- might signify a downtrend.
- ADX is used for confirmation. Trend readings are more likely to be correct when ADX is rising and above 50.
The study takes 2 inputs, a length and an average type. I set them to 14 and Wilder's average, and those stay the defaults in the finished indicator.
The math is short once you see it in code. DI+ comes from up moves: when a bar's high minus the previous high is bigger than the previous low minus this low, that difference counts as plus directional movement. DI- is the mirror image for down moves. ADX averages the gap between the two lines as a share of their total, so it measures trend strength without regard to direction.
The 50 level didn't hold up on real charts. In the video, ADX didn't get to 50 on the SPY chart I tested, and Home Depot capped out at 42, so a rule that waited for ADX above 50 returned zero signals.
I built the MTF DMI after talks with a Volatility Box member about our Dynamic RSI indicator. Its candles suit patient overbought and oversold trading, but they can be too slow for breakout traders. For traders who want to get ahead of fast moves in one direction, the DMI is the go-to tool we found.
What the MTF DMI Indicator Shows
The MTF DMI indicator adds two things to a ThinkOrSwim chart: a row of timeframe labels and colored candles. Every timeframe sits in one of three zones, and the zone sets the color:
| Zone | Condition in the download | Label and candle color |
|---|---|---|
| Bullish | DI+ above DI- and ADX at or above ADXLevels (20) | Green |
| Bearish | DI+ below DI- and ADX at or above ADXLevels (20) | Red |
| Neutral | Neither of the above: ADX below 20, or DI+ equal to DI- | Yellow |
The 17 labels are M, W, 4D, 3D, 2D, D, 4H, 2H, 1H, 30m, 15m, 10m, 5m, 4m, 3m, 2m and 1m. Each one shows only when your chart's timeframe is the same or lower. On a 5-minute chart you see 5m and everything above it, and never the 1m to 4m labels. In the video, moving from a 3-minute chart to a 4-minute chart made the 3m label slide off.
The candles always use the chart's own timeframe. On that 3-minute chart the current candle was yellow, and on the 4-minute chart it turned green, matching the 4m label.
How to Add the MTF DMI to ThinkOrSwim
- Download the zip from this page and unzip it. Inside is one study file,
TI_MTF_DMISTUDY.ts. - Import the file as a study. Our guide on how to import a study into ThinkOrSwim walks through each click.
- To build it by hand instead, click the Studies icon on a chart, choose Create, name the study (I used TI_MTF_DMI), paste in the code from the Code tab, and click OK.
- Add the study to a chart. When you change symbols, the labels take a few seconds to fill in.
- Open the study's settings to change any of the 4 inputs below.
MTF DMI Settings
The MTF DMI study has 4 inputs, and each one applies to all 17 timeframes at once.
| Input | Default | What it does |
|---|---|---|
| coloredCandlesOn | yes | Colors the candles green, red or yellow by the DMI zone of the chart's timeframe. Set it to no to keep your normal candles. The labels stay either way. |
| length | 14 | Number of bars in the averages behind DI+, DI- and ADX, on every timeframe. |
| ADXLevels | 20 | ADX must be at or above this level for a green or red zone. Below it, the timeframe is yellow. |
| averageType | WILDERS | The moving average used to smooth the directional movement and the ADX. |
This step’s code is free with an account. Create one or sign in.
ADXLevels came from member feedback after the first release. Members who trade with the DMI use ADX levels from 15 to 25, so 20 sits in the middle as the default. Lower it and more timeframes turn green or red. Raise it and you get fewer, stronger zones.
How the MTF DMI Code Works
The MTF DMI code does one job per timeframe: it calculates DI+, DI- and ADX on that timeframe's bars, sorts the result into a zone, and prints a label. These steps follow the video.
Step 1: Read the Built-In DMI
I started with the built-in study. The first try at reading DI+ failed with an invalid statement error, because the plot names contain a plus and a minus sign. A community thinkScript example showed the fix: wrap those two names in quotes.
This step’s code is free with an account. Create one or sign in.
Step 2: Turn Crossovers Into Zones
A crossover is true on one bar only, which suits an arrow. Colored candles need a zone, a condition that stays true for as long as one line is above the other.
This step’s code is free with an account. Create one or sign in.
My first test colored candles by these zones. It worked for the most part but left islands: single candles of one color surrounded by another color.
Step 3: Rebuild the DMI for Each Timeframe
The first labels came out wrong. With the built-in DMI(), the monthly label on a daily chart showed red, while the monthly chart itself was yellow: the label was reading the daily DMI. DMI() has no price input, so there is no way to point it at monthly bars.
The fix is to calculate the DMI by hand from each timeframe's highs and lows. I used code by Hubert Senters and Pete Hahn, credited in the header. The monthly block in the download starts with the directional movement:
This step’s code is free with an account. Create one or sign in.
monthHiDiff is this month's high minus last month's. Whichever difference is larger, and above 0, counts.
This step’s code is free with an account. Create one or sign in.
Those averages, times 100, are the plus and minus lines.
This step’s code is free with an account. Create one or sign in.
DX is the gap between the lines as a percentage of their sum, and ADX is its average.
This step’s code is free with an account. Create one or sign in.
The zones close out the block.
Step 4: Check the Chart's Aggregation Period
The aggregation check is the module I first wrote for a multi-timeframe Squeeze, and our free MTF Squeeze indicator uses the same framework. Every variable is declared with def and no value above the if, gets its value inside the if, and is set to 0 in the else.
This step’s code is free with an account. Create one or sign in.
The else block sets each one to 0:
This step’s code is free with an account. Create one or sign in.
GetAggregationPeriod() returns the chart's timeframe. If it is a month or less, the monthly math runs. If not, every monthly value is 0 and no monthly label shows. Our tutorial on aggregation periods shows how to plot a higher-timeframe indicator on a lower-timeframe chart.
Once the monthly block worked, I copied it and used find-and-replace to turn month into week, then into each other timeframe. That works because every variable name starts with its timeframe. The copy-pasting took over 15 minutes, and the study ran to about 1,100 lines.
Step 5: Add the Labels
This step’s code is free with an account. Create one or sign in.
Each timeframe gets 3 AddLabel calls, one per zone, so only the active zone's label appears. In the video I wrote one label with nested colors, which needed a final else (gray) to compile. The download split it into 3 calls on 11/20/19 to keep the label logic from confusing ThinkOrSwim. Our AddLabel tutorial covers the function in more detail.
Step 6: Color the Candles for the Chart's Timeframe
The last block repeats the math with no period, so it runs on the chart's own bars. I made it by copying the monthly block and removing the word month and every period reference. Its zones feed one line:
This step’s code is free with an account. Create one or sign in.
AssignPriceColor checks coloredCandlesOn on every branch. When the input is no, it returns Color.CURRENT and your candles keep their normal colors. Neutral is checked first, then bullish, then bearish.
The Video Build vs the Download
The MTF DMI download is version 2 of the study, not the exact code typed in the video. The update notes in its header are dated 11/14/19 to 11/21/19, and the follow-up DMI Power Move scans video walks through the changes, which came from member feedback.
| Part of the code | Video build (version 1) | Download (version 2) |
|---|---|---|
| Bullish and bearish zones | DI+ above or below DI-, with no ADX condition | DI+ above or below DI-, and ADX at or above ADXLevels |
| Yellow candles | When DI+ and DI- are less than 10 points apart (narrow-range test) | When ADX is below ADXLevels or DI+ equals DI-; narrow-range test removed |
| ADX input | None | ADXLevels, default 20 (renamed from ADXLength on 11/21/19) |
| Plus and minus lines | Average of directional movement divided by ATR, as in the Senters and Hahn code | Average of directional movement, no ATR |
| Labels | One AddLabel per timeframe with nested colors | 3 AddLabel calls per timeframe, one per zone |
| Arrows | Planned, left out for time | Not added; the crossovers are calculated but not plotted |
The narrow-range test took 6 lines per timeframe block, and removing it made version 2 noticeably faster.
Reading the version 2 code, dropping the ATR doesn't change the zones. In the video build, both lines were divided by the same ATR on each bar, so the same line stays on top, and the ATR cancels out of the DX ratio, so ADX comes out the same. Only the raw plus and minus values change scale, and the study doesn't plot them.
Examples From the Video
The MTF DMI examples below are from the day I recorded, so your charts will look different.
- SPY, first colored candles. With zones only, the chart showed a few islands, including a fake bullish reversal.
- The narrow-range threshold. At the false signals I checked on a 5-minute chart and then the daily chart, DI+ and DI- looked to be under 10 points apart. I tried 10 as a starting cutoff and turned candles yellow below it.
- CGC. Candles went from red to yellow. Where I argued the breakout should have turned a candle green, the gap between the lines looked close to the 10-point cutoff, so I let it slide.
- ADX above DI+. On the same chart, one false short came with the ADX line above DI+. Another stretch with ADX above DI+ was a good short, so I didn't turn it into a rule.
- Checking the weekly label. The W label read red, and the plain DMI on a weekly chart confirmed it.
- SPY on a 3-minute chart. Most labels were neutral, with the 1-hour bearish.
How I Read the MTF DMI Labels
The MTF DMI labels show how well the timeframes agree. I look for as many solid colors as I can get, and all green or all red if I want to trade a direction. A mix of colors means the timeframes disagree.
Islands still happen, so I treat the labels and candles as a read on the trend and check price action and levels before acting. Decide where your stop goes before you enter, and size the trade so a stop-out costs a small, fixed share of your account.
If you want ThinkOrSwim to find these setups for you, our DMI Power Move scans use the same zones: a bullish daily chart, a pullback on the 4-hour to 1-hour charts, and a turn back up on a shorter chart.
Common Problems and Fixes
- Invalid statement on DI+ or DI-. Put the plot name in quotes:
DMI(length, averageType)."DI+". - A higher-timeframe label matches your chart. The built-in DMI() always reads the chart's timeframe. Use the manual calculation with
high(period = ...)andlow(period = ...). - "Else block expected". A nested if/else color needs a final
else. - Charts load slowly. Version 2 is faster than the first release. To speed it up more, delete timeframes you don't use, such as the 2-hour, or split the code into smaller copies.
For a general approach to errors like these, see our tutorial on how to fix bugs in thinkScript code.
Using the Framework for Other Indicators
The MTF framework in this study works with other indicators, such as a moving average crossover, as long as the calculation can read each timeframe's prices with period. That is why the DMI had to be rebuilt by hand. Copy the if/else pattern, prefix every name with its timeframe, and let find-and-replace build the rest. You'll find more free studies on our indicators page.
The MTF DMI on real charts
Drawn from real intraday bars with the code on this page, through the Oct 20, 2026 close. Each label runs the post's DMI code on its own timeframe: green when DI+ is above DI- and ADX is at or above 20, red when DI+ is below DI- with ADX at or above 20, yellow otherwise. Hourly and longer intraday bars are built from 30-minute bars starting at 9:30; 10-minute bars from 5-minute bars. Gray labels are timeframes not in our data: 4D, 3D, 2D and 1 to 4 minutes, and the monthly on single stocks, whose daily history in our data starts in mid-2024. Candles take the daily chart's zone color.
XLE: the most green labels on Oct 20

Of 44 stocks and ETFs, XLE had the most timeframes in a bullish zone at the Oct 20, 2026 close: 8 of 10. Yellow on 15m and 10m.
NFLX: the most red labels

NFLX had the most timeframes in a bearish zone: 8 of the 9 shown. Labels that disagree are useful too: a green daily over red hourly charts is the pullback the DMI Power Move scans look for.
By the numbers
Daily bars for the same 44 stocks and ETFs, September 2024 to October 2026. A turn is the first green candle after one that was not green. The gap between 55.8% and 53.5% is small for 538 turns: the color describes the trend you are in more than it calls the next two weeks.
Full thinkScript code
Create a free account or sign in to copy all 1076 lines and download the file.
Download
Download the Multi-Timeframe DMI indicator for ThinkOrSwim. The download is a .zip with one study file, TI_MTF_DMISTUDY.ts. It is version 2 of the indicator, the same code as the Code tab on this page, with 17 timeframe labels, colored candles and an ADXLevels input set to 20. If you haven't added a custom study before, here's how to import an indicator into your ThinkOrSwim platform.
Questions
What is the DMI indicator in ThinkOrSwim?
The DMI, or Directional Movement Index, is a built-in ThinkOrSwim study with three plots: DI+, DI- and ADX. DI+ crossing above DI- suggests an uptrend, DI+ crossing below DI- suggests a downtrend, and ADX confirms the trend. It takes two inputs, a length and an average type, which I set to 14 and Wilder's.
How do I add a multi-timeframe DMI to ThinkOrSwim?
Download the zip from this page, unzip it, and import TI_MTF_DMISTUDY.ts as a study. Or click the Studies icon, choose Create, paste in the code from the Code tab and click OK. Add the study to a chart, and the timeframe labels fill in within a few seconds.
What do the green, red and yellow colors mean on the MTF DMI?
Green means DI+ is above DI- and ADX is at or above 20, a bullish zone. Red means DI+ is below DI- with ADX at or above 20, a bearish zone. Yellow is neutral: ADX is under 20, so neither zone applies. Labels show the zone for each timeframe, and the candles show it for the chart's own timeframe.
Why does the MTF DMI use an ADX of 20 instead of 50?
ThinkOrSwim's documentation says trends are more likely to be correct when ADX is above 50, but in the video ADX almost never got there. It stayed under 50 on SPY and capped out at 42 on Home Depot, so a 50 rule gave no signals. Members who use the DMI suggested 15 to 25, and 20 is the default.
Which timeframes does the MTF DMI show?
It covers 17: monthly, weekly, 4-day, 3-day, 2-day, daily, 4-hour, 2-hour, 1-hour, and 30, 15, 10, 5, 4, 3, 2 and 1 minute. You see the label for your chart's timeframe and every higher one. A 1-minute chart shows all 17, and a daily chart shows D, 2D, 3D, 4D, W and M.
How do I reference DI+ and DI- in thinkScript?
Put the plot names in quotes, because they contain a plus and a minus sign. Write DMI(length, averageType)."DI+" and DMI(length, averageType)."DI-". Without the quotes, ThinkOrSwim reports an invalid statement. ADX needs no quotes: DMI(length, averageType).ADX works as written. In the video, I found the fix in a community code example after my first try failed.
Why is the MTF DMI slow on my computer?
It calculates the DMI for up to 17 timeframes in about 1,100 lines of code. The first version slowed down even a machine with 32 GB of RAM, so version 2 dropped the narrow-range test to cut calculations. To speed it up more, delete timeframes you don't use, such as the 2-hour, or split the code into smaller copies.
How is the MTF DMI different from the built-in DMI?
The built-in DMI plots three lines for one timeframe. The MTF DMI turns those lines into a zone, bullish, bearish or neutral, for 17 timeframes at once, and shows them as labels and colored candles. It recalculates the DMI from each timeframe's highs and lows because the built-in study can't read another timeframe.
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
DMI Power Move Scans
Wilder's Momentum Concept
Dynamic RSI
Smarter Earnings
Advanced Volume Zone Oscillator
Simple Breakout Tool