Update – Python Tutorial: MACD (Moving Average Convergence/Divergence)

Download the accompanying IPython Notebook for this Tutorial from Github. 

I received a question from Sam Khorsand about applying the Python Tutorial: MACD (Moving Average Convergence/Divergence) Tutorial   to multiple stocks. The code below will produce yesterday’s MACD Crossover for a list of stocks. Also, by adding ‘to_string(index = False’), you can clean up the date formatting. Enjoy!

import pandas as pd
from pandas_datareader import data as web
import matplotlib.pyplot as plt
import datetime as dt
%matplotlib inline

def MACD(stock, start, end):
    df = pd.DataFrame(web.DataReader(stock,'google',start,end)['Close'])
    df = df.reset_index()
    df['30 mavg'] = pd.rolling_mean(df['Close'], 30)
    df['26 ema'] = pd.ewma(df['Close'], span=26)
    df['12 ema'] = pd.ewma(df['Close'], span=12)
    df['MACD'] = (df['12 ema'] - df['26 ema'])
    df['Signal'] = pd.ewma(df['MACD'], span=9)
    df['Crossover'] = df['MACD'] - df['Signal']
    return stock, df['Date'][-1:].to_string(),df['Crossover'][-1:].mean()
    

stocks = ['FB', 'AAPL', 'GOOG', 'AMZN', 'TSLA']

d = []

for stock in stocks:
    stock, date, macd = MACD(stock, '1/1/2016', dt.datetime.today())
    d.append({'Stock':stock, 'Date':date, 'MACD':macd})
    
df2 = pd.DataFrame(d)
df2[['Date', 'Stock', 'MACD']]
Date Stock MACD
0 249 2017-09-20 FB -0.211440
1 249 2017-09-20 AAPL -0.828956
2 249 2017-09-20 GOOG -0.069812
3 249 2017-09-20 AMZN 1.028655
4 249 2017-09-20 TSLA 2.287354

 

Python Tutorial: ROC

Download the accompanying IPython Notebook for this Tutorial from Github. 

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):
     return web.DataReader(stock,'google',start,end)['Close']

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):
     return web.DataReader(stock,'google',start,end)['Close']
    
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

Download the IPython Notebook that accompanies this Tutorial from Github. 

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

About 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

Buy - RSI < 30

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

Download the accompanying IPython Notebook for this Tutorial from Github. 

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):
 return web.DataReader(stock,'google',start,end)['Close']

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) / \
 pd.stats.moments.ewma(d, 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):
 return web.DataReader(stock,'google',start,end)['Close']
 
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) / \
 pd.stats.moments.ewma(d, com=period-1, adjust=False)
 return 100 - 100 / (1 + rs)
 
df = pd.DataFrame(get_stock('FB', '1/1/2016', '12/31/2016'))
df['RSI'] = RSI(df['Close'], 14)
df.tail()

Python Tutorial: MACD Signal Line & Centerline Crossovers

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 post, we outlined steps for calculating a stock’s MACD indicator.

In this post, we take MACD a step further by introducing Signal Line and Centerline Crossovers.

Signal Line Crossovers

Signal Line is defined as:

Signal Line: 9-day EMA of MACD Line

Signal line crossovers are the most common MACD signals. The signal line is a 9-day EMA of the MACD Line. As a moving average of the indicator, it trails the MACD and makes it easier to spot MACD turns. A bullish crossover occurs when the MACD turns up and crosses above the signal line. A bearish crossover occurs when the MACD turns down and crosses below the signal line. Crossovers can last a few days or a few weeks, it all depends on the strength of the move.

Let’s use Python to compute the Signal Line.

1.  Start with the MACD Tutorial code.

import pandas.io.data as web 
import pandas as pd 
%matplotlib inline 
import matplotlib.pyplot as plt 

names = ['FB'] 

def get_px(stock, start, end): 
     return web.get_data_yahoo(stock, start, end)['Adj Close'] 
px = pd.DataFrame({n: get_px(n, '1/1/2016', '1/17/2017') for n in names}) 
px['26 ema'] = pd.ewma(px["FB"], span=26) 
px['12 ema'] = pd.ewma(px["FB"], span=12) 
px['MACD'] = (px['12 ema'] - px['26 ema'])

2. Compute the 9 Day Exponential Moving Average of MACD.

px['Signal Line'] = pd.ewma(px['MACD'], span=9)

3. Create Signal Line Crossover Indicator. When MACD > Signal Line, 1. When MACD < Signal Line, 0.

px['Signal Line Crossover'] = np.where(px['MACD'] > px['Signal Line'], 1, 0)
px['Signal Line Crossover'] = np.where(px['MACD'] < px['Signal Line'], -1, px['Signal Line Crossover'])

