Back to Community
Using #Fundamentals growth ranking for healthy growth stock picking strategy

I am excited for the newly added fundamental data function! It is much easier than before to test fundamental strategies that comes up to our minds.

I experimented with a couple of valuation ratios, but what seemed to work was the basic growth rate. This strategy invests evenly to top 100 highest growing stocks, rebalancing monthly.

A restriction I added was that ROIC (return on invested capital) should be above 10%, i.e. companies are making healthy returns on money at hand rather than generating revenue by burning cash

I am looking forward to fundamental data becoming available for live trading!

Clone Algorithm
952
Loading...
Backtest from to with initial capital
Total Returns
--
Alpha
--
Beta
--
Sharpe
--
Sortino
--
Max Drawdown
--
Benchmark Returns
--
Volatility
--
Returns 1 Month 3 Month 6 Month 12 Month
Alpha 1 Month 3 Month 6 Month 12 Month
Beta 1 Month 3 Month 6 Month 12 Month
Sharpe 1 Month 3 Month 6 Month 12 Month
Sortino 1 Month 3 Month 6 Month 12 Month
Volatility 1 Month 3 Month 6 Month 12 Month
Max Drawdown 1 Month 3 Month 6 Month 12 Month
"""
    Healthy growth stock picking strategy
    
    1. Every month, pick high-growth companies
    2. Companies with ROIC of above 10% (return on invested capital)
    3. Every month exit all the positions before entering new ones at the month
"""

import pandas as pd
import numpy as np
import datetime

def initialize(context):
    # Dictionary of stocks and their respective weights
    context.stock_weights = {}
    
    # Rebalance monthly on the first day of the month at market open
    schedule_function(rebalance,                      
                      date_rule=date_rules.month_start(),
                      time_rule=time_rules.market_open())
    
def rebalance(context, data):
    # Track cash to avoid leverage
    cash = context.portfolio.cash
    
    # Exit all positions before starting new ones
    for stock in context.portfolio.positions:
        if stock not in context.fundamental_df:
            order_target(stock, 0)
            cash += context.portfolio.positions[stock].amount
            
    # Create weights for each stock
    weight = create_weights(context, context.stocks)

    # Rebalance all stocks to target weights
    for stock in context.fundamental_df:
        if weight != 0 and stock in data:
            notional = context.portfolio.portfolio_value * weight
            price = data[stock].price
            numshares = int(notional / price)
            
            # Growth companies could be trading thin: avoid them
            if cash > price * numshares and numshares < data[stock].volume * 0.2: 
                order_target_percent(stock, weight)
                cash -= notional - context.portfolio.positions[stock].amount
                
    
def before_trading_start(context): 
    """
      Called before the start of each trading day. 
      It updates our universe with the
      securities and values found from fetch_fundamentals.
    """

    num_stocks = 100
    
    # Setup SQLAlchemy query to screen stocks based on PE ration
    # and industry sector. Then filter results based on 
    # market cap and shares outstanding.
    # We limit the number of results to num_stocks and return the data
    # in descending order.
    fundamental_df = get_fundamentals(
        query(
            # put your query in here by typing "fundamentals."
            fundamentals.operation_ratios.revenue_growth,
            fundamentals.asset_classification.morningstar_sector_code
        )
        .filter(fundamentals.valuation.market_cap > 0)
        .filter(fundamentals.operation_ratios.roic > 0.1)
        .filter(fundamentals.valuation.shares_outstanding != None)
        .order_by(fundamentals.operation_ratios.revenue_growth.desc())
        .limit(num_stocks)
    )

    # Filter out only stocks that fits in criteria
    context.stocks = [stock for stock in fundamental_df]
    
    # Update context.fundamental_df with the securities that we need
    context.fundamental_df = fundamental_df[context.stocks]
    
    update_universe(context.fundamental_df.columns.values)   
    
    record (cash = context.portfolio.cash, asset = context.portfolio.portfolio_value)
    
def create_weights(context, stocks):
    """
        Takes in a list of securities and weights them all equally 
    """
    if len(stocks) == 0:
        return 0 
    else:
        # Buy only 0.9 of portfolio value to avoid borrowing
        weight = .9/len(stocks)
        return weight
        
def handle_data(context, data):
    """
      Code logic to run during the trading day.
      handle_data() gets called every bar.
    """
    pass
    
There was a runtime error.
13 responses

