Back to Community
List out Quality Companies in an Uptrend

I am trying to make a stand-alone script without a back-test to view Quality Companies in this script:

# Quality companies in an uptrend (Dan Whitnabl version with bonds weights  fixed by Vladimir)  
import quantopian.algorithm as algo

# import things need to run pipeline  
from quantopian.pipeline import Pipeline

# import any built-in factors and filters being used  
from quantopian.pipeline.filters import Q500US, Q1500US, Q3000US, QTradableStocksUS, StaticAssets  
from quantopian.pipeline.factors import SimpleMovingAverage as SMA  
from quantopian.pipeline.factors import CustomFactor, Returns

# import any needed datasets  
from quantopian.pipeline.data.builtin import USEquityPricing  
from quantopian.pipeline.data.morningstar import Fundamentals as ms

# import optimize for trade execution  
import quantopian.optimize as opt  
# import numpy and pandas because they rock  
import numpy as np  
import pandas as pd


def initialize(context):  
    # Set algo 'constants'...  
    # List of bond ETFs when market is down. Can be more than one.  
    set_commission(commission.PerTrade(cost=0.00))  
    set_slippage(slippage.FixedSlippage(spread=0.00))  
    context.BONDS = [symbol('IEF'), symbol('TLT')]

    # Set target number of securities to hold and top ROE qty to filter  
    context.TARGET_SECURITIES = 5  
    context.TOP_ROE_QTY = 60 #First sort by ROE

    # This is for the trend following filter  
    context.SPY = symbol('SPY')  
    context.TF_LOOKBACK = 100  
    context.TF_CURRENT_LOOKBACK = 10

    # This is for the determining momentum  
    context.MOMENTUM_LOOKBACK_DAYS = 126 #Momentum lookback  
    context.MOMENTUM_SKIP_DAYS = 2  
    # Initialize any other variables before being used  
    context.stock_weights = pd.Series()  
    context.bond_weights = pd.Series()  
    MIN = 1

    # Should probably comment out the slippage and using the default  
    # set_slippage(slippage.FixedSlippage(spread = 0.0))  
    # Create and attach pipeline for fetching all data  
   # algo.attach_pipeline(make_pipeline(context), 'pipeline')  
    pipe_of_stocks = make_pipeline(context)  
    # Schedule functions  
    # Separate the stock selection from the execution for flexibility  
    select_stocks_and_set_weights(context, pipe_of_stocks)  


def make_pipeline(context):  
    universe = Q3000US()  
    spy_ma50_slice = SMA(inputs=[USEquityPricing.close],  
                         window_length=context.TF_CURRENT_LOOKBACK)[context.SPY]  
    spy_ma200_slice = SMA(inputs=[USEquityPricing.close],  
                          window_length=context.TF_LOOKBACK)[context.SPY]  
    spy_ma_fast = SMA(inputs=[spy_ma50_slice], window_length=1)  
    spy_ma_slow = SMA(inputs=[spy_ma200_slice], window_length=1)  
    trend_up = spy_ma_fast > spy_ma_slow

    cash_return = ms.cash_return.latest.rank(mask=universe) #(mask=universe)  
    fcf_yield = ms.fcf_yield.latest.rank(mask=universe) #(mask=universe)  
    roic = ms.roic.latest.rank(mask=universe) #(mask=universe)  
    ltd_to_eq = ms.long_term_debt_equity_ratio.latest.rank(mask=universe) #, mask=universe)  
    value = (cash_return + fcf_yield).rank() #(mask=universe)  
    #quality = roic + ltd_to_eq + value  
    quality = ltd_to_eq  
    # Create a 'momentum' factor. Could also have been done with a custom factor.  
    returns_overall = Returns(window_length=context.MOMENTUM_LOOKBACK_DAYS+context.MOMENTUM_SKIP_DAYS)  
    returns_recent = Returns(window_length=context.MOMENTUM_SKIP_DAYS)  
    ### momentum = returns_overall.log1p() - returns_recent.log1p()  
    momentum = returns_overall - returns_recent  
    # Filters for top quality and momentum to use in our selection criteria  
    top_quality = quality.top(context.TOP_ROE_QTY, mask=universe)  
    top_quality_momentum = momentum.top(context.TARGET_SECURITIES, mask=top_quality)  
    # Only return values we will use in our selection criteria  
    pipe = Pipeline(columns={  
                        'trend_up': trend_up,  
                        'top_quality_momentum': top_quality_momentum,  
                        },  
                    screen=top_quality_momentum  
                   )  
    message = "pipe: "  
    #for stock in pipe:  
    #    log.info(stock)

    return pipe

