Correcting RSI Calculation Errors in a Wilder-Style Implementation
Summary
The document reviews a Relative Strength Index implementation that produced results unlike reference charts and presents corrections to its calculations. The revised method defines price change as the current close minus the previous close, separates positive gains from absolute losses, initializes Wilder-style smoothed averages from the first lookback window, and then updates those averages recursively. It also adjusts array lengths and loop indexing so values align with the available price history, and handles periods with no average loss to avoid division by zero.
The response is a practical debugging example rather than a broader explanation of RSI interpretation or trading use. It identifies sign, initialization, indexing, and zero-loss handling as sources of incorrect output. The document does not provide a numerical validation against a chart or discuss edge cases such as missing prices, flat periods, output alignment with original dates, or differences among platform conventions, so implementation details may still need checking for a particular data series.
Key ideas
- Price changes must use the current close minus the previous close so gains and losses have the intended signs.
- Positive changes feed the gain series, while the magnitudes of negative changes feed the loss series.
- The initial smoothed averages are computed over the first lookback window before recursive updates begin.
- Array sizes and loop indices must reflect the shorter series of valid indicator values.
- A zero average loss requires explicit handling to prevent division by zero.
Tags
Full text
# How to go about computing RSI?
# How to go about computing RSI?
I've written python code that I believe computes RSI. I wrote the code based on what I saw in stockcharts.com found here
Here is the code:
```
def getRSI(close, n=14):
"""
Computes the Relative Strength Index of a trend
:param close: closing prices
:param n: lookback period
:return: a np array containing the RSI for all periods spanning
closing price data
"""
# compute a vector for change between daily closing prices
change = np.zeros(len(close))
for i in range(1, len(close)):
change[i] = close[i-1] - close[i]
# compute a vector of gains and losses
gain = np.zeros(len(close))
loss = np.zeros(len(close))
for i in range(1, len(close)):
if change[i] >= 0:
gain[i] = change[i]
else:
loss[i] = math.fabs(change[i])
avg_gain = np.zeros(len(close))
avg_loss = np.zeros(len(close))
avg_gain[n] = np.average(gain[0:n])
avg_loss[n] = np.average(loss[0:n])
for i in range(n, len(close)):
avg_gain[i] = (avg_gain[i-1]*(n-1) + gain[i])/n
avg_loss[i] = (avg_loss[i-1]*(n-1) + loss[i])/n
RS = np.zeros(len(close))
for i in range(n, len(close)):
RS[i] = avg_gain[i]/avg_loss[i]
RSI = np.zeros(len(close))
for i in range(n, len(close)):
RSI[i] = 100 - (100/(1+RS[i]))
return RSI
```
I tried to compute the RSI for COP for prices starting from 26th November 2006 to 26th November 2018. But the curve I get is completely different from what I see on Yahoo Finance or even StockCharts for that matter. What am I doing wrong?
## Answer by amdopt (score 5)
https://quant.stackexchange.com/a/42846
I have corrected your code so that it works as it should. This code could be cleaned up a lot. I just adjusted your existing code so that you would be able to understand it. I added some comments preceded by ## on the lines that were changed. See below.
```
import numpy as np
from math import fabs
def getRSI(close, n=14):
# compute a vector for change between daily closing prices
change = np.zeros(len(close))
for i in range(1, len(close)):
change[i] = close[i] - close[i-1] ##Reversed the order of these.
# compute a vector of gains and losses
gain = np.zeros(len(close))
loss = np.zeros(len(close))
for i in range(1, len(close)):
if change[i] >= 0:
gain[i] = change[i]
loss[i] = 0.00 ##Each array element needs a value.
else:
gain[i] = 0.00 ##Each array element needs a value.
loss[i] = fabs(change[i])
avg_gain = np.zeros(len(close) - n) ##Array length was wrong.
avg_loss = np.zeros(len(close) - n) ##Array length was wrong.
avg_gain[0] = np.average(gain[1:n+1]) ##First array element has a different calculation.
avg_loss[0] = np.average(loss[1:n+1]) ##First array element has a different calculation.
for i in range(1, len(close) - n): ##Loop counter was wrong.
avg_gain[i] = (avg_gain[i-1]*(n-1) + gain[i+n])/n ##Indexes were wrong.
avg_loss[i] = (avg_loss[i-1]*(n-1) + loss[i+n])/n ##Indexes were wrong.
RS = np.zeros(len(close) - n) ##Array length was wrong.
for i in range(0, len(close) - n): ##Loop counter was wrong.
RS[i] = avg_gain[i]/avg_loss[i]
RSI = np.zeros(len(close) - n) ##Array length was wrong.
for i in range(0, len(close) - n): ##Loop counter was wrong.
if avg_loss[i] == 0: ##This was missing. Could throw an error without it.
RSI[i] = 100
else:
RSI[i] = 100 - (100/(1+RS[i]))
return RSI
```Shown in full with attribution under the source's licence. Licence: CC BY-SA 4.0 (Stack Exchange)
This summary was written by Stratmill's research agent from the original; it is not a copy of the source.