Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Calculate RSI indicator from pandas DataFrame?

My problem

I tried many libraries on Github but all of them did not produce matching results for TradingView so I followed the formula on this link to calculate RSI indicator. I calculated it with Excel and collated the results with TradingView. I know it's absolutely correct but, but I didn't find a way to calculate it with Pandas.

Formula

              100
RSI = 100 - --------
             1 + RS

RS = Average Gain / Average Loss

The very first calculations for average gain and average loss are simple
14-period averages:

First Average Gain = Sum of Gains over the past 14 periods / 14.
First Average Loss = Sum of Losses over the past 14 periods / 14

The second, and subsequent, calculations are based on the prior averages
and the current gain loss:

Average Gain = [(previous Average Gain) x 13 + current Gain] / 14.
Average Loss = [(previous Average Loss) x 13 + current Loss] / 14.

Expected Results

     close   change     gain     loss     avg_gian    avg_loss        rs  \
0    4724.89      NaN      NaN      NaN          NaN         NaN       NaN   
1    4378.51  -346.38     0.00   346.38          NaN         NaN       NaN   
2    6463.00  2084.49  2084.49     0.00          NaN         NaN       NaN   
3    9838.96  3375.96  3375.96     0.00          NaN         NaN       NaN   
4   13716.36  3877.40  3877.40     0.00          NaN         NaN       NaN   
5   10285.10 -3431.26     0.00  3431.26          NaN         NaN       NaN   
6   10326.76    41.66    41.66     0.00          NaN         NaN       NaN   
7    6923.91 -3402.85     0.00  3402.85          NaN         NaN       NaN   
8    9246.01  2322.10  2322.10     0.00          NaN         NaN       NaN   
9    7485.01 -1761.00     0.00  1761.00          NaN         NaN       NaN   
10   6390.07 -1094.94     0.00  1094.94          NaN         NaN       NaN   
11   7730.93  1340.86  1340.86     0.00          NaN         NaN       NaN   
12   7011.21  -719.72     0.00   719.72          NaN         NaN       NaN   
13   6626.57  -384.64     0.00   384.64          NaN         NaN       NaN   
14   6371.93  -254.64     0.00   254.64   931.605000  813.959286  1.144535   
15   4041.32 -2330.61     0.00  2330.61   865.061786  922.291480  0.937948   
16   3702.90  -338.42     0.00   338.42   803.271658  880.586374  0.912201   
17   3434.10  -268.80     0.00   268.80   745.895111  836.887347  0.891273   
18   3813.69   379.59   379.59     0.00   719.730460  777.109680  0.926163   
19   4103.95   290.26   290.26     0.00   689.053999  721.601845  0.954895   
20   5320.81  1216.86  1216.86     0.00   726.754428  670.058856  1.084613   
21   8555.00  3234.19  3234.19     0.00   905.856968  622.197509  1.455899   
22  10854.10  2299.10  2299.10     0.00  1005.374328  577.754830  1.740140   

       rsi_14  
0         NaN  
1         NaN  
2         NaN  
3         NaN  
4         NaN  
5         NaN  
6         NaN  
7         NaN  
8         NaN  
9         NaN  
10        NaN  
11        NaN  
12        NaN  
13        NaN  
14  53.369848  
15  48.399038  
16  47.704239  
17  47.125561  
18  48.083322  
19  48.846358  
20  52.029461  
21  59.281719  
22  63.505515  

My Code

Import

import pandas as pd
import numpy as np

Load data

df = pd.read_csv("rsi_14_test_data.csv")
close = df['close']
print(close)

0      4724.89
1      4378.51
2      6463.00
3      9838.96
4     13716.36
5     10285.10
6     10326.76
7      6923.91
8      9246.01
9      7485.01
10     6390.07
11     7730.93
12     7011.21
13     6626.57
14     6371.93
15     4041.32
16     3702.90
17     3434.10
18     3813.69
19     4103.95
20     5320.81
21     8555.00
22    10854.10
Name: close, dtype: float64

Change

Calculate change every row

change = close.diff(1)
print(change)

