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/

    AttributeError: 'str' object has no attribute '_name' - The error is clear - but for the life of me I can't see why it's happening

    General Code/Help
    3
    5
    1738
    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
      Capn_Hacky last edited by Capn_Hacky

      It's a multi-data stratergy and I have data objects in the 'next' function cycling as the entries in self.datas - in this function everything seems to work fine in interating with the data objects, in partcular they certainly do have name attributes - this error seems to occur after the cycle of "next's" is complete.

      Apologies if this turns out to be something trivial.

      The stack trace is as follows:

      Traceback (most recent call last):
        File "trader.py", line 472, in <module>
          runstrategy(stocks_of_interest,financial_history, pairs_list)
        File "trader.py", line 346, in runstrategy
          oldsync=args.oldsync)
        File "C:\ProgramData\Anaconda3\envs\finance\lib\site-packages\backtrader\cerebro.py", line 1127, in run
          runstrat = self.runstrategies(iterstrat)
        File "C:\ProgramData\Anaconda3\envs\finance\lib\site-packages\backtrader\cerebro.py", line 1293, in runstrategies
          self._runonce(runstrats)
        File "C:\ProgramData\Anaconda3\envs\finance\lib\site-packages\backtrader\cerebro.py", line 1688, in _runonce
          self._brokernotify()
        File "C:\ProgramData\Anaconda3\envs\finance\lib\site-packages\backtrader\cerebro.py", line 1360, in _brokernotify
          self._broker.next()
        File "C:\ProgramData\Anaconda3\envs\finance\lib\site-packages\backtrader\brokers\bbroker.py", line 1240, in next
          self._get_value()  # update value
        File "C:\ProgramData\Anaconda3\envs\finance\lib\site-packages\backtrader\brokers\bbroker.py", line 440, in _get_value
          comminfo = self.getcommissioninfo(data)
        File "C:\ProgramData\Anaconda3\envs\finance\lib\site-packages\backtrader\broker.py", line 80, in getcommissioninfo
          if data._name in self.comminfo:
      AttributeError: 'str' object has no attribute '_name'
      

      For clarity I can attach the code if that would be helpful but I didn't want to clutter this post unnecessarily?

      Asked for code:

      
      class PairTradingStrategy(bt.Strategy):
          params = dict(
              period=300,
              stake=1,
              qty1=0,
              qty2=0,
              printout=True,
              upper=1,
              lower=-1,
              up_medium=0.75,
              low_medium=-0.75,
              status=0,
              portfolio_value=50,
          )
      
          def log(self, txt, dt=None):
              if self.p.printout:
                  dt = dt or self.data.datetime[0]
                  dt = bt.num2date(dt)
                  print('%s, %s' % (dt.isoformat(), txt))
      
          def notify_order(self, order):
              if order.status in [bt.Order.Submitted, bt.Order.Accepted]:
                  return  # Await further notifications
      
              if order.status == order.Completed:
                  if order.isbuy():
                      buytxt = 'BUY COMPLETE, %.2f' % order.executed.price
                      self.log(buytxt, order.executed.dt)
                  else:
                      selltxt = 'SELL COMPLETE, %.2f' % order.executed.price
                      self.log(selltxt, order.executed.dt)
      
              elif order.status in [order.Expired, order.Canceled, order.Margin]:
                  self.log('%s ,' % order.Status[order.status])
                  pass  # Simply log
      
              # Allow new orders
              self.orderid = None
      
          def __init__(self,pairs_list):
              # To control operation entries
              self.pairs_list = pairs_list
              self.orderid = None
              self.qty1 = self.p.qty1
              self.qty2 = self.p.qty2
              self.upper_limit = self.p.upper
              self.lower_limit = self.p.lower
              self.up_medium = self.p.up_medium
              self.low_medium = self.p.low_medium
              self.status = self.p.status
              self.portfolio_value = self.p.portfolio_value
      
      
              #kalman filter stuff -- curently not sure what its about, just want that beta
              self.delta = 0.0001
              self.Vw = self.delta / (1 - self.delta) * np.eye(2)
              self.Ve = 0.001
              self.beta = np.zeros(2)
              self.P = np.zeros((2, 2))
              self.R = np.zeros((2, 2))
      
      
              # Signals performed with PD.OLS :
              self.transform = btind.OLS_TransformationN(self.data0, self.data1,
                                                         period=self.p.period)
              self.zscore = self.transform.zscore
              #self.beta = pd.ols(self.data0, self.data1, window_type=self.p.period)
      
      
              x = np.asarray([self.data0[0], 1.0]).reshape((1, 2))
              y = self.data1[0]
      
              self.R = self.P + self.Vw  # state covariance prediction
              yhat = x.dot(self.beta)  # measurement prediction
      
              Q = x.dot(self.R).dot(x.T) + self.Ve  # measurement variance
      
              e = y - yhat  # measurement prediction error
      
              K = self.R.dot(x.T) / Q  # Kalman gain
      
              self.beta += K.flatten() * e  # State update
      
              self.P = self.R - K * x.dot(self.R)
      
              sqrt_Q = np.sqrt(Q)
      
              self.lower_limit = -1.5*sqrt_Q
              self.upper_limit = 1.5*sqrt_Q
      
              self.up_medium = sqrt_Q
              self.low_medium = -sqrt_Q
      
              # Checking signals built with StatsModel.API :
              # self.ols_transfo = btind.OLS_Transformation(self.data0, self.data1,
              #                                             period=self.p.period,
              #                                             plot=True)
      
          def next(self):
      
              ########PRETTTYYYYYYYYYY SURE SHORT SELLS ARENT WORKING AS THEY SHOULDDDD......
      
              # data is in self.datas
      
              # for i, d in enumerate(self.datas):
              #     dt, dn = self.datetime.date(), d._name
              #     pos = self.getposition(d).size
      
              #     for p in pairs_list:
              #         if p[0] == d._name:
              #             #no current market orders
              #             if pos == None
      
                  # if self.orderid:
                  #     return  # if an order is active, no new orders are allowed
      
              def get_data_by_name(name):
                  output = None
                  for data in self.datas:
                      #print(data)
                      if data._name == name:
                          output = data
      
      
                  if output is None:
                      #shoulf probably create a log
                      print('Warning: The data with name: '+ name+ ' could not be found.')
      
                  return(output)
      
              print(self.pairs_list)
      
              for pair in self.pairs_list:
                  p0_data = get_data_by_name(pair[0])
                  p1_data = get_data_by_name(pair[1])
                  print(pair)
      
      
                  #if data isnt available just skip it
                  if p0_data is not None and p1_data is not None :
                      print(p0_data)
                      print(p1_data)
                      print(p0_data._name)
                      print(p1_data._name)
      
                      print('positions')
                      print(self.getposition(pair[0]) )
                      print(self.getposition(pair[1]) )
      
                      if self.getposition(pair[0]).size ==0 and self.getposition(pair[1]).size == 0:
      
                          print('hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh')
                          if self.p.printout:
                              print('Self  len:', len(self))
                              print('Data0 len:', len(self.data0))
                              print('Data1 len:', len(self.data1))
                              print('Data0 len == Data1 len:',
                                    len(p0_data) == len(p1_data))
      
                              print('Data0 dt:', p0_data.datetime.datetime())
                              print('Data1 dt:', p1_data.datetime.datetime())
      
                          print('status is', self.status)
                          print('zscore is', self.zscore[0])
      
                          # Step 2: Check conditions for SHORT & place the order
                          # Checking the condition for SHORT
                          if (self.zscore[0] > self.upper_limit) and (self.status != 1):
      
                              # Calculating the number of shares for each stock
                              value = 0.5 * self.portfolio_value  # Divide the cash equally
                              x = int(value / (p0_data.close))  # Find the number of shares for Stock1
                              y = int(value / (p1_data.close))  # Find the number of shares for Stock2
                              print('x + self.qty1 is', x + self.qty1)
                              print('y + self.qty2 is', y + self.qty2)
      
                              # Placing the order
                              self.log('SELL CREATE %s, price = %.2f, qty = %d' % (p0_data._name, p0_data.close[0], x + self.qty1))
                              self.sell(data=p0_data, size=(x + self.qty1))  # Place an order for buying y + qty2 shares
                              self.log('BUY CREATE %s, price = %.2f, qty = %d' % (p1_data._name, p1_data.close[0], y + self.qty2*self.beta[0]))
                              self.buy(data=p1_data, size=(y + self.qty2*self.beta[0]))  # Place an order for selling x + qty1 shares
      
                              # Updating the counters with new value
                              self.qty1 = x  # The new open position quantity for Stock1 is x shares
                              self.qty2 = y  # The new open position quantity for Stock2 is y shares
      
                              # doesnt make sense for multiple feeds self.status = 1  # The current status is "short the spread"
      
                              # Step 3: Check conditions for LONG & place the order
                              # Checking the condition for LONG
                          elif (self.zscore[0] < self.lower_limit) and (self.status != 2):
      
                              # Calculating the number of shares for each stock
                              value = 0.5 * self.portfolio_value  # Divide the cash equally
                              x = int(value / (self.p0_data.close))  # Find the number of shares for Stock1
                              y = int(value / (self.data1.close))  # Find the number of shares for Stock2
                              print('x + self.qty1 is', x + self.qty1)
                              print('y + self.qty2 is', y + self.qty2)
      
                              # Place the order
                              self.log('BUY CREATE %s, price = %.2f, qty = %d' % (p0_data._name, p0_data.close[0], x + self.qty1))
                              self.buy(data=p0_data, size=(x + self.qty1))  # Place an order for buying x + qty1 shares
                              self.log('SELL CREATE %s, price = %.2f, qty = %d' % (p1_data._name, p1_data.close[0], y + self.qty2*self.beta[0]))
                              self.sell(data=p1_data, size=(y + self.qty2*self.beta[0]))  # Place an order for selling y + qty2 shares
      
                              # Updating the counters with new value
                              self.qty1 = x  # The new open position quantity for Stock1 is x shares
                              self.qty2 = y  # The new open position quantity for Stock2 is y shares
                              self.status = 2  # The current status is "long the spread"
      
      
                              # Step 4: Check conditions for No Trade
                              # If the z-score is within the two bounds, close all
                      
                      elif (self.zscore[0] < self.up_medium and self.zscore[0] > self.low_medium):
                          self.log('CLOSE LONG %s, price = %.2f' % (p0_data._name, p0_data.close[0]))
                          self.close(p0_data)
                          self.log('CLOSE LONG %s, price = %.2f' % (p1_data._name, p1_data.close[0]))
                          self.close(p1_data)
                      print('yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy')
      
                  print('got to the ennnnnnnnnndddddddddddddddddd')    
      
          def stop(self):
              print('==================================================')
              print('Starting Value - %.2f' % self.broker.startingcash)
              print('Ending   Value - %.2f' % self.broker.getvalue())
              print('==================================================')
      
      
      
      
      
      def runstrategy(stocks_of_interest,financial_history_dict, pairs_list):
      
          args = parse_args()
      
          # Create a cerebro
          cerebro = bt.Cerebro()
      
          # Get the dates from the args
          fromdate = datetime.datetime.strptime(args.fromdate, '%Y-%m-%d')
          todate = datetime.datetime.strptime(args.todate, '%Y-%m-%d')
      
          # # Create the 1st data
          # data0 = btfeeds.YahooFinanceCSVData(
          #     dataname=args.data0,
          #     fromdate=fromdate,
          #     todate=todate)
      
          # # Add the 1st data to cerebro
          # cerebro.adddata(data0)
      
          # # Create the 2nd data
          # data1 = btfeeds.YahooFinanceCSVData(
          #     dataname=args.data1,
          #     fromdate=fromdate,
          #     todate=todate)
      
          # # Add the 2nd data to cerebro
          # cerebro.adddata(data1)
      
          ############################# data other 
      
      
          # # Simulate the header row isn't there if noheaders requested
          # skiprows = 1 if args.noheaders else 0
          # header = None if args.noheaders else 0
      
          #must be a better way to do this
          stocks_in_order_used = []
          skipped = []
          for stock in stocks_of_interest:
              try:
                  dataframe = financial_history_dict[stock]
                  data = bt.feeds.PandasData(dataname=dataframe)
                  cerebro.adddata(data, name=stock)
              except KeyError:
                      print('skipping ' + stock)
                      skipped += [stock]
              
              #print(dataframe)
      
      
          #bcause doing it here prevents things fucking up
          adj_pairs_list=[]
          print(pairs_list)
          for pair in pairs_list:
              dont_skip = True
              for skip_stock in skipped:
                  if skip_stock in pair:
                      dont_skip = False
      
      
              if dont_skip:
                  adj_pairs_list.append(pair) 
      
          print('adjjjjjjjjjjjjjjj')
          print(adj_pairs_list)
      
          # Add the strategy
          cerebro.addstrategy(PairTradingStrategy,pairs_list = adj_pairs_list,
                              period=args.period,
                              stake=args.stake)
      
          # Add the commission - only stocks like a for each operation
          cerebro.broker.setcash(args.cash)
      
          # Add the commission - only stocks like a for each operation
          cerebro.broker.setcommission(commission=args.commperc)
      
          # And run it
          #cerebro.run()
      
      
          cerebro.run(runonce= not args.runnext,
                       preload= not args.nopreload,
                       oldsync=args.oldsync)
      
          # Plot if requested
          if args.plot:
              cerebro.plot(numfigs=args.numfigs, volume=False, zdown=False)
      
      
      def parse_args():
          parser = argparse.ArgumentParser(description='MultiData Strategy')
      
          parser.add_argument('--data0', '-d0',
                              default='data/csvs/CMP.csv',
                              help='1st data into the system')
      
          parser.add_argument('--data1', '-d1',
                              default='data/csvs/SLCA.csv',
                              help='2nd data into the system')
      
          parser.add_argument('--fromdate', '-f',
                              default='2015-01-01',
                              help='Starting date in YYYY-MM-DD format')
      
          parser.add_argument('--todate', '-t',
                              default='2019-06-01',
                              help='Starting date in YYYY-MM-DD format')
      
          parser.add_argument('--period', default=60, type=int,
                              help='Period to apply to the Simple Moving Average')
      
          parser.add_argument('--cash', default=100, type=int,
                              help='Starting Cash')
      
          parser.add_argument('--runnext', action='store_true',
                              help='Use next by next instead of runonce')
      
          parser.add_argument('--nopreload', action='store_true',
                              help='Do not preload the data')
      
          parser.add_argument('--oldsync', action='store_true',
                              help='Use old data synchronization method')
      
          parser.add_argument('--commperc', default=0.005, type=float,
                              help='Percentage commission (0.005 is 0.5%%')
      
          parser.add_argument('--stake', default=1, type=int,
                              help='Stake to apply in each operation')
      
          parser.add_argument('--plot', '-p', default=True, action='store_true',
                              help='Plot the read data')
      
          parser.add_argument('--numfigs', '-n', default=1,
                              help='Plot using numfigs figures')
      
          return parser.parse_args()
      
      
      
      
      def find_history(auto_save=None ):
          # Note finaical history is a pandas dataframe
          stocks_of_interest = None
          failed_symbols = []
          financial_history = {}
          pairs_list = []
          if not os.path.isfile('co_integration_stock_history.pkl'):
      
              start_date = pd.Timestamp(dt.strptime("2005-06-16", '%Y-%m-%d'))
              end_date = pd.Timestamp(dt.strptime("2019-06-01", '%Y-%m-%d'))
      
              with open('stocks_of_interest.pkl', 'rb') as handle: 
                  print('loading_from_file')
                  stocks_of_interest = pickle.load(handle)
      
      
              for stock in stocks_of_interest:
                  print('Getting ', stock)
                  try:
                      financial_history[stock] = pdr.get_data_yahoo(stock,
                                                                        start_date,
                                                                        end_date)
      
                      print('Loaded ', len(financial_history[stock]), ' histories. For company ',stock,'.')
                  except (ValueError) as e:
                      print('ERROR: Failed to get history for', stock)  
                      failed_symbols.append(stock)
      
                      time.sleep(1)
      
      
              for i, l in enumerate(failed_symbols):
                  if i == 0:
                      print('Failed to load: ')
                  print('\t',l)
      
              with open('co_integration_stock_history.pkl', 'wb') as handle:
                  pickle.dump(financial_history , handle, protocol=pickle.HIGHEST_PROTOCOL)
      
      
          else:
              with open('co_integration_stock_history.pkl', 'rb') as handle: 
                  print('loading_from_file')
                  financial_history = pickle.load(handle)
      
              with open('stocks_of_interest.pkl', 'rb') as handle: 
                  print('loading_from_file')
                  stocks_of_interest = pickle.load(handle)   
      
              with open('stock_pairs_of_interest.pkl', 'rb') as handle: 
                  print('loading_from_file')
                  pairs_list = pickle.load(handle)   
                  print(pairs_list)
      
      
          return stocks_of_interest,financial_history, pairs_list
      
      
      if __name__ == '__main__':
          stocks_of_interest,financial_history, pairs_list = find_history(auto_save=None)
          runstrategy(stocks_of_interest,financial_history, pairs_list)
      '''
      1 Reply Last reply Reply Quote 0
      • A
        ab_trader last edited by

        @east1992 said in AttributeError: 'str' object has no attribute '_name' - The error is clear - but for the life of me I can't see why it's happening:

        I can attach the code if that would be helpful

        Everybody here can read other people minds, sure no script is needed.

        • 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
        C B 2 Replies Last reply Reply Quote 0
        • C
          Capn_Hacky @ab_trader last edited by

          @ab_trader As you like

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

            @ab_trader said in AttributeError: 'str' object has no attribute '_name' - The error is clear - but for the life of me I can't see why it's happening:

            I can attach the code if that would be helpful

            Everybody here can read other people minds, sure no script is needed.

            @east1992 said in AttributeError: 'str' object has no attribute '_name' - The error is clear - but for the life of me I can't see why it's happening:

            @ab_trader As you like

            I think @ab_trader was just trying a prank ...

            In any case ... let me wonder how you write such a script, yet miss the top of the forum

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

            Without the three backticks your code is basically rendered in a form which cannot be properly read.

            @east1992 said in AttributeError: 'str' object has no attribute '_name' - The error is clear - but for the life of me I can't see why it's happening:

              File "C:\ProgramData\Anaconda3\envs\finance\lib\site-packages\backtrader\broker.py", line 80, in getcommissioninfo
                if data._name in self.comminfo:
            AttributeError: 'str' object has no attribute '_name'
            

            The problem is clear: you have created a position for something which is a string and not a data feed. Hence data (which is a str) has no attribute _name

            From what one can read, it is unclear why you need to define a `get_data_by_name', given that a method to retrieve data feeds by name does already exist

            • Docs - Strategy - See getdatabyname

            But playing with the names is for sure the root of the problem.

            1 Reply Last reply Reply Quote -1
            • C
              Capn_Hacky last edited by Capn_Hacky

              Thank you for taking the time to answer my question; unfortunately the proposed answer is incorrect. This makes sense if you consider that a custom getter function devised in the manner above shouldn't functionally alter the rest of the code. Specfically I've implimented the suggested change from:

                                 p0_data = get_data_by_name(pair[0])
                                 p1_data = get_data_by_name(pair[1])
              

              which uses my custom getter function and changed this to

                         p0_data = self.getdatabyname(pair[0])
                         p1_data = self.getdatabyname(pair[1])
              

              This alteration resulted in an identical error, so indeed is unlikely to have functionally altered anything.

              1 Reply Last reply Reply Quote 0
              • 1 / 1
              • First post
                Last post
              Copyright © 2016, 2017, 2018, 2019, 2020, 2021 NodeBB Forums | Contributors