Good work Naoki.
While unrelated to your algo, I noticed an exciting one day portfolio gain of $60K+ from 2008-09-19 to 2008-09-22 due to CDII rising from $0.05 to $5.51. From my clone run, it looked like the 12000+ CDII shares were purchased on 2008-07-01 at $0.10 . Looking at finance.yahoo.com I see CDII prices in the $4 to $7 range in that period; I didnt see any days in the penny-stock range.

I wonder if there is an error in the Quantopian database for CDII in that period or what?

Thanks guys. I submitted a ticket to look into the pricing issue.

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.

Naoki, this is great. Thanks so much for sharing. (I found this via Lesson 3 of the Quantopian Tutorial.)

I cloned it and ran a backtest just now without making any changes, and I ran into this runtime error. The backtest stopped at Feb 26, 2004.

OrderSecurityOutsideUniverse: 0036 You have placed an order with an unexpected security: Security(10583 [MLNK]). Please declare all securities in the initialize function by calling sid(123) for each security that will be used later in your algorithm.
There was a runtime error on line 29.

I couldn't figure out why this is happening. Anyone running into this too?

I suspected at first that it might be because MLNK is outside the universe as of Feb 26, 2004, but then with some logging, I observed that this isn't a problem for other securities that are not in the current context.fundamental_df. Any ideas?

You need to protect against there not being pricing data for thinly traded stocks. The way to typically do this is to check for the stock's presence in the data object (if stock in data) prior to your ordering.

Here's a backtest with the extra checks thrown in.

Clone Algorithm
146
Loading...
Backtest from to with initial capital
Total Returns
--
Alpha
--
Beta
--
Sharpe
--
Sortino
--
Max Drawdown
--
Benchmark Returns
--
Volatility
--
Returns 1 Month 3 Month 6 Month 12 Month
Alpha 1 Month 3 Month 6 Month 12 Month
Beta 1 Month 3 Month 6 Month 12 Month
Sharpe 1 Month 3 Month 6 Month 12 Month
Sortino 1 Month 3 Month 6 Month 12 Month
Volatility 1 Month 3 Month 6 Month 12 Month
Max Drawdown 1 Month 3 Month 6 Month 12 Month
"""
    Healthy growth stock picking strategy
    
    1. Every month, pick high-growth companies
    2. Companies with ROIC of above 10% (return on invested capital)
    3. Every month exit all the positions before entering new ones at the month
"""

import pandas as pd
import numpy as np
import datetime

def initialize(context):
    # Dictionary of stocks and their respective weights
    context.stock_weights = {}
    
    # Rebalance monthly on the first day of the month at market open
    schedule_function(rebalance,                      
                      date_rule=date_rules.month_start(),
                      time_rule=time_rules.market_open())
    
def rebalance(context, data):
    # Track cash to avoid leverage
    cash = context.portfolio.cash
    
    # Exit all positions before starting new ones
    for stock in context.portfolio.positions:
        if stock not in context.fundamental_df:
            if stock in data:
                order_target(stock, 0)
                cash += context.portfolio.positions[stock].amount
            
    # Create weights for each stock
    weight = create_weights(context, context.stocks)

    # Rebalance all stocks to target weights
    for stock in context.fundamental_df:
        if weight != 0 and stock in data:
            notional = context.portfolio.portfolio_value * weight
            price = data[stock].price
            numshares = int(notional / price)
            
            # Growth companies could be trading thin: avoid them
            if cash > price * numshares and numshares < data[stock].volume * 0.2:
                if stock in data:
                    order_target_percent(stock, weight)
                    cash -= notional - context.portfolio.positions[stock].amount
                
    
def before_trading_start(context): 
    """
      Called before the start of each trading day. 
      It updates our universe with the
      securities and values found from fetch_fundamentals.
    """

    num_stocks = 100
    
    # Setup SQLAlchemy query to screen stocks based on PE ration
    # and industry sector. Then filter results based on 
    # market cap and shares outstanding.
    # We limit the number of results to num_stocks and return the data
    # in descending order.
    fundamental_df = get_fundamentals(
        query(
            # put your query in here by typing "fundamentals."
            fundamentals.operation_ratios.revenue_growth,
            fundamentals.asset_classification.morningstar_sector_code
        )
        .filter(fundamentals.valuation.market_cap > 0)
        .filter(fundamentals.operation_ratios.roic > 0.1)
        .filter(fundamentals.valuation.shares_outstanding != None)
        .order_by(fundamentals.operation_ratios.revenue_growth.desc())
        .limit(num_stocks)
    )

    # Filter out only stocks that fits in criteria
    context.stocks = [stock for stock in fundamental_df]
    
    # Update context.fundamental_df with the securities that we need
    context.fundamental_df = fundamental_df[context.stocks]
    
    update_universe(context.fundamental_df.columns.values)   
    
    record (cash = context.portfolio.cash, asset = context.portfolio.portfolio_value)
    
