Backtrader教程:指针 - 开发

  |  

如果必须开发任何东西(除了一个或多个获胜策略之外),那么这个东西就是一个自定义指针。

根据作者的说法,平台内的这种开发很容易。

需要满足以下条件:

  • 从指针派生的类(直接或从现有的子类派生)

  • 定义它将保持lines

    指针必须至少具有 1 line。如果从现有派生,则可能已定义line

  • (可选)定义可以改变行为的参数

  • 可选地提供/自定义一些元素,这些元素可以合理地绘制指针

  • 提供__init__ 完全定义的操作,并将绑定(赋值)到指针的 line,或者提供 next 和(可选) once 方法

    如果在初始化期间可以使用逻辑/算术运算完全定义指针,并将结果分配给 line: 完成

    如果不是这种情况,至少必须提供 anext ,其中指针必须为索引 0 处的 line赋值

    通过提供一次方法,可以优化运行 模式(批处理操作)的计算。

重要提示:幂等性

指针为它们收到的每个柱产生一个输出。无需假设同一柱将被发送多少次。操作必须是幂等的。

这背后的基本原理:

  • 同一根柱线(指数方面)可以多次发送,值会发生变化(即变化的值是收盘价)

例如,这可以「重放」每日会话,但使用可以由5分钟柱组成的日内数据。

它还可以允许平台从即时源中获取值。

虚拟(但功能性)指示器

那么它可以是:

class DummyInd(bt.Indicator):
    lines = ('dummyline',)

    params = (('value', 5),)

    def __init__(self):
        self.lines.dummyline = bt.Max(0.0, self.params.value)

做!指针将始终输出相同的值:0.0 或 self.params.value(如果它恰好大于 0.0)。

相同的指针,但使用下一个方法:

class DummyInd(bt.Indicator):
    lines = ('dummyline',)

    params = (('value', 5),)

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

做!相同的行为。

注意

请注意如何在__init__ 版本中 bt.Max 用于分配给 Line 对象 self.lines.dummyline

bt.Max 返回一个 lines 对象,该对象针对传递给指针的每个柱自动反复运算。

如果max 被使用,assigment将是毫无意义的,因为指针将具有具有固定值的成员变量,而不是 line

在工作期间next 直接使用浮点值完成,并且可以使用标准 max 内置

让我们回想一下,self.lines.dummyline 这是长符号,它可以缩短为:

  • self.l.dummyline

甚至:

  • self.dummyline

后者只有在代码没有用成员属性遮盖它时才有可能。

第 3 和第 last 版提供了优化计算的附加 once 方法:

class DummyInd(bt.Indicator):
    lines = ('dummyline',)

    params = (('value', 5),)

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

    def once(self, start, end):
       dummy_array = self.lines.dummyline.array

       for i in xrange(start, end):
           dummy_array[i] = max(0.0, self.params.value)

更有效,但开发该once 方法已迫使划伤表面。实际上,已经研究了胆量。

无论如何,该__init__ 版本都是最好的:

  • 一切都局限于初始化

  • nextonce (两者都经过优化,因为 bt.Max 已经有了它们)自动提供,无需使用索引和/或公式

无论是开发需要的,指针还可以覆盖与 和 once相关的next方法:

  • prenextnexstart

  • preonceoncestart

手动/自动最短周期

如果可能的话,平台将计算它,但可能需要手动操作。

以下是简单移动平均线的潜在实现:

class SimpleMovingAverage1(Indicator):
    lines = ('sma',)
    params = (('period', 20),)

    def next(self):
        datasum = math.fsum(self.data.get(size=self.p.period))
        self.lines.sma[0] = datasum / self.p.period

虽然看起来不错,但平台不知道最小周期是什么,即使参数被命名为“period”(名称可能具有误导性,并且某些指针会收到几个具有不同用法的“period”)

在这种情况下next ,已经调用了第1 柱,并且everthing会爆炸,因为get无法返回所需的 self.p.period

在解决这种情况之前,必须考虑一些事情:

  • 传递给指针的 data feeds 可能已经具有 最小周期

示例 SimpleMovingAverage 可以在例如以下方面完成:

  • 一般 data feed

    这有一个缺省的最小周期 1 (只需等待进入系统的第 1 根 柱线)

  • 另一条移动平均线...而这又已经有一个句号

    如果这是 20,并且我们的样本移动平均线也有 20,我们最终得到的最小周期为 40 根柱线

    实际上,内部计算显示39 ...因为一旦第一条移动平均线产生了一根柱线,这就会计入下一条移动平均线,这会创建一个重叠的柱线,因此需要39个。

  • 其他也带有周期的指针/对象

缓解这种情况的做法如下:

class SimpleMovingAverage1(Indicator):
    lines = ('sma',)
    params = (('period', 20),)

    def __init__(self):
        self.addminperiod(self.params.period)

    def next(self):
        datasum = math.fsum(self.data.get(size=self.p.period))
        self.lines.sma[0] = datasum / self.p.period

addminperiod 方法是告诉系统考虑该指针所需的额外周期柱,以达到可能存在的任何最小周期。

有时,如果所有计算都是使用已经将其周期需求传达给系统的对象完成的,则绝对不需要这样做。

使用直方图的快速 MACD 实现:

from backtrader.indicators import EMA

