## Python Tutorial: ROC

Python streamlines tasks requiring multiple steps in a single block of code. For this reason, it is a great tool for querying and performing analysis on data.

Last Tutorial, we outlined steps for calculating Relative Strength Index (RSI).
In this Tutorial, we introduce a new technical indicator, the Rate of Change (ROC).

‘The only thing constant is change’

The Rate of Change (ROC) is a technical indicator of momentum that measures the percentage change in price between the current price and the price n periods in the past.

The Rate of Change (ROC) is calculated as follows:

``ROC = ((Most recent closing price - Closing price n periods ago) / Closing price n periods ago) x 100``

The Rate of Change (ROC) is classed as a momentum indicator because it measures strength of price momentum. For example, if a stock’s price at the close of trading today is 10, and the closing price five trading days prior was 7, then the Rate of Change (ROC) over that time frame is approximately 43, calculated as (10 – 7 / 7) x 100 = 42.85.

Positive values indicate upward buying pressure or momentum, while negative values below zero indicate selling pressure or downward momentum. Increasing values in either direction, positive or negative, indicate increasing momentum, and decreasing values indicate waning momentum.

The Rate of Change (ROC) is also sometimes used to indicate overbought or oversold conditions for a security. Positive values that are greater than 30 are generally interpreted as indicating overbought conditions, while negative values lower than negative 30 indicate oversold conditions.

Let’s use Python to compute the Rate of Change (ROC).

1.) Import modules.

```import pandas as pd
import numpy as np
from pandas_datareader import data as web
import matplotlib.pyplot as plt
%matplotlib inline```

2.) Define function for querying daily close.

```def get_stock(stock,start,end):

3.) Define function for Rate of Change (ROC).

```def ROC(df, n):
M = df.diff(n - 1)
N = df.shift(n - 1)
ROC = pd.Series(((M / N) * 100), name = 'ROC_' + str(n))
return ROC```

How does the ROC function work?

3.a.) Function calculates difference in most recent closing price from closing price n periods ago. Sets the value to variable M.
`#M = df.diff(n - 1)`

3.b.) Function calculates closing price n periods ago. Sets the value to variable N.

`#N = df.shift(n - 1)`

3.c.) Function creates series called ROC that is ((M/N) * 100)

`#ROC = pd.Series(((M / N) * 100), name = 'ROC_' + str(n))`

3.d.) Function returns ROC

`#return ROC`

4.) Query daily close for ‘FB’ during 2016.

`df = pd.DataFrame(get_stock('FB', '1/1/2016', '12/31/2016'))`

5.) Run daily close through ROC function. Save series to new column in dataframe.

```df['ROC'] = ROC(df['Close'], 12)
df.tail()```

6.) Plot daily close and ROC.

```df.plot(y=['Close'])
df.plot(y=['ROC'])```

There you have it! We created our ROC indicator. Here’s the full code:

```import pandas as pd
import numpy as np
from pandas_datareader import data as web
import matplotlib.pyplot as plt
%matplotlib inline

def get_stock(stock,start,end):

def ROC(df, n):
M = df.diff(n - 1)
N = df.shift(n - 1)
ROC = pd.Series(((M / N) * 100), name = 'ROC_' + str(n))
return ROC

df = pd.DataFrame(get_stock('FB', '1/1/2016', '12/31/2016'))
df['ROC'] = ROC(df['Close'], 12)
df.tail()```

## Quantopian: RSI Strategy Backtest

Relative Strength Index (RSI) Strategy Backtest

Contact: andrewshamlet@gmail.com // @andrewshamlet

View the Quantopian Backtest here.

Summary

