Quantopian's community platform is shutting down. Please read this post for more information and download your code.
Back to Community
My algorithm does not trade at all

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]))  
2 responses

Alex - can you please "share" the "full backtest" of your algorithm, rather than copy-and-paste the code? The copy-and-paste misses a lot important information, like whitespace formatting, start date, end date, etc.

Disclaimer

The material on this website is provided for informational purposes only and does not constitute an offer to sell, a solicitation to buy, or a recommendation or endorsement for any security or strategy, nor does it constitute an offer to provide investment advisory services by Quantopian. In addition, the material offers no opinion with respect to the suitability of any security or specific investment. No information contained herein should be regarded as a suggestion to engage in or refrain from any investment-related course of action as none of Quantopian nor any of its affiliates is undertaking to provide investment advice, act as an adviser to any plan or entity subject to the Employee Retirement Income Security Act of 1974, as amended, individual retirement account or individual retirement annuity, or give advice in a fiduciary capacity with respect to the materials presented herein. If you are an individual retirement or other investor, contact your financial advisor or other fiduciary unrelated to Quantopian about whether any given investment idea, strategy, product or service described herein may be appropriate for your circumstances. All investments involve risk, including loss of principal. Quantopian makes no guarantees as to the accuracy or completeness of the views expressed in the website. The views are subject to change, and may have become unreliable for various reasons, including changes in market conditions or economic circumstances.

Hi Alex,
When you are declaring your 'long_weight' you have used 1 / len(context.longs).
As 1 is interpreted as an integer by python after it does the division it then rounds it to 0 hence your weight for each stock you are trying to order is 0.
Changing this to '1.0' will fix the problem as python will interpret this as a float type.
Sorry for the rather late reply but I hope this has helped.