class MACD(Indicator):
    lines = ('macd', 'signal', 'histo',)
    params = (('period_me1', 12), ('period_me2', 26), ('period_signal', 9),)

    def __init__(self):
        me1 = EMA(self.data, period=self.p.period_me1)
        me2 = EMA(self.data, period=self.p.period_me2)
        self.l.macd = me1 - me2
        self.l.signal = EMA(self.l.macd, period=self.p.period_signal)
        self.l.histo = self.l.macd - self.l.signal

做!无需考虑最小周期。

  • EMA 代表指数移动平均线(平台内置别名)

    这个(已经在平台中)已经说明了它需要什么

  • 指针 「macd」 和 「signal」 的命名 lines 正在被分配对象,这些对象已经带有声明的(幕后)周期

    • macd 从操作「me1 - me2」中获取周期,而操作又从 me1 和 me2 的周期中获取最大值(这两个周期都是具有不同周期的指数移动平均线)

    • 信号直接取麦克德上指数移动平均线的周期。此 EMA 还考虑了已经存在的 macd 周期和计算自身所需的样本量 (period_signal)

    • histo 取两个操作数“信号 - macd”中的最大值。一旦两者都准备好了,histo也可以产生价值

完整的自订指针

让我们开发一个简单的自定义指针,它「指示」移动平均线(可以用参数修改)是否高于给定数据:

import backtrader as bt
import backtrader.indicators as btind

class OverUnderMovAv(bt.Indicator):
    lines = ('overunder',)
    params = dict(period=20, movav=btind.MovAv.Simple)

    def __init__(self):
        movav = self.p.movav(self.data, period=self.p.period)
        self.l.overunder = bt.Cmp(movav, self.data)

做!如果平均值高于数据,则指针的值为“1”;如果低于数据,则指针的值为“-1”。

作为常规 data feed 1和-1将与 close 价格相比产生1和-1的数据。

虽然在绘图部分可以看到更多,并且在绘图世界中有一个举止和善良的公民,但可以添加一些东西:

import backtrader as bt
import backtrader.indicators as btind

class OverUnderMovAv(bt.Indicator):
    lines = ('overunder',)
    params = dict(period=20, movav=bt.ind.MovAv.Simple)

    plotinfo = dict(
        # Add extra margins above and below the 1s and -1s
        plotymargin=0.15,

        # Plot a reference horizontal line at 1.0 and -1.0
        plothlines=[1.0, -1.0],

        # Simplify the y scale to 1.0 and -1.0
        plotyticks=[1.0, -1.0])

    # Plot the line "overunder" (the only one) with dash style
    # ls stands for linestyle and is directly passed to matplotlib
    plotlines = dict(overunder=dict(ls='--'))

    def _plotlabel(self):
        # This method returns a list of labels that will be displayed
        # behind the name of the indicator on the plot

        # The period must always be there
        plabels = [self.p.period]

        # Put only the moving average if it's not the default one
        plabels += [self.p.movav] * self.p.notdefault('movav')

        return plabels

    def __init__(self):
        movav = self.p.movav(self.data, period=self.p.period)
        self.l.overunder = bt.Cmp(movav, self.data)

推荐阅读

相关文章

Backtrader按日线交易

似乎在世界某个地方有一种权益(Interest)可以总结如下: 使用每日柱线引入订单,但使用开盘价 这来自工单#105订单执行逻辑与当前数据和#101动态投注计算中的对话 backtrader 尝试尽可能保持现实,并且在处理每日柱线时适用以下前提: 当每日柱被评估时,柱线已经结束 这是有道理的,

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

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

Backtrader教程:安装

要求和版本 backtrader 是独立的,没有外部依赖关系(除非要绘图) 基本要求是: Python 2.7 Python 3.2 / 3.3/ 3.4 / 3.5 pypy/pypy3 如果需要绘图,则其他要求: Matplotlib >= 1.4.

Backtrader期货补偿与现货补偿

版本1.9.32.116 增加了对社区中呈现的有趣用例 的支持 以期货开始交易,包括实物交割 让一个指针告诉你一些事情 如果需要, close 现货价格操作,有效地取消实物交割,无论是为了接收货物还是为了必须交付货物(并希望获利)来头寸。

Backtrader教程:操作平台

Line 反复运算器 为了参与操作,plaftorm使用 line 反复运算器的概念。它们已经松散地模仿了Python的反复运算器,但实际上与它们无关。 策略和指针是 line 反复运算器。

Backtrader教程:日志记录 - 编写器

将以下内容写出到流中: csv 流,

Backtrader跨越数字

《backtrader》的发布1.9.27.105纠正了一个疏忽。这是一个疏忽,因为拼图的所有部分都已到位,但启动并不是在所有角落都进行的。 该机制使用一个名为的属性_mindatas,因此让我们将其称为: mindatas。 社区问了这个问题,答案并不是很到位。

数据多时间帧

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

Backtrader 多数据范例

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

Backtrader教程:数据馈送 - 熊猫

注意 pandas 并且必须安装其依赖项 支持Pandas Dataframes似乎受到很多人的关注,他们依赖于已经可用的解析代码来分析不同的数据源(包括CSV)和Pandas提供的其他功能。 数据馈送的重要声明。 注意 这些只是 声明。不要盲目拷贝此代码。