Quantopian's community platform is shutting down. Please read this post for more information and download your code.
Back to Community
How to manage stop-loss

Hey there. I have written a module to manage stop losses. It is modular and can be plugged into any existing algorithm to perform a trailing stop-loss exit. It works for long as well as for short positions.

Functionalities are:

  • identify any open positions and orders with no stop (short and long)
  • create new stop levels
  • manage existing stop levels
  • create StopOrders with appropriate price and amount

To use it, please

  1. Copy my code lines 54-156 into your algorithm,
  2. Add these three lines of code into your algorithm:
# into initialize  
context.SL_Manager = StopLoss_Manager()  
schedule_function(context.SL_Manager.manage_orders, date_rules.every_day(), time_rules.market_open())

# at the end of rebalance and wherever you create new orders  
context.SL_Manager.manage_orders(context, data)  

To demonstrate the functionality, my algorithm opens a long-position for SPY. If this was closed through stop-loss, it will wait 10 days to re-open that position.

Right now, this will for swing-trading but not for pairs-trading. But I am planing to add functionality to handle spread-positions.

Cheers, Sebastian

14 responses

This is awesome really solved a big problem for me thank you!

I'm getting an "attempt to place an order with a stop price of nan", any ideas?

Could be delisted, so add the can_trade() test, and/or could just be a bar with no trades so replace all 'close' with 'price' which is forward filled.

    for sec in self.stops.index:  
        cancel_order(self.stops['id'][sec])  
        if not data.can_trade(sec): continue  
        [ ... etc ]  

Hi, thanks very much for the code. I ran to "attempt to place an order with a stop price of nan" error also. May I know where should I put

for sec in self.stops.index:
cancel_order(self.stops['id'][sec])
if not data.can_trade(sec): continue

Thanks!

Implementing this into my algos, thank you

Has anyone had any luck using this code for futures? Maybe there is an issue with the multiplier or something but I'm getting instantaneous buys and sells at the same prices.

I am also getting this error:

BadOrderParameters: Attempted to place an order with a stop price of nan.

The suggestion above has not worked (or I maybe I have inserted it in the wrong place, anyone know where to insert this??)

for sec in self.stops.index:
cancel_order(self.stops['id'][sec])
if not data.can_trade(sec): continue

same problem... where do I put this piece of code?

thanks

Hi there,

you have to insert the following after line 97.

 if not data.can_trade(sec): continue  

I'm sorry, is this correct?
if not sec in self.stops.index:
self.stops.loc[sec, 'amount'] = amount
else:
self.stops.loc[sec, 'amount'] = +amount

may be it should be
self.stops.loc[sec, 'amount'] += amount
?

Does anyone else get this error message of:

There was a runtime error.
BadOrderParameters: Attempted to place an order with a stop price of nan.

I put in the code after line 97 and still came up with the message. Any ideas?

Same issue

@Anton:
I think you are right that the correct version should be:

self.stops.loc[sec, 'amount'] += amount  

@mark, illia, sebastian
The "BadOrderParameters: Attempted to place an order with a stop price of nan." error arises due to the fact that for some equity
data.current(sec, 'close') is nan in those cases I have replaced it with data.current(sec, "price"). You can replace the lines 96-106 in the original code with the one below.

for sec in self.stops.index:  
            cancel_order(self.stops['id'][sec])  
            if not data.can_trade(sec):  
                continue  
            if self._np.isnan(data.current(sec, 'close')):  
                current_price = data.current(sec, 'price')  
            else:  
                current_price = data.current(sec, 'close')  
            if self._np.isnan(self.stops['price'][sec]):  
                stop = (1-self.params['pct_init'])*current_price  
            else:  
                o = self._np.sign(self.stops['amount'][sec])  
                new_stop = (1-o*self.params['pct_trail'])*current_price  
                stop = o*max(o*self.stops['price'][sec], o*new_stop)  

However I still think that the stop loss manager doesn't work properly, and some orders remain open until to the next rebalance. I also benchmark it with my own implementation of a trailing stop loss and there are differences in performance.

@irfan

Thanks a lot it helped!