Skip to main contentSkip to content
Squeeze Setups A live squeeze scanner built around the Slingshot Squeeze, with 22 years of backtest results behind it. See it, $99/month →
TOS Indicators
  • Tools

    Categories

    • Indicators
    • Backtesters
    • Scans
    • Dashboards
    • thinkScript
    • Member Resources
    Browse Full Library

    Featured Tutorials

    Fair Value Gap Indicator
    Fair Value Gap Indicator
    Indicators

    Download our free Fair Value Gap indicator for ThinkorSwim. It shades every...

    Learn more →
    False Breakout Scanner for ThinkorSwim (Free Scan Pair)
    False Breakout Scanner for ThinkorSwim (Free Scan Pair)
    Scans

    A two-scan pair that flags failed breakouts and failed breakdowns with volume...

    Learn more →
    Heiken Ashi Trend Indicator
    Heiken Ashi Trend Indicator
    Indicators

    Download our Custom Heiken Ashi indicator for ThinkOrSwim. Full ThinkScript code, formula...

    Learn more →

    Popular Posts

    Unusual Volume Pro Scans
    Unusual Volume Pro Scans
    Scans

    4 additional scans to find unusual volume overlapping with key...

    Learn more →
    High Short Interest Near 52 Week Highs (thinkScript)
    High Short Interest Near 52 Week Highs (thinkScript)
    Scans

    Build a simple scan in which to find stocks that...

    Learn more →
    Upcoming Earnings with High Short Interest
    Upcoming Earnings with High Short Interest
    Scans

    Build a scan to find stocks that are likely to...

    Learn more →
  • Courses
    Squeeze Course
    Squeeze Course
    19 Modules

    Scan, backtest, and trade the TTM Squeeze setup with precision.

    View Course →
    Earnings Course
    Earnings Course
    3 Modules

    Master earnings plays with free indicators and proven strategies for ThinkOrSwim.

    View Course →
    V-Shaped Reversals
    V-Shaped Reversals
    7 Modules

    Identify and trade powerful V-shaped reversal patterns with confidence and precision.

    View Course →
    Fibonacci Trading
    Fibonacci Trading
    4 Modules

    Learn to trade Fibonacci retracements and extensions in ThinkOrSwim effectively.

    View Course →
  • Products
    Futures Volatility Box Premium
    Futures Volatility Box

    Volatility models for 10 major futures markets, including the micros.

    Explore Futures VB →
    Stock Volatility Box Premium
    Stock Volatility Box

    Volatility levels for 600+ stocks and ETFs, with a live scanner.

    Explore Stock VB →
    Opening Range Breakouts Premium
    Opening Range Breakouts

    Scans 600+ stocks every 2 seconds for opening range breaks, with a backtester.

    Explore ORB Setups →
My Account
All Indicators
Beginner 24 minutes ThinkOrSwim

Rate of Change Indicator for ThinkorSwim With RSI Signals

A free rate of change indicator for ThinkorSwim that marks the ROC's extreme zones and plots arrows when it turns there with an RSI breakout signal.

Download Indicator
How to install in ThinkOrSwim →
Table of Contents
  • Key Takeaways
  • What Is the Rate of Change Indicator?
  • What Our Rate of Change Indicator Plots
  • The Idea: An Extreme ROC Plus an RSI Breakout
  • How to Add the Rate of Change Indicator to ThinkorSwim
  • How the Rate of Change Code Works
  • Rate of Change Settings
  • Why the Lines Depend on Your Chart’s History
  • What the Indicator Showed in the Video
  • How to Read the Rate of Change Arrows

In this tutorial I build a rate of change indicator for ThinkorSwim, starting from the built-in Rate of Change study. I turn the ROC into a range-bound oscillator: one line at its highest value on the chart, one at its lowest, and a dashed line halfway to each, so you can see when the ROC is in an extreme zone.

Then I add a green arrow when the ROC turns up in the lower zone on the same bar the built-in RSI fires its bullish breakout signal, and a red arrow for the bearish side. The video is unrehearsed, bugs and chart bubble tests included, so it doubles as a lesson in turning an idea into thinkScript for anyone who wants to make a built-in study smarter.

