Backtrader Community

    • 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/

    Check the order status of Multiple Stocks

    General Code/Help
    4
    24
    11118
    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.
    • C
      cwse last edited by

      Hi there,

      My strategy has a datas set with many stocks.

      In the next() module, how do I check for the order status of EACH stock as I am looping through them?

      I know that if I only had one stock I would use:

      if self.isorder():
          return
      

      However each stock for me is referenced to as d for d in self.datas.

      If possible, I would also appreciate advice on how to update the following notify_order and notify_trade code to work with these multiple dataframes "d":

          def notify_order(self, order):  # Methods (def in Class) have access to all the data contained on the instance of the object; they can access and modify anything previously set on self.
              if order.status in [order.Submitted, order.Accepted]:
                  # Buy/Sell order submitted/accepted to/by broker - Nothing to do
                  return
      
              # Check if an order has been completed **Attention: broker could reject order if not enough cash**
              if order.status in [order.Completed, order.Canceled, order.Margin]:
                  if order.isbuy():
                      self.buyprice = order.executed.price
                      self.buycomm = order.executed.comm
                      self.log('BUY EXECUTED, Price: %.2f, Cost: %.2f, Comm %.2f' %(self.buyprice,order.executed.value,self.buycomm))
      
                  else:  # Sell
                      self.log('SELL EXECUTED, Price: %.2f, Cost: %.2f, Comm %.2f' %(order.executed.price,order.executed.value, order.executed.comm))
      
                  self.bar_executed = len(self)  # i.e. num bars elapsed. If using daily data => this is number of days stock held.
      
              self.order = None # Write down: no pending order
      
          def notify_trade(self, trade):
              if trade.isclosed:
                  self.log('OPERATION PROFIT, GROSS %.2f, NET %.2f' %(trade.pnl, trade.pnlcomm))
      

      Thank you!!!!
      cwe

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

        Could you please give a reference where self.isorder is shown in docs or examples?
        I didn't see such check in there, maybe I missed it.

        • If my answer helped, hit reputation up arrow at lower right corner of the post.
        • Python Debugging With Pdb
        • New to python and bt - check this out
        1 Reply Last reply Reply Quote 0
        • C
          cwse last edited by

          it was in one of the doc examples or a blog post... cant remember which :D

          Seems like a useful functionality, but only if I can apply it with multiple dataframes!!

          1 Reply Last reply Reply Quote 0
          • B
            backtrader administrators @cwse last edited by

            @cwse said in Check the order status of Multiple Stocks:

            if self.isorder():
            return

            This is certainly unknown as pointed out by @ab_trader

            order instances carry a reference to the data feed which is targeted by the order. The attribute is data.

            Data feeds also carry an _id attribute holding a scalar value for ease of comparison (in case operator overloading could get in the way when looking to compare to data feed instances)

            1 Reply Last reply Reply Quote 0
            • C
              cwse last edited by

              @ab_trader and @backtrader, appologies for the typo, I meant:

              if self.order: 
                  return
              

              Nonetheless my question still stands. When I create orders I do it as follows:

              self.order = self.buy(data=d)
              

              so how can I check if a specific stock order is outstanding using self.order?
              Can I do this?

              if self.order(data=d)
              

              ... to check if a specific STOCK has an order in process?

              Thanks!

              1 Reply Last reply Reply Quote 0
              • B
                backtrader administrators last edited by

                self.order in that context is just a member attribute in a specific Strategy subclass which is used as a sentinel and starts with None and is either None for not having an order active or contains an Order instance which evaluates to True

                The question still stands, but the answer was already provided. Order instances contain the data for which it was created as a parameter (thanks to python overriding can also be reached as an attribute)

                Using object identification or the allocated _id as pointed out above: if self.order.data is d or if self.order.data._id == d._id

                1 Reply Last reply Reply Quote 0
                • C
                  cwse last edited by

                  Thanks @backtrader, but if I have many orders processing, that logic wouldn't check through all of them, to make sure that this particular stock doesn't have an outstanding order would it? The way the code is written it would seem that it just checks a random order to see if it equals this one, but doesnt check all orders?

                  1 Reply Last reply Reply Quote 0
                  • B
                    backtrader administrators last edited by

                    d stands for one of the data feeds. You would be looping over the data feeds in self.data to check for which one this order is.

                    There is no solution without looping if you have multiple stocks. At some point you have to go over each data feed to check for what you specifically want to know about the things surrounding that particular stock, be it price, be it indicators associated to it, be it orders.

                    1 Reply Last reply Reply Quote 0
                    • C
                      cwse last edited by

                      Hi Backtrader, got an error on that:

                        File "T:/Google Drive/PyCharm/Backtrader.py", line 139, in next
                          if self.order.data is d: #if self.order.data is d or if self.order.data._id == d._id    dont re-order if have a pending order
                      AttributeError: 'NoneType' object has no attribute 'data'
                      
                      B 1 Reply Last reply Reply Quote 0
                      • B
                        backtrader administrators @cwse last edited by

                        @cwse said in Check the order status of Multiple Stocks:

                        AttributeError: 'NoneType' object has no attribute 'data'

                        B 1 Reply Last reply Reply Quote 0
                        • C
                          cwse last edited by

                          This is what I have in next() and that error is occuring:

                              def next(self):  # Methods (def in Class) have access to all the data contained on the instance of the object; they can access and modify anything previously set on self.
                          
                                  for i, d in enumerate(d for d in self.datas if len(d)):  # Loop through Universe of Stocks
                          
                                      if self.broker.getposition(d).size:
                                          self.log('Stock: %s, Close: %.2f, score: %.2f, posn: %.2f' %
                                                   (d._name,d.close[0], d.lines.TOTAL_SCORE[0], self.broker.getposition(d).size))
                          
                                      if d.lines.TOTAL_SCORE[0] >= args.buyscore:
                                          if self.order.data is d: #if self.order.data is d or if self.order.data._id == d._id    dont re-order if have a pending order
                                              return
                                          # BUY!
                                          self.log('CREATE BUY: %s, Close: %.2f, score: %.2f' %(d._name,d.close[0],d.lines.TOTAL_SCORE[0]))
                                          # Keep track of the created order to avoid a 2nd order
                                          self.order = self.buy(data=d)
                          
                                      if d.lines.TOTAL_SCORE[-1] >= args.buyscore and d.lines.TOTAL_SCORE[0] < args.buyscore:
                                          if self.order.data is d: #if self.order.data is d or if self.order.data._id == d._id    dont re-order if have a pending order
                                              return
                                          # SELL! i.e. yesterday we owned it(with all possible default parameters)
                                          self.log('CREATE SELL: %s, Close: %.2f, score: %.2f' %(d._name,d.close[0],d.lines.TOTAL_SCORE[0]))
                                          # Keep track of the created order to avoid a 2nd order
                                          self.order = self.sell(data=d)
                          
                          1 Reply Last reply Reply Quote 0
                          • B
                            backtrader administrators @backtrader last edited by

                            @backtrader said in Check the order status of Multiple Stocks:

                            @cwse said in Check the order status of Multiple Stocks:

                            AttributeError: 'NoneType' object has no attribute 'data'

                            1 Reply Last reply Reply Quote 0
                            • C
                              cwse last edited by

                              Sorry? Could you please elaborate?

                              1 Reply Last reply Reply Quote 0
                              • B
                                backtrader administrators last edited by backtrader

                                NoneType... you are checking something which is None and that contains no attributes. Null pointer ... basics of Python

                                1 Reply Last reply Reply Quote 0
                                • C
                                  cwse last edited by

                                  Yes, because the __init__(self) sets it to None if self.order.data is d: ... and you told me to check in next() like so:
                                  if self.order.data is d:

                                  I am doing my best to read in between the lines here, but It would be awesome if you could just tell me what I should be coding here and save us all the time!

                                  Brad Lloyd 1 Reply Last reply Reply Quote 0
                                  • Brad Lloyd
                                    Brad Lloyd @cwse last edited by

                                    @cwse
                                    I use the following for multiple symbols

                                    in your init where you define self.order = None, make it a dict , self.order = {}

                                    def __init__(self):
                                        self.order = {}
                                        for i, d in enumerate(d for d in self.datas if len(d)):
                                           self.order[d._name] = None
                                    
                                    def notify(self, order):
                                    # standard code for notification 
                                        self.order[order.data._name] = None
                                    
                                    def next(self):
                                       for i, d in enumerate(d for d in self.datas if len(d)):
                                           if not self.order[d._name]:
                                              continue
                                    
                                    1 Reply Last reply Reply Quote 0
                                    • C
                                      cwse last edited by

                                      Thank you @BRAD LLOYD, that seems like a great way to tackle it.

                                      I implemented your code in my strategy, however I am getting a key error for one of my stock data frames in next(), any idea why this might be? The dictionary key should be established in INIT?
                                      Perhaps the self.order dict needs to be defined prior to init?

                                      I have also assumed the dictionary logic applied to self.order, should also apply to self.buyprice and self.buycomm ... it would be great to get your thoughts on this!

                                      I have copied my full strategy below in case you can see any obvious errors.

                                      Thank you,
                                      CWE

                                      class TestStrategy(bt.Strategy):
                                          # Attributes which apply to ALL instances of a Class object are defined here, i.e. prior to __init__
                                          args = parse_args()
                                          params = (
                                              ('printlog', True),
                                          )
                                      
                                          def log(self, txt, dt=None, doprint=False):
                                              ''' Logging function for this strategy'''
                                              if self.p.printlog or doprint:  # NB: self.p = self.params
                                                  dt = dt or self.datas[0].datetime.date(0)
                                                  print('%s, %s' % (dt.isoformat(), txt))
                                      
                                          def __init__(self):  # __init__ = creates object defined by the Class. INITIALISES the object - sets all attributes
                                              # To keep track of pending orders and buy price/commission
                                      
                                              self.order = {}
                                              self.buyprice = {}
                                              self.buycomm = {}
                                              for i, d in enumerate(d for d in self.datas if len(d)):
                                                  self.order[d._name] = None
                                                  self.buyprice[d._name] = None
                                                  self.buycomm[d._name] = None
                                      
                                      
                                          def notify_order(self, order):  # Methods (def in Class) have access to all the data contained on the instance of the object; they can access and modify anything previously set on self.
                                              if order[order.data._name].status in [order[order.data._name].Submitted, order[order.data._name].Accepted]:
                                                  # Buy/Sell order submitted/accepted to/by broker - Nothing to do
                                                  return
                                      
                                              # Check if an order has been completed **Attention: broker could reject order if not enough cash**
                                              if order[order.data._name].status in [order[order.data._name].Completed, order[order.data._name].Canceled, order[order.data._name].Margin]:
                                                  if order[order.data._name].isbuy():
                                                      self.buyprice[order.data._name] = order[order.data._name].executed.price
                                                      self.buycomm[order.data._name] = order[order.data._name].executed.comm
                                                      self.log('BUY EXECUTED, Price: %.2f, Cost: %.2f, Comm %.2f' %(self.buyprice,order.executed.value,self.buycomm))
                                      
                                                  else:  # Sell
                                                      self.log('SELL EXECUTED, Price: %.2f, Cost: %.2f, Comm %.2f' %(order.executed.price,order.executed.value, order.executed.comm))
                                      
                                                  self.bar_executed[order.data._name] = len(self)  # i.e. num bars elapsed. If using daily data => this is number of days stock held.
                                      
                                              self.order[order.data._name] = None #self.order = None # Write down: no pending order
                                      
                                          def notify_trade(self, trade):
                                              if trade.isclosed:
                                                  self.log('OPERATION PROFIT, GROSS %.2f, NET %.2f' %(trade.pnl, trade.pnlcomm))
                                      
                                          def prenext(self):
                                              '''
                                              overrides PRENEXT() so that the "NEXT()" calculations run regardless of when each data date range starts.
                                              Typically PRENEXT would stop NEXT occuring until the minimum period of an indicator has occured, or all dataframe LINES are running.
                                              '''
                                              self.next()
                                      
                                          def next(self):  # Methods (def in Class) have access to all the data contained on the instance of the object; they can access and modify anything previously set on self.
                                      
                                              for i, d in enumerate(d for d in self.datas if len(d)):  # Loop through Universe of Stocks
                                      
                                                  if self.broker.getposition(d).size:
                                                      self.log('Stock: %s, Close: %.2f, score: %.2f, posn: %.2f' %(d._name,d.close[0], d.lines.TOTAL_SCORE[0], self.broker.getposition(d).size))
                                      
                                                  if d.lines.TOTAL_SCORE[0] >= args.buyscore:
                                                      if self.order[d._name]:
                                                          return
                                                      # BUY!
                                                      self.log('CREATE BUY: %s, Close: %.2f, score: %.2f' %(d._name,d.close[0],d.lines.TOTAL_SCORE[0]))
                                                      self.order[d._name] = self.buy(data=d)
                                      
                                                  if d.lines.TOTAL_SCORE[-1] >= args.buyscore and d.lines.TOTAL_SCORE[0] < args.buyscore:
                                                      if self.order[d._name]:
                                                          return
                                                      # SELL! i.e. yesterday we owned it(with all possible default parameters)
                                                      self.log('CREATE SELL: %s, Close: %.2f, score: %.2f' %(d._name,d.close[0],d.lines.TOTAL_SCORE[0]))
                                                      self.order[d._name] = self.sell(data=d)
                                      
                                          def stop(self):
                                              #Print TOTAL PORTFOLIO VALUE
                                              self.log('Ending Value %.2f' %(self.broker.getvalue()),doprint=True)
                                      
                                      Brad Lloyd 1 Reply Last reply Reply Quote 0
                                      • Brad Lloyd
                                        Brad Lloyd @cwse last edited by

                                        @cwse
                                        I create the self.order dict in init and don't have a problem
                                        you would have to run it in debug and figure out what key it fails on

                                        the only thing I could see is that my loop is different as I pass all my symbols as param called portfolio and then just do loop that is

                                        for symbol in self.p.portfolio:
                                        
                                        C 1 Reply Last reply Reply Quote 0
                                        • C
                                          cwse @Brad Lloyd last edited by

                                          @Brad-Lloyd sorry I think you cut the code off short there? what is the portoflio part / loop for and how does it work?

                                          Cheers,

                                          1 Reply Last reply Reply Quote 0
                                          • Brad Lloyd
                                            Brad Lloyd last edited by

                                            I was just saying I did the loop different using 'for' instead of enumerate
                                            but I do something like this

                                            params = ('portfolio', ['AAPL', 'GOOG', 'SPY', 'IWM', 'EEM'])    
                                            
                                            def next(self):
                                                for symbol in self.p.portfolio:
                                            
                                                    d = self.getdatabyname(symbol)
                                                    if self.order[symbol]:
                                                        continue
                                                   
                                                   if self.signal:
                                                        self.order[symbol] = self.buy(d, size=self.trade_size[symbol])
                                            
                                            1 Reply Last reply Reply Quote 0
                                            • 1
                                            • 2
                                            • 1 / 2
                                            • First post
                                              Last post
                                            Copyright © 2016, 2017, 2018, 2019, 2020, 2021 NodeBB Forums | Contributors