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/

    Problem with multiple limit orders as take profit

    General Code/Help
    2
    4
    44
    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.
    • S
      stanski last edited by

      Hello
      I'm trying to set up two TP's with sell-limit orders and one SL with a sell-stop order.
      The problem I'm encountering is that the first trades seem to be correct, but later bt creates multiple sell-limit orders without the buy order.
      What am I doing wrong?

      import backtrader as bt
      from datetime import datetime
      
        
      class SmaCross(bt.Strategy):
          # list of parameters which are configurable for the strategy
          params = dict(
              pfast=100,  # period for the fast moving average
              pslow=50   # period for the slow moving average
          )
      
          def __init__(self):
              self.sma0 = bt.ind.SMA(period=800) 
              sma1 = bt.ind.SMA(period=self.p.pfast)  # fast moving average
              sma2 = bt.ind.SMA(period=self.p.pslow)  # slow moving average
              self.crossover = bt.ind.CrossOver(sma1, sma2)  # crossover signal
      
              
          def log(self, txt, dt=None):
              #Logging function fot this strategy'''
              dt = dt or self.datas[0].datetime.date(0)
              print('%s, %s' % (dt.isoformat(), txt))
              
              
          def notify_order(self, order):
              if order.status in [order.Submitted, order.Accepted]:
                  # Buy/Sell order submitted/accepted to/by broker - Nothing to do
                  return
              if order.status in [order.Completed]:
                  if order.isbuy():
                      self.sell(exectype=bt.Order.Limit, size=1, price=self.data.close[0] * 1.03) 
                      self.sell(exectype=bt.Order.Limit, size=1, price=self.data.close[0] * 1.06) 
                      self.sell(exectype=bt.Order.Stop, size=2, price=self.data.close[0] * 0.98)
                      self.log('BUY EXECUTED, %.2f' % order.executed.price)
      
                  elif order.issell():
                      self.log('SELL EXECUTED, %.2f' % order.executed.price)
                      
                      
          def next(self):
              if not self.position:  # not in the market
                  if self.crossover > 0 and self.datas[0] < self.sma0:  # if fast crosses slow to the upside
                      self.buy_order = self.buy(exectype=bt.Order.Market, size=2)  # enter long
      
      startcash = 10000
      cerebro = bt.Cerebro()  # create a "Cerebro" engine instance
      
      # Create a data feed
      data = bt.feeds.GenericCSVData(
          dataname='data/1inch_perp_28-02_09-03_10S.csv',
          fromdate=datetime(2021, 3, 7),
          todate=datetime(2021, 3, 21),
          timeframe=bt.TimeFrame.Seconds,
          headers=False,
          separator=";",
          volume=5,
          openinterest=-1,
          dtformat=('%d.%m.%Y %H:%M:%S'),
      )
      
      cerebro.adddata(data)  # Add the data feed
      
      cerebro.addstrategy(SmaCross)  # Add the trading strategy
      cerebro.run()  # run it all
      
      portvalue = cerebro.broker.getvalue()
      pnl = portvalue - startcash
      print('Final Portfolio Value: ${}'.format(portvalue))
      print('P/L: ${}'.format(pnl))
      
      cerebro.plot()  # and plot it with a single command
      
      
      2021-03-07, BUY EXECUTED, 38.52
      2021-03-07, SELL EXECUTED, 39.67
      2021-03-07, SELL EXECUTED, 40.82
      2021-03-07, BUY EXECUTED, 40.28
      2021-03-07, SELL EXECUTED, 39.52
      2021-03-07, BUY EXECUTED, 39.05
      2021-03-07, SELL EXECUTED, 38.29
      2021-03-07, BUY EXECUTED, 37.97
      2021-03-08, SELL EXECUTED, 39.13
      2021-03-08, SELL EXECUTED, 40.24
      2021-03-08, SELL EXECUTED, 40.27
      2021-03-08, SELL EXECUTED, 41.41
      2021-03-08, SELL EXECUTED, 41.53
      2021-03-08, SELL EXECUTED, 42.74
      

      link csv file

      run-out 1 Reply Last reply Reply Quote 0
      • run-out
        run-out @stanski last edited by

        @stanski
        You need to split up your stop orders and attach them to the limit orders using one cancels other or OCO. You can find more information here.

        I modified your code below.

        import backtrader as bt
        import datetime
        
        
        class SmaCross(bt.Strategy):
            # list of parameters which are configurable for the strategy
            params = dict(
                pfast=100,  # period for the fast moving average
                pslow=50,  # period for the slow moving average
            )
        
            def __init__(self):
                self.sma0 = bt.ind.SMA(period=800)
                sma1 = bt.ind.SMA(period=self.p.pfast)  # fast moving average
                sma2 = bt.ind.SMA(period=self.p.pslow)  # slow moving average
                self.crossover = bt.ind.CrossOver(sma1, sma2)  # crossover signal
        
            def log(self, txt, dt=None):
                # Logging function fot this strategy'''
                dt = dt or self.datas[0].datetime.datetime(0)
                print("%s, %s" % (dt.isoformat(), txt))
        
            def notify_order(self, order):
                type = "Buy" if order.isbuy() else "Sell"
                self.log(
                    f"{order.data._name:<6} Order: {order.ref:3d}\tType: {type:<5}\tStatus"
                    f" {order.getstatusname():<8} \t"
                    f"Size: {order.created.size:9.4f} Create Price: {order.created.price:9.4f} "
                    f"Position: {self.getposition(order.data).size}"
                )
        
                if order.status in [order.Submitted, order.Accepted]:
                    return
        
                if order.status in [order.Completed]:
                    self.log(
                        f"{order.data._name:<6} {('BUY' if order.isbuy() else 'SELL'):<5} "
                        f"Price: {order.executed.price:6.2f} "
                        f"Cost: {order.executed.value:6.2f} "
                        f"Comm: {order.executed.comm:4.2f} "
                        f"Size: {order.created.size:9.4f} "
                    )
        
                    if order.isbuy():
                        lmt_1 = self.sell(
                            exectype=bt.Order.Limit,
                            size=1,
                            price=self.data.close[0] * 1.03,
                        )
                        self.sell(
                            exectype=bt.Order.Stop,
                            size=1,
                            price=self.data.close[0] * 0.98,
                            oco=lmt_1,
                        )
        
                        lmt_2 = self.sell(
                            exectype=bt.Order.Limit,
                            size=1,
                            price=self.data.close[0] * 1.06,
                        )
                        self.sell(
                            exectype=bt.Order.Stop,
                            size=1,
                            price=self.data.close[0] * 0.98,
                            oco=lmt_2,
                        )
        
            def next(self):
                if not self.position:  # not in the market
                    if (
                        self.crossover > 0 and self.datas[0] < self.sma0
                    ):  # if fast crosses slow to the upside
                        self.buy_order = self.buy(
                            exectype=bt.Order.Market, size=2
                        )  # enter long
            ...
        
        

        It's always a good idea to have more logging when you are unsure of what's going on. Here's some logging for two sets of orders:

        2020-01-06T12:21:00, dev    Order:   1	Type: Buy  	Status Submitted 	Size:    2.0000 Create Price: 3220.7500 Position: 2
        2020-01-06T12:21:00, dev    Order:   1	Type: Buy  	Status Accepted 	Size:    2.0000 Create Price: 3220.7500 Position: 2
        2020-01-06T12:21:00, dev    Order:   1	Type: Buy  	Status Completed 	Size:    2.0000 Create Price: 3220.7500 Position: 2
        2020-01-06T12:21:00, dev    BUY   Price: 3221.00 Cost: 6442.00 Comm: 0.00 Size:    2.0000 
        2020-01-06T12:22:00, dev    Order:   2	Type: Sell 	Status Submitted 	Size:   -1.0000 Create Price: 3317.3725 Position: 2
        2020-01-06T12:22:00, dev    Order:   3	Type: Sell 	Status Submitted 	Size:   -1.0000 Create Price: 3156.3350 Position: 2
        2020-01-06T12:22:00, dev    Order:   4	Type: Sell 	Status Submitted 	Size:   -1.0000 Create Price: 3413.9950 Position: 2
        2020-01-06T12:22:00, dev    Order:   5	Type: Sell 	Status Submitted 	Size:   -1.0000 Create Price: 3156.3350 Position: 2
        2020-01-06T12:22:00, dev    Order:   2	Type: Sell 	Status Accepted 	Size:   -1.0000 Create Price: 3317.3725 Position: 2
        2020-01-06T12:22:00, dev    Order:   3	Type: Sell 	Status Accepted 	Size:   -1.0000 Create Price: 3156.3350 Position: 2
        2020-01-06T12:22:00, dev    Order:   4	Type: Sell 	Status Accepted 	Size:   -1.0000 Create Price: 3413.9950 Position: 2
        2020-01-06T12:22:00, dev    Order:   5	Type: Sell 	Status Accepted 	Size:   -1.0000 Create Price: 3156.3350 Position: 2
        2020-01-17T15:55:00, dev    Order:   2	Type: Sell 	Status Completed 	Size:   -1.0000 Create Price: 3317.3725 Position: 1
        2020-01-17T15:55:00, dev    SELL  Price: 3317.37 Cost: 3221.00 Comm: 0.00 Size:   -1.0000 
        2020-01-17T15:55:00, dev    Order:   3	Type: Sell 	Status Canceled 	Size:   -1.0000 Create Price: 3156.3350 Position: 1
        2020-02-25T13:02:00, dev    Order:   5	Type: Sell 	Status Completed 	Size:   -1.0000 Create Price: 3156.3350 Position: 0
        2020-02-25T13:02:00, dev    SELL  Price: 3156.34 Cost: 3221.00 Comm: 0.00 Size:   -1.0000 
        2020-02-25T13:02:00, dev    Order:   4	Type: Sell 	Status Canceled 	Size:   -1.0000 Create Price: 3413.9950 Position: 0
        2020-02-25T15:52:00, dev    Order:   6	Type: Buy  	Status Submitted 	Size:    2.0000 Create Price: 3113.0000 Position: 2
        2020-02-25T15:52:00, dev    Order:   6	Type: Buy  	Status Accepted 	Size:    2.0000 Create Price: 3113.0000 Position: 2
        2020-02-25T15:52:00, dev    Order:   6	Type: Buy  	Status Completed 	Size:    2.0000 Create Price: 3113.0000 Position: 2
        2020-02-25T15:52:00, dev    BUY   Price: 3113.00 Cost: 6226.00 Comm: 0.00 Size:    2.0000 
        2020-02-25T15:53:00, dev    Order:   7	Type: Sell 	Status Submitted 	Size:   -1.0000 Create Price: 3207.6775 Position: 2
        2020-02-25T15:53:00, dev    Order:   8	Type: Sell 	Status Submitted 	Size:   -1.0000 Create Price: 3051.9650 Position: 2
        2020-02-25T15:53:00, dev    Order:   9	Type: Sell 	Status Submitted 	Size:   -1.0000 Create Price: 3301.1050 Position: 2
        2020-02-25T15:53:00, dev    Order:  10	Type: Sell 	Status Submitted 	Size:   -1.0000 Create Price: 3051.9650 Position: 2
        2020-02-25T15:53:00, dev    Order:   7	Type: Sell 	Status Accepted 	Size:   -1.0000 Create Price: 3207.6775 Position: 2
        2020-02-25T15:53:00, dev    Order:   8	Type: Sell 	Status Accepted 	Size:   -1.0000 Create Price: 3051.9650 Position: 2
        2020-02-25T15:53:00, dev    Order:   9	Type: Sell 	Status Accepted 	Size:   -1.0000 Create Price: 3301.1050 Position: 2
        2020-02-25T15:53:00, dev    Order:  10	Type: Sell 	Status Accepted 	Size:   -1.0000 Create Price: 3051.9650 Position: 2
        2020-02-27T09:31:00, dev    Order:   8	Type: Sell 	Status Completed 	Size:   -1.0000 Create Price: 3051.9650 Position: 0
        2020-02-27T09:31:00, dev    SELL  Price: 3043.00 Cost: 3113.00 Comm: 0.00 Size:   -1.0000 
        2020-02-27T09:31:00, dev    Order:   7	Type: Sell 	Status Canceled 	Size:   -1.0000 Create Price: 3207.6775 Position: 0
        2020-02-27T09:31:00, dev    Order:  10	Type: Sell 	Status Completed 	Size:   -1.0000 Create Price: 3051.9650 Position: 0
        2020-02-27T09:31:00, dev    SELL  Price: 3043.00 Cost: 3113.00 Comm: 0.00 Size:   -1.0000 
        2020-02-27T09:31:00, dev    Order:   9	Type: Sell 	Status Canceled 	Size:   -1.0000 Create Price: 3301.1050 Position: 0
        
        
        S 1 Reply Last reply Reply Quote 3
        • S
          stanski @run-out last edited by

          @run-out Your solution works very nice, but this won't work live, will it? At least it reads in the doc's that there's no live support with oco's, although I see reports that binance api can deal with oco orders. I'm intenting to trade live on a crypto exchange. Do you have experience with oco / live ?

          run-out 1 Reply Last reply Reply Quote 0
          • run-out
            run-out @stanski last edited by

            @stanski Not really but I suspect you would need to manually track your orders and one is complete, send a cancel for the other.

            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(); }); }