• The Relative Strength Index (RSI) is a momentum indicator that compares the magnitude of recent gains and losses over a specified time period. RSI values range from 0 to 100.
• For this strategy, we buy \$FB when the RSI is less than 30, and we will sell \$FB when the RSI is greater than 70. The RSI will be calculated at a minutely frequency, as opposed to a daily frequency.
• During 01/01/16 – 12/31/16,
• The RSI Strategy produces 32.2% return, resulting in \$3,220 pre-tax return.
• FB Buy & Hold produces 10.0% return, resulting in \$1,000 pre-tax return.
• SPY Buy & Hold produces 12.0% return, resulting in \$1,200 pre-tax return.
• Compared to the SPY Buy & Hold, the RSI Strategy produces \$2,220 Alpha whereas FB Buy & Hold produces (\$200) Alpha, both on \$10,000, principal.
• During 05/19/12 – 12/31/16,
• The RSI Strategy produces 147.4% return, resulting in \$14,740 pre-tax return.
• FB Buy & Hold produces 238.5% return, resulting in \$23,850 pre-tax return.
• SPY Buy & Hold produces 89.6% return, resulting in \$8,960 pre-tax return.
• Compared to SPY Buy & Hold, the RSI Strategy produces \$5,780 Alpha whereas FB Buy & Hold produces \$14,890 Alpha, both on \$10,000 principal.
• Thus, on the broader time horizon, FB Buy & Hold outperforms the RSI Strategy.
• The question still stands: what about 2016 makes the RSI Strategy superior in performance to FB Buy & Hold?

Introduction

In this post, we use Quantopian to build and backtest a Relative Strength Index (RSI) trading strategy.

Quantopian

Quantopian provides capital, education, data, a research environment, and a development platform to algorithm authors (quants). Quantopian provides everything a quant needs to create a strategy and profit from it.

Quantopian’s members include finance professionals, scientists, developers, and students from more than 180 countries from around the world. The members collaborate in our forums and in person at regional meetups, workshops, and QuantCon, Quantopian’s flagship annual event.”

In other words, Quantopian is a website where one can build, test, and deploy trading strategies, using Python.

Relative Strength Index

To review, the Relative Strength Index (RSI) is a momentum indicator that compares the magnitude of recent gains and losses over a specified time period to measure speed and change of price movements of a security. It is primarily used to identify overbought or oversold conditions in the trading of an asset.

RSI values range from 0 to 100.

The Relative Strength Index (RSI) is calculated as follows:

``````RSI = 100 - 100 / (1 + RS)

RS = Average gain of last 14 trading days / Average loss of last 14 trading days
``````

Strategy

For this strategy, we buy \$FB when the RSI is less than 30, and we will sell \$FB when the RSI is greater than 70. The RSI will be calculated at a minutely frequency, as opposed to a daily frequency.

``````Trading Strategy

Sell - RSI > 70
``````

Code

Here is the Python code for the RSI Strategy.

```import talib
import numpy as np
import pandas as pd

def initialize(context):
context.stocks = symbols('FB')
context.pct_per_stock = 1.0 / len(context.stocks)
context.LOW_RSI = 30
context.HIGH_RSI = 70

set_benchmark(sid(42950))

def handle_data(context, data):
prices = data.history(context.stocks, 'price', 40, '1d')

rsis = {}

for stock in context.stocks:
rsi = talib.RSI(prices[stock], timeperiod=14)[-1]
rsis[stock] = rsi

current_position = context.portfolio.positions[stock].amount

if rsi > context.HIGH_RSI and current_position > 0 and data.can_trade(stock):
order_target(stock, 0)

elif rsi < context.LOW_RSI and current_position == 0 and data.can_trade(stock):
order_target_percent(stock, context.pct_per_stock)

record(FB_rsi=rsis[symbol('FB')])```

At its foundation, Quantopian code is made up of three chunks: import modules, initialize, and handle_data.

1.) First we import the Talib, Numpy, and Pandas modules. As we’ll see, Talib streamlines the calculation of Technical Indicators.

``````import talib
import numpy as np
import pandas as pd
``````

2.)  The initialize function:

``````def initialize(context):
context.stocks = symbols('FB')
context.pct_per_stock = 1.0 / len(context.stocks)
context.LOW_RSI = 30
context.HIGH_RSI = 70

set_benchmark(sid(42950)) ``````

2.a.) Define the security to trade, \$FB.

``context.stocks = symbols('FB') ``

2.b.) Define the weight of each security. Since the RSI Strategy trades one security, the weight is 1.0. If there were two securities, the weight would be 0.5.

``context.pct_per_stock = 1.0 / len(context.stocks) ``

2.c.) Define the LOW_RSI value as 30

``context.LOW_RSI = 30 ``

2.d.) Define the HIGH_RSI value as 70

``context.HIGH_RSI = 70 ``

