Python量化交易学习笔记(54)——backtrader的一些基本概念2

本文继续记录bt相关的概念内容。

Lines

顾名思义,Lines就是线,比如一段时期的收盘价是一条线,一段时期的成交量是一条线,一段时期的5日均线也是一条线,股票软件上的所有技术指标基本都可以处理为线。在bt中也是主要通过访问线(Lines)来进行各种计算。通过一个小例子来看一下Lines在bt中的使用:

class MyStrategy(bt.Strategy):
    params = dict(period=20)
    def __init__(self):
        self.movav = btind.SimpleMovingAverage(self.data, period=self.p.period)
    def next(self):
        if self.movav.lines.sma[0] > self.data.lines.close[0]:
            print('Simple Moving Average is greater than the closing price')

在上面的代码中,有两处访问了Lines对象:

  • self.movav是一个均线(SimpleMovingAverage)技术指标对象,包含一个lines属性,在lines中又包含sma这样一条line
  • self.data包含一个lines属性,在lines中又包含close这样一条line

像Data Feeds一样,Lines也有快捷访问的方式:

  • xxx.l 对应于xxx.lines
  • xxx.lines_name 对应于xxx.lines.name
  • Strategy和Indicator这样复杂的对象提供了对Lines的快捷访问方式:
    – self.data_name 对应于self.data.lines.name
    – self.data1_name对应于self.data1.lines.name
  • 也可以直接使用lines的名字而不显式的使用 .l 或者 .lines 进行访问,例如:self.data.close(对应于self.data.lines.close)、self.movav.sma(对应于self.movav.lines.sma)

需要注意的是,后两种访问方式是不支持赋值(Setting/Assigning)的。

声明Lines

在开发新的Indicator时,Lines需要被声明。前面介绍了参数(Parameter)在类内被定义时,可以使用元组字典两种形式,而Lines的声明只支持使用元组的形式,例如定义均线(SimpleMovingAverage)的代码如下:

class SimpleMovingAverage(Indicator):
    lines = ('sma',)
    ...

代码里声明了sma这样一条line,后续sma就可以被Strategy或者其他的Indicator进行访问了。这里需要注意,代码中’sma’后面的逗号不能省略,测试后会发现如果逗号被省略lines会被Python3.8解析为string,而不是元组。

Lines是按声明的顺序保存在Indicator中的,bt除了支持使用名字来访问Lines外,还可以按照声明顺序用索引访问Lines,比如在上面的例子中,self.lines[0]就对应的是self.lines.sma。如果有更多Lines,那就可以用中括号[]加上1、2等等来进行索引访问。

Lines的其他快捷访问方式有:

  • self.line 对应于self.lines[0]
  • self.lineX 对应于self.lines[X]
  • self.line_X 对应于self.lines[X]

上面是Lines在Indicator中的快捷访问方式,在Data Feeds中的Lines也有如下快捷访问方式可用:

  • self.dataY 对应于self.data.lines[Y]
  • self.dataX_Y 对应于self.dataX.lines[X]、self.datas[X].lines[Y]

在Data Feeds中访问Lines

在Data Feeds中访问Lines时,代码中经常会省略不写lines,例如:

data = btfeeds.BacktraderCSVData(dataname='mydata.csv')
...
class MyStrategy(bt.Strategy):
    ...
    def next(self):
        if self.data.close[0] > 30.0:
            ...

这里的self.data.close[0]实际上是self.data.lines.close[0]的简写,但是看上去更简短自然。

需要注意的是,**在Data Feeds中,我们可以代码里省略掉lines,但是在Indicator中访问Lines对象时,就不能省略。**原因是bt在实现Indicator的过程中,可能使用了类似于close之类的成员变量保存了一些中间计算结果,如果使用时在代码中省略掉lines(self.close)来访问这些变量,可能会产生错误或者非预期的结果。在Data Feeds中就不存在这些问题,lines只是一系列的数据源。

Lines的长度函数

主要涉及len和buflen两个函数:

  • len返回的是已经被处理过的K线数目,可以应用于Data Feeds、Strategy、Indicator
  • buflen返回的是预加载后的K线总数,只能应用于Data Feeds

这样有两种可能len和buflen返回相同的值(不考虑实时在线Data Feeds的情况):

  • 没有数据被加载
  • 所有加载数据都已经被处理过

Lines和Parameters的继承

Parameters的继承

  • 支持多继承
  • 基类的Parameters将被继承
  • 如果多个基类中定义了相同名称的Parameters,那么继承列表中最后一个基类的该参数默认值,将被子类使用。
  • 如果子类中重新定义了相同的参数,那么这个新的参数的默认值将被使用。

Lines的继承

  • 支持多继承
  • 所有基类的Lines都会被子类继承。如果不同基类中含有相同命名的Lines,那么只会保留一条该命名的line(具体哪条文档中没有说明)。

索引0和-1

在Strategy中只读取Lines的数据,在Indicator中对Lines既做读取也可以做写入操作。当访问Lines时,使用索引0来访问当前K线的数据,就像前面在Strategy访问Lines的例子中:

def next(self):
    if self.movav.lines.sma[0] > self.data.lines.close[0]:
        print('Simple Moving Average is greater than the closing price')

使用索引0来访问当前K线的sma及close值。在访问当前值时,索引0是可以省略,下面的代码和上面示例中条件语句实现相同的功能:

if self.movav.lines.sma > self.data.lines.close:

下面的例子展示了在开发新的Indicator时,使用索引0,对Lines进行赋值的过程。这里以SimpleMovingAverage技术指标为例:

def next(self):
  self.line[0] = math.fsum(self.data.get(0, size=self.p.period)) / self.p.period

在Lines中,访问当前数据使用索引0,访问前一组数据使用索引-1,这和Python中使用-1访问数据中最后一个数据是不同的。下面的例子展示了在Strategy中,使用索引0和-1来比较当前收盘价和前一收盘价的代码:

def next(self):
    if self.data.close[0] > self.data.close[-1]:
        print('Closing price is higher today')

同样,可以使用-2、-3等等访问再向前(过去)的数据。

欢迎大家关注、点赞、转发、留言,感谢支持!
微信群用于学习交流,感兴趣的读者请扫码加微信!
QQ群(676186743)用于资料共享,欢迎加入!

在这里插入图片描述

在这里插入图片描述

Guess you like

Origin blog.csdn.net/m0_46603114/article/details/118874308