Often when a stock spikes upward it quickly drops back down again as people and programs take profit. This is an effort to be one of those programs.
Looking for a price jump over 3.0x, adding to watch_list, and processing anything on that list every 25 minutes, looking for whether the slope of minute prices is downward and close the position if so, taking that profit hopefully before the price drops too far. Upward movement is not hampered.
A comparison of before and after this code. This is a Robinhood algorithm of mine based on an early Charles Witt example and changed quite a bit.
I haven't tried this with other code, could just be overfit. Would like this to evolve to be more dynamic. Ideas.
You can just drop all of the code below at the end of initialize. There's some useful information in the logging window that will tell you if it catches anything. Would be great to hear if it works for you.
The relevant excerpts:
def initialize(context):
context.watch_list = []
for i in range(25, 385, 25): # (start, end, every i minutes)
schedule_function(watch, date_rules.every_day(), time_rules.market_open(minutes=i))
def watch(context, data): # On schedule, process any sids in watch_list
prices = data.history(context.watch_list, 'close', 2, '1d') # Daily, couple days
for s in context.watch_list:
if s not in context.portfolio.positions: # If sold elsewhere, drop it from watch
context.watch_list.remove(s)
continue
# Slope of prices, minute
slp = slope(data.history(s, 'close', 60, '1m').dropna()) # Minutes, note dropna(), important
log.info('{} at {} prv {} {}% slp {}'.format(s.symbol, data.current(s, 'price'), '%.2f' % prices[s][0], '%.0f' % (100 * data.current(s, 'price') / prices[s][0]), '%4f' % slp ))
if slp < 0: # Close if downward
log.info('sell {} at {} prv {} {}%'.format(s.symbol, data.current(s, 'price'), '%.2f' % prices[s][0], '%.0f' % (100 * data.current(s, 'price') / prices[s][0]) ))
order_target(s, 0) # Close/sell
context.watch_list.remove(s)
# Any new for price jump watch_list
prices = data.history(context.portfolio.positions.keys(), 'close', 2, '1d') # Couple days
for s in context.portfolio.positions: # Add to watch_list with price jump
if not data.can_trade(s): continue
if data.current(s, 'price') > 3.0 * prices[s][0]: # If price has jumped upward
if s in context.watch_list: continue
log.info('{} to watch_list at {} prv {} {}%'.format(s.symbol, data.current(s, 'price'), '%.2f' % prices[s][0], '%.0f' % (100 * data.current(s, 'price') / prices[s][0]) ))
context.watch_list.append(s)
import statsmodels.api as sm
def slope(in_list): # Return slope of regression line. [Make sure this list contains no nans]
return sm.OLS(in_list, sm.add_constant(range(-len(in_list) + 1, 1))).fit().params[-1] # slope
As always, use PvR to see clearly.