Back to blog
methodology

Why doesn't my RSI match TradingView?

16 October 2026 6 min read

Quick answer

Your RSI usually doesn't match TradingView for one of three reasons: you smoothed gains and losses with a 14-period EMA or simple average instead of Wilder's smoothing (a 1/14 weight), you started with too little history so the seed still affects the value, or your closes differ (adjusted vs unadjusted, official close vs last trade, a still-forming bar). Use Wilder's smoothing and at least 250 bars of history before the first value you use.

If your RSI doesn't match TradingView, the cause is almost always one of three things, in this order of size: you smoothed the gains and losses with the wrong average, you started the calculation with too little history, or your closing prices are not the same closes. RSI is defined with Wilder's smoothing, which is not a 14-period EMA, and it carries a memory of every bar you feed it, so the same formula on the same index can disagree by several points.

We ran all three variants on the S&P 500's daily closes from FRED to show how far apart they land. On 15 October 2026, with the index closing at 7,744.06, RSI(14) was 51.94 with Wilder's smoothing, 48.47 with a standard 14-period EMA, and 50.07 with a simple 14-day average.

Cause 1: the wrong moving average

RSI averages two series, the up-moves and the down-moves, and then takes RS = average gain / average loss and RSI = 100 - 100 / (1 + RS). The average is where implementations split.

Wilder's smoothing updates each average as (previous average × 13 + today's value) / 14. That is an exponential average with a weight of 1/14 on the newest bar. A "14-period EMA" uses a weight of 2/15, almost twice as heavy, so it reacts faster and swings further. Wilder's 14 behaves roughly like a 27-period EMA (2n - 1). The third variant, sometimes called Cutler's RSI, uses a plain 14-day simple average and drops each bar completely after 14 days.

The difference is not a rounding issue. Over the 250 sessions from 17 October 2025 to 15 October 2026, the three versions of RSI(14) on the same S&P 500 closes gave these results:

  • Wilder's smoothing: above 70 on 22 days, below 30 on 3 days.
  • 14-period EMA: above 70 on 41 days, below 30 on 13 days.
  • 14-day simple average: above 70 on 42 days, below 30 on 8 days.

The EMA version flagged "overbought" almost twice as often, and on its worst day it sat 14.5 points away from the Wilder value. If you are backtesting a 70/30 rule, the smoothing choice changes the trade count before the strategy logic does anything.

TradingView's built-in RSI uses Wilder's smoothing, so that is the one to match. In pandas, the common mistake is ewm(span=14), which is the 2/15 EMA. The Wilder equivalent is ewm(alpha=1/14, adjust=False). Note that pandas seeds that recursion with the first value rather than with a 14-bar average, which is a small seed difference of the kind covered next.

Cause 2: not enough history

Wilder's average never fully forgets. The seed, the first simple average of 14 gains and 14 losses, still carries a weight of (13/14)^k after k more bars: about 35% after 14 bars, 2.5% after 50, 0.06% after 100, and effectively zero after 250. So the RSI you get today depends on where your data starts.

We calculated the 15 October 2026 value again, each time feeding in a different amount of history ending on that day:

  • 15 bars (the minimum): 50.07
  • 20 bars: 55.25
  • 30 bars: 49.24
  • 50 bars: 51.43
  • 100 bars: 51.92
  • 250 bars or more: 51.94

With 20 bars of history the reading is more than three points off. With 100 bars it is still 0.02 off, the same size as the small, stubborn gaps people post about on broker and backtesting forums. A charting platform draws RSI over all the history it has loaded, so its value has converged. A script that downloads "the last 30 days" to compute RSI(14) has not.

The fix is to request at least 250 bars before the first value you intend to use, and to discard the warm-up period rather than plotting it.

Cause 3: the closes are not the same closes

Once the smoothing and the warm-up match, any remaining gap comes from the inputs. Check these before you suspect the formula:

  • Adjusted versus unadjusted prices. A dividend-adjusted or split-adjusted series has different day-to-day changes on and around ex-dates, so the gains and losses differ.
  • Which close. An official closing price and the last trade of the session can differ, and so can a regular-session close and one that includes extended hours.
  • The current bar. On a live chart the latest daily bar is still forming during the session. Compare against the previous, completed bar.
  • The instrument. SPY, the S&P 500 index and the E-mini future are three different price series. They move together, but their RSI values are not identical.

A Wilder RSI you can check

This version follows Wilder's original definition: seed both averages with a simple mean of the first 14 changes, then smooth with a weight of 1/14. It reproduces the worked example in Wilder's 1978 book, which gives about 70.46 on the 15th close.

def wilder_rsi(closes, period=14):
    """closes: list of closing prices, oldest first. Returns RSI per bar (None until seeded)."""
    gains = [max(closes[i] - closes[i - 1], 0) for i in range(1, len(closes))]
    losses = [max(closes[i - 1] - closes[i], 0) for i in range(1, len(closes))]
    avg_gain = sum(gains[:period]) / period   # seed: simple average of the first 14
    avg_loss = sum(losses[:period]) / period
    out = [None] * period

    def rsi(g, l):
        return 100.0 if l == 0 else 100 - 100 / (1 + g / l)

    out.append(rsi(avg_gain, avg_loss))
    for g, l in zip(gains[period:], losses[period:]):
        avg_gain = (avg_gain * (period - 1) + g) / period   # Wilder: alpha = 1/14
        avg_loss = (avg_loss * (period - 1) + l) / period
        out.append(rsi(avg_gain, avg_loss))
    return out

# Wilder's own example: the 15th close should give about 70.46
wilder_example = [44.34, 44.09, 44.15, 43.61, 44.33, 44.83, 45.10, 45.42,
                  45.84, 46.08, 45.89, 46.03, 45.61, 46.28, 46.28]
print(round(wilder_rsi(wilder_example)[-1], 2))

To use it on real data, pass at least 250 closes and ignore the values before your chosen start date. If it still disagrees with a chart by more than a few hundredths, the closes are the next place to look, not the formula.

How to chart RSI so readers can trust it

Plot RSI in its own panel under the price chart, on a fixed 0 to 100 axis, with the 70 and 30 lines drawn in. Put the smoothing method in the label ("RSI(14), Wilder") because, as the counts above show, a 14-period EMA version is a different indicator with the same name. If the chart starts at the beginning of your data, hide the first few dozen bars so the warm-up does not show up as a fake signal. The same rule about labeling the method applies to other running indicators, which is why the anchored VWAP post puts the anchor date and price basis in the caption, and a volume profile is a useful companion panel when you want to see where volume sat rather than how fast price moved.

Where Quadesto fits

Quadesto builds price and indicator charts from your own data or a connected market data source, and the same advice applies whichever tool draws the line: name the smoothing, load the history, and say which closes you used. You can start free.

Ready to try Quadesto?

Connect your data. AI builds the charts. Embed anywhere.

Get Started Free
rsitechnical analysiswilder smoothingtradingviewpython