Tutorial

RSI Strategy in Pine Script: A Step-by-Step Guide

What the Relative Strength Index actually measures, why traders lean on it, and how to build an RSI indicator and a backtestable strategy in Pine Script v6.

11 min read

The Relative Strength Index is one of the first indicators almost every trader meets, and one of the most misunderstood. It shows up as a single line bouncing between 0 and 100 in a pane below your chart, and the folklore around it is simple: above 70 is overbought, below 30 is oversold. That summary is not wrong, but it hides most of what makes the RSI useful and most of the ways it misleads people. This guide explains what the RSI is measuring, why it earned its place on so many charts, and how to build it from scratch in Pine Script v6 on TradingView, first as an indicator and then as a strategy you can run through the Strategy Tester.

By the end you will have code you can paste into the Pine Editor and, more importantly, understand well enough to change. This is a coding tutorial, not trading advice. The RSI is a way to express a question about momentum in code, not a signal that promises anything about outcomes.

What the RSI actually measures

The RSI is a momentum oscillator developed by J. Welles Wilder Jr. and introduced in his 1978 book on technical trading systems. Under the hood it compares the average size of recent up moves to the average size of recent down moves over a lookback period, traditionally 14 bars, and expresses that ratio on a scale from 0 to 100. When up moves dominate, the line pushes toward 100. When down moves dominate, it falls toward 0. A reading near 50 means the two are roughly balanced.

The key word is momentum, not price. The RSI does not care how high or low the price is in absolute terms; it cares about the character of the recent moves. That is why it is called an oscillator: it is bounded and it swings back and forth, which makes it natural to define thresholds like 70 and 30 that mean something consistent across different symbols and price levels. The same 70 reading carries a similar interpretation whether you are looking at a five-dollar stock or a fifty-thousand-dollar one.

Why traders use it

Traders reach for the RSI for two broad reasons. The first is to gauge whether a move has become stretched. A market that has run up quickly can show an RSI in the high 70s or 80s, which some read as a sign that the buying is getting exhausted and a pause or pullback may be near. The mirror case, a deeply oversold reading, is read as potential exhaustion of selling. The second, and arguably more interesting, use is divergence: when price makes a new high but the RSI makes a lower high, the momentum behind the move is fading even though price has not turned yet. Many traders treat that disagreement between price and momentum as an early warning.

The honest caveat, which we will build into the code, is that overbought does not mean "about to fall." In a powerful trend the RSI can sit above 70 for a long stretch while price keeps climbing, and a trader who shorts every overbought reading in that environment gets run over. The RSI is a description of momentum, not a timer.

Building the indicator

Pine Script gives you the RSI as a single built-in function, so the indicator is short. Here is the complete v6 code that plots the line and shades the overbought and oversold zones.

pine
//@version=6
indicator("RSI", overlay = false)

length = input.int(14, "RSI Length")
obLevel = input.int(70, "Overbought")
osLevel = input.int(30, "Oversold")

rsiValue = ta.rsi(close, length)

plot(rsiValue, "RSI", color = color.purple, linewidth = 2)

hline(obLevel, "Overbought", color = color.red)
hline(osLevel, "Oversold", color = color.green)
hline(50, "Midline", color = color.gray, linestyle = hline.style_dotted)

Walking through it: the //@version=6 annotation has to be the first line, and it tells TradingView which language version to compile against. The indicator() declaration sets overlay = false so the RSI draws in its own pane below price rather than on top of it, which matters because the RSI scale of 0 to 100 has nothing to do with the price scale. The three input.int() calls expose the length and the two threshold levels as editable settings. The single line that does the real work is ta.rsi(close, length), which computes the RSI of the closing price over your chosen lookback. Everything after that is presentation: plot() draws the line, and the hline() calls draw the horizontal reference levels at 70, 30, and 50.

Turning it into a backtestable strategy

An indicator shows you the RSI; a strategy acts on it so you can run it through the Strategy Tester. The classic textbook version buys when the RSI crosses back up through the oversold level and exits when it crosses back down through the overbought level. Here is that logic in v6.

pine
//@version=6
strategy("RSI Strategy", overlay = true, margin_long = 100, margin_short = 100)

length  = input.int(14, "RSI Length")
osLevel = input.int(30, "Oversold")
obLevel = input.int(70, "Overbought")

rsiValue = ta.rsi(close, length)

buySignal  = ta.crossover(rsiValue, osLevel)
sellSignal = ta.crossunder(rsiValue, obLevel)

if buySignal
    strategy.entry("Long", strategy.long)

if sellSignal
    strategy.close("Long")

