For code/output blocks: Use ``` (aka backtick or grave accent) in a single line before and after the block. See: http://commonmark.org/help/

Updating Stop Loss based on current profit



  • Hi,

    I am currently issuing a bracket order as follows:

    self.buy_bracket(exectype=bt.Order.Market,
                                     size=qty,
                                     limitprice=cash*3*self.p.risk / qty + self.data.close[0],
                                     stopprice=stop_price,
                                     )
    

    I wish to update the stop order issue based on the profit of the current trade. There is only one trade open at any given moment. I tried to use the trail order and trailpercent method but it doesn't seem to work.

    In general, here's what I would like the system to do:

    if profit > 20, stop loss should be at break-even
    if profit > 40, stop loss should be at 20
    ... and so on.

    Any clever ideas on how to implement it?



  • If you really want action like in that last paragraph, than each next() you cancel existing stop order, calculate profit and new stop price, and issue new stop order. No bracket orders required.

    But it seems that it is not that easy.



  • Cool, thanks!



  • You can manage the stoplimit prices by resetting the price in the stop order. Set the initial stop order manually after the buy, then reset the stop price as price climbs. This has the advantage of not creating and cancelling stop orders over and over.

    I'm not 100% sure this is acceptable to change the price of the outstanding stop order this way, but it's working on my machine.

    You can set the price manually any way you wish.

    I borrowed this code from here.

    class BaseStrategy(bt.Strategy):
        params = dict(fast_ma=10, slow_ma=20,)
    
        def __init__(self):
            self.reset_price = 0
            self.so = []
    
            # omitting a data implies self.datas[0] (aka self.data and self.data0)
            fast_ma = bt.ind.EMA(period=self.p.fast_ma)
            slow_ma = bt.ind.EMA(period=self.p.slow_ma)
            # our entry point
            self.crossup = bt.ind.CrossUp(fast_ma, slow_ma)
    
    
    class ManualStopOrStopTrail(BaseStrategy):
        params = dict(
            stop_loss=0.15,  # price is .15 below the purchase price at intervals.
        )
    
        def notify_order(self, order):
            if not order.status == order.Completed:
                return  # discard any other notification
    
            if order.status == order.Canceled:
                return
    
            if not self.position:  # we left the market
                print("SELL@price: {} {:.2f}".format(self.date, order.executed.price))
                self.so = []
                return
    
            # We have entered the market
            print("BUY @price: {} {:.2f}".format(self.date, order.executed.price))
    
            stop_price = order.executed.price - self.p.stop_loss
            self.so = [self.sell(exectype=bt.Order.Stop, price=stop_price)]
            self.reset_price = order.executed.price + self.p.stop_loss
    
        def next(self):
            self.date = self.data.datetime.date()
            print("{} {:.2f}".format(self.date, self.data[0]))
    
            if len(self.so) > 0 and self.datas[0].close[0] > self.reset_price:
                new_stop_price = self.reset_price - self.p.stop_loss
                print("{} Stop price changed to: {:.2f}".format(self.date, new_stop_price))
                # Change the price in the order in the self.so list.
                self.so[0].created.price = new_stop_price
                # Reset the next price limit
                self.reset_price = self.reset_price + self.p.stop_loss
            else:
                pass
    
            if not self.position and self.crossup > 0:
                # not in the market and signal triggered
                self.buy()
    
    

    Here's an output using .15 cent intervals.

    2004-03-23 22.04
    2004-03-24 22.25
    2004-03-25 23.47
    BUY @price: 2004-03-25 23.38
    2004-03-26 23.57
    2004-03-26 Stop price changed to: 23.38
    2004-03-29 23.84
    2004-03-29 Stop price changed to: 23.52
    2004-03-30 24.39
    2004-03-30 Stop price changed to: 23.67
    2004-03-31 24.24
    2004-03-31 Stop price changed to: 23.82
    2004-04-01 24.73
    2004-04-01 Stop price changed to: 23.97
    2004-04-02 25.08
    2004-04-02 Stop price changed to: 24.12
    2004-04-05 25.00
    2004-04-05 Stop price changed to: 24.27
    SELL@price: 2004-04-05 24.27
    2004-04-06 24.39
    2004-04-07 24.17
    2004-04-08 28.11
    2004-04-12 27.57
    
    


  • It will most probably not work in real live trading. For this to work updating the 'order.created.price' should generate some sort of notification to the broker , and I think there is no such functionality.



  • @vladisld Were you able to verify whether the quick update of the stop loss works in live trading?



  • @booboothefool said in Updating Stop Loss based on current profit:

    @vladisld Were you able to verify whether the quick update of the stop loss works in live trading?

    I didn't try it on a real live broker - not using this technique in my system. However if we'll take a look at the backtrader code, we'll see that updating the price member of the existing order - will just update the price member - that's all. No communication with a broker is done at that point nor in any point further the road ( so it works by chance in internal broker simulator).

    AFAIU updating the existing order through live broker will move the order to the end of the order queue for this particular price - something that is not required for local simulation.

    I believe this was already discussed here


Log in to reply
 

});