I am building a strategy to always buy the cheapest stocks based on PE ratios. However, as I ran backtest, the result showed that the portfolio gain is always 0 - apparently no trades at all. Could anyone help me tackle where is the issue?
"""
Trading Strategy using Fundamental Data
1. Look at stocks in the Q1500US.
2. Go long in the bottom 30 stocks by pe_ratio.
3. Rebalance every month at market open.
"""
from quantopian.algorithm import attach_pipeline, pipeline_output
from quantopian.pipeline import Pipeline
from quantopian.pipeline.data import Fundamentals
from quantopian.pipeline.filters import Q1500US
from quantopian.pipeline.factors import BusinessDaysSincePreviousEvent
def initialize(context):
# Rebalance monthly on the first day of the month at market open
schedule_function(rebalance,
date_rule=date_rules.month_start(days_offset=1),
time_rule=time_rules.market_open())
attach_pipeline(make_pipeline(), 'fundamentals_pipeline')
def make_pipeline():
# Latest p/e ratio.
pe_ratio = Fundamentals.pe_ratio.latest
# Number of days since the fundamental data was updated. In this example, we consider the p/e ratio
# to be fresh if it's less than 5 days old.
is_fresh = (BusinessDaysSincePreviousEvent(inputs=[Fundamentals.pe_ratio_asof_date]) <= 5)
# Q1500US is a pre-defined universe of liquid securities.
# You can read more about it here: https://www.quantopian.com/posts/the-q500us-and-q1500us
universe = Q1500US() & is_fresh
# Bottom 50 stocks ranked by p/e ratio
bottom_pe_stocks = pe_ratio.bottom(100, mask=universe)
# Screen to include only securities tradable for the day
securities_to_trade = (bottom_pe_stocks)
pipe = Pipeline(
columns={
'pe_ratio': pe_ratio,
'longs': bottom_pe_stocks,
},
screen = securities_to_trade
)
return pipe
"""
Runs our fundamentals pipeline before the marke opens every day.
"""
def before_trading_start(context, data):
context.pipe_output = pipeline_output('fundamentals_pipeline')
# The low p/e stocks that we want to long.
context.longs = context.pipe_output[context.pipe_output['longs']].index
def rebalance(context, data):
my_positions = context.portfolio.positions
# If we have at least one long and at least one short from our pipeline. Note that
# we should only expect to have 0 of both if we start our first backtest mid-month
# since our pipeline is scheduled to run at the start of the month.
if len(context.longs) > 0:
# Equally weight all of our long positions.
long_weight = 1/len(context.longs)
# Get our target names for our long baskets. We can display these
# later.
target_long_symbols = [s.symbol for s in context.longs]
log.info("Opening long positions each worth %.2f of our portfolio in: %s" \
% (long_weight, ','.join(target_long_symbols)))
# Open long positions in our bottom p/e stocks.
for security in context.longs:
if data.can_trade(security):
if security not in my_positions:
order_target_percent(security, long_weight)
else:
log.info("Didn't open long position in %s" % security)
closed_positions = []
# 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)
closed_positions.append(security)
log.info("Closing our positions in %s." % ','.join([s.symbol for s in closed_positions]))