Back to Community
Sector exposure help

Hello Quants,
I was wondering if someone could give me a little help on line 50 of this algo so that I can bring sector exposure down.

The algo filters out stocks below $1, market cap below $100m and requires a dollar volume traded per day proportional to the portfolio value. After this, in "Before trading start" it ranks the average of 2 different fundamental parameters for value and cuts this to the best 1000 stocks available. From these 1000 stocks it sorts them by highest 252 day momentum.

It is at this point I need help, to cycle through the list of stocks with momentum and pick the stock with the highest momentum, then the next highest from a different sector, then the next highest from a different sector. Once 1 stock is picked from each of the 11 sectors, I'd like it to cycle to the 2nd best momentum form 1 sector, the next best momentum from a different sector and so on. Is this even possible? I tried adding the optimize, but I can't get that to work with the sorting features I have in the before_trading_start. Any suggestions for code that could accomplish this would be much appreciated.

Clone Algorithm
32
Loading...
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 was taken from Anthony FJ Garner here: https://www.quantopian.com/posts/a-simple-momentum-rotation-system-for-stocks
# This algo is the result of my attempt to bring over my old fundamental algorithm to the modern Q2 changes.  To my suprise, I made a functional algo without much help. haha.  This algo tries to permit me to look at specific value metrics, their interactions when 2 or more are used in combination and also adding a momentum factor.  Average day $ volume minimum increases over time to account for portfolio growth.  Market cap minimum, price minimum and other filters I feel are needed are applied.

# If you want to add a stop loss try here: https://www.quantopian.com/posts/5672ccec6891c22735000212#5718fc37bb3e7d6347000acf

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 CustomFactor, SimpleMovingAverage
from quantopian.pipeline.data import morningstar
from quantopian.pipeline.filters.morningstar import IsPrimaryShare
from quantopian.pipeline.filters import StaticAssets
from quantopian.pipeline.classifiers.morningstar import Sector

import pandas as pd
import numpy as np

class AvgDailyDollarVolumeTraded(CustomFactor):
    inputs = [USEquityPricing.close, USEquityPricing.volume]
    window_length = 20
    def compute(self, today, assets, out, close_price, volume):
        out[:] = np.mean(close_price * volume, axis=0)
class Factor_1(CustomFactor):
    inputs = [morningstar.valuation_ratios.total_yield]
    window_length = 1
    def compute(self, today, assets, out, totalyield):
        out[:] = 1/totalyield[-1]
class Factor_2(CustomFactor):
    inputs = [morningstar.valuation_ratios.pb_ratio]
    window_length = 1
    def compute(self, today, assets, out, pbratio):
        out[:] = pbratio[-1]
class Momentum(CustomFactor): 
    inputs = [USEquityPricing.close]
    window_length = 252
    def compute(self, today, assets, out, close):       
        out[:] = close[-1] / close[-252]
class MarketCap(CustomFactor):
    inputs = [morningstar.valuation.market_cap]
    window_length = 1 
    def compute(self, today, assets, out, market_cap):
        out[:] = market_cap[-1]

def before_trading_start(context, data):
    results = pipeline_output('my_pipeline').dropna()
    
    ranktop = results.sort_values(by='combo_rank', ascending=True).iloc[:1000] #True for low p/x
    rankbottom = results.sort_values(by='combo_rank', ascending=True).iloc[:1000]
    trendingup = ranktop.sort_values(by='momentum', ascending=False).iloc[:context.num_long]
    #topsector = ranktop.bottom(1, groupby=sector) #replace ranktop on line 50 with topsector
    trendingdown = rankbottom.sort_values(by='momentum', ascending=True).iloc[:context.num_short] #True is trending down
    context.shorts = 1 / trendingdown
    context.shorts /= context.shorts.sum()
    context.longs = trendingup
    context.longs /= context.longs.sum()
    record(ranktop=len(ranktop))
    
