Sorry, more about missing attribute 'high', and definition in init not recognised in next
-
So i have a script which is giving me headaches, mostly with "'Lines_LineSeries_LineSeriesStub' object has no attribute 'high'", but also with failure to recognise a signal from init, in next. The df1 dataframe is as follows (head):
open close high low date 2018-12-18 00:05:00 1.13497 1.13518 1.13519 1.13495 2018-12-18 00:10:00 1.13519 1.13533 1.13533 1.13508 2018-12-18 00:15:00 1.13533 1.13527 1.13542 1.13491 2018-12-18 00:20:00 1.13528 1.13517 1.13529 1.13517 2018-12-18 00:25:00 1.13516 1.13508 1.13516 1.13501 2018-12-18 00:30:00 1.13508 1.13495 1.13519 1.13495 2018-12-18 00:35:00 1.13493 1.13462 1.13493 1.13444 2018-12-18 00:40:00 1.13462 1.13471 1.13472 1.13444 2018-12-18 00:45:00 1.13470 1.13478 1.13483 1.13462 2018-12-18 00:50:00 1.13478 1.13493 1.13495 1.13465
The script thus:
class TestStrategy(bt.Strategy): def log(self, txt, dt=None): ''' Logging function for this strategy''' dt = dt or self.datas[0].datetime.datetime(0) print('%s, %s' % (dt.isoformat(sep=' '), txt)) def __init__(self): # Keep a reference to the "close" line in the data[0] dataseries self.dataclose = self.datas[0].close self.order = None trending = bt.indicators.ADX(self.data[0], period=14)>25 directionup = bt.indicators.PlusDI(self.data[0], period=14) - bt.indicators.MinusDI(self.data[0], period=14)>0 directiondn = bt.indicators.PlusDI(self.data[0], period=14) - bt.indicators.MinusDI(self.data[0], period=14)<0 buy_sig = bt.And(trending, directionup) sell_sig = bt.And(trending, directiondn) def notify_order(self,order): if order.status in [order.Submitted, order.Accepted]: return if order.status == order.Completed: if order.isbuy(): self.log('Buy Executed @ %.5f' % order.executed.price) elif order.issell(): self.log('Sell Executed, %.5f' % order.executed.price) self.bar_executed = len(self) self.order = None def next(self): # Simply log the closing price of the series from the reference self.log('Close, %.5f' % self.dataclose[0]) print(self.position) #following line added for debugging print(trending) if buy_sig: self.log('BUY CREATE, %.5f' % self.dataclose[0]) self.order = self.buy() elif sell_sig: self.log('SELL CREATE, %.5f' % self.dataclose[0]) self.order = self.sell() cerebro = bt.Cerebro(exactbars = False) cerebro.broker.set_cash(50000) df1 = df.iloc[:, 0:4] data = bt.feeds.PandasData(dataname=df1 ,fromdate=datetime.datetime(2018, 12, 18), # Do not pass values before this date todate=datetime.datetime(2019, 3, 1) # Do not pass values after this date ) cerebro.adddata(data) cerebro.addstrategy(TestStrategy) cerebro.addsizer(bt.sizers.FixedSize, stake=500) print('Starting Portfolio Value: %.2f' % cerebro.broker.getvalue()) cerebro.run() print('Final Portfolio Value: %.2f' % cerebro.broker.getvalue())
if I substitute datas for data in
```
trending = bt.indicators.ADX(self.datas[0], period=14)>25
directionup = bt.indicators.PlusDI(self.datas[0], period=14) - bt.indicators.MinusDI(self.datas[0], period=14)>0
directiondn = bt.indicators.PlusDI(self.datas[0], period=14) - bt.indicators.MinusDI(self.datas[0], period=14)<0I seem to get past the 'high' issue but then get a problem that 'trending' (and then 'buy_sig' if print(trending) is commented out) is not defined
-
Sorry, first post - how can i edit after posting???
-
Hi,
You can't edit a post.
It seems that the problem comes from your dataset df1 which is not related to backtrader... It has no high column.
-
My bad, didn't read right...
in next() try to access buy_sig[0] as you want to use the value not the line
-
@andydoc1 said in Sorry, more about missing attribute 'high', and definition in init not recognised in next:
buy_sig = bt.And(trending, directionup)
sell_sig = bt.And(trending, directiondn)Your problem is here. The
buy_sig
andsell_sig
are local variables toinit
. You need to addself
in front of them to make the variables available throughout the strategy including thenext
method.if self.buy_sig: self.log('BUY CREATE, %.5f' % self.dataclose[0]) self.order = self.buy() elif self.sell_sig: self.log('SELL CREATE, %.5f' % self.dataclose[0]) self.order = self.sell()
-
@run-out I hate that I cannot edit....
Add in
[0]
after the indicators to ge the value for that bar.if self.buy_sig[0]: self.log('BUY CREATE, %.5f' % self.dataclose[0]) self.order = self.buy() elif self.sell_sig[0]: self.log('SELL CREATE, %.5f' % self.dataclose[0]) self.order = self.sell()
-
@toinou222 so i tried that, seemed like a possibility although the documentation says:
"A complete example which generates a buy signal during init:
class MyStrategy(bt.Strategy): def __init__(self): sma1 = btind.SimpleMovingAverage(self.data) ema1 = btind.ExponentialMovingAverage() close_over_sma = self.data.close > sma1 close_over_ema = self.data.close > ema1 sma_ema_diff = sma1 - ema1 buy_sig = bt.And(close_over_sma, close_over_ema, sma_ema_diff > 0) def next(self): if buy_sig: self.buy()
"
with no mention of index 0 based notationSo my new 'next' is:
def next(self): # Simply log the closing price of the series from the reference self.log('Close, %.5f' % self.dataclose[0]) #print(self.position) if buy_sig[0]: self.log('BUY CREATE, %.5f' % self.dataclose[0]) self.order = self.buy() elif sell_sig[0]: self.log('SELL CREATE, %.5f' % self.dataclose[0]) self.order = self.sell()
However I still get:
*<ipython-input-5-49c7ea4f6a06> in next(self)
39 #print(trending)
40
---> 41 if buy_sig[0]:
42 self.log('BUY CREATE, %.5f' % self.dataclose[0])
43 self.order = self.buy()NameError: name 'buy_sig' is not defined*
-
Try it like this. It will margin out a lot, but basically this works.
def __init__(self): sma1 = btind.SimpleMovingAverage(self.data) ema1 = btind.ExponentialMovingAverage(self.data) close_over_sma = self.data.close > sma1 close_over_ema = self.data.close > ema1 sma_ema_diff = sma1 - ema1 self.buy_sig = bt.And(close_over_sma, close_over_ema, sma_ema_diff > 0) def next(self): if self.buy_sig[0]: self.buy()
-
@run-out so yes it does work thank you. Now I have a further problem - closing the position.
In next, I call
if self.close_sig[0]: self.log('CLOSE ALL, %.5f, %d' % (self.dataclose[0], self.position.size)) self.order = self.close() print(self.position)
logging self.position.size is to show me that that is an int. However, in init where I try to use it as part of my definition of self.close_sig[0] it won't allow it:
self.close_sig = bt.And(detrending #, self.position.size!=0 )
works, but uncommenting the reference to size leads to no logging of 'CLOSE ALL' in the output (there were numerous with it commented).
The other issue I have is with the detrending definition. The following works:
detrending = bt.Or( bt.And( bt.indicators.ADX(self.datas[0] #, period=14 )<=25 , bt.indicators.ADX(self.datas[0] #, period=14 )<=bt.indicators.ADX(self.datas[-1] #, period=14 ) ) # ,bt.And( # bt.indicators.ADX(self.datas[0] # #, period=14 # )<=bt.indicators.ADX(self.datas[-1] # #, period=14 # ) # , bt.indicators.ADX(self.datas[-1] # #, period=14 # )<=bt.indicators.ADX(self.datas[-2] # #, period=14 # ) # ) )
but uncommenting the reference to the [-1] comparison to [-2] leads to the following error:
**---------------------------------------------------------------------------
IndexError Traceback (most recent call last)
<ipython-input-11-3bb162ac7882> in <module>()
13 print('Starting Portfolio Value: %.2f' % cerebro.broker.getvalue())
14
---> 15 cerebro.run()
16
17 print('Final Portfolio Value: %.2f' % cerebro.broker.getvalue())4 frames
<ipython-input-10-ce52eeb03e9e> in init(self)
57 , bt.indicators.ADX(self.datas[-1]
58 #, period=14
---> 59 )<=bt.indicators.ADX(self.datas[-2]
60 #, period=14
61 )IndexError: list index out of range**
i do not see what is wrong in either case...
-
@andydoc1 You should find most of your answers in the docs. Try the following:
-
@andydoc1 said in Sorry, more about missing attribute 'high', and definition in init not recognised in next:
However, in init where I try to use it as part of my definition of self.close_sig[0] it won't allow it:
self.close_sig = bt.And(detrending
#, self.position.size!=0
)works, but uncommenting the reference to size leads to no logging of 'CLOSE ALL' in the output (there were numerous with it commented).
self.position.size
is equal to zero in the__init()__
. it can't be different since this is initialization of the strategy.Read about strategy steps here https://www.backtrader.com/docu/strategy/
-
@andydoc1 said in Sorry, more about missing attribute 'high', and definition in init not recognised in next:
but uncommenting the reference to the [-1] comparison to [-2] leads to the following error:
self.datas[0] - data feed # 1 from all N data feeds added
self.datas[-1] - data feed # N from all N data feeds added
self.datas[-2] - data feed # N-1 from all N data feeds addedThis is how python list indexing works.
if you use only one data feed than evidently
self.datas[-2]
doesn't exist. Also if single data feed is added thanself.datas[0] == self.datas[-1]
.I would recommend you to start reading the docs. It will save your time and help to understand the
bt
.