Why doesn't my ATR match TradingView?
Quick answer
Your ATR usually doesn't match TradingView because you averaged high minus low instead of the true range (which also counts gaps from the previous close), or you smoothed with a simple or 14-period EMA average instead of Wilder's RMA, TradingView's default. On the S&P 500 on 20 October 2026, ATR(14) was 71.13 with true range and RMA, 61.48 with high minus low, and 74.89 with a standard EMA. Load at least 100 to 250 bars before the first value you use.
If your ATR doesn't match TradingView, there are two usual causes. Either you averaged the daily high minus low instead of the true range, which also counts the gap from the previous close, or you smoothed the true range with the wrong average. TradingView's ATR is, by default, an RMA (Wilder's smoothing) of the true range. A simple average or a standard 14-period EMA gives a different number on the same bars.
On the S&P 500 on 20 October 2026, with the index closing at 7,712.57, ATR(14) came out as:
- 71.13 with true range and Wilder's RMA, the TradingView default.
- 71.88 with true range and a 14-day simple average.
- 74.89 with true range and a standard 14-period EMA.
- 61.48 with Wilder's RMA applied to high minus low, ignoring gaps.
We used Cboe's daily S&P 500 index history (open, high, low, close) from January 2000. Its closes match FRED's SP500 series to the cent.
Cause 1: high minus low is not the true range
Wilder defined the true range as the largest of three distances: today's high minus today's low, the absolute distance from today's high to yesterday's close, and the absolute distance from today's low to yesterday's close. TradingView's documentation gives the same formula. The second and third terms exist to capture gaps. If the market opens well above yesterday's close and drifts in a narrow range, the high-low range looks quiet, but the true range records the jump.
On an index that gaps often, this is not a small correction. In the 252 sessions to 20 October 2026, the true range was larger than the high-low range on 114 days, and Wilder's ATR averaged about 15% above the high-low version. The biggest single case was 8 April 2026: the index closed at 6,616.85 the day before and traded between 6,740.28 and 6,793.50, so the high-low range was 53.22 points while the true range was 176.65.
The first bar of any dataset has no previous close. The usual convention, and the one in the code below, is to use high minus low for that bar. It only affects the warm-up.
Cause 2: the wrong average
TradingView's ATR settings let you change the smoothing to SMA, EMA or WMA, but the default is RMA. RMA updates each value as (previous ATR × 13 + today's true range) / 14, which is an exponential average with a weight of 1/14 on the newest bar. A "14-period EMA" uses 2/15, nearly twice that, so it reacts faster to a volatile day and gives back the reading faster afterwards. A 14-day simple average drops each bar completely after 14 sessions, which makes it jump when a big day leaves the window.
On a single day the gap between methods can look minor. Over a year it is not: the largest difference between the simple-average ATR and Wilder's ATR in the 252 sessions we tested was on 25 June 2026, at 123.48 versus 98.04. If your stop-loss or position size is a multiple of ATR, that is a 26% difference in risk on the same day.
In pandas, the common Wilder equivalent is tr.ewm(alpha=1/14, adjust=False).mean(). With a long history that gives the same 71.13 here. Note that it starts from the first true range rather than from a 14-bar average, which is a seed difference, covered next.
Cause 3: not enough history
Wilder's average remembers every bar it has seen, with the weight on old data shrinking by a factor of 13/14 per bar. So the ATR you compute depends on where your data starts. Recomputing the 20 October 2026 value from different starting points:
- 15 bars of history: 71.89
- 50 bars: 70.27
- 100 bars: 71.15
- 250 bars or more: 71.13
With 50 bars the value is almost a point off; with 100 bars it is within a few hundredths. A chart that has loaded years of history has converged. A script that downloads the last month of bars has not. This is the same warm-up effect that makes RSI disagree, and the RSI mismatch post has the full explanation. If the bars themselves differ (a different feed, extended hours, or adjusted prices), no formula will close the gap; check that before anything else.
An ATR in pandas that matches Wilder's definition
import pandas as pd
def atr(df: pd.DataFrame, n: int = 14) -> pd.Series:
prev_close = df["close"].shift(1)
tr = pd.concat([
df["high"] - df["low"],
(df["high"] - prev_close).abs(),
(df["low"] - prev_close).abs(),
], axis=1).max(axis=1) # first bar: high - low, since prev_close is NaN
seed = tr.iloc[:n].mean() # Wilder: start from a simple average of the first n
out = [float("nan")] * (n - 1) + [seed]
for value in tr.iloc[n:]:
out.append((out[-1] * (n - 1) + value) / n)
return pd.Series(out, index=df.index)
# df: daily bars with high, low and close columns, oldest first
print(round(atr(df).iloc[-1], 2))On the S&P 500 bars above, this prints 71.13 for 20 October 2026, both on the full history from 2000 and on the last 250 bars alone.
Charting ATR so the number means something
Plot ATR in its own panel under the price chart, labeled with its settings ("ATR(14), RMA"). Because ATR is in price points, it rises with the price level: 71 points on the S&P 500 today is not comparable to 71 points in 2016. For a long chart, divide by the close and show ATR as a percentage of price. On 20 October 2026 it was 0.92% of the close. ATR measures the range of daily bars, gaps included. It is not the standard deviation of returns, which is what Bollinger Bands and realized volatility use, so do not swap one for the other in a stop or a sizing rule without rechecking the multiple.
Where Quadesto fits
Quadesto builds candlestick and time-series charts from your own OHLC data or a connected market data source. The advice holds in any tool: use the true range, name the smoothing, and load enough history before the first value you show. You can start free.