def initialize(context): # Put any initialization logic here. The context object will be passed to the other methods in your algorithm.
    context.num_securities = 20
    context.num_short = 0 #context.num_securities // 2
    context.num_long = 20 #context.num_securities - context.num_short
    
    context.spy = sid(8554) #SPY # sid(19920) #QQQ # This is not working as benchmark
    context.index_id = sid(8554)
    context.index_avg_window = 100
    context.use_index_trend_filter = True
    context.use_bond_etf = True
    context.bond_etf = sid(23921)
    context.shorts = None
    context.longs = None
    context.tlt = sid(23921) 
    context.tltweight = 0.0 # written as 0.percent
    context.exclusion_list = [sid(8817)]
    schedule_function(rebalance, date_rules.month_start(), time_rule=time_rules.market_open(minutes = 20))
    schedule_function(cancel_open_orders, date_rules.every_day(), time_rules.market_close())
    schedule_function(record_vars, date_rules.every_day(), time_rules.market_close())
    set_commission(commission.PerShare(cost=0.0045, min_trade_cost=1.00))
    set_slippage(slippage.FixedSlippage(spread=0.06))
    #set_slippage(slippage.VolumeShareSlippage(volume_limit=0.5, price_impact=0.0)) #change volume_limit back to 0.1
    
    attach_pipeline(my_pipeline(context), name='my_pipeline') #can also remove name= and just put 'my_pipeline'

def my_pipeline(context):
    sector = Sector()
    Factor1 = Factor_1()
    Factor2 = Factor_2()
    
    mstar = morningstar
    common_stock = mstar.share_class_reference.security_type.latest.eq('ST00000001')
    not_lp_name = ~mstar.company_reference.standard_name.latest.matches('.* L[\\. ]?P\.?$')
    not_lp_balance_sheet = mstar.balance_sheet.limited_partnership.latest.isnull()
    have_market_cap = mstar.valuation.market_cap.latest.notnull()
    not_otc = ~mstar.share_class_reference.exchange_id.latest.startswith('OTC')
    not_wi = ~mstar.share_class_reference.symbol.latest.endswith('.WI')
    not_depository = ~mstar.share_class_reference.is_depositary_receipt.latest
    primary_share = IsPrimaryShare()
    exclusion_filter = ~StaticAssets(context.exclusion_list)
    
    sma_200 = SimpleMovingAverage(inputs=[USEquityPricing.close], window_length=200)
    dollar_volume = AvgDailyDollarVolumeTraded(window_length=20)#, mask=tradable_filter)
    market_cap = MarketCap(window_length=1)
    port_val = context.portfolio.portfolio_value
    dol_vol_min = (port_val*20.0) #1/20 of portfolio value purchase is never more than 1/100 of Avg daily $ vol
    # Screen out penny stocks, low liquidity securities and low market cap.
    
    tradable_filter = (common_stock & not_lp_name & not_lp_balance_sheet &
                      have_market_cap & not_otc & not_wi & not_depository & primary_share & exclusion_filter & (sma_200>1) &                               (market_cap>10**8) & (dollar_volume>dol_vol_min) & (Factor1>0) & (Factor2>0))

    pipe = Pipeline(
                columns = {
                'sector' : sector,
                },
                screen = tradable_filter)
    
    pipe.add(Factor_1(), "Factor1")
    Factor1 = Factor_1()
    pipe.add(Factor_2(), "Factor2")
    Factor2 = Factor_2()
    pipe.add(Momentum(), "momentum")
    momentum = Momentum()
    
    Factor1_rank = Factor1.rank(mask=tradable_filter, ascending=True)
    pipe.add(Factor1_rank, 'F1_rank')
    Factor2_rank = Factor2.rank(mask=tradable_filter, ascending=True)
    pipe.add(Factor2_rank, 'F2_rank')
    combo_raw = (Factor1_rank+Factor2_rank)/2
    
    pipe.add(combo_raw, 'combo_rank')
    
    return pipe

def handle_data(context, data):
    pass

def record_vars(context, data):
    record(leverage=context.account.leverage,
           exposure=context.account.net_leverage,
           num_pos=len(context.portfolio.positions),
           open_orders=len(get_open_orders())) 
    
def cancel_open_orders(context, data):
    for security in get_open_orders():
        for order in get_open_orders(security):
            cancel_order(order)
    