Key Takeaways

  • Our Rate of Change indicator starts from ThinkorSwim’s built-in ROC study: the percent change between the close and the close 14 bars ago.
  • It draws the highest and lowest ROC on the chart as solid red and green lines, using HighestAll and LowestAll, and the halfway point between each line and zero as a dashed line.
  • The upper extreme zone is the space between the upper dashed line and the red line. The lower extreme zone is the space between the lower dashed line and the green line.
  • A green up arrow plots when the ROC is in the lower zone, higher than on the previous bar, and the RSI crosses above its oversold line on the same bar. The red down arrow mirrors it in the upper zone with the RSI crossing below overbought.
  • I built it on a daily Amazon chart and checked it on a 5-minute chart. Our rate of change scans turn the same code into 4 ThinkorSwim scans.

What Is the Rate of Change Indicator?

The rate of change (ROC) indicator measures how far price has moved, in percent, over a set number of bars. The textbook formula is the close minus the close n bars ago, divided by the close n bars ago, times 100. A reading of 5 means price is 5% higher than n bars ago, and -5 means it is 5% lower.

ThinkorSwim’s built-in Rate of Change study uses 14 bars by default and writes the same formula as (price / price[length] - 1) * 100. It plots the ROC around a zero line and shades it from light red near its recent lows to yellow near its recent highs.

The ROC has no fixed upper limit. The RSI stays between 0 and 100, but a ROC reading that is extreme on one chart can be ordinary on another, so the raw number doesn’t tell you whether a reading is extreme for that chart. That’s the gap this indicator fills.

What Our Rate of Change Indicator Plots

Our rate of change indicator keeps the built-in ROC line and zero line. The table shows the 4 lines and 2 arrows it adds:

Plot Code Look What it marks
highestROC HighestAll(ROC) Solid red, weight 3 The highest ROC on the chart
lowestROC LowestAll(ROC) Solid green, weight 3 The lowest ROC on the chart
midPtHighestROC highestROC/2 Dashed light red, weight 1 The start of the upper extreme zone
midPtLowestROC lowestROC/2 Dashed light green, weight 1 The start of the lower extreme zone
bullSignal ROC turns up in the lower zone and the RSI fires UpSignal Green up arrow, weight 3 Bullish signal
bearSignal ROC turns down in the upper zone and the RSI fires DownSignal Red down arrow, weight 3 Bearish signal

The Idea: An Extreme ROC Plus an RSI Breakout

The rate of change idea started on a daily chart of Amazon, with the built-in ROC in the first lower panel and the built-in RSI in the second.

The plan had 2 parts. First, turn the ROC into a range-bound oscillator by marking its high and low, then split the distance from zero to each in half and call the outer halves extreme. Second, flag the bars where the RSI gives a breakout signal while the ROC sits in an extreme zone.

I marked 4 examples on that Amazon chart before writing any code:

  • Bullish. The RSI gave its breakout signal while the ROC was in the lower extreme zone, and price rallied from there.
  • Bearish. The RSI gave a bearish breakout signal with the ROC in the upper extreme zone, and price pulled back a little.
  • Bullish. The same setup on the lower side, followed by a small bounce.
  • Bullish. During an Amazon relief rally shortly before the video, the ROC was well inside the lower extreme zone when the RSI signals came.

In plain terms, a bullish signal says the ROC is slowing down. It is moving from a negative reading toward a positive one, or at least falling less quickly, while the RSI says price is moving up out of oversold territory.

Before coding, I said up front that I had no idea whether this indicator would give an edge. The video is about the process of turning an idea into code, and I wanted it to work on any timeframe.

How to Add the Rate of Change Indicator to ThinkorSwim

The rate of change indicator installs as one study in a lower panel:

  1. Download the zip from this page. Inside is one study file, TI_ROCSTUDY.ts.
  2. Import it as a study. Our guide on how to import a study into ThinkorSwim walks through each click.
  3. Add it to a chart. It opens in a lower panel.
  4. To build it yourself, click the Studies icon and search for the built-in Rate of Change study. Click the scroll icon with the lock next to it, copy all of its code, then click Create, delete anything in the code field and paste. I named mine TI_ROC.

