量化投资之工具篇一:Backtrader从入门到精通(6)-Indicator类源代码解读(1)

本文深入探讨了Backtrader库中的Indicator组件,包括其初始化过程、如何在Strategy中使用以及如何开发自定义指标。Indicator在Strategy的__init__函数中实例化,计算值在初始化时确定,使用时在next函数中应用。文中详细解析了Indicator的生命周期,如LineBuffer的管理、数据计算和存储,并提供了实例代码展示Indicator的创建、使用和绘图控制。此外,还介绍了如何处理不同时间粒度的数据以及混合操作。文章最后给出了一个完整的示例,展示了如何定义和使用一个自定义的OverUnderMovAv指标。

前面的3篇文章我们分别介绍了Cerebro、Data相关类、Strategy类,基本上Backtrader的框架已经具备,从这篇文章开始我们介绍Backtrader的重要部件,从最重要额Indicator开始。

老规矩,从家谱图开始。

家谱图

在这里插入图片描述

是不是很眼熟,对了,和Strategy/Data继承关系基本就是一样的,所以从面向对象来说,他和Strategy/Data基本上就是亲兄弟。在文章2中就明确说了,在Backtrader中,一切都是数据。

另外,看了前面几篇文章,对Backtrader的元类套路很熟悉了吧,后面就不细讲了,有兴趣的话可以对照Strategy来读代码(元类的继承关系以及代码是一样的),后面只讲特殊的处理。

Indicator的实例化和初始化

大家还记得Indicator什么时候实例化的?在Strategy初始化的时候,请参见咱们Strategy代码解读中的MyCustomStrategy的__init__函数:

# 增加MovingAverageSimple指标
        self.sma = bt.indicators.SimpleMovingAverage(
            self.datas[0], period=self.params.maperiod)

然后又是元类MetaBase的一整套动作(doprenew、donew、dopreinit、doinit和dopostinit),具体对照Strategy的代码解读对照,说明下大概:

  • 在MetaLineSeries的donew中,初始化一个LineBuffer存储在lines里面,可以看出,Indicator本质上上也是数据源,拥有Lines(家谱图中也可以看到)。初始化的时候只有一个LineBuffer.

  • 在MetaLineIterator的donew中,会将参数中输入的数据(例子中的self.datas[0])加入datas容器(既然是复数,那么可以输入多个数据,如果有的指标需要多个数据的话)中,这个数据是后续计算Indicator的基本数据。如果参数不输入数据咋办呢?就会将这个Indicator的owner的缺省data加入。Indicator的owner是谁?是MyCustomStrategy,因为是它初始化了这个Indicator。那么MyCustomStrategy的缺省data,也就是是MyCustomStrategy的第一个数据(self.datas[0])。那MyCustomStrategy的第一个数据是谁?就是Cerebro加入的第一个数据。所以不输入这个参数数据也可以(文章2有说明,代码原理在这里)。

  • 以上实例化完成,就开始初始化了__init__了,首先就进入到MovingAverageSimple的__init__了:

    def __init__(self):
            # Before super to ensure mixins (right-hand side in subclassing)
            # can see the assignment operation and operate on the line
            self.lines[0] = Average(self.data, period=self.p.period)
    
            super(MovingAverageSimple, self).__init__()
    
    1. 首先就是在实例化一个Average,各种均线指标是非常重要也使用广泛的指标。Average是非常基本的一个类,提供的是简单的算术平均结果,这个记住如何使用就行了,具体代码就不看了。这里记住,第一个line就是Average实例化的时候返回的一个LineBuffer实例,也就是具体的数据在Average中计算。可以看出,数据的计算是在初始化的时候。
    2. 调用父类的__init__,没做啥。
  • 下面就是dopostinit了,在MetaLineIterator的dopostinit中,将自己(初始化后的SimpleMovingAverage实例)传递给自己的owner(MyCustomStrategy),MyCustomStrategy就可以使用这个Indicator了。

至此初始化完成。

Indicator的使用

Indicator的代码流程

前面一再强调,Indicator逻辑(继承关系)上和Data是一样的,所以它的使用基本和Data类是一样的。区别在于:Data的数据通过从元素数据(比如PandaData中 获取),而Indicator的数据来自于计算(比如本例中计算的移动平均值)。有了数据之后,我们循着它代码来看,这些数据是如何使用的。

在Cerebro以及Strategy的代码解读中,我们可以看出Indicator的使用轨迹,从Cerebro的runstrategies->_runonce–>Strategy的_oncepost,代码:

def _oncepost(self, dt):
        for indicator in self._lineiterators[LineIterator.IndType]:
            if len(indicator._clock) > len(indicator):
                indicator.advance()

首先要调用Indicator的Advance:

def advance(self, size=1):
        # Need intercepting this call to support datas with
        # different lengths (timeframes)
        if len(self) < len(self._clock):
            self.lines.advance(size=size)

可以看出,直接就到Indicator所有line的advance了,line(LineBuffer)的advance干啥了,PandasData类详解的时候说明过:所有line索引idx后移,长度计数增加。这里只改索引,不涉及底层数据。也就是当前数据移到下一个了。这个数据不断后移,移到大于最小周期之后,就进入MyCustomStrategy的next了,在这个next中,可以直接对Indicator的指标数据应用进行处理:

def next(self):
        # 记录下本次的close和sma值
        self.log('Close:%.3f' % self.data.close[0])
        self.log('sma:%.3f' % self.sma[0])
   
        # 检查是否还有订单未处理,有的话等等
        if self.order:
            return
        #Check if we are in the market
        if not self.position:
            # 大于均线就买
            if self.dataclose[0] > self.sma[0]:
                # BUY, BUY, BUY!!! (with all possible default parameters)
                self.log('BUY CREATE, %.2f' % self.dataclose[0])
                # Keep track of the created order to avoid a 2nd order
                self.order = self.buy()
        else:

            if self.dataclose[0] < self.sma[0]:
                # 小于均线卖卖卖!
                self.log('SELL CREATE, %.2f' % self.dataclose[0])

                # Keep track of the created order to avoid a 2n
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值