def create_weights(context, stocks):
    """
        Takes in a list of securities and weights them all equally 
    """
    if len(stocks) == 0:
        return 0 
    else:
        # Buy only 0.9 of portfolio value to avoid borrowing
        weight = .9/len(stocks)
        return weight
        
def handle_data(context, data):
    """
      Code logic to run during the trading day.
      handle_data() gets called every bar.
    """
    pass
    
There was a runtime error.

The line 29 is removing the stock from portfolio when it is no longer in the top growth group.
That is why when you saw an error, MLNK was out of the universe.

It is not in universe, but it is usually still in data because you hold the stock. But it was not trading Feb 26, 2004 at the minute you tried to sell.

As Josh pointed out, it is always a good thing to check if the stock is trading in that particular day and minute for backtesting, which I did not for this line.
Thank you for finding this out, A. Roy, and for the proper fix, Josh.

Hello, I am new here, and wondering if I can ask a few basic questions.

  1. Inside "rebalance" function, exit and entry algo have following respective lines:
    cash += context.portfolio.positions[stock].amount
    cash -= notional - context.portfolio.positions[stock].amount
    The first line is to take account of the added $ amount when you sell existing stocks, and the second line is the deducted $ amount when you buy new stocks. However, I don't understand why you subtract notional AND $ amount.

  2. Inside "create_weight" function, the way you define weight ensures that 10% of your portfolio (=stock+cash) is always cash, right?
    weight = .9/len(stocks)

Hello,

  1. You are right. First line is deducing the $ amount when selling the stock, next line is adding the $ amount when buying. But I made some misunderstanding and a mistake in the original code. Please see the comment in the updated version attached.

  2. Yes, 10% of portfolio is cash. This is to avoid accidental leveraging. These growth stocks are more volatile and less liquid, and if you buy them 100%, you might end up buying over 100%. If you repeat this multiple times, leveraging just goes up and up. 90% stock 10% safeguards it.

Clone Algorithm
415
Loading...
Backtest from to with initial capital
Total Returns
--
Alpha
--
Beta
--
Sharpe
--
Sortino
--
Max Drawdown
--
Benchmark Returns
--
Volatility
--
Returns 1 Month 3 Month 6 Month 12 Month
Alpha 1 Month 3 Month 6 Month 12 Month
Beta 1 Month 3 Month 6 Month 12 Month
Sharpe 1 Month 3 Month 6 Month 12 Month
Sortino 1 Month 3 Month 6 Month 12 Month
Volatility 1 Month 3 Month 6 Month 12 Month
Max Drawdown 1 Month 3 Month 6 Month 12 Month
"""
    Healthy growth stock picking strategy
    
    1. Every month, pick high-growth companies
    2. Companies with ROIC of above 10% (return on invested capital)
    3. Every month exit all the positions before entering new ones at the month
"""

import pandas as pd
import numpy as np
import datetime

def initialize(context):
    # Dictionary of stocks and their respective weights
    context.stock_weights = {}
    
    # Rebalance monthly on the first day of the month at market open
    schedule_function(rebalance,                      
                      date_rule=date_rules.month_start(),
                      time_rule=time_rules.market_open())
    
def rebalance(context, data):
    # Track cash to avoid leverage
    cash = context.portfolio.cash
    
    # Exit all positions before starting new ones
    for stock in context.portfolio.positions:
        if stock not in context.fundamental_df:
            if stock in data:
                order_target(stock, 0)
                
                #cash += context.portfolio.positions[stock].amount
                
                ###### This line should be
                cash += context.portfolio.positions[stock].amount * data[stock].price
                 
                # positions[stock].amount returns the number of shares.
                # To convert to the cash that will be available after sale, it should be multiplied with price
                 
    # Create weights for each stock
    weight = create_weights(context, context.stocks)

    # Rebalance all stocks to target weights
    for stock in context.fundamental_df:
        if weight != 0 and stock in data:
            notional = context.portfolio.portfolio_value * weight
            price = data[stock].price
            numshares = int(notional / price)
            
            # Growth companies could be trading thin: avoid them
            if cash > price * numshares and numshares < data[stock].volume * 0.2:
                if stock in data:
                    order_target_percent(stock, weight)
                    # cash -= notional - context.portfolio.positions[stock].amount
                    
                    ### This line should be
                    cash -= notional
                
    
