Building Sentiment Indicator class: TypeError: must be real number, not LineBuffer
-
Hi,
First time posting here and I am a beginner in python. I am trying to build a new Sentiment strategy that executes buy/sell based on changes in sentiment scores analyzed from tweets about certain companies. I first run a twitter text search and use NLTK on the tweets to get sentiment scores. I then store the sentiment data as a dict (date_sentiment) with keys = date and values = score. Everything works until here but after building the sentiment Indicator and run cerebro, I keep getting the error message "TypeError: must be real number, not LineBuffer". I suspect the problem lies somewhere in the Sentiment class, but I couldn't figure out what went wrong. Could someone please help me with this problem?
Any input would be greatly appreciated!```
code_textclass 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)
-
self.sentiment = None Sentiment(self.data)
seems the variable is always none?
but anyway, when you see "TypeError: must be real number, not LineBuffer", that means, you should add 3 characters "[0]" after your variable, such as:
print(self.sentiment) # ---change to ---> print(self.sentiment[0]) -
@Kevin-Fu said in Building Sentiment Indicator class: TypeError: must be real number, not LineBuffer:
Any input would be greatly appreciated
But you provide no input with regards to the error. Only
TypeError: must be real number, not LineBuffer
Python exceptions provided a stacktrace which points to the different line numbers in the stack ... allowing to trace the error to the origin point (and showing any potential intermediate conflict)
The error is only telling us that you are passing an object (a
LineBuffer
) there where afloat
should have been passed by you. But not where you are doing it ... which is in the stacktrace ... -
@Kevin-Fu said in Building Sentiment Indicator class: TypeError: must be real number, not LineBuffer:
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
In any case that's probably where the error happens. There is no definition of
self.sentiment
and the indicator understands you are looking for the line namedsentiment
. The problems- Lack of variable initialization
- Conflicting naming