Quantopian's community platform is shutting down. Please read this post for more information and download your code.
Back to Community
Pair trading code problem

Hello Everyone,

Can you please tell me why I have a problem at line 55? with a zero division problem? z = (spread - meanPrice)/stdPrice

I can't seem to find why it does not work, please let me know if you can find the solution. I attached the code below.

Thank you very much!

Sincerely,
Terence

import statsmodels.api as sm
import numpy as np
import pandas as pd

def initialize(context):
context.notional=20000

context.pair_list=[  
           [sid(15634), sid(2637)], #utilities  
           [sid(22660),sid(9038)],#energy  
           [sid(3149),sid(20940)], #industrials  
           [sid(42700),sid(7239)],  
           [sid(4010),sid(24757)],  
           [sid(1335),sid(20088)], #financials  
           [sid(24491),sid(19177)], #basic materials  
           [sid(42596),sid(41149)], #communications  
           [sid(7687),sid(2754)], #consumer cyclical  
           [sid(2254),sid(4521)]  
           ]

pct_per_algo= 1.0 / len(context.pair_list)  

context.algos=pd.Series([Pair_Trade(context.pair_list[t][0], context.pair_list[t][1], pct_per_algo) for t in range(0, (len(context.pair_list)))])  

def handle_data(context, data):
context.algos.apply(lambda algo: algo.handle_data(context, data))

class Pair_Trade(object):

def __init__(self, stk0, stk1, pct_of_account):  
    self.stk0=stk0  
    self.stk1=stk1  
    self.pct=pct_of_account


def handle_data(self, context, data):  
    cash=context.notional*self.pct  
    cash=float(cash)  
    price_history = history(bar_count=200, frequency='1d', field='price')  

    beta = self.ols_transform(price_history, self.stk0, self.stk1)  
    beta=float(beta)  


    spread=data[self.stk0].price - beta*(data[self.stk1].price)  

    rVal = self.getMeanStd(price_history, beta, self.stk0, self.stk1)  
    meanPrice, stdPrice = rVal  

    z = (spread - meanPrice)/stdPrice

    if z>2 and context.portfolio.positions[self.stk0].amount==0 and context.portfolio.positions[self.stk1].amount==0:  
        order_value(self.stk1, cash)  
        order_value(self.stk0, -cash)

    elif z<-2 and context.portfolio.positions[self.stk0].amount==0 and context.portfolio.positions[self.stk1].amount==0 :  
        order_value(self.stk0, cash)  
        order_value(self.stk1, -cash)  

    elif abs(z)<0.5 and context.portfolio.positions[self.stk0].amount!=0 and context.portfolio.positions[self.stk1].amount!=0:  
        order_target(self.stk0, 0)  
        order_target(self.stk1, 0)  
    record(cash=cash)  

def getMeanStd(self, prices, beta, sid0, sid1):  
    meanPrice = np.mean(prices[sid0] - beta*prices[sid1])  
    stdPrice= np.std(prices[sid0] - beta*prices[sid1])  
    if meanPrice is not None and stdPrice is not None :  
        return (meanPrice, stdPrice)  
    else:  
        return None  


def ols_transform(self, prices, sid0, sid1):  
    """  
    Computes regression coefficient (slope and intercept)  
    via Ordinary Least Squares between two SIDs.  
    """  
    p0 = prices[sid0]  
    p1 = sm.add_constant(prices[sid1], prepend=True)  
    intercept, slope =sm.OLS(p0, p1).fit().params  
    return slope  
3 responses

Just throwing ideas out. The IDE warns that the stocks you've chosen do not always overlap in history which I suppose means you could potentially have no data for one of your stock objects in the Pair_Trade class so you might want to check that data exists for these stock before using them in your handle_data method:

if stk0 in data and stk1 in data:  
    # ok to do stuff  

You can mitigate divide by 0 error by just adding a check that stdPrice != 0 before using it for division.

z = 0  
if stdPrice != 0:  
    z = (spread - meanPrice)/stdPrice  

Hello Bailey,

The problem is that it used to work last year, I haven't touched it for a while and it seems that no matter what tickers I use, I get the same error. I did try mitigating your divide by 0 error, but the returns are just extremely flat now. Is there something that I am missing with Quantopian over the past year?

stdPrice==0 could occur due to calculating the standard deviation of just a single element, for example numpy.std([5.6]) gives 0.0.