def select_stocks_and_set_weights(context, data):  
    """  
    Select the stocks to hold based upon data fetched in pipeline.  
    Then determine weight for stocks.  
    Finally, set bond weight to 1-total stock weight to keep portfolio fully invested  
    Sets context.stock_weights and context.bond_weights used in trade function  
    """  
    # Get pipeline output and select stocks  
    df = algo.pipeline_output('pipeline')  
    current_holdings = context.portfolio.positions  
    # Define our rule to open/hold positions  
    # top momentum and don't open in a downturn but, if held, then keep  
    rule = 'top_quality_momentum & (trend_up or (not trend_up & index in @current_holdings))'  
    stocks_to_hold = df.query(rule).index  
    message = "Hello"  
    log.info(message)  
    for stock in stocks_to_hold:  
        log.info(stock)  
    # Set desired stock weights  
    # Equally weight  
    stock_weight = 1.0 / context.TARGET_SECURITIES  
    context.stock_weights = pd.Series(index=stocks_to_hold, data=stock_weight)  
    # Set desired bond weight  
    # Open bond position to fill unused portfolio balance  
    # But always have at least 1 'share' of bonds  
    ### bond_weight = max(1.0 - context.stock_weights.sum(), stock_weight) / len(context.BONDS)  
    bond_weight = max(1.0 - context.stock_weights.sum(), 0) / len(context.BONDS)  
    context.bond_weights = pd.Series(index=context.BONDS, data=bond_weight)  
2 responses

I was able to get the companies to list out with a couple pointers - Thank you. But, I need help in getting the time period to set to most current. Please advise.

# Quality companies in an uptrend (Dan Whitnabl version with bonds weights  fixed by Vladimir)  
import quantopian.algorithm as algo

# import things need to run pipeline  
from quantopian.pipeline import Pipeline

# import any built-in factors and filters being used  
from quantopian.pipeline.filters import Q500US, Q1500US, Q3000US, QTradableStocksUS, StaticAssets  
from quantopian.pipeline.factors import SimpleMovingAverage as SMA  
from quantopian.pipeline.factors import CustomFactor, Returns

# import any needed datasets  
from quantopian.pipeline.data.builtin import USEquityPricing  
from quantopian.pipeline.data.morningstar import Fundamentals as ms

# import optimize for trade execution  
import quantopian.optimize as opt  
# import numpy and pandas because they rock  
import numpy as np  
import pandas as pd


def initialize(context):  
    # Set algo 'constants'...  
    # List of bond ETFs when market is down. Can be more than one.  
    set_commission(commission.PerTrade(cost=0.00))  
    set_slippage(slippage.FixedSlippage(spread=0.00))  
    context.BONDS = [symbol('IEF'), symbol('TLT')]

    # Set target number of securities to hold and top ROE qty to filter  
    context.TARGET_SECURITIES = 5  
    context.TOP_ROE_QTY = 60 #First sort by ROE

    # This is for the trend following filter  
    context.SPY = symbol('SPY')  
    context.TF_LOOKBACK = 100  
    context.TF_CURRENT_LOOKBACK = 10

    # This is for the determining momentum  
    context.MOMENTUM_LOOKBACK_DAYS = 126 #Momentum lookback  
    context.MOMENTUM_SKIP_DAYS = 2  
    # Initialize any other variables before being used  
    context.stock_weights = pd.Series()  
    context.bond_weights = pd.Series()  
    MIN = 1

    # Should probably comment out the slippage and using the default  
    # set_slippage(slippage.FixedSlippage(spread = 0.0))  
    # Create and attach pipeline for fetching all data  
    algo.attach_pipeline(make_pipeline(context), 'pipeline')  
    # Schedule functions  
    # Separate the stock selection from the execution for flexibility  
    schedule_function(  
        select_stocks_and_set_weights,  
        date_rules.week_start(),  
        time_rules.market_open(minutes = MIN)  
    )  
    schedule_function(  
        trade,  
        date_rules.week_start(),  
        time_rules.market_open(minutes = MIN)  
    )   