0         NaN
1     -346.38
2     2084.49
3     3375.96
4     3877.40
5    -3431.26
6       41.66
7    -3402.85
8     2322.10
9    -1761.00
10   -1094.94
11    1340.86
12    -719.72
13    -384.64
14    -254.64
15   -2330.61
16    -338.42
17    -268.80
18     379.59
19     290.26
20    1216.86
21    3234.19
22    2299.10
Name: close, dtype: float64

Gain and loss

get gain and loss from change

is_gain, is_loss = change > 0, change < 0
gain, loss = change, -change
gain[is_loss] = 0
loss[is_gain] = 0
​
gain.name = 'gain'
loss.name = 'loss'
print(loss)

0         NaN
1      346.38
2        0.00
3        0.00
4        0.00
5     3431.26
6        0.00
7     3402.85
8        0.00
9     1761.00
10    1094.94
11       0.00
12     719.72
13     384.64
14     254.64
15    2330.61
16     338.42
17     268.80
18       0.00
19       0.00
20       0.00
21       0.00
22       0.00
Name: loss, dtype: float64

Calculate fist avg gain and loss

Mean of n prior rows

n = 14
avg_gain = change * np.nan
avg_loss = change * np.nan
​
avg_gain[n] = gain[:n+1].mean()
avg_loss[n] = loss[:n+1].mean()
​
avg_gain.name = 'avg_gain'
avg_loss.name = 'avg_loss'
​
avg_df = pd.concat([gain, loss, avg_gain, avg_loss], axis=1)
print(avg_df)

       gain     loss  avg_gain    avg_loss
0       NaN      NaN       NaN         NaN
1      0.00   346.38       NaN         NaN
2   2084.49     0.00       NaN         NaN
3   3375.96     0.00       NaN         NaN
4   3877.40     0.00       NaN         NaN
5      0.00  3431.26       NaN         NaN
6     41.66     0.00       NaN         NaN
7      0.00  3402.85       NaN         NaN
8   2322.10     0.00       NaN         NaN
9      0.00  1761.00       NaN         NaN
10     0.00  1094.94       NaN         NaN
11  1340.86     0.00       NaN         NaN
12     0.00   719.72       NaN         NaN
13     0.00   384.64       NaN         NaN
14     0.00   254.64   931.605  813.959286
15     0.00  2330.61       NaN         NaN
16     0.00   338.42       NaN         NaN
17     0.00   268.80       NaN         NaN
18   379.59     0.00       NaN         NaN
19   290.26     0.00       NaN         NaN
20  1216.86     0.00       NaN         NaN
21  3234.19     0.00       NaN         NaN
22  2299.10     0.00       NaN         NaN

The very first calculations for average gain and the average loss is ok but I don't know how to apply pandas.core.window.Rolling.apply for the second, and subsequent because they are in many rows and different columns. It may be something like this:

avg_gain[n] = (avg_gain[n-1]*13 + gain[n]) / 14

My Wish - My Question

  • The best way to calculate and work with technical indicators?
  • Complete the above code in "Pandas Style".
  • Does the traditional way of coding with loops reduce performance compared to Pandas?
like image 570
Thai D. V. Avatar asked Jul 12 '19 11:07

Thai D. V.


People also ask

How is the RSI calculated?

It's calculated using average price gains and losses over a given period of time. The default time period is 14 periods, with values bounded from 0 to 100. The MACD measures the relationship between two EMAs, while the RSI measures price change momentum in relation to recent price highs and lows.


1 Answers

There is an easier way, the package talib.

import talib   
close = df['close']
rsi = talib.RSI(close, timeperiod=14)

If you'd like Bollinger Bands to go with your RSI that is easy too.

upperBB, middleBB, lowerBB = talib.BBANDS(close, timeperiod=20, nbdevup=2, nbdevdn=2, matype=0)

You can use Bollinger Bands on RSI instead of the fixed reference levels of 70 and 30.

upperBBrsi, MiddleBBrsi, lowerBBrsi = talib.BBANDS(rsi, timeperiod=50, nbdevup=2, nbdevdn=2, matype=0)

Finally, you can normalize RSI using the %b calcification.

normrsi = (rsi - lowerBBrsi) / (upperBBrsi - lowerBBrsi)

info on talib https://mrjbq7.github.io/ta-lib/

info on Bollinger Bands https://www.BollingerBands.com

like image 133
John Avatar answered Oct 11 '22 19:10

John