How the Rate of Change Code Works

The rate of change code adds range lines, extreme zones and signals to ThinkorSwim’s built-in ROC, one block at a time. I tested each block before moving to the next, often with a chart bubble, which is a good habit when you build your own studies.

Step 1: The Range Lines

plot highestROC = HighestAll(ROC);
plot lowestROC = LowestAll(ROC);

HighestAll and LowestAll return the highest and lowest ROC across every bar loaded on the chart. They give the ROC a top and a bottom, so it reads like a range-bound oscillator.

Step 2: The Halfway Lines

plot midPtHighestROC = highestROC/2;
plot midPtLowestROC = lowestROC/2;

Each dashed line sits halfway between zero and the highest or lowest ROC. The full formula is the highest ROC minus 0, divided by 2, so the code skips the minus zero. The space between a dashed line and its solid line is the extreme zone.

Step 3: Formatting

highestROC.setLineWeight(3);
highestROC.setDefaultColor(Color.Red);
midPtHighestROC.setLineWeight(1);
midPtHighestROC.setStyle(Curve.Short_Dash);
midPtHighestROC.setDefaultColor(Color.light_red);

The outer lines are red and green at weight 3, and the halfway lines light red and light green, dashed, at weight 1. I set the colors in code so they stay the same on any platform setup.

Step 4: The Extreme Zones

def extremeHigh = ROC < HighestROC and ROC >= midPtHighestROC;
def extremeLow = ROC > LowestROC and ROC <= midPtLowestROC;

extremeHigh is true when the ROC is below the red line and at or above the upper dashed line. extremeLow is the mirror image. I used greater than or equal to and less than or equal to on the dashed lines so a reading right on the line counts.

To check extremeHigh, I added a temporary yellow chart bubble that printed only when it was true, then commented it out once the bubbles matched the zone.

Step 5: The RSI Breakout Signals

def RSIUpSignal = RSI().upSignal;
def RSIDownSignal = RSI().downSignal;

The RSI part doesn’t copy any RSI code. RSI() calls ThinkorSwim’s built-in RSI study, and the name after the dot picks one of its plots. UpSignal fires when the RSI crosses above its oversold line and DownSignal when it crosses below its overbought line.

To test it, I put a chart bubble on RSIUpSignal and loaded the RSI with its breakout signals set to yes. Every green RSI arrow had a bubble. The test line is still in the download, commented out:

#AddChartBubble(RSIUpSignal, ROC, RSIUpSignal, color.yellow);

Our Dynamic RSI indicator also calls the built-in RSI study instead of copying it, with reference RSI(RSI_Period), and builds Bollinger Bands on it.

Step 6: The ROC Turn

def ROCUpSignal = extremeLow and (ROC > ROC[1]);
def ROCDownSignal = extremeHigh and (ROC < ROC[1]);

ROCUpSignal is true when the ROC is in the lower extreme zone and higher than on the previous bar, so it has stopped falling and started to turn. ROCDownSignal is the mirror in the upper zone. While testing, I plotted each one as arrows on its own to confirm it.

Step 7: The Final Arrows

plot bullSignal = if ROCUpSignal and RSIUpSignal then ROC else double.nan;
plot bearSignal = if ROCDownSignal and RSIDownSignal then ROC else double.nan;
bullSignal.setPaintingStrategy(PaintingStrategy.Arrow_Up);

A signal needs both conditions on the same bar. The then ROC else double.nan part puts the arrow on the ROC line. Without it the arrows sit on the zero line, which is what happened on my first try.

Rate of Change Settings

The rate of change indicator has 3 inputs. Everything else sits in the code.

Setting Default What it does
length 14 How many bars back the ROC compares the close with.
colorNormLength 14 Bars used to shade the ROC line from light red to yellow. Colors only.
price close The price the ROC measures.
Halfway divisor (in the code) 2 Where the dashed lines sit between zero and the outer lines.
RSI settings (in the code) Built-in defaults RSI() with empty parentheses uses the built-in RSI’s own inputs, including its overbought and oversold lines.

Dividing by a larger number than 2 moves the dashed lines toward zero, so more bars count as extreme and more bars can produce arrows. In the video I mentioned a sensitivity factor as one way to improve the indicator.