def make_pipeline(context):  
    universe = Q3000US()  
    spy_ma50_slice = SMA(inputs=[USEquityPricing.close],  
                         window_length=context.TF_CURRENT_LOOKBACK)[context.SPY]  
    spy_ma200_slice = SMA(inputs=[USEquityPricing.close],  
                          window_length=context.TF_LOOKBACK)[context.SPY]  
    spy_ma_fast = SMA(inputs=[spy_ma50_slice], window_length=1)  
    spy_ma_slow = SMA(inputs=[spy_ma200_slice], window_length=1)  
    trend_up = spy_ma_fast > spy_ma_slow

    cash_return = ms.cash_return.latest.rank(mask=universe) #(mask=universe)  
    fcf_yield = ms.fcf_yield.latest.rank(mask=universe) #(mask=universe)  
    roic = ms.roic.latest.rank(mask=universe) #(mask=universe)  
    ltd_to_eq = ms.long_term_debt_equity_ratio.latest.rank(mask=universe) #, mask=universe)  
    value = (cash_return + fcf_yield).rank() #(mask=universe)  
    #quality = roic + ltd_to_eq + value  
    quality = ltd_to_eq  
    # Create a 'momentum' factor. Could also have been done with a custom factor.  
    returns_overall = Returns(window_length=context.MOMENTUM_LOOKBACK_DAYS+context.MOMENTUM_SKIP_DAYS)  
    returns_recent = Returns(window_length=context.MOMENTUM_SKIP_DAYS)  
    ### momentum = returns_overall.log1p() - returns_recent.log1p()  
    momentum = returns_overall - returns_recent  
    # Filters for top quality and momentum to use in our selection criteria  
    top_quality = quality.top(context.TOP_ROE_QTY, mask=universe)  
    top_quality_momentum = momentum.top(context.TARGET_SECURITIES, mask=top_quality)  
    # Only return values we will use in our selection criteria  
    pipe = Pipeline(columns={  
                        'trend_up': trend_up,  
                        'top_quality_momentum': top_quality_momentum,  
                        },  
                    screen=top_quality_momentum  
                   )  
    return pipe

def select_stocks_and_set_weights(context, data):  
    """  
    Select the stocks to hold based upon data fetched in pipeline.  
    Then determine weight for stocks.  
    Finally, set bond weight to 1-total stock weight to keep portfolio fully invested  
    Sets context.stock_weights and context.bond_weights used in trade function  
    """  
    # Get pipeline output and select stocks  
    df = algo.pipeline_output('pipeline')  
    current_holdings = context.portfolio.positions  
    # Define our rule to open/hold positions  
    # top momentum and don't open in a downturn but, if held, then keep  
    rule = 'top_quality_momentum & (trend_up or (not trend_up & index in @current_holdings))'  
    stocks_to_hold = df.query(rule).index  
    # Set desired stock weights  
    # Equally weight  
    stock_weight = 1.0 / context.TARGET_SECURITIES  
    context.stock_weights = pd.Series(index=stocks_to_hold, data=stock_weight)  
    # Set desired bond weight  
    # Open bond position to fill unused portfolio balance  
    # But always have at least 1 'share' of bonds  
    ### bond_weight = max(1.0 - context.stock_weights.sum(), stock_weight) / len(context.BONDS)  
    bond_weight = max(1.0 - context.stock_weights.sum(), 0) / len(context.BONDS)  
    context.bond_weights = pd.Series(index=context.BONDS, data=bond_weight)  
def trade(context, data):  
    """  
    Execute trades using optimize.  
    Expects securities (stocks and bonds) with weights to be in context.weights  
    """  
    #print(context.stock_weights)  
    # Create a single series from our stock and bond weights  
    total_weights = pd.concat([context.stock_weights, context.bond_weights])

    # Create a TargetWeights objective  
    target_weights = opt.TargetWeights(total_weights) 

    print(total_weights)  

I found the date start and end date input boxes in the right window.