Backtrader: Creating Analyzers

We have covered using Backtrader’s analyzers in an earlier post. At that time, we looked at using the built-in TradeAnalyzer and SQN to provide some meaningful feedback as to how our strategy performed. In this post  we shall go a step further and create our own analyzer.

Backtrader might not be the first thing that comes to mind when thinking about statistical analysis. However, there are some positives to consider that make it a good choice. Namely, you can use a platform you are familiar with. No need to spend hours running through tutorials for other frameworks “better suited” to statistical analysis. If you can leverage your Backtrader skills to do the same in less time why not? Another benefit is that analyzers can provide immediate feedback in real-time or as soon as the Backtest ends. No need to export your final data into another framework for further analysis.

Creating an Analyzer

We are going to create a simple analyzer to count the number of times price action hits a pivot indicators p, s1, s2, r1 and r2 lines. Knowing how frequently the pivot is hit might be useful in helping to find an edge. Alternatively, it may also be useful in determining stop placement if you know that s2 is only hit x% of the time. These are just examples and the code in the post is intended to spark ideas only. You may want to expand on the analysis in the code or look at another area which interests you.

Pivot Points Analyzer

Code Commentary

First things first. To create an analyzer we need to inherit from Backtraders Analyzerclass. Following this, the __init_() is fairly straightforward. We just import Backtrader’s PivotPointindicator and turn off plotting.

Next we move onto the more interesting create_analysis() method. Here we setup the metrics that need to be tracked by the analyzer. Backtrader uses an AutoOrderedDict()for storing the metrics that you want to track. An ordered dictionary allows the analyzers inherited print() method to print the metrics in a fixed and defined order. If you have ever tried printing values from a normal dictionary, you may have noticed that the order in which the keys are printed can seem a bit random. (It is likely not random, but I certainly do not know the logic). Speaking of the print() method, there will be an example of how to call it later.

Backtrader’s built-in analyzers use a naming convention for the dictionary that is used to store metrics to be printing. It is called self.rets. You will notice in the code example, I have one dictionary which follows this convention and one which does not. (counts and rets). The reasoning is because I am primarily interested in the percentage/frequency that the pivots are hit rather than the absolute number of times. As such, did not want the counts to be included in the rets dictionary and printed at the same time.

next()

Analyzers have a next() method just like indicators and strategies. As such this makes it easy to take your knowledge developed so far and apply it to an analyzer. The next() method for this analyzer checks to see if the high of the data is above the pivot AND the low of the data is below it. This signifies that the pivot was broken during the bar.

stop()

The stop() method is called at the end of the backtesting. This is also available in strategies and indicators. An example of this was shown in the post Backtrader: Live trading shutdown.

In the code example above, we use stop() to build the final percentages from the count dict. If you wanted to access the analyzer during a run. I.e Live or access values during a strategies next() method, the analyzer could be improved to calculate the percentages every bar.

Adding the analyzer

You might have noticed in the code example above, no code has been provided to setup cerebro or define a strategy. This is because I want to keep the analyzer code modularized in a separate location for reuse. For an overview on how to create python modules for your Backtrader projects see this post: Backtrader: Making modular code. The analyzer will be imported into a strategy when required.

Ok – So now lets assume you have this Analyzer stored in a module. To use the analyzer you would need to create a script like below:

The code above will not run out of the box. It is for example purposes only. Here is why:

  • The code assumes the analyzer is saved in an sub module analyzers which is part of the extensions module. You could emulate this, create your own module structure or simply copy and paste the analyzer into the main script.
  • The code uses my own data saved from Oanda. You will need to replace this part with your own data and data setup.

Adding the analyzer and getting the results is pretty easy. Once imported, you add it with a single line cerebro.addanalyzer(pivotPointAnalyzer). Then to access the results you can print them after the run using the lines:

And that is all there is to it. Once setup and ran you should see some output that looks like this:

Output from the pivot point analyzer