One way to add it is to replace that 2 with an input. This edit is my suggestion and is not in the video or the download. Put the input line under the other inputs and replace the two midpoint lines:

input sensitivity = 2;
plot midPtHighestROC = highestROC / sensitivity;
plot midPtLowestROC = lowestROC / sensitivity;

With sensitivity at 2 the indicator plots exactly as the download does. Keep it above 1: at 1 or below, the dashed lines reach or pass the solid ones and the extreme zones disappear.

Why the Lines Depend on Your Chart’s History

HighestAll and LowestAll read every bar loaded on the chart, so the range lines depend on your chart’s time range. A 1-year daily chart and a 5-year daily chart of the same stock can draw different red and green lines, and so different extreme zones and arrows.

The lines also move when the ROC sets a new high or low, which can change which past bars count as extreme. Before you judge an old arrow, check the chart’s time range. Because extremeHigh needs the ROC below the red line, the one bar that sets the highest ROC never counts as extreme, and the same goes for the lowest.

Our rate of change scans show the same effect in the Scan tab. A 30-minute bearish signal on Apple appeared on the chart only after I cut the chart’s history from 90 days to 15 days.

What the Indicator Showed in the Video

The finished rate of change indicator plotted fewer arrows on the daily Amazon chart than my 4 planning examples. Two sets of signals showed up, both while the ROC was still in an extreme zone. My guess in the video was that in the earlier examples, the RSI signal and the ROC turn didn’t line up on the same bar.

On a 5-minute chart, the arrows plotted the way I expected. I loaded the RSI alongside to confirm each green arrow came with an RSI breakout signal and a rising ROC. At the end I pointed out that you can switch to another market, such as the S&P futures, and the indicator should keep plotting the same way.

One turn the indicator missed was a bearish one that came after the extreme edge had already been crossed. To catch it, the code would need context: remember that the extreme edge was crossed, then accept a turn lower just below it. I left that for a separate tutorial.

How to Read the Rate of Change Arrows

A rate of change arrow marks momentum turning at an extreme on the same bar the RSI breaks out. A bullish arrow says the ROC has stopped falling inside the lower zone while the RSI climbs out of oversold. In the planning examples, what followed ranged from a rally to a small bounce or a slight pullback, so not every arrow leads to a big move.

Treat an arrow as a read on momentum and check it against price levels before acting. Decide where your stop goes first, and size the position so a stop-out costs a small, fixed share of your account.

For more ways to work with momentum, our Smarter MACD starts from the built-in MACD code the same way, and if a change of your own throws an error, our guide on how to fix bugs in thinkScript code can help you track it down.

Rate of Change Indicator.ts
#
# TD Ameritrade IP Company, Inc. (c) 2007-2022
#

# Modified by TOS Indicators
#Home of the Volatility Box
#Indicator: Rate of Change x RSI
#Code written in 2022
#Full Tutorial: https://www.tosindicators.com/indicators/rate-of-change


declare lower;

input length = 14;
input colorNormLength = 14;
input price = close;

assert(length > 0, "'length' must be positive: " + length);

plot ROC = if price[length] != 0 then (price / price[length] - 1) * 100 else 0;
plot ZeroLine = 0;

ROC.DefineColor("Highest", Color.YELLOW);
ROC.DefineColor("Lowest", Color.LIGHT_RED);
ROC.AssignNormGradientColor(colorNormLength, ROC.color("Lowest"), ROC.color("Highest"));
ZeroLine.SetDefaultColor(GetColor(5));

plot highestROC = HighestAll(ROC);
plot lowestROC = LowestAll(ROC);

plot midPtHighestROC = highestROC/2;
plot midPtLowestROC = lowestROC/2;

highestROC.setLineWeight(3);
lowestROC.setLineWeight(3);
highestROC.setDefaultColor(Color.Red);
lowestROC.setDefaultColor(Color.Green);

midPtHighestROC.setLineWeight(1);
midPtLowestROC.setLineWeight(1);
midPtHighestROC.setStyle(Curve.Short_Dash);
midPtLowestROC.setStyle(Curve.Short_Dash);
midPtHighestROC.setDefaultColor(Color.light_red);
midPtLowestROC.setDefaultColor(Color.light_green);


