Back to Community
Weighting when no stocks appear in short / long results

My first time posting - I hope I am providing enough information....

I am using the following to assign weights and rebalance my portfolio on a weekly basis. It is a long / short portfolio, with 50% long and 50% short. Can any one help with the following?

  1. There are times when there are no stocks that meet the "short" criteria, and my short.secs list is empty. As a result, I get a "divide by zero" error when attempting to assign weights. In those cases, I would like to short SPY with 50% of the portfolio to balance the account. I suspect this is an if/then statement, but I can't figure out how to apply.

  2. Similar to the above, I occasionally will have only 1 stock in the short.secs list. I don't want to have 50% of my account short in one stock, so I need to create a maximum exposure limit for each stock (for example, 5%). The remaining 45% would be replaced by a short SPY position.

def before_trading_start(context, data):  
    """  
    Called every day before market open.  
    """  
    #Pipeline_output returns a pandas DataFrame with the results of our factors and filters.  
    context.output = pipeline_output('my_pipeline')  
    #Sets the list of securities we want to long as the securities with a 'True'  
    #value in the long_positions column.  
    context.long_secs = context.output[context.output['long_positions']]  
    context.short_secs = context.output[context.output['short_positions']]

    #A list of the securities that we want to order today.  
    context.security_list = context.long_secs.index.union(context.short_secs.index).tolist()

    # A set of the same securities, sets have faster lookup.  
    context.security_set = set(context.security_list)

def my_assign_weights(context):  
    #Set the allocations to even weights for each long position, and even weights  
    # for each short position.  
    long_weight = context.long_leverage / len(context.long_secs)  
    short_weight = context.short_leverage / len(context.short_secs)  
    return long_weight, short_weight  
def my_rebalance(context,data):  
    """  
    This rebalancing function is called according to our schedule_function settings.  
    """

    long_weight, short_weight = my_assign_weights(context)

    #For each security in our universe, order long or short positions according  
    # to our context.long_secs and context.short_secs lists.  
    for stock in context.security_set:  
        if data.can_trade(stock):  
            if stock in context.long_secs.index:  
                order_target_percent(stock, long_weight)  
            elif stock in context.short_secs.index:  
                order_target_percent(stock, short_weight)

    # Sell all previously held positions not in our new context.security_list.  
    for stock in context.portfolio.positions:  
        if stock not in context.security_set and data.can_trade(stock):  
            order_target_percent(stock, 0)

    # Log the long and short orders each week.  
    log.info("This week's longs: "+", ".join([long_.symbol for long_ in context.long_secs.index]))  
    log.info("This week's shorts: "  +", ".join([short_.symbol for short_ in context.short_secs.index]))

    log.info('Rebalance Completed')

1 response

I discovered a pretty simple solution to the first problem (no stocks meeting the short / long criteria). Adding an "if" statement to make sure that there are stocks on the list seems to solve the problem:

if len(context.long_secs) > 0:  
        long_weight = context.long_leverage / len(context.long_secs)  
    else:  long_weight = 0  
    if len(context.short_secs) > 0:  
        short_weight = context.short_leverage / len(context.short_secs)  
    else:  short_weight = 0