Also, just in case I've misdiagnosed where the error is coming from, here is the full strategy code. Just a simple monthly rebalanced vol-timed long momentum strategy to get working as a proof of concept.
from zipline.pipeline import Pipeline, CustomFactor
from zipline.pipeline.data import USEquityPricing
from zipline.pipeline.data import sharadar
from zipline.pipeline.factors import AverageDollarVolume, SimpleMovingAverage
from zipline.pipeline.filters import AllPresent, All
from zipline.api import *
from zipline.api import record
import zipline.api as algo
from codeload.tradable_stocks import TradableStocksUS
from quantrocket.zipline import backtest
import logging as log
import numpy as np
import os
import pandas as pd
def initialize(context):
schedule_function(rebalance, date_rules.month_start(), time_rules.market_open(hours=0.5))
schedule_function(record_vars, date_rules.month_start(), time_rules.market_close())
attach_pipeline(make_pipeline(), 'pipeline')
set_commission(commission.PerShare(cost=0.0, min_trade_cost=0))
set_slippage(slippage.VolumeShareSlippage(volume_limit=0.50, price_impact=0.0))
class ComputeMomentum(CustomFactor):
inputs = [USEquityPricing.close]
window_length = 250
def compute(self, today, assets, out, close):
out[:] = close[225] / close[0]
def make_pipeline():
in_sp500 = sharadar.SP500.in_sp500.latest
stock_filter = TradableStocksUS()
universe_mask = in_sp500 & stock_filter
universe = USEquityPricing.volume.latest.top(1000, mask=universe_mask)
Momentum = ComputeMomentum(mask=universe)
sma20 = SimpleMovingAverage(inputs=[USEquityPricing.close], window_length=20, mask=universe)
sma50 = SimpleMovingAverage(inputs=[USEquityPricing.close], window_length=50, mask=universe)
sma100 = SimpleMovingAverage(inputs=[USEquityPricing.close], window_length=100, mask=universe)
sma200 = SimpleMovingAverage(inputs=[USEquityPricing.close], window_length=200, mask=universe)
return Pipeline(
columns={
'Momentum': Momentum,
'sma20': sma20,
'sma50': sma50,
'sma100': sma100,
'sma200': sma200,
},
screen=(universe),
)
def before_trading_start(context, data):
context.SPY = algo.sid('FIBBG000BDTBL9')
pipe_results = pipeline_output('pipeline')
momentum = pipe_results['Momentum']
momentum15 = momentum.sort_values(ascending=False).nlargest(15)
context.longs = momentum15.index
def compute_weights(context, data):
prices = data.history(context.SPY, 'price', 20, '1d')
returns = prices.pct_change()
std_20 = returns.std() * np.sqrt(250)
if std_20 < 0.18:
weight = 1
else:
weight = 0
return weight
def rebalance(context, data):
context.weight = compute_weights(context, data)
momentum_weight = 1.0 / len(context.longs) * context.weight
# Liquidate old positions
for security in context.portfolio.positions:
if security not in context.longs and data.can_trade(security):
order_target_percent(security, 0)
# Buy new positions
for security in context.longs:
if data.can_trade(security):
order_target_percent(security, momentum_weight)
def record_vars(context, data):
record(
leverage = context.account.leverage,
cash = context.portfolio.cash/context.portfolio.portfolio_value,
weight = context.weight
)
This latest run came back looking for calendar XPHL again. Neither calendars are listed in the docs: trading calendars
And lastly as a sanity check:
from quantrocket.zipline import get_bundle_config
get_bundle_config('usstock-1min')
Returns:
{'ingest_type': 'usstock',
'sids': None,
'universes': None,
'free': False,
'data_frequency': 'minute',
'calendar': 'XNYS',
'start_date': '2007-01-03'}
Thanks again!