def extremeHigh = ROC < HighestROC and ROC >= midPtHighestROC;
def extremeLow = ROC > LowestROC and ROC <= midPtLowestROC;

def RSIUpSignal = RSI().upSignal;
def RSIDownSignal = RSI().downSignal;

def ROCUpSignal = extremeLow and (ROC > ROC[1]);
def ROCDownSignal = extremeHigh and (ROC < ROC[1]);

plot bullSignal = if ROCUpSignal and RSIUpSignal then ROC else double.nan;
plot bearSignal = if ROCDownSignal and RSIDownSignal then ROC else double.nan;

bullSignal.setPaintingStrategy(PaintingStrategy.Arrow_Up);
bullSignal.setDefaultColor(Color.Green);
bullSignal.setLineWeight(3);


bearSignal.setPaintingStrategy(PaintingStrategy.Arrow_Down);
bearSignal.setDefaultColor(Color.Red);
bearSignal.setLineWeight(3);
#AddChartBubble(RSIUpSignal, ROC, RSIUpSignal, color.yellow);

Want the .ts file and the one-click import? Both come with a free account.

Create Free Account Login
The rate of change (ROC) indicator measures the percent change in price over a set number of bars: the close minus the close n bars ago, divided by the close n bars ago, times 100. ThinkorSwim's built-in study uses 14 bars. A positive reading means price is higher than 14 bars ago, and a negative reading means it is lower.
It keeps the built-in ROC line and adds lines at the highest and lowest ROC on the chart, plus dashed lines halfway to each, which mark the extreme zones. It also plots a green or red arrow when the ROC turns inside an extreme zone on the same bar the built-in RSI fires its breakout signal.
The upper zone runs from half the highest ROC on the chart up to the highest ROC. The lower zone runs from half the lowest ROC down to the lowest ROC. HighestAll and LowestAll find those values across every bar loaded on the chart, and the code divides each by 2 for the dashed lines.
Three things on the same bar: the ROC is in the lower extreme zone, the ROC is higher than on the previous bar, and the built-in RSI fires its UpSignal by crossing above its oversold line. The bearish arrow needs the ROC in the upper zone, lower than on the previous bar, and the RSI crossing below its overbought line.
The highest and lowest lines come from HighestAll and LowestAll, which read every bar on the chart. Load more or less history and the highest and lowest ROC can change, which moves the dashed lines, the extreme zones and the arrows. Compare charts that load the same time range.
Yes. I built it on a daily Amazon chart, then switched to a 5-minute chart, and the arrows plotted the way I expected, lining up with the RSI's breakout signals. The code has no timeframe setting, so it reads whatever chart you put it on. At the end of the video I said it should plot the same way on other markets, such as the S&P futures.
Open the study's settings and change length, which defaults to 14. It sets how many bars back the ROC compares the close with. colorNormLength, also 14, only changes the line's color shading. The RSI part uses the built-in RSI's own settings, so changing length doesn't change the RSI signals.
Yes. Our rate of change scans tutorial pastes this indicator's code into a ThinkorSwim scan filter and comes with 4 ready-made scans: bullish signal, bearish signal, lower extreme zone and upper extreme zone. A scan filter takes exactly one plot, so every other plot becomes a def.

Here are some resources that you may find useful:

  • How to import an indicator into ThinkOrSwim (video tutorial)
  • Rate of Change scans for ThinkOrSwim
  • Dynamic RSI indicator
  • Smarter MACD indicator
  • More free ThinkOrSwim indicators
Featured Tools:
Stock Volatility Box

Stock Volatility Box

Spot reversal zones across 600 stocks & ETFs.

  • Hourly & daily models
  • Powerful Live Scanner
  • Built for day traders
Futures Volatility Box

Futures Volatility Box

Pinpoint reversal zones in 10 major futures markets.

  • 5 models (incl. Scalper)
  • ThinkOrSwim & TradingView
  • SPX traders
ORB Setups

ORB Setups