def rebalance(context, data):
    tltweight = context.tltweight
    weight = (0.98-tltweight)/context.num_securities
    #order_target_percent(context.tlt, tltweight)
    
    if (context.use_index_trend_filter):
        index_history = data.history(context.index_id, "close", context.index_avg_window, "1d")
        index_sma = index_history.mean()  # Average of index history
        current_index = index_history[-1]  # get last element
        bull_market = current_index > index_sma # declare bull if index is over average
    if context.use_index_trend_filter:
        can_buy = bull_market # if trend filter is used, only buy in bull markets
    else:
        can_buy = True # else always buy
    equity_weight = 0.0
    
    for security in context.portfolio.positions:
        if get_open_orders(security):
            continue
        if data.can_trade(security):
            if security not in (context.longs.index | context.shorts.index):
                if (security.sid != context.bond_etf):
                    order_target_percent(security, 0)
    
    for security in context.shorts.index:
        if get_open_orders(security):
            continue
        if data.can_trade(security):
            order_target_percent(security, -weight)
            
    for security in context.longs.index:
        if get_open_orders(security):
            continue
        if data.can_trade(security):
            if (security in context.portfolio.positions) or (can_buy):
                order_target_percent(security, weight)
                equity_weight += weight
              
    etf_weight = max(0.98 - equity_weight, 0.0)
    if can_buy == True:
        order_target_percent(context.bond_etf, 0.0)
    if (context.use_bond_etf) and can_buy == False:
        order_target_percent(context.bond_etf, etf_weight)
There was a runtime error.
6 responses

Hello Darth.
This might work.

topByMomentum = results.groupby('sector')['momentum'].nlargest(2)  

When placed inside 'before_trading_start', this will create a dataframe from your pipeline output containing the symbols that have the largest 2 momentums for each sector. nsmallest(2) would get you the 2 smallest momentums.
Hope that helps.

Hello Bryan,
Thank you for your input. I tried you suggestion but get an error "Expected assets argument to be of type or iterable of type Asset". I also tried this:

ranktop = results.sort_values(by='combo_rank', ascending=True).iloc[:1000]
topbymomentum = ranktop.sort_values(by='momentum', ascending=True)
topbysector = topbymomentum.groupby('sector')
topofall = topbysector.iloc[:context.num_long]
context.longs = topofall

This brings up the error "Cannot access callable attribute 'iloc' of 'DataFrameGroupBy' objects, try using the 'apply' method". Ultimately I'd like to take the 1000 stocks after ranking them on value, then be able to sort by momentum, whereby if my final long count goal was 20 stocks for example I'd have at most 3 stocks from any sector.

Do you have any other ideas?

Darth,
Sorry, but it's getting late and I'm leaving in the morning to take my boys to the gulf coast for a couple of weeks.
This will give you the top three momentums by sector. Maybe ditch the iloc 1000 idea?
Best of luck.

Clone Algorithm
9
Loading...
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 was taken from Anthony FJ Garner here: https://www.quantopian.com/posts/a-simple-momentum-rotation-system-for-stocks
# This algo is the result of my attempt to bring over my old fundamental algorithm to the modern Q2 changes.  To my suprise, I made a functional algo without much help. haha.  This algo tries to permit me to look at specific value metrics, their interactions when 2 or more are used in combination and also adding a momentum factor.  Average day $ volume minimum increases over time to account for portfolio growth.  Market cap minimum, price minimum and other filters I feel are needed are applied.

# If you want to add a stop loss try here: https://www.quantopian.com/posts/5672ccec6891c22735000212#5718fc37bb3e7d6347000acf

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 CustomFactor, SimpleMovingAverage
from quantopian.pipeline.data import morningstar
from quantopian.pipeline.filters.morningstar import IsPrimaryShare
from quantopian.pipeline.filters import StaticAssets
from quantopian.pipeline.classifiers.morningstar import Sector

import pandas as pd
import numpy as np

class AvgDailyDollarVolumeTraded(CustomFactor):
    inputs = [USEquityPricing.close, USEquityPricing.volume]
    window_length = 20
    def compute(self, today, assets, out, close_price, volume):
        out[:] = np.mean(close_price * volume, axis=0)
class Factor_1(CustomFactor):
    inputs = [morningstar.valuation_ratios.total_yield]
    window_length = 1
    def compute(self, today, assets, out, totalyield):
        out[:] = 1/totalyield[-1]
class Factor_2(CustomFactor):
    inputs = [morningstar.valuation_ratios.pb_ratio]
    window_length = 1
    def compute(self, today, assets, out, pbratio):
        out[:] = pbratio[-1]