The strategy() declaration replaces indicator(). Note that the entries use ta.crossover(rsiValue, osLevel) rather than a simple rsiValue < osLevel test. The difference matters: a plain less-than check is true on every bar the RSI stays below 30, so it would try to enter repeatedly. The crossover is true only on the single bar where the RSI moves from below the level to above it, which is the moment momentum is turning back up. The order calls live inside if blocks because that is required in v6, where the older when parameter on strategy.entry() has been removed. If you are porting an older RSI script, that is one of several changes covered in our guide to migrating from Pine Script v5 to v6.

Two ways people trade the RSI

The threshold approach above is the most common, but it is not the only one, and the two main styles suit very different markets.

Overbought/OversoldRSI Divergence
What it readsAbsolute RSI levelRSI shape vs price shape
Best marketRange-boundTurning points in a trend
Common trapFiring early in strong trendsSeeing patterns that are not there
Pine building blockta.rsi() plus a thresholdta.rsi() plus pivot logic

The overbought and oversold approach works best in a range-bound market that keeps reverting to a mean, which is exactly where a fixed 70 or 30 line has meaning. Its weakness is a strong trend, where the RSI can stay pinned in an extreme zone for weeks. Divergence, by contrast, tries to catch the moment a trend loses steam, but it is harder to code cleanly and prone to false readings, since a fading momentum reading does not guarantee a reversal. Neither is a magic setting; each is a tool for a particular kind of market.

Adding a trend filter

Because the raw overbought and oversold approach struggles in trends, a common refinement is to only take oversold entries when the broader trend is up, so the strategy is buying dips within an uptrend rather than fighting a downtrend. A long-term moving average is the simplest filter.

pine
//@version=6
strategy("RSI With Trend Filter", overlay = true, margin_long = 100, margin_short = 100)

length   = input.int(14, "RSI Length")
osLevel  = input.int(30, "Oversold")
trendLen = input.int(200, "Trend Filter Length")

rsiValue = ta.rsi(close, length)
trendMA  = ta.sma(close, trendLen)

buySignal  = ta.crossover(rsiValue, osLevel)
aboveTrend = close > trendMA

if buySignal and aboveTrend
    strategy.entry("Long", strategy.long)

if ta.crossunder(rsiValue, 50)
    strategy.close("Long")

Notice that buySignal is assigned to its own variable before it is used in the if condition. This is a habit worth building. In v6 the and operator evaluates lazily, meaning the right side can be skipped when the left already settles the result, and functions like ta.crossover() need to run on every bar to track their state correctly. Hoisting the call into its own line guarantees it executes each bar. That small discipline prevents a whole class of subtle bugs, some of which we cover in why Pine Script won't compile. This version also exits when the RSI falls back through the midline at 50 rather than waiting for a full overbought reading, which tends to lock in exits sooner.

The honest pitfalls

The biggest mistake with the RSI is treating an extreme reading as a signal to trade against the trend. Overbought is not a sell signal and oversold is not a buy signal; they are descriptions of momentum that only become actionable in the right context. This is why the trend filter above exists, and why divergence traders wait for confirmation rather than acting on the divergence alone.

The second pitfall is over-tuning the length. It is tempting to keep nudging the lookback until the backtest looks its best on one chart, but a number hand-picked to fit past data on a single symbol rarely behaves the same on the next symbol or the next stretch of history. Treat the length as a setting to reason about, not a dial to optimize blindly, and judge any RSI strategy across a meaningful sample of trades rather than a lucky handful. If you want to see how the RSI value is computed step by step from a price series, our RSI calculator shows the math with the Pine Script equivalent alongside it.

Building it faster

Typing this out by hand is the best way to learn what each line does, and if you are learning Pine Script that is exactly what you should do. If you already know the rules you want and just need working code, describing them in plain English is faster than assembling the script line by line. A tool like PineScripter generates the v6 code, and when it does not compile it reads TradingView's error and fixes it automatically instead of making you copy the error back and forth. You can see how that workflow compares across tools in our roundup of the best AI Pine Script generators, and if you are brand new, our guide to turning a trading idea into testable Pine Script is a good next read.

The takeaway

The RSI is one built-in function, ta.rsi(), plus a threshold or a divergence rule wrapped in an indicator or a strategy. It is a genuinely useful momentum gauge as long as you remember what it measures and where it breaks. Build it, filter it for the market you are testing, and judge it across a real sample rather than a handful of lucky crosses. Knowing an indicator's weaknesses is as much a part of using it well as knowing how to code it.


Disclaimer: PineScripter is a coding tool for Pine Script development. It does not provide financial advice and does not guarantee trading profits. Always backtest strategies thoroughly and understand the risks before live trading.