Find the best Opening Range Breakout setups.

  • Powerful real-time scanner
  • Instant backtests
  • 2+ years data

Get Free Access

Create a free account for downloads and new tutorial alerts.

Create Free Account

Related tutorials and research

How to Build a Rate of Change Scan in ThinkorSwim

How to Build a Rate of Change Scan in ThinkorSwim

Scans · Beginner
How to Build a Fair Value Gap Indicator in ThinkorSwim

How to Build a Fair Value Gap Indicator in ThinkorSwim

Indicators · Beginner-Friendly
How to Build a Heiken Ashi Trend Dots Indicator in ThinkorSwim

How to Build a Heiken Ashi Trend Dots Indicator in ThinkorSwim

Indicators · Beginner-Friendly
How to Build a Commodities Tracker in ThinkorSwim

How to Build a Commodities Tracker in ThinkorSwim

Indicators · Beginner
Trend Squeeze Indicator for ThinkorSwim

Trend Squeeze Indicator for ThinkorSwim

Indicators · Beginner
Volume Intensity Indicator for ThinkorSwim

Volume Intensity Indicator for ThinkorSwim

Indicators · Beginner-Friendly

Ready to Trade With an Edge?

Join 40,000+ traders using institutional-grade tools for ThinkOrSwim.

Get the Bundle
TOS Indicators

Premium thinkorswim indicators, scans, and trading tools to help you trade smarter.

ThinkOrSwim Tools

  • Indicators
  • Scans
  • Backtesters
  • Dashboards
  • thinkScript
  • Browse All

Courses

  • Squeeze Course
  • Earnings Course
  • V-Shaped Reversals
  • Fibonacci Trading

Products

  • Futures Volatility Box
  • Stock Volatility Box
  • ORB Setups
  • Shop All

Guides

  • TTM Squeeze
  • Automated Trading
  • Volatility Trading
  • Opening Range Breakouts
  • Trade Reports
  • Contact Us

© 2026 TOS Indicators. All rights reserved.

Privacy Policy Terms of Service Disclaimer Accessibility

The information contained on this website is solely for educational purposes, and does not constitute investment advice. The risk of trading in securities markets can be substantial. You must review and agree to our Terms of Service prior to using this site.

U.S. Government Required Disclaimer - Commodity Futures Trading Commission. Futures and options trading has large potential rewards, but also large potential risk. You must be aware of the risks and be willing to accept them in order to invest in the futures and options markets. Don't trade with money you can't afford to lose. This website is neither a solicitation nor an offer to Buy/Sell futures or options. No representation is being made that any account will or is likely to achieve profits or losses similar to those discussed on this website. The past performance of any trading system or methodology is not necessarily indicative of future results.

Individual results may vary, and testimonials are not claimed to represent typical results. All testimonials are by real people, and may not reflect the typical purchaser's experience, and are not intended to represent or guarantee that anyone will achieve the same or similar results.

TOS Indicator's Traders and employees will NEVER manage or offer to manage a customer or individual's options, stocks, currencies, futures, or any financial markets or securities account. If someone claiming to represent or be associated with TOS Indicator solicits you for money or offers to manage your trading account, do not provide any personal information and contact us immediately.

CFTC RULE 4.41 - HYPOTHETICAL OR SIMULATED PERFORMANCE RESULTS HAVE CERTAIN LIMITATIONS. UNLIKE AN ACTUAL PERFORMANCE RECORD, SIMULATED RESULTS DO NOT REPRESENT ACTUAL TRADING. ALSO, SINCE THE TRADES HAVE NOT BEEN EXECUTED, THE RESULTS MAY HAVE UNDER-OR-OVER COMPENSATED FOR THE IMPACT, IF ANY, OF CERTAIN MARKET FACTORS, SUCH AS LACK OF LIQUIDITY, SIMULATED TRADING PROGRAMS IN GENERAL ARE ALSO SUBJECT TO THE FACT THAT THEY ARE DESIGNED WITH THE BENEFIT OF HINDSIGHT. NO REPRESENTATION IS BEING MADE THAT ANY ACCOUNT WILL OR IS LIKELY TO ACHIEVE PROFIT OR LOSSES SIMILAR TO THOSE SHOWN.