Backtrader规范与非规范

  |  

这个问题或多或少地出现了几次:这样:

  • backtrader如何最好/规范地实现这一点或那样?

作为 backtrader 的目标之一,可以灵活地 支持尽可能多的情况和用例,答案很简单:“至少在几种方式上”。针对指针进行汇总,对于这些问题最常发生的情况:

  • 方法中__init__ 100% 声明性

  • 100%逐步next 的方法

  • 对于声明性部分无法涵盖所有必需计算的复杂方案,混合上述两者

快速查看 backtrader 中的内置指针可发现所有这些指针都是以声明性方式实现的。原因

  1. 更容易做到

  2. 更易于阅读

  3. 更优雅

  4. 自动管理矢量化和基于偶数的实现

什么?!?!自动实现的矢量化??

是的。如果指针完全在方法内部__init_ 实现,那么Python中元类和操作数重载的魔力将提供以下内容

  • 矢量化实现(运行回溯测试时的缺省设置)

  • 基于事件的实现(例如,用于即时交易)

另一方面,如果在方法中next 实现的指针的任何部分:

  • 这是直接用于基于事件的运行的代码。

  • 矢量化将通过在每个数据点的next 后台调用方法来模拟

    注意

    这意味着,即使特定指针没有矢量化实现,所有其他拥有它的指针仍将以矢量化方式运行。

资金流量指数:一个例子

社区用户@Rodrigo Brito 发布了一个版本的「资金流量指数」 指针,该指针使用该 next 方法进行实施。

代码

class MFI(bt.Indicator):
    lines = ('mfi', 'money_flow_raw', 'typical', 'money_flow_pos', 'money_flow_neg')

    plotlines = dict(
        money_flow_raw=dict(_plotskip=True),
        money_flow_pos=dict(_plotskip=True),
        money_flow_neg=dict(_plotskip=True),
        typical=dict(_plotskip=True),
    )

    params = (
        ('period', 14),
    )

    def next(self):
        typical_price = (self.data.close[0] + self.data.low[0] + self.data.high[0]) / 3
        money_flow_raw = typical_price * self.data.volume[0]

        self.lines.typical[0] = typical_price
        self.lines.money_flow_raw[0] = money_flow_raw

        self.lines.money_flow_pos[0] = money_flow_raw if self.lines.typical[0] >= self.lines.typical[-1] else 0
        self.lines.money_flow_neg[0] = money_flow_raw if self.lines.typical[0] <= self.lines.typical[-1] else 0

        pos_period = math.fsum(self.lines.money_flow_pos.get(size=self.p.period))
        neg_period = math.fsum(self.lines.money_flow_neg.get(size=self.p.period))

        if neg_period == 0:
            self.lines.mfi[0] = 100
            return

        self.lines.mfi[0] =  100 - 100 / (1 +  pos_period / neg_period)

注意

保持原样,包括长 lines ,必须水平滚动

@Rodrigo布里托已经注意到,临时lines的使用(除了mfilines除外)可能是承认优化的东西。确实,但以作者*的拙见,实际上一切都承认一些优化。

为了有共同的工作基础,可以使用StockCharts的「资金流量指数」定义,并看到上面的实现是好的。这是链接:

有了这个,指针的快速规范实现MFI

class MFI_Canonical(bt.Indicator):
    lines = ('mfi',)
    params = dict(period=14)

    def __init__(self):
        tprice = (self.data.close + self.data.low + self.data.high) / 3.0
        mfraw = tprice * self.data.volume

        flowpos = bt.ind.SumN(mfraw * (tprice > tprice(-1)), period=self.p.period)
        flowneg = bt.ind.SumN(mfraw * (tprice < tprice(-1)), period=self.p.period)

        mfiratio = bt.ind.DivByZero(flowpos, flowneg, zero=100.0)
        self.l.mfi = 100.0 - 100.0 / (1.0 + mfiratio)

人们应该能够立即注意到

  • 定义了单个 linemfi 。没有临时工。

  • 事情看起来更干净,不需要[0] 数组索引

  • 这里或那里没有单曲if

  • 更紧凑,更易读

