Analyzing / optmimizing one strategy on multiple assets / DataFeeds
I would like to run a strategy over multiple DataFeeds to measure its performance over multiple assets. I believe there must be some Backtrader concept for this simple usecase, which I'm not aware of at the moment.
I just added a second and third DataFeed cerebro.adddata(data), but the strategy is just executed on the first. (What makes sense if I look at examples for strategies working on multiple assets at the same time, which access multiple datafeeds)
I also find no parameter for cerebro.run() e.g. to run multiple times and no documentation for my case.
It seems I have to implement this by myself and to refeed the different DataFeeds in a loop and start cerebro.run() multiple times? I somehow can't imagine, thats the case.
Furthermore could Backtrader combine analysis results over multiple asset runs for me or would I have to combine them by myself?
And those questions also apply to optimizing. Could I run an optimization not just over one, but multiple DataFeeds in one cerebro.run()?
I'm not going to implement a strategy that works on the same time on multiple assets, I'm just going to run a strategy over multiple assets for analysis / optimization. It shouldn't matter if the strategy is internally executed subsequently or in parallel, as this should lead to the same results.
Could you please clarify what do you want:
- Run the strategy on different assets independently (sequentially) and compare results
- Run the strategy on the several assets as portfolio - issuing orders and making trades on them at the same run.
Both scenarios are possible to implement and you don't need to run
The first one
... or if possible and if still independent in parallel in multiple threads for parallelization, faster results. But conceptionally independent. I'm going to analyse / optimize the strategy on its own per single asset and compare results by myself or better using some tools if possible even for this case.
You can use your data feed as a one of the strategy parameters and run optimization. In this case multiple threads can be used. Check out
optstrategyhere. Also you may check out
getdatabyname()method to get correct data into strategy.
We can come up with other approaches, but they will push runs sequentially or will use the same broker account, it will be hard to split outputs such as profits, drawdowns etc.
Would I do the same if I'm not optimizing? So if I want to run my strategy over different assets and just get analyzer results? But in this case with no optimization parameters and just the data?
This feels a bit hacky and I'm wondering why this is not documented and if I'm doing something wrong. Let me rephrase:
When backtesting your strategy, wouldn't you do it over multiple assets and not just one? Whats the best practise to backtest over multiple assets and why is this not documented as this should be such a basic usecase?
Sorry if I'm still a bit puzzled on a conceptional level. I understood your technical solution. Thanks!
Optimization is not just alternating indicator periods as most of the algotraders think :), but has much broader meaning. Selection of the assets or even asset time frames is also optimization. So conceptually this approach is correct.
If you want alternate only data feeds and skip other parameters, than use only data feed parameter with
When backtesting your strategy, wouldn't you do it over multiple assets and not just one?
It depends on the trader's vision, experience and beliefs. :) One believes in the single asset strategies, one believes that strategy should work on the number of assets.
run-out last edited by
@trdr I would add that I view the power of Backtrader is to run a complete backtest on a set of data, with a set of parameters. It kicks out great analytical results built in or what I've made and added in.
I frequently run multi-parameter/datas testing, and I control all of these parameters on my own, calling backtrader each time with the parameters and data I've set out.
It's now my job to decide how to blend these together. Personally I use spreadsheets for single test results and a database to combine results for multi test analysis.
I could be wrong, but I don't think backtrader is here to do everything soup to nuts, but what it does, it does super well.
Happy coding :)
Don't get me wrong, I became already a big fan of backtrader. And big thanks to the author(s)! It's unbelievable how fast you could prototype ideas and I like the overall concepts and its simplicity! @run-out I totally see your point and will perform my own analysis. I've already pyfolio integrated and wanted to ensure, that I'm not reinventing something.
Thanks to @ab_trader I'm now able to perform optimizations on multiple assets by
- passing the names of the multiple DataFeeds to my strategy during optimization
- use a given DataFeed by setting it via self.data in my strategy
def __init__(self): if self.params.data_name is not None: self.data = self.getdatabyname(self.params.data_name)
This works fine so far!
At the moment I'm struggling with a Problem where the Analyzer seems to have Problems working on the given DataFeeds? I reset self.data there as well and even tried to pass self.data as first argument to the SMA.
class MyAnalyzer(bt.Analyzer): params = () def __init__(self): if self.strategy.params.data_name is not None: self.data = self.strategy.getdatabyname(self.strategy.params.data_name) self.ma_fast = btind.MovingAverageSimple(period=5, plotname='Analyzer MA fast')
but I'm getting an error, which comes from the SMA calculation:
Exception in thread Thread-3: Traceback (most recent call last): File "/home/trading/.pyenv/versions/3.5.9/lib/python3.5/threading.py", line 914, in _bootstrap_inner self.run() File "/home/trading/.pyenv/versions/3.5.9/lib/python3.5/threading.py", line 862, in run self._target(*self._args, **self._kwargs) File "/home/trading/.pyenv/versions/3.5.9/lib/python3.5/multiprocessing/pool.py", line 463, in _handle_results task = get() File "/home/trading/.pyenv/versions/3.5.9/lib/python3.5/multiprocessing/connection.py", line 251, in recv return ForkingPickler.loads(buf.getbuffer()) AttributeError: Can't get attribute 'AutoInfoClass_pl_LineSeries_pl_LineIterator_pl_DataAccessor_pl_ObserverBase_pl_Observer_pl_DataTrades_50b29187c1c944dfb72df69c6fbf3be2' on <module 'backtrader.metabase' from '/home/trading/.pyenv/versions/backtrader/lib/python3.5/site-packages/backtrader/metabase.py'>
The Problem also occours if I pass only one DataFeed via optstrategy.
Do you have any insights how to get the Analyzer also run with the different DataFeeds or just the DataFeed the according Strategy is using?
it might be an issue with the
multiprocessing, seems you use it. that is higher than my level. :)
analyzersare used to get some values from the strategy, make some calcs and return the value. Not sure that adding
initof the analyzer is conceptually right, but for sure possible. if you share your goal, we can try to come up with the (maybe more optimal) idea.
data feed you selected by name in the strategy also should be accessible in analyzer using
another thing - using this
self.data = self.strategy.getdatabyname(self.strategy.params.data_name)
is imho not good.
self.datais a first data feed you passed into
adddata. now you reset it, so this can affect internal
btmechanics. try to use another variable name.
Well, I used
self.dataon purpose, because I wanted to reset data to the data provided by an argument. But as you say, if this is a reference to
self.datasthen I'm screwing my own data up, by resetting the first DataFeed. I'll try it with my own member variable and try to pass data to an Indicator.
I'm still working on the simple case, to let a simple strategy optimize over more than just one DataFeed. As much as I like Backtrader now, I'm confused why this seems to be so hard and I'm wondering why it's not documented or no recipe exists, as the support for running over multiple assets seems to me as a very basic feature in backtesting.
E.g the current approach just seems not to fit into the overall backtrader architecture. I would have to rewrite all strategies to support multiple assets. I would have expected, that there would be just a data argument in some base class that would allow to pass a DataFeed.
vladisld last edited by
AttributeError: Can't get attribute 'AutoInfoClass_pl_LineSeries_pl_LineIterator_pl_DataAccessor_pl_ObserverBase_pl_Observer_pl_DataTrades
The following post may provide some clue about DataTrades observer pickling:
Alternatively you may try to disable the standard observers and analyzers while running optimizations using
stdstats=Falseduring Cerebro engine initialization.
Nice, I got it to work!
@ab_trader I validated overwriting
self.datawould not overwrite the first element in
self.datas. But just setting
self.datato a new DataFeed would not help anyways, so it's cleaner to use an own variable and the custom DataFeed must be passed as first argument to an indicator.
@vladisld thanks a lot!
stdstats=Falsesolved my problem!