class Momentum(CustomFactor): 
    inputs = [USEquityPricing.close]
    window_length = 252
    def compute(self, today, assets, out, close):       
        out[:] = close[-1] / close[-252]
class MarketCap(CustomFactor):
    inputs = [morningstar.valuation.market_cap]
    window_length = 1 
    def compute(self, today, assets, out, market_cap):
        out[:] = market_cap[-1]

def before_trading_start(context, data):
    results = pipeline_output('my_pipeline').dropna()
    #print(results[['sector','momentum']])
    topbymomentum = results.groupby('sector')['momentum'].nlargest(3)
    print(topbymomentum)
    ranktop = results.sort_values(by='combo_rank', ascending=True).iloc[:1000] #True for low p/x
    rankbottom = results.sort_values(by='combo_rank', ascending=True).iloc[:1000]
    trendingup = ranktop.sort_values(by='momentum', ascending=False).iloc[:context.num_long]
    sectors = results.sector.unique()
    trendingdown = rankbottom.sort_values(by='momentum', ascending=True).iloc[:context.num_short] #True is trending down
    context.shorts = 1 / trendingdown
    context.shorts /= context.shorts.sum()
    context.longs = trendingup
    context.longs /= context.longs.sum()
    record(ranktop=len(ranktop))
    
def initialize(context): # Put any initialization logic here. The context object will be passed to the other methods in your algorithm.
    context.num_securities = 20
    context.num_short = 0 #context.num_securities // 2
    context.num_long = 20 #context.num_securities - context.num_short
    
    context.spy = sid(8554) #SPY # sid(19920) #QQQ # This is not working as benchmark
    context.index_id = sid(8554)
    context.index_avg_window = 100
    context.use_index_trend_filter = True
    context.use_bond_etf = True
    context.bond_etf = sid(23921)
    context.shorts = None
    context.longs = None
    context.tlt = sid(23921) 
    context.tltweight = 0.0 # written as 0.percent
    context.exclusion_list = [sid(8817)]
    schedule_function(rebalance, date_rules.month_start(), time_rule=time_rules.market_open(minutes = 20))
    schedule_function(cancel_open_orders, date_rules.every_day(), time_rules.market_close())
    schedule_function(record_vars, date_rules.every_day(), time_rules.market_close())
    set_commission(commission.PerShare(cost=0.0045, min_trade_cost=1.00))
    set_slippage(slippage.FixedSlippage(spread=0.06))
    #set_slippage(slippage.VolumeShareSlippage(volume_limit=0.5, price_impact=0.0)) #change volume_limit back to 0.1
    
    attach_pipeline(my_pipeline(context), name='my_pipeline') #can also remove name= and just put 'my_pipeline'

def my_pipeline(context):
    sector = Sector()
    Factor1 = Factor_1()
    Factor2 = Factor_2()
    
    mstar = morningstar
    common_stock = mstar.share_class_reference.security_type.latest.eq('ST00000001')
    not_lp_name = ~mstar.company_reference.standard_name.latest.matches('.* L[\\. ]?P\.?$')
    not_lp_balance_sheet = mstar.balance_sheet.limited_partnership.latest.isnull()
    have_market_cap = mstar.valuation.market_cap.latest.notnull()
    not_otc = ~mstar.share_class_reference.exchange_id.latest.startswith('OTC')
    not_wi = ~mstar.share_class_reference.symbol.latest.endswith('.WI')
    not_depository = ~mstar.share_class_reference.is_depositary_receipt.latest
    primary_share = IsPrimaryShare()
    exclusion_filter = ~StaticAssets(context.exclusion_list)
    
    sma_200 = SimpleMovingAverage(inputs=[USEquityPricing.close], window_length=200)
    dollar_volume = AvgDailyDollarVolumeTraded(window_length=20)#, mask=tradable_filter)
    market_cap = MarketCap(window_length=1)
    port_val = context.portfolio.portfolio_value
    dol_vol_min = (port_val*20.0) #1/20 of portfolio value purchase is never more than 1/100 of Avg daily $ vol
    # Screen out penny stocks, low liquidity securities and low market cap.
    
    tradable_filter = (common_stock & not_lp_name & not_lp_balance_sheet &
                      have_market_cap & not_otc & not_wi & not_depository & primary_share & exclusion_filter & (sma_200>1) &                               (market_cap>10**8) & (dollar_volume>dol_vol_min) & (Factor1>0) & (Factor2>0))

    pipe = Pipeline(
                columns = {
                'sector' : sector,
                },
                screen = tradable_filter)
    
    pipe.add(Factor_1(), "Factor1")
    Factor1 = Factor_1()
    pipe.add(Factor_2(), "Factor2")
    Factor2 = Factor_2()
    pipe.add(Momentum(), "momentum")
    momentum = Momentum()
    
    Factor1_rank = Factor1.rank(mask=tradable_filter, ascending=True)
    pipe.add(Factor1_rank, 'F1_rank')
    Factor2_rank = Factor2.rank(mask=tradable_filter, ascending=True)
    pipe.add(Factor2_rank, 'F2_rank')
    combo_raw = (Factor1_rank+Factor2_rank)/2
    
    pipe.add(combo_raw, 'combo_rank')
    
    return pipe

