Is backtrader event driven or vectorized?
-
Sorry for the complete noob question. I am new to backtrader, but it looks promising
-
backtrader takes a dual approach to the problem. This is controlled with the
runonce
(boolean) parameter to either a instantiation ofCerebro
or tocerebro.run
like inThe default is
runonce=True
cerebro = Cerebro(runonce=True) # or False
or
cerebro = Cerebro() ... ... cerebro.run(runonce=True) # or False
1.
runonce=True
This could be called a pseudo-vectorized of half-vectorized approach. Built-in operations feature a
once
method which calculate things in batch mode in a tight inner loop.-
Data feeds are fully pre-loaded
-
Indicators (and sub-indicators thereof) are pre-calculated in batch-mode
-
Then, the
Strategy
instance(s) are run step-by-step
Being the goal to offer an increase in speed, but still allow for fine grained logic in the
next
method of the strategyRough calculations indicate that it is somehow between
20-30%
thanrunonce=False
Drawback: Because indicators are precalculated (and therefore the buffers are preallocated), the data synchronization mechanism cannot pause the actual movement of a data feed when synchronizing the timestamps for the strategy, keeping the buffers to the final same length. This has no actual impact for backtesting but because
matplotlib
expects all things to have the samex
length for plotting, it may not be possible to create a plot of the backtesting.Drawback 2: The implementation of this mode prevented that some indicators can be fully defined in recursive terms with a single formula. A choice had to be made between having this or having the recursive formulas.
Nice Thing: If a user implements a custom
Indicator
and only provides anext
method (intented for step-by-step, see below), the code automatically detects it and will still pre-calculate the indicator using thenext
method instead of the missingonce
method. The calculation loop will not be so tight as it could be, but users don't have to worry about implementingonce
2.
runonce=False
This is a 100% step-by-step mode. Also named
next
because only thenext
method of the different indicators, strategies et al., play a role.Everything is calculated one step at a time. The reason being the addition of data feeds which would be providing the data points one step at a time (not necessarily live feeds, it could have been reading out of a socket from a database connection).
If
cerebro
is run withpreload=False
(disable the preloading of data feeds) it will switch to this mode. -
-
@backtrader
when I turn on the runonce=False,(nothing else changed) the final value is greatly reduced...
from 16700 to 2700...
Really confused why. Could you please give some explains? Many thanks! -
@shaodaodao Changing the value of
runonce
parameter should have no influence on the back testing / optimizations results - it's purely a performance optimization ( at least in theory )There is a small chance that there is bug of cause - but I suspect there is something in your code that may interfere with the way the framework is supposed to work - however without seeing the full code - it is hard to tell.
If you could provide your code ( or just a sample of it that demonstrates the issue) + sample data - we'll be able to tell for sure.
-
@vladisld
I found an interesting issue.
Because I used bt.talib.BBands and customized some parameters, then after cerebro run the final value is huge different for runonce=true or false.
But when I switched to Backtrader's own BBands and set the same parameters, this bug doesn't exist.So I guess the connection with ta-lib has some issues for runonce selection.
-
@shaodaodao said in Is backtrader event driven or vectorized?:
Because I used bt.talib.BBands and customized some parameters, then after cerebro run the final value is huge different for runonce=true or false
That's interesting. As I've said above, it would be great if you could share some code sample + data (simplified as you wish) - so we could play with it and see what causes this discrepancy.