"""
Trading Strategy using Fundamental Data
1. Look at stocks in the Q1500US.
2. Filter stocks by low pe_ratio. Prefer book valuation but unsupported.
3. Go long on momentum from this filter.
4. Rebalance every week day 1 at market open. I want a minimum number of days to hold and daily rebalance, will figure out later.
"""
from quantopian.algorithm import attach_pipeline, pipeline_output
from quantopian.pipeline import Pipeline
from quantopian.pipeline.data import morningstar
from quantopian.pipeline.filters.morningstar import Q1500US
from quantopian.pipeline.data.builtin import USEquityPricing
from quantopian.pipeline.factors import SimpleMovingAverage
def initialize(context):
# Rebalance monthly on the first day of the week at market open
schedule_function(rebalance,
date_rule=date_rules.week_start(days_offset=1),
time_rule=time_rules.market_open())
my_pipe = make_pipeline()
attach_pipeline(my_pipe, 'value_momo_pipeline')
def make_pipeline():
# Latest p/b ratio.
pe_ratio = morningstar.valuation_ratios.pe_ratio.latest
# Q1500US is a pre-defined universe of liquid securities.
universe = Q1500US()
pe_stocks = pe_ratio.bottom(250, mask = universe)
# Momentum of pe stocks
SMA_10 = SimpleMovingAverage(inputs = [USEquityPricing.close], window_length=10, mask = pe_stocks)
SMA_30 = SimpleMovingAverage(inputs = [USEquityPricing.close], window_length=30, mask = pe_stocks)
percent_diff = (SMA_10 - SMA_30) / SMA_30
longs = percent_diff.bottom(50)
# Screen to include only securities tradable for the day
securities_to_trade = (longs)
pipe = Pipeline(
columns={
'pe_ratio': pe_ratio,
'longs': longs,
},
screen = (securities_to_trade),
)
return pipe
"""
Runs our fundamentals pipeline before the market opens every day.
"""
def before_trading_start(context, data):
# Gets our pipeline output every day.
context.output = pipeline_output('value_momo_pipeline')
# The low p/e stocks that we want to long.
context.longs = context.output[context.output['longs']].index.tolist()
def rebalance(context, data):
my_positions = context.portfolio.positions
if (len(context.longs) > 0):
# Equally weight all of our long positions
long_weight = 1/len(context.longs)
print(len(context.longs))
print(long_weight)
# Open long positions in our stocks.
for security in context.longs:
if data.can_trade(security) and security not in my_positions:
order_target_percent(security, long_weight)
# Close our previous positions that are no longer in our pipeline.
for security in my_positions:
if security not in context.longs and data.can_trade(security):
order_target_percent(security, 0)
Above is the code that I have been basically copying from examples and trying to make up new things as I go. I am running into an issue where the length of my securities to trade is 50, but when I compute weights as 1/length it comes out as 0, not 0.02. I was feeling pretty good about everything when I finally got it to run and saw things ticking, then realized nothing was being traded. Woot. What's the fix? I've been trying now for a couple hours, true Newbington Bear here. Thanks.
P.S. The two numbers it's printing is number of longs out of pipeline and weights.