def handle_data(context, data):
    pass

def record_vars(context, data):
    record(leverage=context.account.leverage,
           exposure=context.account.net_leverage,
           num_pos=len(context.portfolio.positions),
           open_orders=len(get_open_orders())) 
    
def cancel_open_orders(context, data):
    for security in get_open_orders():
        for order in get_open_orders(security):
            cancel_order(order)
    
def rebalance(context, data):
    tltweight = context.tltweight
    weight = (0.98-tltweight)/context.num_securities
    #order_target_percent(context.tlt, tltweight)
    
    if (context.use_index_trend_filter):
        index_history = data.history(context.index_id, "close", context.index_avg_window, "1d")
        index_sma = index_history.mean()  # Average of index history
        current_index = index_history[-1]  # get last element
        bull_market = current_index > index_sma # declare bull if index is over average
    if context.use_index_trend_filter:
        can_buy = bull_market # if trend filter is used, only buy in bull markets
    else:
        can_buy = True # else always buy
    equity_weight = 0.0
    
    for security in context.portfolio.positions:
        if get_open_orders(security):
            continue
        if data.can_trade(security):
            if security not in (context.longs.index | context.shorts.index):
                if (security.sid != context.bond_etf):
                    order_target_percent(security, 0)
    
    for security in context.shorts.index:
        if get_open_orders(security):
            continue
        if data.can_trade(security):
            order_target_percent(security, -weight)
            
    for security in context.longs.index:
        if get_open_orders(security):
            continue
        if data.can_trade(security):
            if (security in context.portfolio.positions) or (can_buy):
                order_target_percent(security, weight)
                equity_weight += weight
              
    etf_weight = max(0.98 - equity_weight, 0.0)
    if can_buy == True:
        order_target_percent(context.bond_etf, 0.0)
    if (context.use_bond_etf) and can_buy == False:
        order_target_percent(context.bond_etf, etf_weight)
There was a runtime error.

Bryan,
Had a look at your suggestion and this is what I came up with. I'm getting a new error. Any suggestions?

Clone Algorithm
32
Loading...
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 was taken from Anthony FJ Garner here: https://www.quantopian.com/posts/a-simple-momentum-rotation-system-for-stocks
# This algo is the result of my attempt to bring over my old fundamental algorithm to the modern Q2 changes.  To my suprise, I made a functional algo without much help. This algo tries to permit me to look at specific value metrics, their interactions when 2 or more are used in combination and also adding a momentum factor.  Average day $ volume minimum increases over time to account for portfolio growth.  Market cap minimum, price minimum and other filters I feel are needed are applied.

# If you want to add a stop loss try here: https://www.quantopian.com/posts/5672ccec6891c22735000212#5718fc37bb3e7d6347000acf

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 CustomFactor, SimpleMovingAverage
from quantopian.pipeline.data import morningstar
from quantopian.pipeline.filters.morningstar import IsPrimaryShare
from quantopian.pipeline.filters import StaticAssets
from quantopian.pipeline.classifiers.morningstar import Sector

import pandas as pd
import numpy as np

class AvgDailyDollarVolumeTraded(CustomFactor):
    inputs = [USEquityPricing.close, USEquityPricing.volume]
    window_length = 20
    def compute(self, today, assets, out, close_price, volume):
        out[:] = np.mean(close_price * volume, axis=0)
