2.2 RSI

The Relative Strength Index (RSI), is treated as a predictive momentum indicator. It generates values between 0 and 100 based on whether the previous days closed up or down. According to http://www.investopedia.com/terms/r/rsi.asp, an RSI over 70 or below 30 means a stock is “overbought” or “oversold,” respectively.

The same article says that large surges or drops in price may create “false” buy or sell signals. It claims that RSI is best used as a “complement.”

The RSI has one parameter measuring the lookback period. It is usually set to 14 trading days.

This notebook defines formulas which add an RSI column. Some strategies will use these formulas to define bull and bear signals.

Import Packages

In [1]:
import numpy as np
import pandas as pd
import cPickle as pickle
shortUniverse = True

Load Pickle Data

First, we’ll load the pickle we developed in the previous section. The new prices dataframe is given a new name to reflect edits made during this notebook.

In [2]:
if shortUniverse:
    with open('intermediaries/prices.p', 'rb') as handle:
        prices = pickle.load(handle)
else:
    with open('intermediaries/prices-full.p', 'rb') as handle:
        prices = pickle.load(handle)

Development of RSI

The following formula adds an RSI column to a price dataframe. The calculation steps are as follows.

  1. Add column ‘U‘, giving the upwards daily dollar change in the stock. Is zero for downward days.
  2. Add column ‘D‘, giving the downwards daily dollar change in the stock. Is zero for upward days.
  3. Add columns ‘U_EMA‘ and ‘D_EMA‘, which provide exponential smoothing of ‘U‘ and ‘D‘, respectively, with parameter 1/14 as the alpha value.
  4. If ‘D_EMA‘ == 0, then set ‘D_EMA‘ to an aribtrarily low value (i.e. .01).
  5. Add column ‘RS’ which is equal to ‘U_EMA‘ divided by ‘D_EMA‘.
  6. Add column ‘RSI’ which is equal to 100 - (100/(1 + RS)).
  7. Remove all new columns except for ‘RSI’.
In [3]:
def add_RSI(df, lag=14):
    df['U'] = df['close'] - df.groupby('symbol')['close'].shift(1)
    df['D'] = -1 * df['U']
    df.loc[df['U'] < 0, 'U'] = 0
    df.loc[df['D'] < 0, 'D'] = 0
    df['U_EMA'] = pd.ewma(df['U'], span=14, min_periods=14, adjust=True)
    df['D_EMA'] = pd.ewma(df['D'], span=14, min_periods=14, adjust=True)
    df.loc[df['D_EMA'] == 0, 'D_EMA'] = .01
    df['RS'] = df['U_EMA'] / df['D_EMA']
    df['RSI'] = 100 - (100 / (1 + df['RS']))
    df = df.drop(['U', 'D', 'U_EMA', 'D_EMA', 'RS'], axis=1)
    return df
In [4]:
prices = add_RSI(prices)

Output Example

The first 11th through 20th observations are displayed below.

In [5]:
prices.head(20).tail(10)
Out[5]:
sector symbol open high low close volume ret_cc ret_oc ret_co RSI
Date
2015-01-16 XLP PG 86.347025 87.681347 86.270235 87.594956 8815700 0.015350 0.014349 1.001012e-03 NaN
2015-01-20 XLP PG 87.594956 88.113327 86.874997 87.537361 9869900 -0.000658 -0.000658 -2.381447e-09 NaN
2015-01-21 XLP PG 86.779006 87.537362 86.039843 87.095788 6974500 -0.005057 0.003644 -8.700966e-03 NaN
2015-01-22 XLP PG 88.014947 88.643350 86.883826 88.575677 7211200 0.016849 0.006351 1.049813e-02 NaN
2015-01-23 XLP PG 88.140625 88.159964 86.961162 87.086847 6745700 -0.016951 -0.012028 -4.923751e-03 NaN
2015-01-26 XLP PG 86.961162 86.961162 85.791368 86.603461 9371700 -0.005566 -0.004122 -1.444257e-03 45.450963
2015-01-27 XLP PG 84.205862 84.312208 83.161747 83.616131 14417400 -0.035103 -0.007028 -2.807524e-02 26.374203
2015-01-28 XLP PG 83.751478 84.022181 82.185312 82.320660 14033400 -0.015614 -0.017232 1.617366e-03 21.796561
2015-01-29 XLP PG 82.929723 83.248759 82.320659 82.823377 12054500 0.006088 -0.001283 7.371424e-03 27.435896
2015-01-30 XLP PG 82.262648 82.388333 81.450563 81.489235 14685300 -0.016239 -0.009446 -6.793194e-03 22.473427

Save Formulas

No new price file is created. However, add_RSI have been added to the separate document “helper_functions.py” which can be imported into future tests.

Potential Extensions

This space is reserved.