量化交易学习(三十四)backtrader文档——指标的开发
今天这篇是backtrader文档的学习笔记。主要介绍了怎样开发指标。
官方文档链接:https://www.backtrader.com/docu/inddev/
指标开发
如果必须开发任何东西(除了一个或多个获胜策略之外),那么这个东西就是自定义指标。
自定义指标的开发要做以下事情:
-
从 Indicator 派生的类(直接派生或从现有子类派生)
-
定义它将持有的线对象
指标必须至少有 1 条线。如果从现有线对象派生,则线对象可能已经定义
-
可以选择定义改变指标行为的参数
-
可选择提供/定制一些能够合理绘制指标的元素
-
在__init__中完全定义一个绑定(赋值)了指标类中行对象的运算,或者定义next及once(可选)方法
如果指标可以在初始化期间用逻辑/算术运算完全定义,并将结果分配给线对象。
如果不是这种情况,则必须定义一个next方法,给线对象索引为 0 处赋值
通过定义once方法可以实现runonce模式(批量操作)计算的优化。
重要注意事项:幂等性
指标为它们收到的每个柱数据产生一个输出。无需假设同一个柱数据将被发送多少次。操作必须是幂等的。
这背后的理由:
- 同一个柱(按索引)可以多次发送,并且值不断变化(即变化的值是收盘价)
例如,这使得能够“重放”每日走势,但可使用由 5 分钟柱线组成的日内数据。
它还可以让平台从实时数据源中获取数据。
模拟的(作为演示的)指标
那么是否可以是:
1 | class DummyInd(bt.Indicator): |
完毕!该指标将始终输出相同的值:如果恰好大于 0.0,则为self.params.value否则为 0.0。
相同的指标通过next方法实现:
1 | class DummyInd(bt.Indicator): |
完毕!它们能实现同样的操作。
注意:请注意在__init__版本中如何将bt.Max赋值给 Line 对象self.lines.dummyline。
bt.Max返回一个线对象,该对象会自动迭代传递给指标的每个bar。
如果改为使用python标准的max函数,则赋值将毫无意义,因为指标将具有一个具有固定值的成员变量,而不是一条线。
在next方法执行期间直接使用python标准内置的max函数比较浮点值
让我们回想一下,self.lines.dummyline是一个很长的符号,它可以缩短为:
- self.l.dummyline
甚至: - self.dummyline
仅当代码未使用成员属性掩盖时,后者才可能实现。
第三个也是最后一个版本提供了一种额外的once方法来优化计算:
1 | class DummyInd(bt.Indicator): |
这样写更有效,但开发once方法不得不触及底层细节。
无论如何,__init__
版本是最好的:
- 一切都在初始化函数中完成
- next和once(都经过优化,因为bt.Max已经有了它们)自动提供,无需使用索引和/或式子
如果开发需要,该指标还可以重写与next和once相关的方法:
- prenext和nexstart
- preonce和oncestart
手动/自动最短周期
如果可能,平台会计算它,但可能需要手动操作。
这是简单移动平均线的潜在实现:
1 | class SimpleMovingAverage1(Indicator): |
虽然听起来不错,但即使参数被命名为“period”,平台也不知道最小周期是多少(该名称可能会产生误导,并且某些指标会收到多个具有不同用途的“period”)
在这种情况下,第一个bar之后会调用next方法,并且所有事情都无法正常开展,因为 get 无法返回所需的self.p.period。
在解决问题之前,必须考虑一些事情:
- 传递给指标的数据馈送可能已经带有最小周期
SimpleMovingAverage可以这样实现:
- 一个有规律的数据源
默认最小周期为 1(只需等待第一个柱进入系统)
- 另一个移动平均线…而这又已经有一个周期
如果它的周期是 20,并且我们的例子中移动平均线周期也是 20,那么我们最终得到的最小周期为 40 个柱
实际上,内部计算显示为 39……因为一旦第一个移动平均线生成了一根柱线,它就计入下一个移动平均线,从而创建了一个重叠的柱线,因此需要 39 个bar。
- 其他的指标/对象也会带有周期。
缓解这种情况的方法如下:
1 | class SimpleMovingAverage1(Indicator): |
addminperiod方法告诉系统考虑该指标所需的额外周期柱,以考虑可能存在的最小周期。
有时不需要这样做,如果所有计算都是使用已经向系统传达其周期需求的对象完成的。
使用直方图快速实现MACD :
1 | from backtrader.indicators import EMA |
完毕!无需考虑最小周期。
- EMA代表指数移动平均线(平台内置别名)
这个(已经在平台中)已经说明了它需要什么
-
指标“macd”和“signal”的命名线正在被赋值给已经带有声明的(幕后)周期的对象
-
macd 从“me1 - me2”中获取周期,该操作从 me1 和 me2 的周期中获取最大值(它们都是具有不同周期的指数移动平均线)
-
singal 直接采用 macd 的指数移动平均线的周期。该 EMA 还考虑了已经存在的 macd 周期和计算自身所需的样本量 (period_signal)
-
histo 取两个操作数“signal - macd”中的最大值。一旦两者都准备好了,histo 也可以产生一个值
-
完整的自定义指标
让我们开发一个简单的自定义指标,它“指示”移动平均线(可以使用参数修改)是否高于给定数据:
1 | import backtrader as bt |
完毕!如果平均值高于数据,则该指标的值为“1”;如果低于数据,则该指标的值为“-1”。
可以再添加一些画图参数,作图:
1 | import backtrader as bt |
这一篇就到这里啦。欢迎大家点赞、转发、私信。还没有关注我的朋友可以关注 江达小记