2.e.) Define the benchmark to which we will compare our strategy. In the example, the benchmark is set to \$FB, essentially a buy and hold strategy. Remove ‘set_benchmark()’ to set the benchmark to the standard, ‘SPY’, or market rate.

``set_benchmark(sid(42950)) ``

3.)  The handle_data function:

``````def handle_data(context, data):
prices = data.history(context.stocks, 'price', 40, '1d')

rsis = {}

for stock in context.stocks:
rsi = talib.RSI(prices[stock], timeperiod=14)[-1]
rsis[stock] = rsi

current_position = context.portfolio.positions[stock].amount

if rsi > context.HIGH_RSI and current_position > 0 and data.can_trade(stock):
order_target(stock, 0)

elif rsi < context.LOW_RSI and current_position == 0 and data.can_trade(stock):
order_target_percent(stock, context.pct_per_stock)

record(FB_rsi=rsis[symbol('FB')])
``````

3.a.) Query the ‘FB’ historical price data for the past 40 trading days.

``prices = data.history(context.stocks, 'price', 40, '1d') ``

3.b.) Create dictionary of RSI values.

``rsis = {} ``

3.c.) Create for loop for RSI calculation and order logic.

``for stock in context.stocks: ``

3.d.) Use Talib to calculate Relative Strength Index.

``rsi = talib.RSI(prices[stock], timeperiod=14)[-1]``

3.e.) Save Talib output to dictionary.

``rsis[stock] = rsi ``

3.f.) Save current portfolio positions in order to not execute too many/few orders.

``current_position = context.portfolio.positions[stock].amount ``

3.g.) Order logic: if RSI is greater than 70 and positions are greater than 0, then sell all positions.

``````if rsi > context.HIGH_RSI and current_position > 0 and data.can_trade(stock):
order_target(stock, 0) ``````

3.h.) Order logic: if RSI is less than 30 and positions are equal to 0, then buy positions equal to weight defined in initialize function.

``````elif rsi < context.LOW_RSI and current_position == 0 and data.can_trade(stock):
order_target_percent(stock, context.pct_per_stock)
``````

3.i.) Chart RSI data for \$FB.

``record(FB_rsi=rsis[symbol('FB')])``

1 Year Performance

For the time period, 01/01/16 – 12/31/16

 % Return Principal Pre-Tax Return Alpha RSI Strategy 32.2% \$10,000 \$3,220 \$2,220 FB Buy & Hold 10.0% \$10,000 \$1,000 (\$200) SPY Buy & Hold 12.0% \$10,000 \$1,200 N/A

We backtest the RSI Strategy with a \$10,000 principal for the time period, 01/01/16 – 12/31/16.

During 01/01/16 – 12/31/16,

• The RSI Strategy produces 32.2% return, resulting in \$3,220 pre-tax return.
• FB Buy & Hold produces 10.0% return, resulting in \$1,000 pre-tax return.
• SPY Buy & Hold produces 12.0% return, resulting in \$1,200 pre-tax return.
• Compared to the SPY Buy & Hold, the RSI Strategy produces \$2,220 Alpha whereas FB Buy & Hold produces (\$200) Alpha, both on \$10,000, principal.

Beyond 1 Year Performance

Yes, \$2,220 Alpha on \$10,000 principal is impressive.

Before we go and bet the farm, let’s see how the RSI Strategy performs over a longer time period.

Since the ‘FB’ IPO occurred on 05/18/12, we will backtest for the period 05/19/12 – 12/31/16.

For the time period, 05/19/12 – 12/31/16

 % Return Principal Pre-Tax Return Alpha RSI Strategy 147.4% \$10,000 \$14,740 \$5,780 FB Buy & Hold 238.5% \$10,000 \$23,850 \$14,890 SPY Buy & Hold 89.6% 10,000 \$8,960 N/A

During 05/19/12 – 12/31/16,

• The RSI Strategy produces 147.4% return, resulting in \$14,740 pre-tax return.
• FB Buy & Hold produces 238.5% return, resulting in \$23,850 pre-tax return.
• SPY Buy & Hold produces 89.6% return, resulting in \$8,960 pre-tax return.
• Compared to SPY Buy & Hold, the RSI Strategy produces \$5,780 Alpha whereas FB Buy & Hold produces \$14,890 Alpha, both on \$10,000 principal.

