【答读者问38】backtrader如何自定义技术指标?
作者: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这个功能的,这个在前面也说过无数次了,自己用多进程跑吧,前面案例里面有很多可以参考一下。


版权所有,转载本站文章请注明出处:云子量化, http://www.woniunote.com/article/88
上一篇:【TWS API 翻译系列】21、TWS API和IB中的新闻和公告
下一篇:【答读者问39】谈一谈如何基于python和backtrader进行因子研究?