Backtrader实际使用方式

  |  

最后,似乎已经付出了开发 backtrader是值得的。

在观察 last 周的欧洲市场时,似乎世界末日了,一位朋友问我是否可以看看我们图表包中的数据,看看与以前类似情况相比,下跌幅度如何。

当然可以,但我说我可以做的不仅仅是查看图表,因为我可以快速:

  • 创建一个快速LegDown 指示器来测量跌落的范围。它也可能被命名为 HighLowRangeHiLoRange。幸运的是,如果这被认为是必要的,可以通过以下方式解决 alias

  • 创建一个LegDownAnalyzer 将收集结果并对其进行排序的

这导致了一个额外的请求:

  • 未来5天,10天,15天,20天跌后的复苏(交易...

    通过一个LegUp 指针解决,该指针将值写回以与相应的“LegDown”对齐

工作很快完成(在我的空闲时间内),并与请求者分享了结果。但。。。作为我看到的唯一问题:

  • 自动化方面的改进bt-run.py

    • 多种策略/observers/analyzers ,具有分离的kwargs

    • 将指针直接注入策略,每个指针都有 kwargs

    • 单一情节论证也接受瓦格斯

  • API 中的Analyzer 改进,使结果具有自动 打印 功能(作为 dict 类似 -的实例返回)并具有直接 data 访问别名

尽管如此:

  • 由于我编写的实现组合,出现了一个晦涩的错误,通过混合声明和附加使用来对齐LegDownLegUpnext

    引入该错误是为了简化单个数据与多个Lines数据的传递,以便 Indicators 可以作为单个数据对每个 lines 进行操作

后者将我推入:

  • 添加一个与LineDelay “展望”“未来”相反的背景对象

    这实际上意味着实际值被写入过去的数组位置

一旦上述所有问题都到位,就该重新测试上述请求带来的(小?)挑战可以更容易,更快地(在实现时间内)解决得有多好。

最后,从1998年到今天,Eurostoxx 50 Future的运行和结果:

bt-run.py \
    --csvformat vchartcsv \
    --data ../datas/sample/1998-2015-estx50-vchart.txt \
    --analyzer legdownup \
    --pranalyzer \
    --nostdstats \
    --plot

====================
== Analyzers
====================
##########
legdownupanalyzer
##########
Date,LegDown,LegUp_5,LegUp_10,LegUp_15,LegUp_20
2008-10-10,901.0,331.0,69.0,336.0,335.0
2001-09-11,889.0,145.0,111.0,239.0,376.0
2008-01-22,844.0,328.0,360.0,302.0,344.0
2001-09-21,813.0,572.0,696.0,816.0,731.0
2002-07-24,799.0,515.0,384.0,373.0,572.0
2008-01-23,789.0,345.0,256.0,319.0,290.0
2001-09-17,769.0,116.0,339.0,405.0,522.0
2008-10-09,768.0,102.0,0.0,120.0,208.0
2001-09-12,764.0,137.0,126.0,169.0,400.0
2002-07-23,759.0,331.0,183.0,285.0,421.0
2008-10-16,758.0,102.0,222.0,310.0,201.0
2008-10-17,740.0,-48.0,219.0,218.0,116.0
2015-08-24,731.0,nan,nan,nan,nan
2002-07-22,729.0,292.0,62.0,262.0,368.0
...
...
...
2001-10-05,-364.0,228.0,143.0,286.0,230.0
1999-01-04,-370.0,219.0,99.0,-7.0,191.0
2000-03-06,-382.0,-60.0,-127.0,-39.0,-161.0
2000-02-14,-393.0,-92.0,90.0,340.0,230.0
2000-02-09,-400.0,-22.0,-46.0,96.0,270.0
1999-01-05,-438.0,3.0,5.0,-107.0,5.0
1999-01-07,-446.0,-196.0,-6.0,-82.0,-50.0
1999-01-06,-536.0,-231.0,-42.0,-174.0,-129.0

2015年8月的回合排名第13。显然,一个不常见的现象,尽管发生了更大的情况。

对于静态主义者和聪明的数学头脑来说,从指向上方的后续腿中该做什么比我多得多。

有关实现的详细信息(请参阅末尾的整个模块代码):LegUpDownAnalyzer

  • 它像其他对象一__init__ 样创建指针: StrategiesIndicators 通常是通常的嫌疑人

    这些指针会自动注册到分析器所附加到的策略中

  • 就像策略一样,Analyzer 它有 self.datas (一个数据数字)和别名: self.dataself.data0self.data1 ...

  • 再次像策略:nexstartstop 钩子(指针中不存在这些钩子)

    在这种情况下,用于:

    • nextstart:记录策略的初始起点

    • stop:因为事情已经完成而进行最终计算

  • 注意:其他方法,如startnextprenext在这种情况下不需要

  • LegDownUpAnalyzer 方法 print 已被覆盖,不再调用该 pprint 方法,而是创建计算的CSV打印输出

经过多次交谈,由于我们加入了--plot 混合...图表。

最后是由legupdown 加载的 bt-run模块。

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

import itertools
import operator

import six
from six.moves import map, xrange, zip

import backtrader as bt
import backtrader.indicators as btind
from backtrader.utils import OrderedDict


class LegDown(bt.Indicator):
    '''
    Calculates what the current legdown has been using:
      - Current low
      - High from ``period`` bars ago
    '''
    lines = ('legdown',)
    params = (('period', 10),)

    def __init__(self):
        self.lines.legdown = self.data.high(-self.p.period) - self.data.low


class LegUp(bt.Indicator):
    '''
    Calculates what the current legup has been using:
      - Current high
      - Low from ``period`` bars ago

    If param ``writeback`` is True the value will be written
    backwards ``period`` bars ago
    '''
    lines = ('legup',)
    params = (('period', 10), ('writeback', True),)

    def __init__(self):
        self.lu = self.data.high - self.data.low(-self.p.period)
        self.lines.legup = self.lu(self.p.period * self.p.writeback)


class LegDownUpAnalyzer(bt.Analyzer):
    params = (
        # If created indicators have to be plotteda along the data
        ('plotind', True),
        # period to consider for a legdown
        ('ldown', 10),
        # periods for the following legups after a legdown
        ('lups', [5, 10, 15, 20]),
        # How to sort: date-asc, date-desc, legdown-asc, legdown-desc
        ('sort', 'legdown-desc'),
    )

    sort_options = ['date-asc', 'date-des', 'legdown-desc', 'legdown-asc']

    def __init__(self):
        # Create the legdown indicator
        self.ldown = LegDown(self.data, period=self.p.ldown)
        self.ldown.plotinfo.plot = self.p.plotind

        # Create the legup indicators indicator - writeback is not touched
        # so the values will be written back the selected period and therefore
        # be aligned with the end of the legdown
        self.lups = list()
        for lup in self.p.lups:
            legup = LegUp(self.data, period=lup)
            legup.plotinfo.plot = self.p.plotind
            self.lups.append(legup)

    def nextstart(self):
        self.start = len(self.data) - 1

    def stop(self):
        # Calculate start and ending points with values
        start = self.start
        end = len(self.data)
        size = end - start

        # Prepare dates (key in the returned dictionary)
        dtnumslice = self.strategy.data.datetime.getzero(start, size)
        dtslice = map(lambda x: bt.num2date(x).date(), dtnumslice)
        keys = dtslice

        # Prepare the values, a list for each key item
        # leg down
        ldown = self.ldown.legdown.getzero(start, size)
        # as many legs up as requested
        lups = [up.legup.getzero(start, size) for up in self.lups]

        # put legs down/up together and interleave (zip)
        vals = [ldown] + lups
        zvals = zip(*vals)

        # Prepare sorting options
        if self.p.sort == 'date-asc':
            reverse, item = False, 0
        elif self.p.sort == 'date-desc':
            reverse, item = True, 0
        elif self.p.sort == 'legdown-asc':
            reverse, item = False, 1
        elif self.p.sort == 'legdown-desc':
            reverse, item = True, 1
        else:
            # Default ordering - date-asc
            reverse, item = False, 0

        # Prepare a sorted array of 2-tuples
        keyvals_sorted = sorted(zip(keys, zvals),
                                reverse=reverse,
                                key=operator.itemgetter(item))

        # Use it to build an ordereddict
        self.ret = OrderedDict(keyvals_sorted)

    def get_analysis(self):
        return self.ret

    def print(self, *args, **kwargs):
        # Overriden to change default behavior (call pprint)
        # provides a CSV printout of the legs down/up
        header_items = ['Date', 'LegDown']
        header_items.extend(['LegUp_%d' % x for x in self.p.lups])
        header_txt = ','.join(header_items)
        print(header_txt)

        for key, vals in six.iteritems(self.ret):
            keytxt = key.strftime('%Y-%m-%d')
            txt = ','.join(itertools.chain([keytxt], map(str, vals)))
            print(txt)

推荐阅读

相关文章

Backtrader期货展期

并非每个供应商都为可以交易的工具提供连续的未来。有时提供的数据是仍然有效的到期日期的数据,即:仍在交易的日期 这在回溯测试方面并不是很有帮助,因为数据分散在几个不同的仪器上,这些仪器另外...时间重叠。 能够正确地将这些仪器的数据从过去连接到连续的流中,可以减轻疼痛。

Backtrader教程:分析仪

无论是回溯测试还是交易,能够分析交易系统的性能是了解是否不仅获得了利润,而且是否在风险太大的情况下实现了利润,或者与参考资产(或无风险资产)相比,是否真的值得付出努力的关键。 这就是对象家族的用武之Analyzer 地:提供对所发生事件甚至实际发生的事情的分析。

Backtrader教程:数据馈送 - 展期交割

并非每个供应商都为可以交易的工具提供连续的未来。有时提供的数据是仍然有效的到期日期的数据,即:仍在交易的日期 这在回溯测试方面并不是很有帮助,因为数据分散在几个不同的仪器上,这些仪器另外...时间重叠。 能够正确地将这些仪器的数据从过去连接到连续的流中,可以减轻疼痛。

Backtrader教程:Cerebro - 优化 - 改进

backtrader版本1.8.12.99改进了在多处理过程中管理data feeds和结果的方式。

Backtrader交叉回溯测试陷阱

在backtrader 社区中 ,倾向于重复的事情是,用户解释了拷贝在例如 TradingView 中获得的回溯测试结果的意愿,这些天非常流行,或者其他一些回溯测试平台。

Backtrader教程:日期时间 - 管理

在 1.5.0 版之前, backtrader 使用直接的方法来进行时间管理,因为数据源计算的任何日期时间都只是按面值使用。 对于任何用户输入也是如此,例如可以提供给任何数据源的参数fromdate (或 sessionstart)的情况 考虑到直接控制冻结的数据源以进行回溯测试,这种方法很好。

Backtrader蟒蛇隐藏的力量3

Last,但并非最不重要的一点是,在这个系列中,关于如何在 backtrader 中使用Python的隐藏功能是一些神奇变量是如何出现的。

Backtrader信号策略

操作 backtrader 也是可能的,而无需编写策略。虽然这是首选方式,但由于构成机器的对象层次结构,使用信号也是可能的。

Backtrader开发指针

经过 backtrader 微调(因为它已经运行了一段时间),我决定不仅通过GitHub分享它,还告诉世界它在那里,并在“Reddit”中发布它的存在。 在评论了为什么交易/算法交易平台会弹出,以及关于支持许多同时交易的即时交易的平台的私人问题之后,我得出的结论是,我自己的孩子应该拥有自己的博客。 我们来了。

Backtrader教程:数据馈送 - 多个时间帧

有时投资决策是使用不同的时间框架做出的: 每周评估趋势 每天运行条目 或者5分钟对60分钟。 这意味着需要组合多个时间帧的数据backtrader 来支持这种组合。 对它的本机支持已经内置。