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 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