class Factor_1(CustomFactor):
    inputs = [morningstar.valuation_ratios.total_yield]
    window_length = 1
    def compute(self, today, assets, out, totalyield):
        out[:] = 1/totalyield[-1]
class Factor_2(CustomFactor):
    inputs = [morningstar.valuation_ratios.pb_ratio]
    window_length = 1
    def compute(self, today, assets, out, pbratio):
        out[:] = pbratio[-1]
class Momentum(CustomFactor): 
    inputs = [USEquityPricing.close]
    window_length = 252
    def compute(self, today, assets, out, close):       
        out[:] = close[-1] / close[-252]
class MarketCap(CustomFactor):
    inputs = [morningstar.valuation.market_cap]
    window_length = 1 
    def compute(self, today, assets, out, market_cap):
        out[:] = market_cap[-1]

def before_trading_start(context, data):
    results = pipeline_output('my_pipeline').dropna()
    
    ranktop = results.sort_values(by='combo_rank', ascending=False).tail(1000) #True for low p/x
    topbymomentum = ranktop.groupby('sector')['momentum'].nlargest(2)
    topofall = topbymomentum 
    #topofall = tobbymomentum.sort_values(by='momentum', ascending=False).tail(:context.num_long)
    
    rankbottom = results.sort_values(by='combo_rank', ascending=True).iloc[:1000]
    trendingdown = rankbottom.sort_values(by='momentum', ascending=True).iloc[:context.num_short] #True is trending down
    context.shorts = 1 / trendingdown
    context.shorts /= context.shorts.sum()
    context.longs = topofall #trendingup
    context.longs /= context.longs.sum()
    record(ranktop=len(ranktop))
    
def initialize(context): # Put any initialization logic here. The context object will be passed to the other methods in your algorithm.
    context.num_securities = 20
    context.num_short = 0 #context.num_securities // 2
    context.num_long = 20 #context.num_securities - context.num_short
    
    context.spy = sid(8554) #SPY # sid(19920) #QQQ # This is not working as benchmark
    context.index_id = sid(8554)
    context.index_avg_window = 100
    context.use_index_trend_filter = True
    context.use_bond_etf = True
    context.bond_etf = sid(23921)
    context.shorts = None
    context.longs = None
    context.tlt = sid(23921) 
    context.tltweight = 0.0 # written as 0.percent
    context.exclusion_list = [sid(8817)]
    schedule_function(rebalance, date_rules.month_start(), time_rule=time_rules.market_open(minutes = 20))
    schedule_function(cancel_open_orders, date_rules.every_day(), time_rules.market_close())
    schedule_function(record_vars, date_rules.every_day(), time_rules.market_close())
    set_commission(commission.PerShare(cost=0.0045, min_trade_cost=1.00))
    set_slippage(slippage.FixedSlippage(spread=0.06))
    #set_slippage(slippage.VolumeShareSlippage(volume_limit=0.5, price_impact=0.0)) #change volume_limit back to 0.1
    
    attach_pipeline(my_pipeline(context), name='my_pipeline') #can also remove name= and just put 'my_pipeline'

