An article on quantitative framework backtrader to understand the Indicator indicator


The previous series of articles have introduced the principles and application scenarios of technical indicators such as SMA, EMA, MACD, KDJ, RSI, and BOLL. If you haven’t seen it yet, it is recommended to follow the official account to check it out.

The Backtrader framework has more than 100 built-in technical analysis indicators, which are encapsulated in the backtrader.indicators package, which can greatly reduce development costs and increase the speed of strategy iteration.


Indicators indicators can be used in two places: one is used in strategies; the other is used in other indicators.

Using the built-in indicators in Backtrader is very easy, just:

  • Instantiate the corresponding indicator in the __init__ method of the strategy

  • Use or check the corresponding indicator value or its derivative value in the next method

Below is an example of using the SMA simple moving average indicator.

import backtrader as bt

class MyStrategy(bt.Strategy):
    params = (('period', 20),)

    def __init__(self):
        self.sma = bt.indicators.SMA(, period=self.p.period)

    def next(self):
       if self.sma[0] >[0]:

It should be noted:

  • Any metrics declared in the __init__ method will be calculated before the next method is called

  • Any operation on the lines object in the __init__ method will generate other line objects (python operator overloading), while the next method will generate regular python types, such as floats or bools

  • The __init__ method operates faster and makes the logic of the next method simpler.

  • The __init__ method does not support some python operators and needs to be processed using bt built-in functions, such as bt.And, bt.Or, bt.All, bt.Any. In addition to these, backtrader also provides bt.Cmp, bt.If, bt.Max, bt.Min, bt.Sum, bt.DivByZero and other functions

The list of native indicators supported by backtrader can be viewed on the official website: Indicators - Reference - Backtrader

It should be noted that backtrader also supports indicator aliases, such as SMA can also be written as MovingAverageSimple or SimpleMovingAverage


SMA, SimpleMovingAverage
Non-weighted average of the last n periods


movav = Sum(data, period) / period

Using TA-Lib

Although Backtrader comes with many indicators, it is relatively easy to add new indicators. However, because TA-lib is widely used, everyone trusts it, and backtrader also integrates TA-Lib.

import backtrader as bt

class MyStrategy(bt.Strategy):
    params = (('period', 20),)

    def __init__(self):
        self.sma = bt.talib.SMA(, timeperiod=self.p.period)

The above is an example of using SMA in talib in backtrader. It can be seen that the usage method is not much different.

Help documentation can be viewed through  print(bt.talib.SMA.__doc__) .

>>> print(bt.talib.SMA.__doc__)
SMA([input_arrays], [timeperiod=30])

Simple Moving Average (Overlap Studies)

    price: (any ndarray)
    timeperiod: 30

The list of talib indicators supported by backtrader can be viewed on the official website: Indicators - ta-lib - Reference - Backtrader

Custom indicators

# 继承自bt.Indicator或其他已存在的指标类
class DummyInd(bt.Indicator):
    # 定义持有的lines,至少需要1个line
    lines = ('dummyline',)
    # params参数可选
    params = (('value', 5),)

    # plotinfo可选,用来控制绘图行为
    plotinfo = dict(subplot=False)

    # __init__方法或next方法必选
    def __init__(self):
        self.lines.dummyline = bt.Max(0.0, self.params.value)

In the sample code, this indicator will output 0.0, or self.params.value, depending on whether self.params.value is greater than 0.0.

In addition to implementing it in the __init__ method, the indicator calculation can also be implemented in the next method, as shown below.

    def next(self):
        self.lines.dummyline[0] = max(0.0, self.params.value)

In addition to efficiency and readability, when it comes to the peroid minimum period, the next method needs to handle it by itself, and the __init__ method does not need special processing. Therefore, the best way is to implement it in the __init__ method. If it cannot be implemented, consider implementing it in the next method. The runonce mode can also be calculated and optimized through the once method.

Metric visualization

If the program calls cerebro.plot, then

  • All declared indicators are plotted automatically

  • The lines object generated by the operation will not be drawn, such asclose_over_sma = > self.sma

  • If you want to draw the lines object generated by the operation, you can use LinePlotterIndicator the class. The name parameter is the name of the line held by the indicator.

close_over_sma = > self.sma
LinePlotterIndicator(close_over_sma, name='Close_over_SMA')

The plotting of the indicator can be controlled through the plotinfo declaration. plotinfo can be tuple, dict or OrderedDict.

class MyIndicator(bt.Indicator):

    plotinfo = dict(subplot=False)

# 可以实例化后单独设置
myind = MyIndicator(, someparam=value)
myind.plotinfo.subplot = True

# 也可以实例化时设置
myind = MyIndicator(, someparams=value, subplot=True)

The parameter list of plotinfo is: plot (whether to draw, the default is True), subplot (whether to draw in a separate window, the default is True, this parameter is False for MA class indicators), plotname (the name of the indicator chart, the default is the indicator class name), plotabove (plot position is above the data, default is False), plotlinelabels, plotymargin, plotyticks, plotlines, plotyhlines, plotforce.

Conclusion & Communication

Follow the WeChat public account: Zhuge Shuo Talk for more content. At the same time, you can also get an invitation to join the quantitative investment seminar group to communicate and discuss with many practitioners and technical experts. The number of places is limited, so don’t miss it.

Writing articles is not easy. If you think this article is helpful to you, please give it a thumbs up and forward it to give me the motivation to keep writing good articles.


Guess you like