4
\$\begingroup\$

I am trying to program the calculation of the relative strength index indicator described on a stockcharts.com page.

On the same page there are Excel formulas used for calculations.

My code below is accurate, but when I have many rows, its execution is quite slow, so I believe that it could be optimized.

import pandas as pd
import numpy as np

pd.set_option('display.width', 300)

close = [44.3389, 44.0902, 44.1497, 43.6124, 44.3278, 44.8264, 45.0955, 45.4245, 45.8433, 46.0826, 45.8931, 46.0328, 45.6140, 46.2820, 46.2820, 46.0028, 46.0328, 46.4116, 46.2222, 45.6439, 46.2122, 46.2521, 45.7137, 46.4515, 45.7835, 45.3548, 44.0288, 44.1783, 44.2181, 44.5672, 43.4205, 42.6628, 43.1314]
date = pd.date_range('20170101',periods=len(close))

df = pd.DataFrame(close, columns=['close'], index=date)

period = 14

df['delta'] = df['close'].diff()
df['up'] = df['dn'] = df['delta']

df.loc[df['up'][df['up'] < 0].index, 'up'] = 0
df.loc[df['dn'][df['dn'] > 0].index, 'dn'] = 0
df['dn'] = abs(df['dn']) 

df['avg_gain'] = df['avg_loss'] = 0
df['rs'] = df['rsi'] = np.nan

df.loc[df.index[period], 'avg_gain'] = np.mean(df.iloc[1:period + 1]['up'])
df.loc[df.index[period], 'avg_loss'] = np.mean(df.iloc[1:period + 1]['dn'])
df.loc[df.index[period], 'rs'] = df.loc[df.index[period], 'avg_gain'] / df.loc[df.index[period], 'avg_loss']
df.loc[df.index[period], 'rsi'] = 100.0 - (100.0 / (1.0 + df.loc[df.index[period], 'rs']))

# can this part be optimized?
avg_gain = df[0:period + 1]['avg_gain'].values
avg_loss = df[0:period + 1]['avg_loss'].values

for idx in range(period + 1, len(df.index)):
    avg_gain = np.append(avg_gain, ((avg_gain[idx - 1] * (period - 1)) + df.up.values[idx]) / period)
    avg_loss = np.append(avg_loss, ((avg_loss[idx - 1] * (period - 1)) + df.dn.values[idx]) / period)

df['avg_gain'] = avg_gain
df['avg_loss'] = avg_loss
# end of can this part be optimized?

df['rs'] = df['avg_gain'] / df['avg_loss']
df['rsi'] = 100.0 - (100.0 / (1.0 + df['rs']))

print(df)

The for loop is the biggest performance problem.

Another question I have is how do I avoid potential division by zero at this line?

df['rs'] = df['avg_gain'] / df['avg_loss']
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.