Thus, on the broader time horizon, FB Buy & Hold outperforms the RSI Strategy.

Concluding Thought

Over the long term, money would go further with the FB Buy & Hold strategy.

The question still stands: what about 2016 makes the RSI Strategy superior in performance to FB Buy & Hold?

Until next time!

## Python Tutorial: RSI

Python streamlines tasks requiring multiple steps in a single block of code. For this reason, it is a great tool for querying and performing analysis on data.

Last Tutorial, we outlined steps for calculating Price Channels.

In this Tutorial, we introduce a new technical indicator, the Relative Strenght Index (RSI).

The Relative Strength Index (RSI) is a momentum indicator developed by noted technical analyst Welles Wilder, that compares the magnitude of recent gains and losses over a specified time period to measure speed and change of price movements of a security. It is primarily used to identify overbought or oversold conditions in the trading of an asset.

The Relative Strength Index (RSI) is calculated as follows:

``````RSI = 100 - 100 / (1 + RS)

RS = Average gain of last 14 trading days / Average loss of last 14 trading days
``````

RSI values range from 0 to 100.

Traditional interpretation and usage of the RSI is that RSI values of 70 or above indicate that a security is becoming overbought or overvalued, and therefore may be primed for a trend reversal or corrective pullback in price. On the other side, an RSI reading of 30 or below is commonly interpreted as indicating an oversold or undervalued condition that may signal a trend change or corrective price reversal to the upside.

Let’s use Python to compute the Relative Strenght Index (RSI).

1.) Import modules (numpy included).

``````import pandas as pd
import numpy as np
from pandas_datareader import data as web
import matplotlib.pyplot as plt
%matplotlib inline``````

2.) Define function for querying daily close.

``````def get_stock(stock,start,end):

3.) Define function for RSI.

``````def RSI(series, period):
delta = series.diff().dropna()
u = delta * 0
d = u.copy()
u[delta > 0] = delta[delta > 0]
d[delta < 0] = -delta[delta < 0]
u[u.index[period-1]] = np.mean( u[:period] ) #first value is sum of avg gains
u = u.drop(u.index[:(period-1)])
d[d.index[period-1]] = np.mean( d[:period] ) #first value is sum of avg losses
d = d.drop(d.index[:(period-1)])
rs = pd.stats.moments.ewma(u, com=period-1, adjust=False) / \
return 100 - 100 / (1 + rs)``````

How does the RSI function work?

– 3.a.) Function creates two series of daily differences.

– 3.b.) One series is daily positive differences, i.e. gains.

– 3.c.) One series is daily negative difference, i.e. losses.

– 3.d.) Average daily positive differences for the period specified.

– 3.e.) Average daily negative difference for the period specified.

– 3.f.) RS is set equal to Exponential Moving Average of daily positive differences for the period sepcified / Exponential Moving Average of daily positive differences for the period sepcified.

– 3.g) Return 100 – 100 / (1 + RS)

4.) Query daily close for ‘FB’ during 2016.

``df = pd.DataFrame(get_stock('FB', '1/1/2016', '12/31/2016'))``

5.) Run daily close through RSI function. Save series to new column in dataframe.

``````df['RSI'] = RSI(df['Close'], 14)
df.tail()``````

6.) Plot daily close and RSI.

``````df.plot(y=['Close'])
df.plot(y=['RSI'])``````

There you have it! We created our RSI indicator. Here’s the full code:

``````import pandas as pd
import numpy as np
from pandas_datareader import data as web
import matplotlib.pyplot as plt
%matplotlib inline

def get_stock(stock,start,end):

def RSI(series, period):
delta = series.diff().dropna()
u = delta * 0
d = u.copy()
u[delta > 0] = delta[delta > 0]
d[delta < 0] = -delta[delta < 0]
u[u.index[period-1]] = np.mean( u[:period] ) #first value is sum of avg gains
u = u.drop(u.index[:(period-1)])
d[d.index[period-1]] = np.mean( d[:period] ) #first value is sum of avg losses
d = d.drop(d.index[:(period-1)])
rs = pd.stats.moments.ewma(u, com=period-1, adjust=False) / \