RSI and the Stochastic oscillator both print 0–100 momentum readings, but they measure different things: RSI compares the average size of up-closes to down-closes, while the Stochastic measures where the latest close sits inside the recent high–low range. Because the denominators differ, there are market conditions where the two must mathematically disagree — this guide shows the formulas, validated Pine v6 for each, and a script that highlights those disagreement bars. Educational material only, not financial advice; no oscillator reading is a prediction, and trading carries a real risk of loss.
RSI measures the magnitude of recent gains relative to recent losses — it asks "when price moved, how much of that movement was up?" The Stochastic oscillator measures the position of the latest close within the recent high–low range — it asks "where inside the last N bars' territory did we just close?" Both are bounded 0–100 and both get called "overbought/oversold" indicators, but they are built from different raw materials and can read very differently on the same bar.
The cleanest way to see it is through their denominators. RSI's denominator is the smoothed average of down-moves: RSI = 100 − 100 / (1 + RS), where RS is average gain divided by average loss over the lookback. Only close-to-close changes enter the calculation; intrabar highs and lows are invisible to it. The Stochastic's denominator is the total range: %K = 100 × (close − lowest low) / (highest high − lowest low). Close-to-close changes as such are invisible to it — only where the close lands inside the range matters.
The provenance differs too. RSI comes from J. Welles Wilder's New Concepts in Technical Trading Systems (1978), which is also why its smoothing is Wilder's own running average (what Pine calls ta.rma()) rather than a simple mean. The Stochastic is credited to and was popularised by George Lane, who framed it with the observation that closes tend to cluster near the top of the range in advances and near the bottom in declines.
Neither indicator predicts anything — each is a deterministic transformation of past prices. This article explains what each transformation does, shows correct Pine v6 for both, and identifies the conditions where their readings must part ways. It is educational material, not a trading recommendation.
Wilder's RSI over length n works in three steps. First, split each bar's close-to-close change into a gain part (max(change, 0)) and a loss part (max(−change, 0)). Second, smooth each stream with Wilder's running average — an EMA-like recursion with α = 1/n, which Pine exposes as ta.rma(). Third, form the ratio: RS = avgGain / avgLoss, and map it into 0–100 with RSI = 100 − 100 / (1 + RS).
Building it by hand next to the built-in is the best way to internalise it — the two lines should overlay exactly:
//@version=6
// Educational only — validate before trading; not financial advice.
indicator("RSI: built-in vs manual", overlay = false)
len = input.int(14, "Length", minval = 1)
chg = ta.change(close)
up = ta.rma(math.max(chg, 0), len)
down = ta.rma(math.max(-chg, 0), len)
rsiManual = down == 0 ? 100 : up == 0 ? 0 : 100 - 100 / (1 + up / down)
plot(ta.rsi(close, len), "Built-in RSI", color = color.new(color.purple, 0))
plot(rsiManual, "Manual RSI", color = color.new(color.orange, 60), linewidth = 3)
hline(70, "Upper")
hline(30, "Lower")Three properties follow directly from the construction. RSI = 50 means average gains equal average losses — a genuine neutral point, which is why 50-line behaviour gets attention in trend analysis. Extremes require one-sidedness: RSI only approaches 100 when losses nearly vanish from the window, so a strong advance that still contains normal red bars will read 60–75, not 95. And because Wilder's smoothing has a long memory (α = 1/14 by default), RSI decays gradually — a single large bar shifts it, but never resets it. It is a rate-of-one-sidedness gauge, smoothed hard, blind to everything except how closes changed.
Lane's Stochastic is simpler arithmetic with very different behaviour. The raw line is:
%K = 100 × (close − lowestLow(n)) / (highestHigh(n) − lowestLow(n))
with n = 14 as the common default. A reading of 100 means the close is the highest point of the last 14 bars' territory; 0 means it's the lowest; 50 means dead centre of the range. In the standard "slow" configuration, that raw %K is smoothed with a 3-period SMA, and a further 3-period SMA of the result gives the %D signal line.
//@version=6
// Educational only — validate before trading; not financial advice.
indicator("Slow Stochastic %K / %D", overlay = false)
kLen = input.int(14, "%K length", minval = 1)
kSmooth = input.int(3, "%K smoothing", minval = 1)
dLen = input.int(3, "%D length", minval = 1)
k = ta.sma(ta.stoch(close, high, low, kLen), kSmooth)
d = ta.sma(k, dLen)
plot(k, "%K", color = color.new(color.teal, 0))
plot(d, "%D", color = color.new(color.orange, 0))
hline(80, "Upper")
hline(20, "Lower")Note what enters the formula that RSI never sees: high and low. The Stochastic is a range-position gauge, so intrabar extremes matter as much as closes. That has two immediate consequences. First, the indicator pins easily: in a steady advance where each close sits near the top of the trailing range, %K rides 80–100 for as long as the advance lasts — "overbought" is a description of position, not a reversal signal. Second, the denominator can be reset by a single bar: one huge-range bar entering the 14-bar window inflates highestHigh − lowestLow and mechanically compresses %K, even if closes barely moved. RSI, indifferent to ranges, doesn't budge on that same bar. Same 0–100 scale, genuinely different machine underneath.
Because the denominators differ, certain price paths force the two oscillators apart — no parameter tuning reconciles them.
The grinding trend. Price steps higher with shallow, regular pullbacks, each close near the top of the trailing range. Stochastic: pinned at 80–100, because range position is what it measures. RSI: stuck in the 55–70 zone, because the pullback bars keep feeding the loss average in the denominator. One screams "extreme," the other says "moderately strong" — both correct, about different questions.
The sideways shelf near highs. After a rally, price consolidates flat just under its peak. RSI decays toward 50 as gains and losses balance inside the window. The Stochastic stays elevated for as long as the consolidation sits in the upper part of the lookback range. Here RSI reads "momentum gone," Stochastic reads "still at the top."
The range-expansion bar. One violent wide-range bar enters the window. The Stochastic's denominator inflates and %K compresses toward the middle even if the close-to-close change was small; RSI barely moves, since it never sees intrabar range. The disagreement is instant and purely mechanical.
This script paints the bars where the two are on opposite sides of their midzones:
//@version=6
// Educational only — validate before trading; not financial advice.
indicator("RSI vs Stochastic disagreement", overlay = false)
len = input.int(14, "Shared length", minval = 1)
r = ta.rsi(close, len)
k = ta.stoch(close, high, low, len)
plot(r, "RSI", color = color.new(color.purple, 0))
plot(k, "Stoch %K", color = color.new(color.teal, 0))
hline(50, "Mid")
split = (r > 60 and k < 40) or (r < 40 and k > 60)
bgcolor(split and barstate.isconfirmed ? color.new(color.yellow, 85) : na)Run it on any liquid symbol and the highlighted bars cluster exactly where the three cases above predict — the divergences are structural properties of the formulas, not noise.
Neither is "better," because they are answers to different questions. If you want to know how one-sided recent closing momentum has been, RSI is the direct measurement. If you want to know where price just closed relative to its recent territory, the Stochastic is the direct measurement. In quiet, mean-reverting ranges, the Stochastic's range-position reading maps naturally onto "stretched toward an edge"; in persistent trends, it pins at an extreme and stays there, while RSI's harder smoothing and loss-fed denominator keep it more graded. Neither behaviour is a flaw — each is the formula doing exactly what it says.
A few honest cautions before either goes into a strategy. "Overbought" and "oversold" are descriptions of a statistic, not reversal forecasts — trending markets routinely stay pinned far longer than a counter-trend position survives. Using both indicators together is not confirmation in any statistical sense: they share the same input series and are strongly correlated most of the time, so agreement between them is the default, not evidence. And every threshold you pick — 70/30, 80/20, the lookback length, the smoothing — is a degree of freedom that can be curve-fit to history; a threshold combination selected because it backtested well on one symbol has memorised that symbol's past, and out-of-sample testing is the only honest check.
If you code either into a Pine strategy, validate the mechanics before believing any tester output: signals gated on barstate.isconfirmed, no unshifted higher-timeframe requests, stop inputs actually wired into strategy.exit(). ForexCodes' validator and audit tooling exist to make that pass automatic. And the standing disclaimer applies with full force: this article is educational only and not financial advice. An oscillator reading describes the past window of prices, a backtest describes past data, and trading on either carries a real risk of loss.
Educational only — not financial advice. Trading involves substantial risk of loss.