Backtrader: Making modular code

This weeks post is not directly related to Backtrader but will definitely come in useful as our journey into backtesting develops. The more we develop, the more tools end up in our tool box. Indicators, strategies, reports, analyzers, you name it. However, it is no good having so many tools if we can never find them. Worse still is buying another wrench when we already have 10 of them! What I am blabbering on about? Well, our project folder is our tool box and the files inside it are it’s compartments. If we don’t organize things efficiently it becomes hard to find that nice piece of code you developed 6 months ago. Then if we do manage to find it, should we just copy and paste it into a new script, we will end up with multiple wrenches in our tool box. The problem with this is not so much the waste of having lots of versions of the same code, it is when you notice there is problem and you then need to apply the same fix to multiple different scripts. It can be a real pain.

There must be a better way

And there is! Modular code allows you to organized and re-use the code you have already developed in a much neater way. Better still, when you need to make a fix, you only need to do it once. In Python, we have been using modules from day one. Especially in these tutorials. Any time we are using the importstatement, we are using a module. Fortunately, creating a module in Python is very simple and is not limited to packages installed via pip and then stored in a part of your computers file-system that you rarely step foot into.

Go Modular

To create a module simply:
  1. Create a folder in your working directory and give it a name. This will be the name of your module. The example below uses “extensions” as the module / folder name.
  2. Create an empty file in the folder with the name This signals to Python that the directory is a module.
Creating Modules
Created an extensions folder
Creating modules
  And that is it. We have a module. If you now try and import it from a script, you will not receive an error.
Importing the module
Opening python and importing the module
  Note: Your module name must not contain a dash - e.g. my-module. If it does, you will received a SyntaxError when trying to import it.


If you have followed along and imported the module, you may notice that a __pycache__folder has appeared in the directory. When you run a python program, the interpreter must convert your script to something called bytecode before it is executed. The pycache stores a cached version of the module in bytecode. This makes it a little quicker to run in future because it already converted and cached. You can largely ignore this folder. If you delete it, do not worry, it will be remade next time you run the module.

Back to our modules

So now we have a module, it is time to do something useful with it. Lets place an indicator inside the extensions folder so we can re-use the same indicator in multiple scripts. For this example I will take the pivot/swing indicator posted in the code snippet: Swing Indicator. When adding this code to the module we have a couple of options (which all boil down to personal preference):
  1. Create an file which contains all our indicators
  2. Create an indicators sub-module which then contains a python file for each indicator
First lets take the swing indicator code and paste it into a file called
import backtrader as bt

class SwingInd(bt.Indicator):
    A Simple swing indicator that measures swings (the lowest/highest value)
    within a given time period.
    lines = ('swings', 'signal')
    params = (('period',7),)

    def __init__(self):

        #Set the swing range - The number of bars before and after the swing
        #needed to identify a swing
        self.swing_range = (self.p.period * 2) + 1

    def next(self):
        #Get the highs/lows for the period
        highs =
        lows =
        #check the bar in the middle of the range and check if greater than rest
        if highs.pop(self.p.period) > max(highs):
            self.lines.swings[-self.p.period] = 1 #add new swing
            self.lines.signal[0] = 1 #give a signal
        elif lows.pop(self.p.period) < min(lows):
            self.lines.swings[-self.p.period] = -1 #add new swing
            self.lines.signal[0] = -1 #give a signal
            self.lines.swings[-self.p.period] = 0
            self.lines.signal[0] = 0
Notice that we still need to make an import call of another module inside our new module (import backtrader as bt). This is because the code inside it requires the Backtrader module. It does not matter if you have imported Backtrader in the script which imports the indicator. It still needs to be imported here. You should now have a directory that looks like this:
Extensions folder after adding the indicators module
After adding the indicators module

Import the Indicator

Finally, we should make a simple script that shall import the indicator.
import backtrader as bt
from datetime import datetime
from extensions.indicators import SwingInd

class simpleStrategy(bt.Strategy):

    def __init__(self):
        self.piv = SwingInd(period=7)

#Create an instance of cerebro
cerebro = bt.Cerebro(stdstats=False)

#Add our strategy

#Get Apple data from Yahoo Finance.
data = bt.feeds.YahooFinanceData(
    fromdate = datetime(2016,1,1),
    todate = datetime(2017,1,1),
    buffered= True

#Add the data to Cerebro

# Run over everything

#Finally plot the end results
You can see the line from extensions.indicators import SwingInd gives us access to the swing indicator without needing to add all the indicators code inside our script. Running the script will give you some output as follows. In it you can see the swing indicator has been added to the bottom of the chart. Imported Swing Indicator Results For further reading on creating modules and importing, take a look at these references:
  1. The official documentation:
  2. Another, more detailed tutorial on modules:

Find This Post Useful?

If this post saved you time and effort, please consider support the site! There are many ways to support us and some won’t even cost you a penny.