Navigation

    Backtrader Community

    • Register
    • Login
    • Search
    • Categories
    • Recent
    • Tags
    • Popular
    • Users
    • Groups
    • Search
    For code/output blocks: Use ``` (aka backtick or grave accent) in a single line before and after the block. See: http://commonmark.org/help/

    Multiple stop loss issued

    General Code/Help
    2
    13
    127
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • Eduardo Menges Mattje
      Eduardo Menges Mattje last edited by

      I have this code for a RSI strategy that I've tried to implement Stop Loss.

      import backtrader as bt
      from datetime import datetime
      
      
      class firstStrategy(bt.Strategy):
          params = (
              ('stopLoss', 0.25),
              ('upperband', 75),
              ('lowerband', 25),
              ('period', 9)
          )
      
          def __init__(self):
              self.rsi = bt.indicators.RelativeStrengthIndex(self.data.close, period=9, safediv=True)
              self.order = None
              self.stopOrder = None
      
          def notify_order(self, order):
              if order.status in [order.Submitted, order.Accepted]:
                  return
      
              if order.status in [order.Completed]:
                  if order.isbuy():
                      if self.params.stopLoss:
                          self.stopOrder = self.close(price=order.executed.price, exectype=bt.Order.StopTrail,
                                                      trailpercent=self.params.stopLoss)
              self.order = None
      
          def next(self):
              if not self.position:
                  if self.rsi <= 25:
                      self.buy()
              elif self.rsi >= 75:
                  self.close()
      
          # def next(self):
          #     if not self.position:
          #         if self.rsi <= 25:
          #             self.buy()
          #     elif self.rsi >= 75:
          #         self.close()
      
      
      startcash = 100
      
      cerebro = bt.Cerebro()
      
      cerebro.addstrategy(firstStrategy)
      
      data = bt.feeds.GenericCSVData(
          dataname='NEOUSDT-15m-data.csv',
          fromdate=datetime(2020, 2, 1, 0, 0),
          todate=datetime(2020, 6, 1, 0, 0),
          timeframe=bt.TimeFrame.Minutes,
          compression=15,
          dtformat='%Y-%m-%d %H:%M:%S'
      )
      
      cerebro.adddata(data)
      
      cerebro.broker.setcash(startcash)
      
      cerebro.addsizer(bt.sizers.PercentSizer, percents=90)  # Set the order size
      
      cerebro.addanalyzer(bt.analyzers.DrawDown, _name='Drawdown')
      
      cerebro.broker.setcommission(commission=0.0001, margin=False)
      
      cerebro.run()
      
      portvalue = round(cerebro.broker.getvalue(), 2)
      pnl = round(portvalue - startcash, 2)
      
      print('Final Portfolio Value: ${}'.format(portvalue))
      print('P/L: ${}'.format(pnl))
      cerebro.plot(style='candlestick')
      
      

      The results were quite ridiculous, and the graph showed that multiple Stop Loss order were issued, even tho the order was supossed to be closed, as you can see:
      alt text
      So what can I do to stop it?

      1 Reply Last reply Reply Quote 0
      • Eduardo Menges Mattje
        Eduardo Menges Mattje last edited by

        I've changed the code, and now I'm trying to use a bracket order. However, the trailpercent arg doesn't do a thing. It can be 0.1, it can be 1, or even 100, and the results are same. This is the new code:

        import backtrader as bt
        from datetime import datetime
        
        
        class firstStrategy(bt.Strategy):
            params = (
                ('stopLoss', 0.25),
                ('upperband', 75),
                ('lowerband', 25),
                ('period', 9)
            )
        
            def __init__(self):
                self.rsi = bt.indicators.RelativeStrengthIndex(self.data.close, period=self.p.period, upperband=self.p.upperband, lowerband=self.p.lowerband, safediv=True)
        
            def next(self):
                if not self.position and self.rsi <= self.p.lowerband:
                        # self.buy()
                        self.buy_bracket(exectype=bt.Order.Market, price=self.data.close, limitexec=None, stopexec=bt.Order.StopTrail, trailpercent=0.1, stopprice=self.data.close)
                elif self.rsi >= self.p.upperband:
                    self.close()
        
        
        startcash = 100
        
        cerebro = bt.Cerebro()
        
        cerebro.addstrategy(firstStrategy)
        
        data = bt.feeds.GenericCSVData(
            dataname='NEOUSDT-15m-data.csv',
            fromdate=datetime(2020, 2, 1, 0, 0),
            todate=datetime(2020, 6, 1, 0, 0),
            timeframe=bt.TimeFrame.Minutes,
            compression=15,
            dtformat='%Y-%m-%d %H:%M:%S'
        )
        
        cerebro.adddata(data)
        
        cerebro.broker.setcash(startcash)
        
        cerebro.addsizer(bt.sizers.PercentSizer, percents=90)  # Set the order size
        
        cerebro.addanalyzer(bt.analyzers.DrawDown, _name='Drawdown')
        
        cerebro.broker.setcommission(commission=0.0001, margin=False)
        
        cerebro.run()
        
        portvalue = round(cerebro.broker.getvalue(), 2)
        pnl = round(portvalue - startcash, 2)
        
        print('Final Portfolio Value: ${}'.format(portvalue))
        print('P/L: ${}'.format(pnl))
        cerebro.plot(style='candlestick')
        
        

        If this is intended behaviour, can I use another kind of order?

        A 1 Reply Last reply Reply Quote 0
        • Eduardo Menges Mattje
          Eduardo Menges Mattje last edited by

          BUMP....

          1 Reply Last reply Reply Quote 0
          • A
            ab_trader last edited by

            Looks like your first script with StopTrail orders worked as expected. You used 25% stop from the price of order execution. Your first orders were executed at prices around 14.5 - 15.5 and you stops were set to approx 11.5 - 12.0. You can see them executed at that spike of the cash, 6 red triangles in a row.

            1 Reply Last reply Reply Quote 0
            • A
              ab_trader @Eduardo Menges Mattje last edited by

              @Eduardo-Menges-Mattje said in Multiple stop loss issued:

              However, the trailpercent arg doesn't do a thing. It can be 0.1, it can be 1, or even 100

              Just to clarify (Docs - Orders - StopTrail)

              Percentage based distance: trailpercent=0.02 (i.e.: 2%)

              You start with 0.1 which is 10% and your price range is much less than this value. You need to use much less % of stop in order to hit it before your self.close() closes position in regular way.

              You may want to add more logging into your script, this will help you to understand what is going on.

              1 Reply Last reply Reply Quote 0
              • Eduardo Menges Mattje
                Eduardo Menges Mattje last edited by

                @ab_trader said in Multiple stop loss issued:

                Just to clarify (Docs - Orders - StopTrail)

                Percentage based distance: trailpercent=0.02 (i.e.: 2%)

                You start with 0.1 which is 10% and your price range is much less than this value. You need to use much less % of stop in order to hit it before your self.close() closes position in regular way.
                Even with trailpercent=0.01, the result is the same as 0.1 or any other value. As I said, it is as if trailpercent is completely disregarded.

                You may want to add more logging into your script, this will help you to understand what is going on.
                Ok. This is the code with the logging:

                import backtrader as bt
                from datetime import datetime
                
                
                class firstStrategy(bt.Strategy):
                    params = dict(
                        stopLoss=0.01,
                        upperband=75,
                        lowerband=25,
                        period=9
                    )
                
                    def log(self, txt, dt=None):
                        dt = dt or self.data.datetime[0]
                        if isinstance(dt, float):
                            dt = bt.num2date(dt)
                        print('%s, %s' % (dt.isoformat(), txt))
                
                    def notify_order(self, order):
                        if order.status in [order.Completed]:
                            if order.isbuy():
                                self.log(
                                    'BUY EXECUTED, Price: %.2f, Cost: %.2f, Comm %.2f' %
                                    (order.executed.price,
                                     order.executed.value,
                                     order.executed.comm))
                
                            else:
                                self.log('SELL EXECUTED, Price: %.2f, Cost: %.2f, Comm %.2f' %
                                         (order.executed.price,
                                          order.executed.value,
                                          order.executed.comm))
                
                        self.order = None
                
                    def __init__(self):
                        self.rsi = bt.indicators.RelativeStrengthIndex(period=self.p.period, upperband=self.p.upperband,
                                                                       lowerband=self.p.lowerband, safediv=True)
                
                    def next(self):
                        if not self.position and self.rsi <= self.p.lowerband:
                            # self.buy()
                            self.buy_bracket(exectype=bt.Order.Market, price=self.data.close, limitexec=None,
                                             stopexec=bt.Order.StopTrail, trailpercent=self.p.stopLoss, stopprice=self.data.close)
                            self.log('BUY CREATE, exectype Market, price %.2f' % self.data.close[0])
                        elif self.position and self.rsi >= self.p.upperband:
                            self.close()
                            self.log('BUY CREATE, exectype Close, price %.2f' % self.data.close[0])
                
                
                startcash = 100
                
                cerebro = bt.Cerebro()
                
                cerebro.addstrategy(firstStrategy)
                
                data = bt.feeds.GenericCSVData(
                    dataname='NEOUSDT-15m-data.csv',
                    fromdate=datetime(2020, 2, 1, 0, 0),
                    todate=datetime(2020, 6, 1, 0, 0),
                    timeframe=bt.TimeFrame.Minutes,
                    compression=15,
                    dtformat='%Y-%m-%d %H:%M:%S'
                )
                
                cerebro.adddata(data)
                
                cerebro.broker.setcash(startcash)
                
                cerebro.addsizer(bt.sizers.PercentSizer, percents=90)  # Set the order size
                
                cerebro.addanalyzer(bt.analyzers.DrawDown, _name='Drawdown')
                
                cerebro.broker.setcommission(commission=0.0001, margin=False)
                
                cerebro.run()
                
                portvalue = round(cerebro.broker.getvalue(), 2)
                pnl = round(portvalue - startcash, 2)
                
                print('Final Portfolio Value: ${}'.format(portvalue))
                print('P/L: ${}'.format(pnl))
                cerebro.plot(style='candlestick')
                
                

                This is the log with trailpercent=0.01:
                https://controlc.com/90e3b126
                This is the log with trailpercent=0.10:
                https://controlc.com/80136684

                1 Reply Last reply Reply Quote 0
                • A
                  ab_trader last edited by

                  I'll take a look. Also please log ohlc prices and rsi values.

                  1 Reply Last reply Reply Quote 0
                  • Eduardo Menges Mattje
                    Eduardo Menges Mattje last edited by

                    @ab_trader said in Multiple stop loss issued:

                    I'll take a look. Also please log ohlc prices and rsi values.

                    This is the csv file: https://drive.google.com/file/d/1zx6Ywdts38sHVJqr9ZYfYV5Izxh_MBVk/view?usp=sharing

                    1 Reply Last reply Reply Quote 0
                    • Eduardo Menges Mattje
                      Eduardo Menges Mattje last edited by

                      BUMP....

                      1 Reply Last reply Reply Quote 0
                      • Eduardo Menges Mattje
                        Eduardo Menges Mattje last edited by

                        So it turns out that this is intended behaviour.
                        StopTrail compares the latest price, not the executed price.

                        1 Reply Last reply Reply Quote 1
                        • A
                          ab_trader last edited by

                          Good you figured this out. Maybe this is true in your case since you use Market order as a first order.For this type of order the execution price is unknown at the moment when order is issued. You passed close prices and maybe stoptrail started to work from that value.

                          I didn't have a chance to go thru all the info you dropped here. Especially having no RSI values and having outputs started from the middle of the whole price array. But I am still thinking that my guess above is true. Even 1% stop trail is large for your set of prices.

                          1 Reply Last reply Reply Quote 2
                          • Eduardo Menges Mattje
                            Eduardo Menges Mattje last edited by

                            @ab_trader said in Multiple stop loss issued:

                            Good you figured this out. Maybe this is true in your case since you use Market order as a first order.For this type of order the execution price is unknown at the moment when order is issued. You passed close prices and maybe stoptrail started to work from that value.

                            I didn't have a chance to go thru all the info you dropped here. Especially having no RSI values and having outputs started from the middle of the whole price array. But I am still thinking that my guess above is true. Even 1% stop trail is large for your set of prices.

                            Is there a way for StopLoss to trigger only when executed price - current price <= percentage?

                            1 Reply Last reply Reply Quote 0
                            • A
                              ab_trader last edited by

                              bt's stop order triggers when the current price is lower than the stop price. so stop price need to be defined as executed price * ( 1 - stop percent).

                              i've played with your data and script, and it seems to me that the issue is in the stoptrail side of the bracket order. I've changed it to the regular stop order, it worked as expected but with the StopTrail the results were weird.

                              In your case if you want to do the following:

                              • issue market buy order based on rsi value
                              • than issue stoptrail order with the position open
                              • and issue closing order based on rsi condition with the cancellation of the existing stoptrail order

                              than you may want to take a look on the OCO orders.

                              1 Reply Last reply Reply Quote 1
                              • 1 / 1
                              • First post
                                Last post
                              Copyright © 2016, 2017, 2018 NodeBB Forums | Contributors
                              $(document).ready(function () { app.coldLoad(); }); }