如果一个人绘制一个图表,两者都针对相同的数据集运行,它看起来像这样

该图表显示,规范版本和非规范版本显示相同的值和发展,除了在开头

  • 非规范版本从一开始就提供价值

  • 它传递的是无意义的值(100.0 直到它传递 1 个额外的值,这也是不好的),因为它不能正确传递

相比之下:

  • 规范版本在达到最小预热期 后自动开始提供值。

  • 不需要人工干预(它必须肯定是「人工智能」或「机器学习」,...双关语

查看受影响区域的 close图片

注意

当然,在非规范版本中,可以通过这样做来缓解这种情况:

  • 子类化,其中bt.ind.PeriodN已经有一个period参数,并且知道如何处理它(并在 期间__init__调用super

另请注意,规范版本也考虑了公式中可能的零除情况的分步next 代码。

        if neg_period == 0:
            self.lines.mfi[0] = 100
            return

        self.lines.mfi[0] =  100 - 100 / (1 +  pos_period / neg_period)

而这是另一种方式

        mfiratio = bt.ind.DivByZero(flowpos, flowneg, zero=100.0)
        self.l.mfi = 100.0 - 100.0 / (1.0 + mfiratio)

没有许多lines,一个return语句和对输出line的不同赋值,有计算的单个声明mfiratio和单个赋值(遵循StockCharts公式)到输出linemfi

结论

希望这能揭示一些在以规范(即:声明性__init_)或非规范方式(逐步与数组索引) next实现某些内容时的差异。

推荐阅读

相关文章

Backtrader对逐笔报价数据重新采样

backtrader 已经可以从分钟数据中重新采样。接受价格变动数据不是问题,只需将 4 个常用字段(open、 high、 low、 close)设置为价格变动值。 但是传递要重新采样的逐笔报价数据再次生成相同的数据。作为或版本 1.1.11.88,情况已不再如此。

Backtrader教程:数据馈送 - 重新采样

如果数据仅在单个时间范围内可用,并且必须在不同的时间范围内进行分析,则是时候进行一些重新采样了。 “重采样”实际上应该称为“上采样”,因为一个人从源时间帧到更大的时间帧(例如:几天到几周) backtrader 内置支持通过筛选器对象传递原始数据,从而进行重采样。

Backtrader绘制日期范围

该版本1.9.31.x 增加了制作部分绘图的功能。 使用策略实例中保存的完整时间戳数组的索引 或者使用实际datetime.date 或 datetime.datetime 实例来限制必须绘制的内容。 一切都超过标准cerebro.plot。

Backtrader教程:过滤器 - 参考

工作阶段筛检程序 类 backtrader.filters。

Backtrader智能质押

版本 1.6.4.93 标志着 backtrader 的一个重要里程碑,即使版本号的更改很小。 职位大小调整是阅读Van K. Tharp的《Trade Your Way To Financial Freedom 》后,为这个项目奠定基础的事情之一。

Backtrader教程:绘图 - 日期范围

该版本1.9.31.x 增加了制作部分绘图的功能。 使用策略实例中保存的完整时间戳数组的索引 或者使用实际datetime.date 或 datetime.datetime 实例来限制必须绘制的内容。 一切都超过标准cerebro.plot。

Backtrader混合时间帧

1.3.0.92版本带来了混合来自不同时间帧的数据(来自 data feeds 和/或指针)的可能性。 到版本:https://github.com/mementum/backtrader/发布/标签/1.3.0.92 背景:指示器是智能哑对象。 他们很聪明,因为他们可以进行复杂的计算。

Backtrader蟒蛇隐藏的力量3

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

Backtrader 多数据范例

社区中的几个主题似乎以如何跟踪订单为导向,特别是当几个data feeds在起作用时,还包括当多个订单一起工作时,

Backtrader现实咬合

上一篇文章设法拷贝了该BTFD 策略,发现真正的收益 16x 而不是 31x。 但正如拷贝期间所指出的: 不收取佣金 使用2x 杠杆不收取利息 这就提出了一个显而易见的问题: 当收取佣金和利息时,这16x中有多少会存在? 幸运的是,前面的示例足够灵活,可以对其进行试验。