def before_trading_start(context): 
    """
      Called before the start of each trading day. 
      It updates our universe with the
      securities and values found from fetch_fundamentals.
    """

    num_stocks = 100
    
    # Setup SQLAlchemy query to screen stocks based on PE ration
    # and industry sector. Then filter results based on 
    # market cap and shares outstanding.
    # We limit the number of results to num_stocks and return the data
    # in descending order.
    fundamental_df = get_fundamentals(
        query(
            # put your query in here by typing "fundamentals."
            fundamentals.operation_ratios.revenue_growth,
            fundamentals.asset_classification.morningstar_sector_code
        )
        .filter(fundamentals.valuation.market_cap > 0)
        .filter(fundamentals.operation_ratios.roic > 0.1)
        .filter(fundamentals.valuation.shares_outstanding != None)
        .order_by(fundamentals.operation_ratios.revenue_growth.desc())
        .limit(num_stocks)
    )

    # Filter out only stocks that fits in criteria
    context.stocks = [stock for stock in fundamental_df]
    
    # Update context.fundamental_df with the securities that we need
    context.fundamental_df = fundamental_df[context.stocks]
    
    update_universe(context.fundamental_df.columns.values)   
    
    record (cash = context.portfolio.cash, asset = context.portfolio.portfolio_value)
    
def create_weights(context, stocks):
    """
        Takes in a list of securities and weights them all equally 
    """
    if len(stocks) == 0:
        return 0 
    else:
        # Buy only 0.9 of portfolio value to avoid borrowing
        
        ## Additional comment
        ## Growh stock could have lower liquidity than the largest stocks
        ## It is likely to be more volatiles than the largest stocks
        ## If you make the weight 100% total, you might end up buying more than 100% by the time
        ## all the orders are fulfilled.  If that happens, everytime you will be increasing leverage.
        weight = .9/len(stocks)
        return weight
        
def handle_data(context, data):
    """
      Code logic to run during the trading day.
      handle_data() gets called every bar.
    """
    pass
    
We have migrated this algorithm to work with a new version of the Quantopian API. The code is different than the original version, but the investment rationale of the algorithm has not changed. We've put everything you need to know here on one page.
There was a runtime error.
undamental_df = get_fundamentals(  
        **query(  
            # put your query in here by typing "fundamentals."  
            fundamentals.operation_ratios.revenue_growth,  
            fundamentals.asset_classification.morningstar_sector_code**  
        )  
        .filter(fundamentals.valuation.market_cap > 0)  
        .filter(fundamentals.operation_ratios.roic > 0.1)  
        .filter(fundamentals.valuation.shares_outstanding != None)  
        .order_by(fundamentals.operation_ratios.revenue_growth.desc())  
        .limit(num_stocks)  
    )  

Hi Naoki,
I don't fully understand what the code inside query does specifically the morningstar_sector_code. Could you shed some light on that for me? Thank You

There are a lot of people who do not know and I can see that is the case here so I will answer instead. Good question.

The query section populates the dataframe with the particular values.
Since those values are not being used, there's no need to collect them.
That's the case in a lot of algorithms.
When the values are not being used, just leave query empty like this:

    fundamental_df = get_fundamentals(  
        query()  
        .filter(fundamentals.valuation.market_cap > 0)  
        .filter(fundamentals.operation_ratios.roic > 0.1)  
        .filter(fundamentals.valuation.shares_outstanding != None)  
        .order_by(fundamentals.operation_ratios.revenue_growth.desc())  
        .limit(num_stocks)  
    )  