Centerline Crossovers

Centerline crossovers are the next most common MACD signals. A bullish centerline crossover occurs when the MACD Line moves above the zero line to turn positive. This happens when the 12-day EMA of the underlying security moves above the 26-day EMA. A bearish centerline crossover occurs when the MACD moves below the zero line to turn negative. This happens when the 12-day EMA moves below the 26-day EMA.

Centerline crossovers can last a few days or a few months. It all depends on the strength of the trend. The MACD will remain positive as long as there is a sustained uptrend. The MACD will remain negative when there is a sustained downtrend.

4. Create Centerline Crossover Indicator. When MACD > 0, 1. When MACD < 0, 0.

px['Centerline Crossover'] = np.where(px['MACD'] > 0, 1, 0)
px['Centerline Crossover'] = np.where(px['MACD'] < 0, -1, px['Centerline Crossover'])

Plotting Crossovers

Last post, we posed the question: ‘When would you enter the position 😕 ?’

Now that we understand Signal Line Crossovers, let’s propose that we enter the position, ‘buy’, on 1, and we exit the position, ‘sell’, on -1.

5. Create Buy/Sell Indicator, based on Signal Line Crossovers. Multiply by 2 to increase size of indicator when plotted, so ‘buy’ on 2 and ‘sell’ on -2.

px['Buy Sell'] = (2*(np.sign(px['Signal Line Crossover'] - px['Signal Line Crossover'].shift(1))))

6. Plot close price, MACD & Signal Line, and Signal Line & Centerline Crossovers.

px.plot(y=['FB'], title='Close')
px.plot(y= ['MACD', 'Signal Line'], title='MACD & Signal Line')
px.plot(y= ['Centerline Crossover', 'Buy Sell'], title='Signal Line & Centerline Crossovers', ylim=(-3,3))

There you have it! We created MACD Signal Line and Centerline Crossovers, and based on the Crossovers, plotted ‘buy’ and ‘sell’ indicators.

Based on the entry and exit points, can you calculate the P&L? Stay tuned to find out.

Here’s the full code:

import pandas.io.data as web 
import pandas as pd 
%matplotlib inline 
import matplotlib.pyplot as plt 

names = ['FB'] 

def get_px(stock, start, end): 
     return web.get_data_yahoo(stock, start, end)['Adj Close'] 
px = pd.DataFrame({n: get_px(n, '1/1/2016', '1/17/2017') for n in names}) 
px['26 ema'] = pd.ewma(px["FB"], span=26) 
px['12 ema'] = pd.ewma(px["FB"], span=12) 
px['MACD'] = (px['12 ema'] - px['26 ema'])
px['Signal Line'] = pd.ewma(px['MACD'], span=9)
px['Signal Line Crossover'] = np.where(px['MACD'] > px['Signal Line'], 1, 0)
px['Signal Line Crossover'] = np.where(px['MACD'] < px['Signal Line'], -1, px['Signal Line Crossover'])
px['Centerline Crossover'] = np.where(px['MACD'] > 0, 1, 0)
px['Centerline Crossover'] = np.where(px['MACD'] < 0, -1, px['Centerline Crossover'])
px['Buy Sell'] = (2*(np.sign(px['Signal Line Crossover'] - px['Signal Line Crossover'].shift(1))))

px.plot(y=['FB'], title='Close')
px.plot(y= ['MACD', 'Signal Line'], title='MACD & Signal Line')
px.plot(y= ['Centerline Crossover', 'Buy Sell'], title='Signal Line & Centerline Crossovers', ylim=(-3,3))

Python Tutorial: MACD (Moving Average Convergence/Divergence)

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.

In this post, we outline steps for calculating a stock’s MACD indicator. But first, what is MACD (Moving Average Convergence/Divergence)?

Developed by Gerald Appel in the late seventies, MACD is one of the simplest and most effective momentum indicators available. MACD turns two trend-following indicators, moving averages, into a momentum oscillator by subtracting the longer moving average from the shorter moving average. As a result, MACD offers the best of both worlds: trend following and momentum.

To calculate MACD, the formula is:

MACD: (12-day EMA - 26-day EMA)

EMA stands for Exponential Moving Average.

With that background, let’s use Python to compute MACD.

1. Start with the 30 Day Moving Average Tutorial code.

import pandas as pd
import pandas.io.data as web

stocks = ['FB']
def get_stock(stock, start, end):
     return web.get_data_yahoo(stock, start, end)['Adj Close']
px = pd.DataFrame({n: get_px(n, '1/1/2016', '12/31/2016') for n in names})
px

