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/

    Stock prediction using sentiment analysis error

    General Code/Help
    3
    3
    392
    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.
    • Shubham Puri
      Shubham Puri last edited by

      I've been getting different errors and since I'm new to backtrader, its been difficult to resolve it.
      First I was using YahooFinance Data and it was giving me this error:
      AttributeError: 'NoneType' object has no attribute 'close'

      Then I changed it to Quandl and now it is giving me this error:

      Starting Portfolio Value: 100000.00
      ---------------------------------------------------------------------------
      TypeError                                 Traceback (most recent call last)
      <ipython-input-71-0bf63207fcf8> in <module>
          145     cerebro.broker.setcommission(commission=0.001)
          146     print('Starting Portfolio Value: %.2f' % cerebro.broker.getvalue())
      --> 147     cerebro.run()
          148     print('Final Portfolio Value: %.2f' % cerebro.broker.getvalue())
          149 
      
      ~/Library/Python/3.7/lib/python/site-packages/backtrader/cerebro.py in run(self, **kwargs)
         1125             # let's skip process "spawning"
         1126             for iterstrat in iterstrats:
      -> 1127                 runstrat = self.runstrategies(iterstrat)
         1128                 self.runstrats.append(runstrat)
         1129                 if self._dooptimize:
      
      ~/Library/Python/3.7/lib/python/site-packages/backtrader/cerebro.py in runstrategies(self, iterstrat, predata)
         1291                     self._runonce_old(runstrats)
         1292                 else:
      -> 1293                     self._runonce(runstrats)
         1294             else:
         1295                 if self.p.oldsync:
      
      ~/Library/Python/3.7/lib/python/site-packages/backtrader/cerebro.py in _runonce(self, runstrats)
         1650         '''
         1651         for strat in runstrats:
      -> 1652             strat._once()
         1653             strat.reset()  # strat called next by next - reset lines
         1654 
      
      ~/Library/Python/3.7/lib/python/site-packages/backtrader/lineiterator.py in _once(self)
          295 
          296         for indicator in self._lineiterators[LineIterator.IndType]:
      --> 297             indicator._once()
          298 
          299         for observer in self._lineiterators[LineIterator.ObsType]:
      
      ~/Library/Python/3.7/lib/python/site-packages/backtrader/lineiterator.py in _once(self)
          315         # indicators are each called with its min period
          316         self.preonce(0, self._minperiod - 1)
      --> 317         self.oncestart(self._minperiod - 1, self._minperiod)
          318         self.once(self._minperiod, self.buflen())
          319 
      
      ~/Library/Python/3.7/lib/python/site-packages/backtrader/indicator.py in oncestart_via_nextstart(self, start, end)
          122 
          123             self.advance()
      --> 124             self.nextstart()
          125 
          126     def once_via_next(self, start, end):
      
      ~/Library/Python/3.7/lib/python/site-packages/backtrader/lineiterator.py in nextstart(self)
          345 
          346         # Called once for 1st full calculation - defaults to regular next
      --> 347         self.next()
          348 
          349     def next(self):
      
      <ipython-input-71-0bf63207fcf8> in next(self)
           25         if date in date_sentiment:
           26             self.sentiment = date_sentiment[date]
      ---> 27         self.lines.sentiment[0] = self.sentiment
           28 
           29 
      
      ~/Library/Python/3.7/lib/python/site-packages/backtrader/linebuffer.py in __setitem__(self, ago, value)
          220             value (variable): value to be set
          221         '''
      --> 222         self.array[self.idx + ago] = value
          223         for binding in self.bindings:
          224             binding[ago] = value
      
      TypeError: must be real number, not LineBuffer
      

      Here's my code:

      from __future__ import (absolute_import, division, print_function,
                                  unicode_literals)
      
      %matplotlib inline
      import warnings
      warnings.filterwarnings('ignore')
      
      import backtrader as bt
      import backtrader.indicators as btind
      import datetime
      import os.path
      import sys
      
      class Sentiment(bt.Indicator):
          lines = ('sentiment',)
          plotinfo = dict(
              plotymargin=0.15,
              plothlines=[0],
              plotyticks=[1.0, 0, -1.0])
          
          def next(self):
              self.date = self.data.datetime
              date = bt.num2date(self.date[0]).date()
              prev_sentiment = self.sentiment
              if date in date_sentiment:
                  self.sentiment = date_sentiment[date]
              self.lines.sentiment[0] = self.sentiment
      
      
      
      class SentimentStrat(bt.Strategy):
          params = (
              ('period', 15),
              ('printlog', True),
          )
      
          def log(self, txt, dt=None, doprint=False):
              ''' Logging function for this strategy'''
              if self.params.printlog or doprint:
                  dt = dt or self.datas[0].datetime.date(0)
                  print('%s, %s' % (dt.isoformat(), txt))
      
          def __init__(self):
              # Keep a reference to the "close" line in the data[0] dataseries
              self.dataclose = self.datas[0].close
              # Keep track of pending orders
              self.order = None
              self.buyprice = None
              self.buycomm = None
              self.sma = bt.indicators.SimpleMovingAverage(
                  self.datas[0], period=self.params.period)
              self.date = self.data.datetime
              self.sentiment = None
              Sentiment(self.data)
              
          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
              
              # Check if an order has been completed
              # Attention: broker could reject order if not enough cash
              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))
                      self.buyprice = order.executed.price
                      self.buycomm = order.executed.comm
                  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)     
                  
              elif order.status in [order.Canceled, order.Margin, order.Rejected]:
                  self.log('Order Canceled/Margin/Rejected')
                  
              # Write down: no pending order
              self.order = None
              
          def notify_trade(self, trade):
              if not trade.isclosed:
                  return
      
              self.log('OPERATION PROFIT, GROSS %.2f, NET %.2f' %
                       (trade.pnl, trade.pnlcomm))
          
          ### Main Strat ###
          def next(self):
              # log closing price of the series from the reference
              self.log('Close, %.2f' % self.dataclose[0])
              
              date = bt.num2date(self.date[0]).date()
              prev_sentiment = self.sentiment
              if date in date_sentiment:
                  self.sentiment = date_sentiment[date]
              
              # Check if an order is pending. if yes, we cannot send a 2nd one
              if self.order:
                  return
              print(self.sentiment)
              # If not in the market and previous sentiment not none
              if not self.position and prev_sentiment:
                  # buy if current close more than sma AND sentiment increased by >= 0.5
                  if self.dataclose[0] > self.sma[0] and self.sentiment - prev_sentiment >= 0.5:
                      self.log('BUY CREATE, %.2f' % self.dataclose[0])
                      self.order = self.buy()
                      
              # Already in the market and previous sentiment not none
              elif prev_sentiment:
                  # sell if current close less than sma AND sentiment decreased by >= 0.5
                  if self.dataclose[0] < self.sma[0] and self.sentiment - prev_sentiment <= -0.5:
                      self.log('SELL CREATE, %.2f' % self.dataclose[0])
                      self.order = self.sell()
      
          def stop(self):
              self.log('(MA Period %2d) Ending Value %.2f' %
                       (self.params.period, self.broker.getvalue()), doprint=True)
              
          
      if __name__ == '__main__':
          cerebro = bt.Cerebro()
          
          # Strategy
          cerebro.addstrategy(SentimentStrat)
      
          # Data Feed
          data = bt.feeds.Quandl(
              dataname = 'FB',
      #        fromdate = earliest_date,
              fromdata = datetime.datetime(2019,10,4),
              todate = datetime.datetime(2019,10,22),
              reverse = False
          )
          
          cerebro.adddata(data)
      
          cerebro.broker.setcash(100000.0)
          cerebro.addsizer(bt.sizers.FixedSize, stake=10)
          cerebro.broker.setcommission(commission=0.001)
          print('Starting Portfolio Value: %.2f' % cerebro.broker.getvalue())
          cerebro.run()
          print('Final Portfolio Value: %.2f' % cerebro.broker.getvalue())
          
          cerebro.plot()
      
      B 1 Reply Last reply Reply Quote 0
      • A
        ab_trader last edited by

        @Shubham-Puri said in Stock prediction using sentiment analysis error:

            if date in date_sentiment:
                self.sentiment = date_sentiment[date]
        

        seems that date_sentiment is not defined in the Sentiment class. Also self.sentiment is not defined as well. At least in the code shown.

        • 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 1
        • B
          backtrader administrators @Shubham Puri last edited by

          @Shubham-Puri said in Stock prediction using sentiment analysis error:

                  if date in date_sentiment:
                      self.sentiment = date_sentiment[date]
                  self.lines.sentiment[0] = self.sentiment
          

          The first time you go into the code the if date in date_sentiment evaluates to False. As such the declaration and assigment of self.sentiment = xxxxxxx is not executed and this member attribute does NOT exist.

          You then do

          self.lines.sentiment[0] = self.sentiment
          

          The best the indicator can do, given the undefined self.sentiment is to look in the lines declaration and see if sentiment exists there ... and yes. It is a line buffer which you try to assign to itself in a point in time.

          Define self.sentiment to have another name and you will quickly see the error popping up.

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