Skip to content

Developing an Indicator

After much ado in fine tuning backtrader (give it had already been running for a while) I decided to not only share it via GitHub but to also tell the world it was there and posted about its existence in "Reddit".

Following a comment about why trading/algorithmic trading platforms pop up and a private question about the platform supporting live trading for many simultenaous tickers I came to the conclusion that my own child deserved its own blog.

And here we are. But let’s focus on business.

backtrader is meant to let me experiment quickly with ideas and check what my eyes may have told me it may be a chance.

backtrader (right now) is all about backtesting and has not been connected to any live trading platform and may not even be (although I do believe the technical implementation would allow for it)

When I use the expression "experimenting with ideas" I mean two things:

  1. Being able to quickly draft an indicator and be able to visually evaluate its behavior

  2. Be it the case, engage in developing potential strategy around that indicator or a combination with others

My personal trading is 100% judgemental in that no single decision is taken by an automated system. But I look at what indicators have to tell. Whether the "indications" are really a signal or not, it’s left to my faulty human mind.

But let’s experiment. Right after publishing for the 1st time to Reddit I added a well known indicator:

  • Trix

Stockcharts has a nice discussion on Trix at: ChartSchool - Trix

Let’s experiment how to do it, with the minimum possible of lines:

from __future__ import (absolute_import, division, print_function,
                        unicode_literals)

import backtrader as bt
import backtrader.indicators as btind


class MyTrix(bt.Indicator):

    lines = ('trix',)
    params = (('period', 15),)

    def __init__(self):
        ema1 = btind.EMA(self.data, period=self.p.period)
        ema2 = btind.EMA(ema1, period=self.p.period)
        ema3 = btind.EMA(ema2, period=self.p.period)

        self.lines.trix = 100.0 * (ema3 - ema3(-1)) / ema3(-1)

And the Trix indicator is up and running. Looking at this and as the author of the platform I do truly believe my goal of being able to quickly experiment with new ideas with ease of use … has been reached.

A breakdown of the development:

  • lines = (‘trix’,)

    This tuple defines the output lines (just one in this case) of the indicator. This statement at the beginning of the class declaration generates a lot of background action during class creation and object instantiation.

    Suffice to say that the object has an attribute "lines" which hold the "trix".

    As a bonus and if the name "trix" is not used inside the indicator itself, the "line" could also be reached with "self.trix". But for clarity I do prefer "self.lines.trix"

    Additional access methods:

    • self.l.trix

    • self.lines[0] … being the index is the one corresponding to the position in the tuple

  • params = ((‘period’, 15),)

    This tuple of tuples (can also be a dict or OrderedDict) defines the parameters the indicator accepted and declares the default values.

    The burden of parsing kwargs is taken off the shoulders of the users.

    Parameters can be accessed with the "self.params.xxxxx" notation or with the shorthand "self.p.xxxxx"

  • The calculation (where EMA stands for ExponentialMovingAverage)

    • ema1 = btind.EMA(self.data, period=self.p.period)

      A new bonus is shown … "self.data". This seems to come out of the blue but this is again pre-processing done in the background for the indicator.

      Any "data" passed to the indicator for calculation is intercepted and placed in a self.datas array, where the usual self.datas[0] could be used to reach the first data.

      Shorthands do exist and look like: self.data and self.data0 for the first data in the array. From then onwards self.data1, self.data2.

      Trix only needs one data

    • ema2 = btind.EMA(ema1, period=self.p.period)

      Not much to say. EMA uses ema1 as input data

    • ema3 = btind.EMA(ema2, period=self.p.period)

      Even less to say

    • self.lines.trix = 100.0 * (ema3 - ema3(-1)) / ema3(-1)

      First and foremost a simple 1-period percentage difference calculation is done.

      The magic ema3(-1) is a notation to indicate: the previous value of ema.

      And the result of the calculation is assigned to the output "line" "trix" defined during class creation.

Easy Peasy. But "experimenting" would not be done if I didn’t get visual feedback of what Trix is doing (even if Stockcharts has a nice essay on it).

Note

The actual Trix implemenation has some additionals bells and whistles mostly itended to beautify plotting which are of no relevance for this post.

We assume we have put the MyTrix indicator in a mytrix.py file.

from __future__ import (absolute_import, division, print_function,
                        unicode_literals)

import backtrader as bt
import backtrader.feeds as btfeeds

from mytrix import MyTrix


class NoStrategy(bt.Strategy):
    params = (('trixperiod', 15),)

    def __init__(self):
        MyTrix(self.data, period=self.p.trixperiod)


if __name__ == '__main__':
    # Create a cerebro entity
    cerebro = bt.Cerebro()

    # Add a strategy
    cerebro.addstrategy(NoStrategy, trixperiod=15)

    # Create a Data Feed
    datapath = ('../datas/2006-day-001.txt')
    data = bt.feeds.BacktraderCSVData(dataname=datapath)

    # Add the Data Feed to Cerebro
    cerebro.adddata(data)

    # Run over everything
    cerebro.run()

    # Plot the result
    cerebro.plot()

And the visual output is below (open the chart in a new window/tab for a full size image), hopefully showing how quickly and easy an indicator can be created and visually evaluated with backtrader

image