Resolve this error!
-
Hi
I am trying to run a bollinger band strategy on some prices. my dataframe is pretty simple. Only contains datetime (it is the index column) and the closing price. However, when I run this code, I am getting below error. What is the reason for that? What am I missing?
Can anyone please guide me and I am happy to take on a lesson with anyone at a fair rate if needed!
Thanks in advance.
My data frame = df. The df.tail() is as per displayed below.
Datetime close
2020-11-18 09:51:38 13.855
2020-11-18 09:52:25 13.855
2020-11-18 09:52:25 13.855
2020-11-18 09:52:27 13.855
2020-11-18 09:52:27 13.855Code below:
code_text ```class teststrat(bt.Strategy): params = ( ('n',20), ('m',2),# Tuple of tuples containing any variable settings required by the strategy. ('printlog',False), # Stop printing the log of the trading strategy ) def __init__(self): self.dataclose= self.datas[0].close # Keep a reference to the "close" line in the data[0] dataseries self.order = None # Property to keep track of pending orders. There are no orders when the strategy is initialized. self.buyprice = None self.buycomm = None self.redline = None self.blueline = None # Add Bband indicator for use in the trading strategy self.bband = bt.indicators.BBands( self.datas[0], period=self.params.n, devfactor=self.params.m) def log(self, txt, dt=None, doprint=False): if self.params.printlog or doprint: # Add if statement to only log of printlog or doprint is True dt = dt or self.datas[0].datetime.date(0) print('{0},{1}'.format(dt.isoformat(),txt)) def notify_order(self, order): # 1. If order is submitted/accepted, do nothing if order.status in [order.Submitted, order.Accepted]: return # 2. If order is buy/sell executed, report price executed if order.status in [order.Completed]: if order.isbuy(): self.log('BUY EXECUTED, Price: {0:8.2f}, Size: {1:8.2f} Cost: {2:8.2f}, Comm: {3:8.2f}'.format( order.executed.price, order.executed.size, order.executed.value, order.executed.comm)) self.buyprice = order.executed.price self.buycomm = order.executed.comm else: self.log('SELL EXECUTED, {0:8.2f}, Size: {1:8.2f} Cost: {2:8.2f}, Comm{3:8.2f}'.format( order.executed.price, order.executed.size, order.executed.value, order.executed.comm)) self.bar_executed = len(self) #when was trade executed # 3. If order is canceled/margin/rejected, report order canceled elif order.status in [order.Canceled, order.Margin, order.Rejected]: self.log('Order Canceled/Margin/Rejected') self.order = None def notify_trade(self,trade): if not trade.isclosed: return self.log('OPERATION PROFIT, GROSS {0:8.2f}, NET {1:8.2f}'.format( trade.pnl, trade.pnlcomm)) def next(self): # Simply log the closing price of the series from the reference self.log('Close, %.2f' % self.dataclose[0]) # Check if an order is pending ... if yes, we cannot send a 2nd one if self.order: return if self.dataclose < self.bband.lines.bot and not self.position: self.redline = True if self.dataclose > self.bband.lines.top and self.position: self.blueline = True if self.dataclose > self.bband.lines.mid and not self.position and self.redline: # BUY, BUY, BUY!!! (with all possible default parameters) self.log('BUY CREATE, %.2f' % self.dataclose[0]) # Keep track of the created order to avoid a 2nd order self.order = self.buy() if self.dataclose > self.bband.lines.top and not self.position: # BUY, BUY, BUY!!! (with all possible default parameters) self.log('BUY CREATE, %.2f' % self.dataclose[0]) # Keep track of the created order to avoid a 2nd order self.order = self.buy() if self.dataclose < self.bband.lines.mid and self.position and self.blueline: # SELL, SELL, SELL!!! (with all possible default parameters) self.log('SELL CREATE, %.2f' % self.dataclose[0]) self.blueline = False self.redline = False # Keep track of the created order to avoid a 2nd order self.order = self.sell() # Create a cerebro entity cerebro = bt.Cerebro() # Add a strategy cerebro.addstrategy(teststrat) # Create a Data Feed data = bt.feeds.PandasData(dataname = df) #, openinterest=False,open=False,high=False,low=False,close=-1,volume=False) # Add the Data Feed to Cerebro cerebro.adddata(data) # Datas are in a subfolder of the samples. Need to find where the script is # because it could have been called from anywhere #modpath = os.path.dirname(os.path.abspath(sys.argv[0])) #datapath = os.path.join(modpath, 'TSLA-USD.csv') strats = cerebro.optstrategy( teststrat, n=range(10,50), m=range(1,5), printlog=False) # Set our desired cash start cerebro.broker.setcash(10000.0) # Add a FixedSize sizer according to the stake cerebro.addsizer(bt.sizers.FixedSize, stake=5) # Set the commission cerebro.broker.setcommission(commission=0.002) # Print out the starting conditions print('Starting Portfolio Value: %.2f' % cerebro.broker.getvalue()) # Run over everything cerebro.run() # Print out the final result print('Final Portfolio Value: %.2f' % cerebro.broker.getvalue()) # Plot the result cerebro.plot() Starting Portfolio Value: 10000.00 --------------------------------------------------------------------------- AttributeError Traceback (most recent call last) <ipython-input-78-2914091a02c7> in <module> 137 138 # Run over everything --> 139 cerebro.run() 140 141 # Print out the final result ~\AppData\Local\Continuum\anaconda3\lib\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: ~\AppData\Local\Continuum\anaconda3\lib\site-packages\backtrader\cerebro.py in runstrategies(self, iterstrat, predata) 1210 data._start() 1211 if self._dopreload: -> 1212 data.preload() 1213 1214 for stratcls, sargs, skwargs in iterstrat: ~\AppData\Local\Continuum\anaconda3\lib\site-packages\backtrader\feed.py in preload(self) 436 437 def preload(self): --> 438 while self.load(): 439 pass 440 ~\AppData\Local\Continuum\anaconda3\lib\site-packages\backtrader\feed.py in load(self) 477 478 if not self._fromstack(stash=True): --> 479 _loadret = self._load() 480 if not _loadret: # no bar use force to make sure in exactbars 481 # the pointer is undone this covers especially (but not ~\AppData\Local\Continuum\anaconda3\lib\site-packages\backtrader\feeds\pandafeed.py in _load(self) 266 267 # convert to float via datetime and store it --> 268 dt = tstamp.to_pydatetime() 269 dtnum = date2num(dt) 270 self.lines.datetime[0] = dtnum AttributeError: 'str' object has no attribute 'to_pydatetime'
-
@curious_one said in Resolve this error!:
code_text > > # Datas are in a subfolder of the samples. Need to find where the script is > # because it could have been called from anywhere > #modpath = os.path.dirname(os.path.abspath(sys.argv[0])) > #datapath = os.path.join(modpath, 'TSLA-USD.csv') >
ignore this section in the code pls unless you think it is relevant.. thx
-
@curious_one your datetime is a string, try converting it to datetime objects. Look at pandas to_datetime() method.
df.Datetime = pandas.to_datetime( df.Datetime, format='%Y-%m-%d %H:%M:%S')
-
@dasch Appreciate the help ! It seems to fix the error and the code is running as I am typing this :)
-
Hi, after fixing the datetime such that it is datetimeindex, I can run the code with no errors. However, now the code does not stop running and it has technically no output other than this: "Starting Portfolio Value: 10000.00".
The code has been running (as shown in image screenshot below with the * circled in pink) in Jupyter notebook for at least 15 minutes and I only have 3000 rows and 2 columns worth of data containing Date on the index and Close price in another column. Hence, I am very puzzled by this.
I have copy and pasted the code below. Can someone help please? Thank you vm in advance~!
code_text class teststrat(bt.Strategy): params = ( ('n',20), ('m',2),# Tuple of tuples containing any variable settings required by the strategy. ('printlog',False), # Stop printing the log of the trading strategy ) def __init__(self): self.dataclose= self.datas[0].close # Keep a reference to the "close" line in the data[0] dataseries self.order = None # Property to keep track of pending orders. There are no orders when the strategy is initialized. self.buyprice = None self.buycomm = None self.redline = None self.blueline = None # Add Bband indicator for use in the trading strategy self.bband = bt.indicators.BBands( self.datas[0], period=self.params.n, devfactor=self.params.m) def log(self, txt, dt=None, doprint=False): if self.params.printlog or doprint: # Add if statement to only log of printlog or doprint is True dt = dt or self.datas[0].datetime.date(0) print('{0},{1}'.format(dt.isoformat(),txt)) def notify_order(self, order): # 1. If order is submitted/accepted, do nothing if order.status in [order.Submitted, order.Accepted]: return # 2. If order is buy/sell executed, report price executed if order.status in [order.Completed]: if order.isbuy(): self.log('BUY EXECUTED, Price: {0:8.2f}, Size: {1:8.2f} Cost: {2:8.2f}, Comm: {3:8.2f}'.format( order.executed.price, order.executed.size, order.executed.value, order.executed.comm)) self.buyprice = order.executed.price self.buycomm = order.executed.comm else: self.log('SELL EXECUTED, {0:8.2f}, Size: {1:8.2f} Cost: {2:8.2f}, Comm{3:8.2f}'.format( order.executed.price, order.executed.size, order.executed.value, order.executed.comm)) self.bar_executed = len(self) #when was trade executed # 3. If order is canceled/margin/rejected, report order canceled elif order.status in [order.Canceled, order.Margin, order.Rejected]: self.log('Order Canceled/Margin/Rejected') self.order = None def notify_trade(self,trade): if not trade.isclosed: return self.log('OPERATION PROFIT, GROSS {0:8.2f}, NET {1:8.2f}'.format( trade.pnl, trade.pnlcomm)) def next(self): # Simply log the closing price of the series from the reference self.log('Close, %.2f' % self.dataclose[0]) # Check if an order is pending ... if yes, we cannot send a 2nd one if self.order: return if self.dataclose < self.bband.lines.bot and not self.position: self.redline = True if self.dataclose > self.bband.lines.top and self.position: self.blueline = True if self.dataclose > self.bband.lines.mid and not self.position and self.redline: # BUY, BUY, BUY!!! (with all possible default parameters) self.log('BUY CREATE, %.2f' % self.dataclose[0]) # Keep track of the created order to avoid a 2nd order self.order = self.buy() if self.dataclose > self.bband.lines.top and not self.position: # BUY, BUY, BUY!!! (with all possible default parameters) self.log('BUY CREATE, %.2f' % self.dataclose[0]) # Keep track of the created order to avoid a 2nd order self.order = self.buy() if self.dataclose < self.bband.lines.mid and self.position and self.blueline: # SELL, SELL, SELL!!! (with all possible default parameters) self.log('SELL CREATE, %.2f' % self.dataclose[0]) self.blueline = False self.redline = False # Keep track of the created order to avoid a 2nd order self.order = self.sell() # Create a cerebro entity cerebro = bt.Cerebro() # Add a strategy cerebro.addstrategy(teststrat) # Create a Data Feed data = bt.feeds.PandasData(dataname = df_daily) #, openinterest=False,open=False,high=False,low=False,close=-1,volume=False) # Add the Data Feed to Cerebro cerebro.adddata(data) # Datas are in a subfolder of the samples. Need to find where the script is # because it could have been called from anywhere #modpath = os.path.dirname(os.path.abspath(sys.argv[0])) #datapath = os.path.join(modpath, 'TSLA-USD.csv') strats = cerebro.optstrategy( teststrat, n=range(10,50), m=range(1,5), printlog=False) # Set our desired cash start cerebro.broker.setcash(10000.0) # Add a FixedSize sizer according to the stake cerebro.addsizer(bt.sizers.FixedSize, stake=5) # Set the commission cerebro.broker.setcommission(commission=0.002) # Print out the starting conditions print('Starting Portfolio Value: %.2f' % cerebro.broker.getvalue()) # Run over everything cerebro.run() # Print out the final result print('Final Portfolio Value: %.2f' % cerebro.broker.getvalue()) # Plot the result cerebro.plot() Starting Portfolio Value: 10000.00
-