上一篇文章从总体上介绍了backtrader的功能和使用方法,这篇文章将从局部进行更加细致的讨论,为后续我们使用backtrader打下更加坚实的基础。
目录
一些重要概念
数据源(data feed)
backtrader策略运行的重要基础上数据源,如果没有数据,策略也就没有执行的逻辑基础。
数据源的传递
在backtrader中,数据源是以数组的形式或者对数组的快捷访问的方式提供给strategy(策略)作为成员变量使用的。这句话怎么理解呢?翻译一下,就是:
1、strategy这个类里面有个成员变量datas是个数组,用于存储数据源。数据源按照加入的先后顺序保存在datas中。策略在执行过程,会使用这些数据。上一篇文章中我们测试的策略中都会使用数据源中的close价格作为策略判断的依据。
2、访问数据源可以通过访问数组的方式,或者对数组的快捷方式访问。比如:
def __init__(self):
# Keep a reference to the "close" line in the data[0] dataseries
self.dataclose = self.datas[0].close
self.dataclosetest = self.data0.close
其中datas[0].close就是数组访问方式,self.data0.close就是快捷访问方式,两者保存的数据完全一样,如下:
array('d', [4869.459, 4869.411, 4843.062, 4933.726, 4992.829, 4972.132, 4970.013, 5013.522, 4991.66, 4917.162, 4867.319, 4807.698, 4855.94, 4821.768, 4853.196, 4849.428, 4877.37, 4883.828, 4833.928, 4866.383])
array('d', [4869.459, 4869.411, 4843.062, 4933.726, 4992.829, 4972.132, 4970.013, 5013.522, 4991.66, 4917.162, 4867.319, 4807.698, 4855.94, 4821.768, 4853.196, 4849.428, 4877.37, 4883.828, 4833.928, 4866.383])
有的同学可能眼尖,发现strategy的__init__没有输入参数(除了self自身),我们的数组只是加入到cerebro中,它怎么就能直接使用datas数组了呢?这个是backtrader自身框架处理的,也就是,系统加入的数据源会按照加入的顺序自动呈现到strategy内部的data变量上,大家只需要知道如何使用即可。注意,与此类似的还要Indicators。
数据源的快捷访问
上一节已经说明,这里总结下,对数据源的快捷访问方式如下:
-
self.data 等价self.datas[0]
-
self.dataX 等价 self.datas[X]
示例如下:
class MyStrategy(bt.Strategy):
params = dict(period=20)
def __init__(self):
sma = btind.SimpleMovingAverage(self.data, period=self.params.period)
数据源的缺省访问
如果只有一个数据源,你甚至都不用显式指定,系统会缺省使用self.datas[0],也就是第一个加入的数据源,示例:
class MyStrategy(bt.Strategy):
params = dict(period=20)
def __init__(self):
sma = btind.SimpleMovingAverage(period=self.params.period)
...
调用SimpleMovingAverage的时候完全就丢掉self.data了。这种情况下,Indicator(本例中就是SimpleMovingAverage)会使用策略创建时输入的第一个数据,就是self.data (或者self.data0 或者self.datas[0],哥仨是一个意思])
万物皆为数据源
在backtrader中,不仅仅输入的数据是数据源,任何indicator(指标)以及任何对输入数据的操作(加,减,比较,求和,求平均... )结果均可称为数据源。上一个例子中SimpleMovingAverage对self.datas[0]进行求平均,其结果sma就是一个新的数据源。如下例子,展示了作为数据源的指标以及操作结果
class MyStrategy(bt.Strategy):
params = dict(period1=20, period2=25, period3=10, period4)
def __init__(self):
sma1 = btind.SimpleMovingAverage(self.datas[0], period=self.p.period1)
# sma2是对sma1进行移动平均的结果。
sma2 = btind.SimpleMovingAverage(sma1, period=self.p.period2)
# 对数据源进行算数加减的结果
something = sma2 - sma1 + self.data.close
# 对算数结果再进行移动平均的结果
sma3 = btind.SimpleMovingAverage(something, period=self.p.period3)
# 比较操作也可以
greater = sma3 > sma1
# 对True/False值进行移动平均操作,虽然没啥意义,但是也有效。
sma3 = btind.SimpleMovingAverage(greater, period=self.p.period4)
基本上,所有的通过对数据源进行的各种操作,其结果也会生成一个数据源的对象。
参数
在backtrader中,所有的类都按照如下方法来使用参数:
1、声明一个带有缺省值的参数作为类的一个属性(元组或者字典结构)。
2、关键字类型参数(**kwargs)会扫描匹配的参数,将值赋值给对应的参数,完成后从**kwargs删除。
3、这些参数都可以在类实例中通过访问成员变量self.params(也可以简写为self.p)来使用。
之前的实例中我们已经提供了参数的使用方法,下面看看使用元组(包含元组)以及字典方式的不同之处。
使用元组实例:
class MyStrategy(bt.Strategy):
params = (('period', 20),)
def __init__(self):
sma = btind.SimpleMovingAverage(self.data, period=self.p.period)
使用字典的实例:
class MyStrategy(bt.Strategy):
params = dict(period=20)
def __init__(self):
sma = btind.SimpleMovingAverage(self.data, period=self.p.period)
Lines
Lines是一个非常重要的概念,在上一篇文章中做了详细的说明,从使用用户(通常是strategy)的角度来说,就是包括一个或多个line,这些line是一系列的数据,在图中可以形成一条线(line),例如使用股票的收盘价就可以形成一条线,这个大家在股票软件上就可以看到。
我们关心的是如何访问这个Line,上一篇文章已有示例,这里再看看一个简单的例子:
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]:
本例中,使用了两个Lines对象:
-
self.data: 这个本身包含一个lines属性,该lines还包含一个close属性。这句话啥意思了?就是说,self.data本身包含多条line,其中一个line就是close(收盘价)。参见前一篇文章中的示例图。
-
self.movav:这个是一个SimpleMovingAverage的指标(indicator),本身就包含一个具有lines属性的sma。这里特殊注意一下,计算SimpleMovingAverage使用的self.data,没有指定具体Line的话,缺省用的是close价进行计算。
这两个line,也就是close和sma,可以通过索引0来访问并比对,索引为0的含义前面讲过,就是系统当前正在处理的数据行(bar)。
还有简单的方法访问lines:
-
xxx.lines 可以简化为 xxx.l
-
xxx.lines.name可以简化为xxx.lines_name
一些复杂的对象也可以通过如下方法访问:
-
self.data_name 等于 self.data.lines.name
-
如果有多个变量的话,也可以self.data1_name 替代self.data1.lines.name
此外,Line的名字也可以通过如下方式访问:
-
self.data.close and self.movav.sma
通过如下一段代码来看看效果:
self.log('dataclose, %.2f' % self.dataclose[0])
self.log('data_close, %.2f' % self.data_close[0])

本文详细解读了backtrader中的数据源、数据操作符及策略使用,包括数据源传递、快捷访问、参数继承与Lines的使用,帮助读者为策略开发打下坚实基础。
-重要概念以及平台的使用技巧&spm=1001.2101.3001.5002&articleId=121274859&d=1&t=3&u=9c6a3998ed224685aa263ef035e1585a)
4万+

被折叠的 条评论
为什么被折叠?



