Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Developing an Indicator

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

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

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

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

backtrader (right now) is all about backtesting and has not been connectedto any live trading platform and may not even be (although I do believe thetechnical 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 byan 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 addeda 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 btimport backtrader.indicators as btindclass 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 ofthe platform I do truly believe my goal of being able to quickly experiment withnew 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 theindicator. This statement at the beginning of the class declarationgenerates a lot of background action during class creation and objectinstantiation.

    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 doprefer "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 theparameters 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 theshorthand "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 bluebut this is again pre-processing done in the background for theindicator.

      Any "data" passed to the indicator for calculation is intercepted andplaced in aself.datas array, where the usualself.datas[0]could be used to reach the first data.

      Shorthands do exist and look like: self.data and self.data0 for thefirst 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 calculationis 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 visualfeedback of what Trix is doing (even if Stockcharts has a nice essay on it).

Note

The actual Trix implemenation has some additionals bells and whistlesmostly itended to beautify plotting which are of no relevance for thispost.

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

from __future__ import (absolute_import, division, print_function,                        unicode_literals)import backtrader as btimport backtrader.feeds as btfeedsfrom mytrix import MyTrixclass 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 fullsize image), hopefully showing how quickly and easy an indicator can be createdand visually evaluated withbacktrader

image


[8]ページ先頭

©2009-2025 Movatter.jp