How about this for dealing with stock splits (and maybe other extreme jumps).
A portable self-contained single function. Tailor the two variables offset and _days_out as you wish.
The attached backtest contains a test mode that simulates a split and this is the output:
2015-09-22 split:75 INFO TSLA price jump 130.50 to 230.50, possible split, excluding 63 days
2015-12-21 split:79 INFO Clearing TSLA possible split exclusion after 63 days, now 232.56
def handle_data(context, data):
for stock in data:
if split(stock, context, data): continue
# Your other code, ordering etc ...
def split(s, c, data):
''' Try to detect a stock split or reverse split and quarantine the stock for x days.
Especially important in the live/real environment where any indicators involving prices
could possibly lead to an erroneous (disastrous) buy or sell,
also for the rare backtest splits mistakenly not adjusted for awhile.
Input: c is context, s is the stock object
Output: 0 if not excluded, 1 if excluded
'''
if 'excludes' not in c:
c.excludes = {
'_days_out': 63, # Number of days to keep them out of trading
'_date_prv': get_datetime().date()
}
offset = .4 # Ratio above or below previous price to consider too much of a jump,
# and therefore a possible split (or reverse split).
exclude = 0
sym = s.symbol
price = data[s].price
if sym not in c.excludes:
c.excludes[sym] = {
'price_prv': price,
'days_out' : -1 # Not out, initialization
}
return 0
price_prv = c.excludes[sym]['price_prv']
if price > price_prv + price_prv * offset \
or price < price_prv - price_prv * offset: # If price change beyond offset up or down
c.excludes[sym] = {
'price_prv': price,
'days_out' : 0 # Begin exclusion
}
exclude = 1
log.info('{} price jump {} to {}, possible split, excluding {} days'.format(
sym, '%.2f' % c.excludes[sym]['price_prv'], '%.2f' % price_prv, c.excludes['_days_out']))
if c.excludes[sym]['days_out'] >= c.excludes['_days_out']:
c.excludes[sym]['days_out'] = -1 # Reset, no longer excluded
log.info('Clearing {} possible split exclusion after {} days, now {}'.format(
sym, c.excludes['_days_out'], '%.2f' % price))
if get_datetime().date() != c.excludes['_date_prv']: # New day
c.excludes['_date_prv'] = get_datetime().date() # Save the new date as previous
if c.excludes[sym]['days_out'] != -1:
c.excludes[sym]['days_out'] += 1 # Is excluded, increment days
exclude = 1
c.excludes[sym]['price_prv'] = price_prv # New previous price
if exclude:
return 1
return 0