How to Code RSI in Pine Script: Inputs, Plots, and Alerts
An RSI script is useful when you need a specific display or alert rule. TradingView's built-in RSI already supports configurable inputs; custom code lets you make the conditions explicit and combine them with other logic. The example below plots RSI and distinguishes entering an extreme zone from leaving it.

What the calculation measures
RSI compares smoothed upward and downward changes in the selected source. Its usual expression is 100 - 100 / (1 + RS), where RS is the ratio of the smoothed gains to smoothed losses. Wilder's smoothing matters: replacing it with a simple rolling average changes the calculation. Use ta.rsi() unless you specifically intend to implement another variant.
A length of 14 means 14 chart bars, not necessarily 14 days. The source is also part of the definition: changing close to another price series changes the result. TradingView describes the calculation and built-in settings in its RSI reference.
The familiar 70 and 30 levels are reference thresholds, not automatic orders or guarantees of a reversal. RSI can remain high or low during a trend.
A complete RSI indicator
This example uses Pine Script v6, a positive length, ordered thresholds, and bar-close confirmation for the four alert conditions. The plotted RSI still develops while the current bar is open.
//@version=6
indicator("RSI with Confirmed Threshold Alerts", overlay=false)
length = input.int(14, "RSI length", minval=1)
source = input.source(close, "Source")
upper = input.float(70.0, "Upper threshold", minval=0, maxval=100)
lower = input.float(30.0, "Lower threshold", minval=0, maxval=100)
if lower >= upper
runtime.error("Lower threshold must be below upper threshold.")
rsi = ta.rsi(source, length)
lineColor = rsi > upper ? color.red : rsi < lower ? color.green : color.blue
plot(rsi, "RSI", color=lineColor, linewidth=2)
upperLine = hline(upper, "Upper", color=color.gray)
lowerLine = hline(lower, "Lower", color=color.gray)
hline(50, "Midpoint", color=color.new(color.gray, 60))
fill(upperLine, lowerLine, color=color.new(color.blue, 94))
enterUpper = ta.crossover(rsi, upper)
leaveUpper = ta.crossunder(rsi, upper)
enterLower = ta.crossunder(rsi, lower)
leaveLower = ta.crossover(rsi, lower)
alertcondition(enterUpper and barstate.isconfirmed, "Enter upper zone", "{{ticker}} RSI entered upper zone. RSI: {{plot_0}}")
alertcondition(leaveUpper and barstate.isconfirmed, "Leave upper zone", "{{ticker}} RSI left upper zone. RSI: {{plot_0}}")
alertcondition(enterLower and barstate.isconfirmed, "Enter lower zone", "{{ticker}} RSI entered lower zone. RSI: {{plot_0}}")
alertcondition(leaveLower and barstate.isconfirmed, "Leave lower zone", "{{ticker}} RSI left lower zone. RSI: {{plot_0}}")
The crossover functions are evaluated on every bar before confirmation is applied. This keeps their historical series calculation separate from the decision to emit an event.
alertcondition() requires a constant message string. Concatenating str.tostring(rsi) into that message is not valid. The example uses TradingView's {{plot_0}} placeholder, referring to the first plot() call, to include the RSI value. If you reorder or add plots, review that reference. An alert() call is another option when a dynamically constructed message is needed; its setup differs.
Create the running alert
Add the script to the chart, select its source and thresholds, then open TradingView's Create Alert dialog. Select the script and one of its four named conditions. Use a bar-close frequency consistent with the confirmed-bar rule. See the official alerts documentation for the distinction between code conditions and running alerts.
A crossing is a transition, not a continuous state. With the default upper level, an RSI move from 69 to 71 enters the upper zone. Staying at 72 on the next bar does not produce another crossover. Returning from above 70 to below 70 is a different condition. These are hypothetical values used to explain the rules.
TradingView saves a copy of the script and inputs when an alert is created. After changing the code, symbol, timeframe, or thresholds, review and recreate the alert as needed. Historical crossings help inspect logic; they do not retrospectively send live notifications.
Verify the output before adding more rules
Compare this plot with the built-in RSI using the same symbol, timeframe, source, and length. Allow for the initial history needed by the calculation. Check identifiable bars at a threshold crossing and bars where RSI remains on the same side. If values differ, first check the data and settings rather than assuming one implementation is better.
Next inspect the open bar and its close. A developing RSI can cross a level and return before the bar closes. This script deliberately suppresses that temporary crossing as an alert. That choice introduces a wait for confirmation; it does not predict the next bar.
A divergence detector is a separate feature. It needs rules for choosing price and RSI pivots, matching them, and handling confirmation delays. Plotting a pivot marker on an earlier candle must not imply that it was known on that candle. TradingView's repainting guide explains this timing problem.
When to use custom code
Use the built-in indicator when its settings cover the job. Use a custom script when you need an exact alert definition, a combined filter, or an auditable calculation. More conditions do not establish better performance: an indicator has no simulated trades until you define a strategy's entries, exits, sizing, costs, and execution assumptions.
Pineify can help draft or edit these rules. Review the final code and checking result, then test the behavior in TradingView. A successful syntax check confirms neither trading profitability nor the absence of every runtime or data issue.


