Stock prediction using sentiment analysis error
-
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()
-
@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 theSentiment
class. Alsoself.sentiment
is not defined as well. At least in the code shown. -
@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 toFalse
. As such the declaration and assigment ofself.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 ifsentiment
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.