To see that, try as is, with a breakpoint on line 88 (in the algo above), and type fundamental_df in the debugger console window (hit [Enter]).
Then make that just query() and repeat.
Maybe someone here or from Q can round that out with some finer points in exploring pandas dataframes (technically a panel in this case, although also a dataframe, I think, a single dataframe inside a panel, there could be more than one unless I'm mistaken, something like that).
Query and filters can be entirely different from each other.

This is an example of combining a couple of dataframes (or panels), using the values from query, and assembling a score from those values.

    c = context  
    f = fundamentals  
    panel1 = get_fundamentals(  
        query(  
            f.cash_flow_statement.cash_flow_from_continuing_operating_activities,  
            f.operation_ratios.roa,  
            f.cash_flow_statement.operating_cash_flow,  
            f.valuation_ratios.ev_to_ebitda,  
            f.operation_ratios.current_ratio,  
            f.valuation_ratios.pb_ratio,  
            #f.valuation_ratios.pe_ratio,  
        )  
        .filter(f.share_class_reference.is_primary_share == True)  
        .filter(f.share_class_reference.is_depositary_receipt == False)  
        .filter(f.operation_ratios.roa > .002)  
        .filter(f.valuation.market_cap > 3000e6)  
        .filter(f.cash_flow_statement.cash_flow_from_continuing_operating_activities > 0)  
        .order_by(f.valuation.market_cap.desc())  
        .limit(120)  # 30-40.6  80-36.7  300-29.1  
    )  
    panel = panel1  
    '''  
    # Use to add some manually  
    panel2 = get_fundamentals(    # Fundamentals for specific symbols  
        query(  
            f.cash_flow_statement.cash_flow_from_continuing_operating_activities,  
            f.operation_ratios.roa,  
            f.cash_flow_statement.operating_cash_flow,  
            f.valuation_ratios.ev_to_ebitda,  
            f.operation_ratios.current_ratio,  
            f.valuation_ratios.pb_ratio,  
        )  
        .filter(f.company_reference.primary_symbol.in_(['TSLA']))  
        #.filter(f.company_reference.primary_symbol.in_(['ENLK', 'PKD', 'TSLA', 'NNBR', 'OWW']))  
    )  
    panel = panel1.append(panel2)               # creates dupes  
    panel = panel.groupby(panel.index).sum()    # dedupe  
    '''  
    # Normalize the values 0 to 100 in relation to each other  
    for i in range(len(panel)): # 0 and 1 for two elements in query above, they are indexes  
        value_list = panel.iloc[i, :].values  
        top    = max(value_list)  
        bottom = min(value_list)  
        count  = 0  
        for v in value_list:    # each value across all stocks  
            prcnt = 100 * (v - bottom) / (top - bottom)  # where this value sits, percentage  
            panel[panel.columns[count]][i] = prcnt  
            count += 1  
    c.fstocks = []  
    for s in panel.columns.values:  
        if s.symbol in c.excludes: continue  
        if '_' in s.symbol: continue  
        c.fstocks.append(s)  
        # panel[s][1] is operation_ratios.roa  
        # Try multiplying these also, instead of adding them  
        score =     panel[s][0] + panel[s][1] + panel[s][2] + panel[s][3] + panel[s][4] - panel[s][5]  
        if np.isnan(score):  
            c.fscore[s] = 0  
        else:  
            c.fscore[s] = score  
    update_universe( c.fstocks )  

Just curious, why do you care about the ROIC if you rebalance monthly? I'm thinking the ROIC is a good caution against midterm to longterm health of the company but if you rebalance monthly won't it sell the stock and buy another upwardly mobile stock?

Another version inspired by the author's aglo.

Clone Algorithm
58
Loading...
Backtest from to with initial capital
Total Returns
--
Alpha
--
Beta
--
Sharpe
--
Sortino
--
Max Drawdown
--
Benchmark Returns
--
Volatility
--
Returns 1 Month 3 Month 6 Month 12 Month
Alpha 1 Month 3 Month 6 Month 12 Month
Beta 1 Month 3 Month 6 Month 12 Month
Sharpe 1 Month 3 Month 6 Month 12 Month
Sortino 1 Month 3 Month 6 Month 12 Month
Volatility 1 Month 3 Month 6 Month 12 Month
Max Drawdown 1 Month 3 Month 6 Month 12 Month
"""
This is a template algorithm on Quantopian for you to adapt and fill in.
"""
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

def initialize(context):
    """
    Called once at the start of the algorithm.
    """
    # Rebalance every day, 3-hour after market open.
    #schedule_function(my_rebalance, date_rules.every_day(), time_rules.market_open(hours=3))

    # Rebalance every week, 3-hour after market open.
    #schedule_function(my_rebalance, date_rules.week_start(days_offset=0), time_rules.market_open(minutes=180))

    # Rebalance monthly on the first day of the month at market open
    schedule_function(my_rebalance,
                      date_rule=date_rules.month_start(),
                      time_rule=time_rules.market_open())

    # Record tracking variables at the end of each day.
    schedule_function(my_record_vars, date_rules.every_day(), time_rules.market_close())

    # Create our dynamic stock selector.
    attach_pipeline(my_pipeline(context), 'my_pipeline')

def my_pipeline(context):
    """
    A function to create our dynamic stock selector (pipeline). Documentation on
    pipeline can be found here: https://www.quantopian.com/help#pipeline-title
    """
    pipe = Pipeline()

    # Create a dollar volume factor.
    dollar_volume = AverageDollarVolume(window_length=1)
    pipe.add(dollar_volume, 'dollar_volume')

    # Pick the top 1% of stocks ranked by dollar volume.
    high_dollar_volume = dollar_volume.percentile_between(90, 100)
    pipe.set_screen(high_dollar_volume)

    return pipe

def before_trading_start(context, data):
    """
    Called every day before market open.
    """
    context.output = pipeline_output('my_pipeline')

    """
      Called before the start of each trading day.
      It updates our universe with the
      securities and values found from fetch_fundamentals.
    """

    num_stocks = 200

    # Setup SQLAlchemy query to screen stocks based on PE ration
    # and industry sector. Then filter results based on
    # market cap and shares outstanding.
    # We limit the number of results to num_stocks and return the data
    # in descending order.
    fundamental_df = get_fundamentals(
        query(
            # put your query in here by typing "fundamentals."
            fundamentals.operation_ratios.revenue_growth,
            fundamentals.valuation_ratios.peg_ratio,
            #fundamentals.valuation_ratios.forward_pe_ratio,
            fundamentals.valuation_ratios.pe_ratio,
            #fundamentals.income_statement.ebit
            fundamentals.earnings_ratios.diluted_eps_growth,
            fundamentals.operation_ratios.operation_income_growth
        )
        # No Financials (103), Real Estate (104) or Utility (207) Stocks, no ADR or PINK, only USA
        .filter(fundamentals.company_reference.country_id == "USA")
        .filter(fundamentals.asset_classification.morningstar_sector_code != 103)
        .filter(fundamentals.asset_classification.morningstar_sector_code != 104)
        .filter(fundamentals.asset_classification.morningstar_sector_code != 207)
        .filter(fundamentals.share_class_reference.is_depositary_receipt == False)
        .filter(fundamentals.share_class_reference.is_primary_share == True)

        # Only pick active stocks
        .filter(fundamentals.share_class_reference.share_class_status == "A")
        # Only Common Stock
        .filter(fundamentals.share_class_reference.security_type == "ST00000001")
        .filter(fundamentals.company_reference.primary_exchange_id != "OTCPK")
        .filter(fundamentals.valuation.market_cap >= 2e9)
        .filter(fundamentals.valuation.market_cap < 200e9)
        .filter(fundamentals.operation_ratios.roic > 0.1)
        .filter(fundamentals.valuation_ratios.pe_ratio < 50)
        .filter(fundamentals.valuation_ratios.pe_ratio > 3)
        .filter(fundamentals.operation_ratios.revenue_growth > 0.0)
        .filter(fundamentals.operation_ratios.operation_income_growth > 0.0)
        .filter(fundamentals.earnings_ratios.diluted_eps_growth > 0.0)

        .filter(fundamentals.valuation.shares_outstanding != None)
        .filter(fundamentals.valuation_ratios.ev_to_ebitda != None)

        .order_by(fundamentals.operation_ratios.revenue_growth.desc())
        .limit(num_stocks)
    )

    # Filter out only stocks that fits in criteria
    df = fundamental_df.T
    df['growth_score'] = (df['diluted_eps_growth'] + df['operation_income_growth'] + df['revenue_growth'])/3

    df['pe_growth'] = df['pe_ratio']/df['growth_score']
    df = df.sort(columns='pe_growth', ascending=True)
    df = df[(df['pe_growth'] < 250) & (df['pe_growth'] > 20)]

    context.security_list = list(df.index[:60])
    print df.head(20) # ['forward_pe_ratio']

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.
    """
    # Exit all positions before starting new ones
    for stock in context.portfolio.positions:
        if stock not in context.security_list:
            if data.can_trade(stock):
                order_target_percent(stock, 0)

    for stock in context.security_list:
        if data.can_trade(stock):
            order_target_percent(stock, 1.0/len(context.security_list))


def my_record_vars(context, data):
    """
    Plot variables at the end of each day.
    """
    record(leverage = context.account.leverage)

def handle_data(context,data):
    """
    Called every minute.
    """
    pass
There was a runtime error.

Has anyone live traded this algo? If yes, what were the results like?

When I cloned this I couldn't run it because it is based on API 1.0, so I tried to change it to API 2.0, but then the results are not near as good (worse than the benchmark). Can anyone tell me what I did wrong?

Clone Algorithm
26
Loading...
Backtest from to with initial capital
Total Returns
--
Alpha
--
Beta
--
Sharpe
--
Sortino
--
Max Drawdown
--
Benchmark Returns
--
Volatility
--
Returns 1 Month 3 Month 6 Month 12 Month
Alpha 1 Month 3 Month 6 Month 12 Month
Beta 1 Month 3 Month 6 Month 12 Month
Sharpe 1 Month 3 Month 6 Month 12 Month
Sortino 1 Month 3 Month 6 Month 12 Month
Volatility 1 Month 3 Month 6 Month 12 Month
Max Drawdown 1 Month 3 Month 6 Month 12 Month
"""
    Healthy growth stock picking strategy
    
    1. Every month, pick high-growth companies
    2. Companies with ROIC of above 10% (return on invested capital)
    3. Every month exit all the positions before entering new ones at the month
"""

import pandas as pd
import numpy as np
import datetime

def initialize(context):
    # Dictionary of stocks and their respective weights
    context.stock_weights = {}
    
    # Rebalance monthly on the first day of the month at market open
    schedule_function(rebalance,                      
                      date_rule=date_rules.month_start(),
                      time_rule=time_rules.market_open())
    
def rebalance(context, data):
    # Track cash to avoid leverage
    cash = context.portfolio.cash
    
    # Exit all positions before starting new ones
    for stock in context.portfolio.positions:
        if stock not in context.fundamental_df:
            order_target(stock, 0)
            cash += context.portfolio.positions[stock].amount
            
    # Create weights for each stock
    weight = create_weights(context, context.stocks)

    # Rebalance all stocks to target weights
    for stock in context.fundamental_df:
        #if weight != 0 and stock in data:
        if weight != 0 and data.can_trade(stock):
            notional = context.portfolio.portfolio_value * weight
            #price = data[stock].price
            price = data.current(stock, 'price')
            numshares = int(notional / price)
            
            # Growth companies could be trading thin: avoid them
            #if cash > price * numshares and numshares < data[stock].volume * 0.2: 
            if cash > price * numshares and numshares < data.current(stock, 'volume') * 0.2: 
                order_target_percent(stock, weight)
                cash -= notional - context.portfolio.positions[stock].amount
                
    
def before_trading_start(context, data): 
    """
      Called before the start of each trading day. 
      It updates our universe with the
      securities and values found from fetch_fundamentals.
    """

    num_stocks = 100
    
    # Setup SQLAlchemy query to screen stocks based on PE ration
    # and industry sector. Then filter results based on 
    # market cap and shares outstanding.
    # We limit the number of results to num_stocks and return the data
    # in descending order.
    fundamental_df = get_fundamentals(
        query(
            # put your query in here by typing "fundamentals."
            fundamentals.operation_ratios.revenue_growth,
            fundamentals.asset_classification.morningstar_sector_code
        )
        .filter(fundamentals.valuation.market_cap > 0)
        .filter(fundamentals.operation_ratios.roic > 0.1)
        .filter(fundamentals.valuation.shares_outstanding != None)
        .order_by(fundamentals.operation_ratios.revenue_growth.desc())
        .limit(num_stocks)
    )

    # Filter out only stocks that fits in criteria
    context.stocks = [stock for stock in fundamental_df]
    
    # Update context.fundamental_df with the securities that we need
    context.fundamental_df = fundamental_df[context.stocks]
    
    #update_universe(context.fundamental_df.columns.values)   
    
    record (cash = context.portfolio.cash, asset = context.portfolio.portfolio_value)
    
def create_weights(context, stocks):
    """
        Takes in a list of securities and weights them all equally 
    """
    if len(stocks) == 0:
        return 0 
    else:
        # Buy only 0.9 of portfolio value to avoid borrowing
        weight = .9/len(stocks)
        return weight
        
def handle_data(context, data):
    """
      Code logic to run during the trading day.
      handle_data() gets called every bar.
    """
    pass
    
There was a runtime error.