Optimizer gives me " only size-1 arrays can be converted to Python scalars" error
-
I've been trying to optimize a new strategy that I have based off of previous strategies. The previous strategies work, but the new one gives me an error saying "only size-1 arrays can be converted to Python scalars" from inside cerebro.run(). Does anybody have an idea of what would be causing this?
The optimizer works when I put a single value into the parameter instead of using np.arange. for bbfactor So it's most likely an issue with that, but I can't figure out what's going on.
import datetime import backtrader as bt from strategies import * import numpy as np cerebro = bt.Cerebro(optreturn=False) data = bt.feeds.GenericCSVData( dataname=tickerSymbol + '_'+ Interval + '_data.csv', fromdate = datetime.datetime(2019, 10, 1), todate = datetime.date.today(), nullvalue=0.0, dtformat=('%Y-%m-%d'), datetime=0, open=1, high=2, low=3, close=4, volume=5, openinterest=-1 ) cerebro.adddata(data) #Add analyzer to Cerebro cerebro.addanalyzer(bt.analyzers.SharpeRatio, _name='sharpe_ratio') cerebro.addanalyzer(bt.analyzers.SQN, _name='SQN') #Add strategy to Cerebro cerebro.optstrategy(BB_EMA, emaperiod=np.arange(20,40,5), bbperiod=np.arange(20,40,5), bbfactor=np.arange(1,4,1)) #Default position size cerebro.broker.setcash(10000.0) cerebro.addsizer(bt.sizers.PercentSizerInt,percents = 99) if __name__ == '__main__': optimized_runs = cerebro.run() final_results_list = [] print('EMA Period|BB Period|BB factor| PnL| SQN') # for SQN analysis for run in optimized_runs: for strategy in run: PnL = round(strategy.broker.get_value() - 10000,2) sqn = strategy.analyzers.SQN.get_analysis() sqnF = '{:<10}|{:<9}|{:<9}|{:<6}|{:<18}' final_results_list.append([strategy.params.emaperiod, strategy.params.bbperiod, strategy.params.bbfactor, PnL, sqn['sqn']]) sort_by_sharpe = sorted(final_results_list, key=lambda x: x[3], reverse=True) filter(None, sort_by_sharpe) #print(sort_by_sharpe) for line in sort_by_sharpe[:5]: if line is not None: print(sqnF.format(*line)) print('\n1.6 - 1.9 Below average \n2.0 - 2.4 Average \n2.5 - 2.9 Good \n3.0 - 5.0 Excellent \n5.1 - 6.9 Superb \n7.0 - Holy Grail')
Error log:
--------------------------------------------------------------------------- RemoteTraceback Traceback (most recent call last) RemoteTraceback: """ Traceback (most recent call last): File "C:\Users\David\Anaconda3\lib\multiprocessing\pool.py", line 119, in worker result = (True, func(*args, **kwds)) File "C:\Users\David\Anaconda3\lib\site-packages\backtrader\cerebro.py", line 1007, in __call__ return self.runstrategies(iterstrat, predata=predata) File "C:\Users\David\Anaconda3\lib\site-packages\backtrader\cerebro.py", line 1293, in runstrategies self._runonce(runstrats) File "C:\Users\David\Anaconda3\lib\site-packages\backtrader\cerebro.py", line 1652, in _runonce strat._once() File "C:\Users\David\Anaconda3\lib\site-packages\backtrader\lineiterator.py", line 297, in _once indicator._once() File "C:\Users\David\Anaconda3\lib\site-packages\backtrader\lineiterator.py", line 297, in _once indicator._once() File "C:\Users\David\Anaconda3\lib\site-packages\backtrader\linebuffer.py", line 630, in _once self.oncestart(self._minperiod - 1, self._minperiod) File "C:\Users\David\Anaconda3\lib\site-packages\backtrader\lineroot.py", line 165, in oncestart self.once(start, end) File "C:\Users\David\Anaconda3\lib\site-packages\backtrader\linebuffer.py", line 758, in once self._once_val_op(start, end) File "C:\Users\David\Anaconda3\lib\site-packages\backtrader\linebuffer.py", line 793, in _once_val_op dst[i] = op(srca[i], srcb) TypeError: only size-1 arrays can be converted to Python scalars """ The above exception was the direct cause of the following exception: TypeError Traceback (most recent call last) <ipython-input-4-2f6d49262766> in <module> 51 52 if __name__ == '__main__': ---> 53 optimized_runs = cerebro.run() 54 55 final_results_list = [] ~\Anaconda3\lib\site-packages\backtrader\cerebro.py in run(self, **kwargs) 1141 1142 pool = multiprocessing.Pool(self.p.maxcpus or None) -> 1143 for r in pool.imap(self, iterstrats): 1144 self.runstrats.append(r) 1145 for cb in self.optcbs: ~\Anaconda3\lib\multiprocessing\pool.py in next(self, timeout) 733 if success: 734 return value --> 735 raise value 736 737 __next__ = next # XXX TypeError: only size-1 arrays can be converted to Python scalars
-
could you please share the code the BB_EMA strategy - at least its
__init__
method - so that we could see how the indicators we defined and/or line operations were used. -
def __init__(self): self.dataclose = self.datas[0].close # Order variable will contain ongoing order details/status self.order = None self.bb = bt.indicators.BBands(self.datas[0], period = self.params.bbperiod, devfactor = self.params.bbfactor, ) self.ema = bt.indicators.EMA(self.datas[0], period=self.params.emaperiod)
This init has been used in other strategies and has no problems. I'm not sure what's going on.
-
I have this problem too. any solution?
-
Please try to call the
optstrategy
with explicit array forbbfactor
:cerebro.optstrategy(BB_EMA, emaperiod=np.arange(20, 40, 5), bbperiod=np.arange(20, 40, 5), bbfactor=[1.0, 2.0, 3.0, 4.0])
It seems
np.arange
with floating numbers cause some problems. If this is indeed the problem, will update with more investigation info. -
@vladisld Had the same issue. problem is that arange returns numpy datatypes which causes this operation to return a numpy array:
stddev = self.p.devfactor * StdDev(self.data, ma, period=self.p.period, movav=self.p.movav)
Converting self.p.devfactor to a standard float fixes the problem
-
@hghhgghdf-dfdf Do you mind helping me a bit on this? I'm trying to convert devfactor to float with no avail.
-
Have you tried just using a list instead of numpy.arange?
-
Yeah, using a list instead of numpy.arange helps.
Looks like the reason causing this error is inside BBands indicator class. Because, for example, feeding ATR indicator with numpy.arange array works perfect!