作者:yunjinqi 类别:
日期:2022-03-20 12:29:00
阅读:2274 次 消耗积分:0 分
云子量化免费阅读传送链接
在前面的文章中其实已经讲过不少关于如何自定义技术指标的文章,在这篇文章中,继续探讨如何在backtrader中自定义技术指标的问题。
谈及在backtrader中自定义一个个的技术指标,这样使用起来确实可以实现无缝对接,但是大概率效率会降低一些的,尤其是一些不能向量化实现的指标(不能在init中实现出来,需要在next中实现),会降低回测的速度,后续推荐使用pandas提前计算好相应的指标,直接把这些指标值加载到backtrader中,可以参考下面的文章,这是比较推荐的方法。
【答读者问23】计算指标的时候是直接使用pandas计算好指标加载进去速度快,还是在backtrader中计算指标速度快?(2021-11-17更新,修复pandas增加列添加问题)
【答读者问25】如何把一个pandas计算的指标改造成一个backtrader的指标?
关于如何实现自定义技术指标,在前面的文章中,也有过讲解,可以看下这些文章:
47、backtrader的一些基本概念—技术指标(indicator)的使用教程
48、backtrader的一些基本概念----如何创建一个新的技术指标(indicator)-(2021-10-17更新)
49、【backtrader股票策略】如何实现跨周期调用技术指标的策略?
75 [backtrader期货策略]十大经典策略-分时均线交叉策略
下面开始今天的主题:有读者咨询不知道在自定义indicator的时候如何获取股票的前n个数据?以及如何应用bt自带的ReduceN?
class xxx(bt.Indicator):
# 需要在lines里面声明指标带的名称,line的名称,可以使用self.lines.xxx或者self.l.xxx或者甚至使用self.xxx
lines = ('yyy',)
# 可能需要的参数值,可以不需要
# 在这个指标中,使用每个交易日收盘的时间作为参数,使用开盘时间的话,如果夜盘开盘时间节假日的时候可能没有,使用收盘可能更准确一些,金融期货需要额外调整下时间
params = (("zzz",None),)
# 可以在init里面计算相应的逻辑,能够在init实现,就可以只使用init,如果在init里面不能够完全实现,那么,就可以考虑使用next和once
# 另外,如果想要避免因为数据不足导致计算指标不准,希望等到数据充足之后在计算,可以增加一个self.addminperiod
def __init__(self):
# self.addminperiod(self.p.yyy)
# 调用过去的data的数据,使用self.data
# 调用过去的close这个line,使用self.data.close
# 能够根据open,high,low,close这些line实现的指标,尽可能直接在init里面实现,比如求三价均线
# self.yyy = (self.data.close+self.data.high+self.data.low)/3
pass
# next是每个bar都会运行一次,如果指标不能再init中实现,一般都是可以在next中实现的
def next(self):
# 如果不能在init直接实现,可以直接在next里面对数据进行调用
# 获取当前的最高价 self.data.high[0]
# 获取n个bar之前的最低价 self.data.low[-1*n]
# 取得n个bar到n-m个bar之间的收盘价,self.data.close.get(m,ago = n-m) 需要对ago验证下,看是不是多一位或者少一位
# 调取数据的方式跟在策略里面是比较类似的
使用指标的时候,直接调用 bt.indicators.xxx(data,zzz = None),即可实现运行。股票的前n个数据的取得,可以直接参考上面代码中的注释。
关于ReduceN的含义,这个涉及到几个继承之外,还涉及到reduce的用法、functools.partial,理解python这两个函数的应用之后,基本上也就理解这个类的用法了。
class ReduceN(OperationN):
'''
Calculates the Reduced value of the ``period`` data points applying
``function``
Uses the built-in ``reduce`` for the calculation plus the ``func`` that
subclassess define
Formula:
- reduced = reduce(function(data, period)), initializer=initializer)
Notes:
- In order to mimic the python ``reduce``, this indicator takes a
``function`` non-named argument as the 1st argument, unlike other
Indicators which take only named arguments
'''
lines = ('reduced',)
func = functools.reduce
def __init__(self, function, **kwargs):
if 'initializer' not in kwargs:
self.func = functools.partial(self.func, function)
else:
self.func = functools.partial(self.func, function,
initializer=kwargs['initializer'])
super(ReduceN, self).__init__()
相对来说,我还是比较推荐直接用pandas或者numpy先计算好相应的指标,这两个包已经无数人的优化,并且底层基于C和Fortan等语言,效率会很高。对于通过自定义indicator这样的方法实现的指标或者通过自定义analyzer实现的绩效统计,效率应该并没有达到极致,还是需要改进。如果时间和精力许可,等我实现了numpy写成的line之后,会对indicator和analyzer进行改造。
至于优化参数啥的,我一直不推荐使用optstrategy这个功能的,这个在前面也说过无数次了,自己用多进程跑吧,前面案例里面有很多可以参考一下。