To get to know the quantopian system I'm trying to convert the zipline pairtrade example for use on quantopian and am having some trouble. It works when I press the 'Build Algorithm' button in the IDE. When I try to run a full backtest I get a message saying 'Your algorithm couldn't be backtested because it has some code problems.'
There aren't any error messages or any problems in the IDE so I'm stumped.
Here's the code (I'm don't know how to share the algorithm, there isn't a button for that here)
import numpy as np
import statsmodels.api as sm
@batch_transform(refresh_period=10, window_length=10)
def ols_transform(data, sid1, sid2):
"""
Computes regression coefficient (slope and intercept)
via Ordinary Least Squares between two SIDs.
"""
p0 = data.price[sid1]
p1 = sm.add_constant(data.price[sid2])
slope, intercept = sm.OLS(p0, p1).fit().params
return slope, intercept
def initialize(context, window_length=50):
context.spreads = []
context.invested = 0
context.window_length = window_length
context.ols_transform = ols_transform
context.sid1 = sid(5885) # pepsi
context.sid2 = sid(4283) # coke
context.max_notional = 1000000.1
#context.min_notional = -1000000.0
def handle_data(context, data):
if context.sid1 not in data or context.sid2 not in data:
# missing price for one of the stocks
return
######################################################
# 1. Compute regression coefficients between PEP and KO
params = context.ols_transform(data, context.sid1, context.sid2)
if params is None:
return
intercept, slope = params
######################################################
# 2. Compute spread and zscore
zscore = compute_zscore(context, data, slope, intercept)
record(
zscore=zscore,
spread=data[context.sid1].price / data[context.sid2].price,
PEP=data[context.sid1].price / 10, # divide by 10 for better graph scale
KO=data[context.sid2].price / 10 # divide by 10 for better graph scale
)
######################################################
# 3. Place orders
place_orders(context, data, zscore)
def compute_zscore(context, data, slope, intercept):
"""
1. Compute the spread given slope and intercept.
2. zscore the spread.
"""
spread = (data[context.sid1].price - (slope * data[context.sid2].price + intercept))
context.spreads.append(spread)
spread_wind = context.spreads[-context.window_length:]
zscore = (spread - np.mean(spread_wind)) / np.std(spread_wind)
return zscore
def place_orders(context, data, zscore):
"""
Buy spread if zscore is > 2, sell if zscore < .5.
"""
trans_size = int(context.portfolio.cash / 2)
if zscore >= 2.0 and not context.invested:
order(context.sid1, int(trans_size / data[context.sid1].price))
order(context.sid2, -int(trans_size / data[context.sid2].price))
context.invested = True
elif zscore <= -2.0 and not context.invested:
order(context.sid2, -int(trans_size / data[context.sid2].price))
order(context.sid1, int(trans_size / data[context.sid1].price))
context.invested = True
elif abs(zscore) < .5 and context.invested:
sell_spread(context)
context.invested = False
def sell_spread(context):
"""
decrease exposure, regardless of position long/short.
buy for a short position, sell for a long.
"""
ko_amount = context.portfolio.positions[context.sid2].amount
order(context.sid2, -1 * ko_amount)
pep_amount = context.portfolio.positions[context.sid1].amount
order(context.sid1, -1 * pep_amount)