I am trying to implement this algo, but I get a runtime error on line 252
Would someone know what is wrong?
I copy the algo here in case you cant see the source code
"""
Select 10 stocks from Q500US universe based on following ranking system:
1) VALUATION 60%
- Price to Book ratio (lowest).......33%
- TTM PE (lowest)....................33%
- 5 year Sales % CAGR (highest)......33% <--- coded with growth_score, but not exactly correct, i.e. should be only growth of sales
2) MOMENTUM 40%
- 3 Months Pct Change................50%
- 3 Months Pct Change 3 Months ago...50%
Rules:
- Entry if SMA50 > SMA200 with following settings:
- Exit if SMA50 <= SMA200 with following settings:
"""
from quantopian.algorithm import attach_pipeline,pipeline_output
from quantopian.pipeline import Pipeline
from quantopian.pipeline.data.builtin import USEquityPricing
from quantopian.pipeline.factors import AverageDollarVolume,SimpleMovingAverage
from quantopian.pipeline.filters.morningstar import Q500US
from quantopian.pipeline.data import morningstar
# from quantopian.pipeline.data import Fundamentals as income_statement
# from quantopian.pipeline.data import Fundamentals as balance_sheet
from quantopian.pipeline.data import Fundamentals as valuation_ratios
from quantopian.pipeline.data import Fundamentals as valuation
# from quantopian.pipeline.classifiers.fundamentals import Sector
from quantopian.pipeline import CustomFactor
import numpy
#========================================================================================
'''
Set constants
'''
# Set quarter look-back period
trading_days_in_year = 252
Q1=-1
Q2=0-(trading_days_in_year/4)
Q3=0-(trading_days_in_year/4)*2
Q4=0-(trading_days_in_year/4)*3
# Set number of stocks going long during positive market trends
target_stocks = 10
#Set Max leverage
stocks_long_max_leverage = +1.0
spy = sid(8554)
#========================================================================================
def initialize(context):
"""
Called once at the start of the algorithm.
"""
# Rebalance every day, 1 hour after market open.
schedule_function(my_rebalance, date_rules.every_day(),time_rules.market_open(minutes=5))
# Record tracking variables at the end of each day.
schedule_function(my_record_vars, date_rules.every_day(), time_rules.market_close())
# # Import SPY for 130/30 portfolio
# context.spy = sid(8554)
# # Import IEI for adverse market conditions
# context.iei = sid(33151)
my_pipe = make_pipeline()
attach_pipeline(my_pipe,'my_pipeline')
# Keep track of market conditions
context.spy_uptrend = False
context.spy_downtrend = False
#========================================================================================
'''
RELATIVE STRENGTH SIGNALS
'''
# 3 months momentum
class Momentum3M(CustomFactor):
# Pre-declare inputs and window_length
inputs = [USEquityPricing.close]
window_length = 62
# Compute factor1 value
def compute(self, today, assets, out, close):
out[:] = close[-2]/close[-62]
# 3 months momentum 3 months ago
class Momentum3M3M(CustomFactor):
# Pre-declare inputs and window_length
inputs = [USEquityPricing.close]
window_length = 120
# Compute factor2 value
def compute(self, today, assets, out, close):
out[:] = close[-60]/close[-120]
#========================================================================================
'''VALUATION RATIOS'''
# Calculate trailing 12 months EPS sum
class EPS_TTM(CustomFactor):
inputs = [morningstar.earnings_report.basic_eps]
window_length = trading_days_in_year
def compute(self, today, asset_ids, out, eps):
out[:] = eps[Q1] + eps[Q2] + eps[Q3] + eps[Q4]
# Latest Price to Book ratio
class Price_to_book(CustomFactor):
inputs = [morningstar.valuation_ratios.pb_ratio]
window_length = 2
def compute(self, today, asset_ids, out, pb):
out[:] = pb[-1]
# Past 5 years revenue growth rate
class Growth5yr(CustomFactor):
inputs = [morningstar.asset_classification.growth_score]
window_length = trading_days_in_year
def compute(self, today, asset_ids, out, value):
out[:] = value[-1]
#========================================================================================
def make_pipeline():
# Base universe set to the Q500US
base_universe = Q500US()
'''
Import momentum signals
'''
momentum3M = Momentum3M()
# pipe.add(momentum3M, 'momentum3M')
momentum3M3M = Momentum3M3M()
# pipe.add(momentum3M3M, 'momentum3M3M')
'''
Rank momentum signals
'''
momentum3M_rank = momentum3M.rank(mask=base_universe, ascending=False)
# pipe.add(momentum3M_rank, 'mom3M_rank')
momentum3M3M_rank = momentum3M3M.rank(mask=base_universe, ascending=False)
# pipe.add(momentum3M3M_rank, 'mom3M3M_rank')
# Combine momentum ranking
mom_comb = (momentum3M_rank*0.5 + momentum3M3M_rank*0.5)
# my_pipe.add(mom_comb, 'Momentum combination')
# Rank the mom_comb
mom_rank = mom_comb.rank(mask=base_universe, ascending=False)
# pipe.add(mom_rank, 'Momentum Rank')
'''
Valuation ratios
'''
# Last quarter Price to Book ratio
pb_ratio = Price_to_book()
# Get last closing price
yesterday_close = USEquityPricing.close.latest
# Trailing 12 months PE ratio
eps_ttm = EPS_TTM()
pe_ttm = eps_ttm / yesterday_close
# 5 year growth
growth = Growth5yr()
# growth = morningstar.asset_classification.growth_score.latest
'''
Rank valuation ratios
'''
# dividend yield
pb_rank = pb_ratio.rank(mask=base_universe, ascending=True)
pe_rank = pe_ttm.rank(mask=base_universe, ascending=True)
growth_rank = growth.rank(mask=base_universe, ascending=False)
# Combine Valuation ranking
val_comb = (pb_rank*0.33 + pe_rank*0.33 + growth_rank*0.33)
# Rank the val_comb
val_rank = val_comb.rank(mask=base_universe, ascending=False)
'''
Combined Total Rank (Momentum + Valuation)
'''
comb = (val_rank * 0.6 + mom_rank * 0.4)
# Rank the combined ranking
comb_rank = comb.rank(mask=base_universe, ascending=False)
'''
Return values
'''
pipe = Pipeline(
screen = base_universe,
columns = {
'Mom Value': mom_comb,
'Val Value':val_comb,
'Total Ranking':comb_rank
}
)
return pipe
#========================================================================================
def before_trading_start(context, data):
"""
Called every day before market open.
"""
context.output = pipeline_output('my_pipeline')
# These are the long securities that we are interested in trading each day in favourable mkt conditions
# i.e. SMA50 > SMA200
context.long_list = context.output.sort(['comb_rank'], ascending=False).iloc[:target_stocks]
#========================================================================================
def my_assign_weights(context, data):
"""
Assign weights to securities that we want to order.
"""
pass
#========================================================================================
def my_rebalance(context,data):
"""
Execute orders according to our schedule_function() timing.
"""
# Check that list of stocks to buy is not empty
try:
long_stocks_weight = stocks_long_max_leverage / float(len(context.long_list))
except ZeroDivisionError:
long_stocks_weight = 0.0
log.info('no stocks to buy today')
# Calcualte SMA50 and SMA200 for entry/exit and hedge rules
sma_50 = SimpleMovingAverage(inputs=[USEquityPricing.close], window_length=50, mask=spy)
sma_200 = SimpleMovingAverage(inputs=[USEquityPricing.close], window_length=200, mask=spy)
# When SMA50 > SMA200 go 130% long on list of stocks and 30% short on SPY
if sma_50 > sma_200:
for long_stock in context.long_list.index:
if data.can_trade(long_stock):
order_target_percent(long_stock, long_stocks_weight)
context.spy_uptrend = True
context.spy_downtrend = False
# When SMA50 <= SMA200 go 100% long on bond ETF
elif sma_50 <= sma_200:
order_target_percent(long_stock, 0.0)
context.spy_uptrend = False
context.spy_downtrend = True
# for stock in context.portfolio.positions.iterkeys():
# # if stock not in context.long_list.index and stock not in context.short_list.index:
# if stock not in context.long_list.index:
# order_target(stock, 0)
#========================================================================================
def my_record_vars(context, data):
"""
Plot variables at the end of each day.
"""
# Record and plot the leverage of our portfolio over time.
record(leverage = context.account.leverage)
print "Long List"
log.info("\n" + str(context.long_list.sort(['comb_rank'], ascending=True)))
#========================================================================================
def handle_data(context,data):
"""
Called every minute.
"""
pass
#========================================================================================
# def daily_clean(context, data):
# for stock in context.portfolio.positions:
# if stock not in context.security_set and data.can_trade(stock):
# order_target_percent(stock, 0)