def my_pipeline(context):
    sector = Sector()
    Factor1 = Factor_1()
    Factor2 = Factor_2()
    
    mstar = morningstar
    common_stock = mstar.share_class_reference.security_type.latest.eq('ST00000001')
    not_lp_name = ~mstar.company_reference.standard_name.latest.matches('.* L[\\. ]?P\.?$')
    not_lp_balance_sheet = mstar.balance_sheet.limited_partnership.latest.isnull()
    have_market_cap = mstar.valuation.market_cap.latest.notnull()
    not_otc = ~mstar.share_class_reference.exchange_id.latest.startswith('OTC')
    not_wi = ~mstar.share_class_reference.symbol.latest.endswith('.WI')
    not_depository = ~mstar.share_class_reference.is_depositary_receipt.latest
    primary_share = IsPrimaryShare()
    exclusion_filter = ~StaticAssets(context.exclusion_list)
    
    sma_200 = SimpleMovingAverage(inputs=[USEquityPricing.close], window_length=200)
    dollar_volume = AvgDailyDollarVolumeTraded(window_length=20)#, mask=tradable_filter)
    market_cap = MarketCap(window_length=1)
    port_val = context.portfolio.portfolio_value
    dol_vol_min = (port_val*20.0) #1/20 of portfolio value purchase is never more than 1/100 of Avg daily $ vol
    # Screen out penny stocks, low liquidity securities and low market cap.
    
    tradable_filter = (common_stock & not_lp_name & not_lp_balance_sheet &
                      have_market_cap & not_otc & not_wi & not_depository & primary_share & exclusion_filter & (sma_200>1) &                               (market_cap>10**8) & (dollar_volume>dol_vol_min) & (Factor1>0) & (Factor2>0))

    pipe = Pipeline(
                columns = {
                'sector' : sector,
                },
                screen = tradable_filter)
    
    pipe.add(Factor_1(), "Factor1")
    Factor1 = Factor_1()
    pipe.add(Factor_2(), "Factor2")
    Factor2 = Factor_2()
    pipe.add(Momentum(), "momentum")
    momentum = Momentum()
    
    Factor1_rank = Factor1.rank(mask=tradable_filter, ascending=True)
    pipe.add(Factor1_rank, 'F1_rank')
    Factor2_rank = Factor2.rank(mask=tradable_filter, ascending=True)
    pipe.add(Factor2_rank, 'F2_rank')
    combo_raw = (Factor1_rank+Factor2_rank)/2
    
    pipe.add(combo_raw, 'combo_rank')
    
    return pipe

def handle_data(context, data):
    pass

def record_vars(context, data):
    record(leverage=context.account.leverage,
           exposure=context.account.net_leverage,
           num_pos=len(context.portfolio.positions),
           open_orders=len(get_open_orders())) 
    
def cancel_open_orders(context, data):
    for security in get_open_orders():
        for order in get_open_orders(security):
            cancel_order(order)
    
def rebalance(context, data):
    tltweight = context.tltweight
    weight = (0.98-tltweight)/context.num_securities
    #order_target_percent(context.tlt, tltweight)
    
    if (context.use_index_trend_filter):
        index_history = data.history(context.index_id, "close", context.index_avg_window, "1d")
        index_sma = index_history.mean()  # Average of index history
        current_index = index_history[-1]  # get last element
        bull_market = current_index > index_sma # declare bull if index is over average
    if context.use_index_trend_filter:
        can_buy = bull_market # if trend filter is used, only buy in bull markets
    else:
        can_buy = True # else always buy
    equity_weight = 0.0
    
    for security in context.portfolio.positions:
        if get_open_orders(security):
            continue
        if data.can_trade(security):
            if security not in (context.longs.index | context.shorts.index):
                if (security.sid != context.bond_etf):
                    order_target_percent(security, 0)
    
    for security in context.shorts.index:
        if get_open_orders(security):
            continue
        if data.can_trade(security):
            order_target_percent(security, -weight)
            
    for security in context.longs.index:
        if get_open_orders(security):
            continue
        if data.can_trade(security):
            if (security in context.portfolio.positions) or (can_buy):
                order_target_percent(security, weight)
                equity_weight += weight
              
    etf_weight = max(0.98 - equity_weight, 0.0)
    if can_buy == True:
        order_target_percent(context.bond_etf, 0.0)
    if (context.use_bond_etf) and can_buy == False:
        order_target_percent(context.bond_etf, etf_weight)
There was a runtime error.

Hey Darth,

That error is being thrown from your for loop code block beginning at line 178. If you 'print(security)' from within that block you'll notice that 'security' contains (101, Equity(1595 [CLF])). I'm guessing 101 is the sector.
By inserting 'security = security[1]' as a new line at 179 the symbol will be stripped out and work as expected.
Like this:

for security in context.longs.index:  
        security = security[1]  
        if get_open_orders(security):  
            continue  
        #print(security, weight)  
        if data.can_trade(security):  
            if (security in context.portfolio.positions) or (can_buy):  
                order_target_percent(security, weight)  
                equity_weight += weight  

Your other ordering sections don't seem to be affected by this, but you might want to check to make sure.
When looping through lists of lists remember that they are zero based indices. security[0] is the first element, security[1] is the 2nd and so on.
You might already know that, but thought I'd throw it in just in case.
Hope that helps.
Bryan

Bryan,
I want to thank you for your help, the suggestions you have made have fixed the problem. Everything is working well thanks to you!