2. Compute the 26 Day Exponential Moving Average. We must call the column by the stock ticker.

px['26 ema'] = pd.ewma(px["FB"], span=26)

3. Then the 12 Day Exponential Moving Average.

px['12 ema'] = pd.ewma(px["FB"], span=12)

4. Subtract the 26 Day EMA from the 12 Day EMA, arriving at the MACD.

px['MACD'] = (px['12 ema'] - px['26 ema'])

5. Plot close price against MACD.

px.plot(y= ['FB'], title='FB')
px.plot(y= ['MACD'], title='MACD')

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

import pandas.io.data as web
import pandas as pd
%matplotlib inline
import matplotlib.pyplot as plt

names = ['FB']
def get_px(stock, start, end): 
     return web.get_data_yahoo(stock, start, end)['Adj Close']
px = pd.DataFrame({n: get_px(n, '1/1/2016', '1/17/2017') for n in names})
px['26 ema'] = pd.ewma(px["FB"], span=26)
px['12 ema'] = pd.ewma(px["FB"], span=12)
px['MACD'] = (px['12 ema'] - px['26 ema'])
px.plot(y= ['FB'], title='FB')
px.plot(y= ['MACD'], title='MACD')

So when would you enter the position 😕 ?

Python Tutorial: Plot 30 Day Moving Average

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 post we created a DataFrame containing the daily ticker data for a specific stock and calculated its 30 day moving average. In this post, we will take it a step further and plot the DataFrame in order to visualize its contents.

1. Code from last post.

import pandas as pd
import pandas.io.data as web

stocks = ['FB']
def get_stock(stock, start, end):
     return web.get_data_yahoo(stock, start, end)['Adj Close']
px = pd.DataFrame({n: get_px(n, '1/1/2016', '12/31/2016') for n in names})
px['30 mavg'] = pd.rolling_mean(px, 30)
px

2. Import the matplotlib modules.

import matplotlib.pyplot as plt
%matplotlib inline

3. Call the plot function.

plt.plot(px)

There you have it! We used matplotlib to visualize our DataFrame. Looks like the stock tanked towards the end of 2016, perhaps due to the US Presidential Election 😉 

Here is the full code:

import pandas as pd 
import pandas.io.data as web 
import matplotlib.pyplot as plt
%matplotlib inline

stocks = ['FB'] 
def get_stock(stock, start, end):
     return web.get_data_yahoo(stock, start, end)['Adj Close'] 
px = pd.DataFrame({n: get_px(n, '1/1/2016', '12/31/2016') for n in names}) 
px['30 mavg'] = pd.rolling_mean(px, 30) 
plt.plot(px)

Python Tutorial: Query Stock Data, Calculate 30 Day Moving Average

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. In this post we will use Python to pull ticker data for a specific stock and then calculate its 30 day moving average. Here are the steps:

1. Import the pandas modules.

import pandas as pd
import pandas.io.data as web

2. Create a list of the stocks for which you would like to query ticker data. For this example, we will pull ticker data for Facebook, ‘FB’. If you would like to add other stocks, simply add the symbols to the list separated by commas.

stocks = ['FB']

Or

stocks = ['FB','AAPL','GOOG','AMZN']

3. Write function to query data from yahoo finance. The function takes three arguments: the stock, the start date, and the end date. It returns the daily ‘Adj Close’. If you would like to pull a different value, simply switch it for ‘Adj Close’ without the brackets.

def get_stock(stock,start,end):
     return web.get_data_yahoo(stock,start,end)['Adj Close']

Or

def get_stock(stock,start,end):
     return web.get_data_yahoo(stock,start,end)['Volume']

4. Call function for the date range, 1/1/2016 – 12/31/2016. Use the ‘for n in stocks’ logic in case you have more than one stock for which you would like to pull data. Compile query in DataFrame, saved to variable ‘px’.

px = pd.DataFrame({n: get_stock(n, '1/1/2016', '12/31/2016') for n in stocks})

5. Add new column to DataFrame in which you calculate the 30 day moving average. Call DataFrame to view contents.

px['30 mavg'] = pd.rolling_mean(px, 30)
px

There you have it! We created a DataFrame containing the daily ticker data for a specific stock and then calculated its 30 day moving average. Here is the full code:

import pandas as pd
import pandas.io.data as web

stocks = ['FB']
def get_stock(stock, start, end):
     return web.get_data_yahoo(stock, start, end)['Adj Close']
px = pd.DataFrame({n: get_px(n, '1/1/2016', '12/31/2016') for n in names})
px['30 mavg'] = pd.rolling_mean(px, 30)
px