有不少的读者咨询如何更快的学习backtrader,在这一讲中,我将基于自己的经验与理解,分享下对backtrader整体框架的理解,以便能够让大家在学习的过程中能够事半功倍。
预计在下一篇文章中,将会分享一下,学习backtrader需要掌握的一些python基础语法。
理解backtrader有捷径
量化交易框架中的回测功能,是对市场行为的近似模拟,一个量化框架中回测功能的好坏,就看是否能够尽可能接近实际的市场。
从这个角度去理解回测框架,回测的根本其实是对信息的处理。所以,如何把数据加载到backtrader中,如何获取行情数据并计算相应的指标,如何下单交易,这三个任务是学习backtrader必须要掌握的。下单之后计算账户的盈亏,这个是broker自动实现的,不需要大家再费心去自己编程实现,这个是为什么去使用一个编写好的量化框架的原因,可以节省大量的时间和精力。
理解backtrader的捷径在于类比,和Excel进行类比,可以让我们对backtrader的大体框架有直观的认识。我在前面的文章《如何理解backtrader的line以及对line进行操作?》以及《backtrader的一些基本概念—技术指标(indicator)的使用教程》,都进行了简短的介绍,在这里重新总结一下。
self.datas 与 excel工作簿关系
当我们通过cerebro.adddata把数据添加到cerebro中之后,我们就可以使用self.datas来调取相应的数据。
self.datas 是一个列表,列表中的每一个元素都是一个data 。可以想象一个excel文件,有很多工作簿,每一个工作簿对应一data。self.datas里面至少有一个data,如果需要,也可以有很多的data,每个data都可以设定一个名称,就像工作簿可以设定一个名称一样,这个时候就可以使用self.getdatabyname(xxx)找到名称指定的数据。如果没对数据设定名称,就像默认的工作簿名称一样,使用index指引调用数据,比如sef.datas[1]调用的是第二个加载进cerebro中的数据,按照pytho的列表默认的语法,调用第一个数据使用self.datas[0]。
line与excel中列的关系
backtrader中基本的数据结构就是line,大部分都是line,比如data,indicator等。
我们可以把一个line想象成excel中的一个列,比如data相当于一个工作簿,data中的open,high,low,close,volume,就相当于excel工作簿建了这几个列,很显然,工作簿中的列是可以扩展的,可以有很多个列,同样的,backtrader作为一个功能完善的框架,也是可以扩展数据,增加不同的数据的。比如在基础的行情数据之外,增加一列包含pe数据。关于如何扩展行情数据,可以参考以前的文章。
在backtrader中,可以对line进行取值。line[0]相当于当前bar的值,line[-1]相当于前一个bar的值,line[1]相当于下一个bar的值,注意,line[1]使用了未来的数据,轻易不要使用,而且在最后一个bar使用的时候会报错。line的取值相当于excel中指定了列以后,对行进行操作。
总结一下这段的要点:一个line就相当于一列。对line的取值操作就相当于确定了excel表中的某列之后,取得那个row的值一样。
不同的data之间的对齐
如果加载的是一个data,就不用考虑时间对齐的问题。但是我们回测或者交易的时候,很有可能使用多个数据,这个时候就需要考虑不同数据之间的时间对齐问题。
backtrader的处理机制是以第一个数据的时间为基准,每一次next运行,都会把第一个数据的时间往下移动一格时间间隔,通俗点讲,就是next会使得data从当前bar移动到下个bar,使得下个bar成为当前bar。
当出现多个数据的时候,是怎么以第一个数据的时间为基准呢?假设我们现在加载了两个数据到backtrader中,一个是日线数据,一个是周线数据(同样道理,也可以换成1分钟和5分钟),backtrader的一个潜在原则就是,需要把短周期的数据加载到第一个,即以日线作为第一个数据,周线作为第二个数据。日线数据从2021年8月1日到2021年8月31日,共22个交易日;周线数据在每周五收盘的时候形成,一共有4个。正常情况下,如果在next中调用数据,由于日线 数据和周线数据并不是都在8月2日到8月5日之间存在数据,所以这几个日期的日线 bar是不运行的,直到日线和周线数据都存在了才行;如果想要提前调用日线的数据,即在8月2号与8月5号也运行next,就需要在prenext中的调用self.next,即
def prenext(self): self.next()
在8月6号,日线与周线都有了数据,这个时候使用self.datas[0].close[0]
与self.datas[1].close[0],就可以分别取得了周五的日收盘价和周收盘价。
值得提醒的是,在8月9号,也就是在下个周一,分别调用两者的收盘价的话,在日线上获取的是下周一的日收盘价,在周线上获得的仍然是本周五的收盘价,如果计算了技术指标,取得的技术指标的值,也是周五的周数据的指标值,这个在写策略的时候一定要好好考虑。
同样的道理,如果是多股票数据,中间存在某些停牌的日期,那么,在next中获取数据 的时候,获取到的仍然是停牌前的数据,记得第一个数据的日期一定是要全的,否则,可能造成回测的时候跳过某些交易日。所以,第一个数据,最好是用相应的指数数据。
如果把data之间的对齐和excel表格做对比,代表data的一个个工作簿都以第一个数据的时间为基准,第一个data的开始时间与结束时间作为多个工作簿的开始与结束时间(如果没有使用参数限定开始与结束时间的话),如果第一个工作簿后面的很多工作簿在开始和结束之间存在其他时间,会被剔除,如果缺少时间,会用上个bar的数据进行填充。
strategy\position\broker与excel列的关系
strategy中buy,sell,close,分别相当于在excel工作簿中long,short两个列进行操作。
buy操作:
如果当前short列的仓位是0,就会在long的列增加size个仓位。
如果当前short列的仓位大于0,如果buy的size大于short的仓位,就会把short的变为0,同时在long的列上增加size减去原有的short的仓位。如果原有的short的仓位大于buy的size,就会在原有的short的仓位上减去buy的size.
sell操作也比较类似。
close的操作是long和short的那个列上存在仓位,就平掉那个。使用的时候可以限定平多少,一般情况下都是全平掉。
position可以想象成某个数据上有多少持仓这样的一列。有多少个数据就有多少个列。这样,想要查询某个数据上有多少持仓,就可以使用self.getposition(data).size进行查询。
broker里面储存了好多变量的值,其中最主要的是value和cash,即当前账户的价值与当前账户可用现金。可以在strategy中使用self.broker.get_value()和self.broker.get_cash调用。
backtrader的框架实际上比这要复杂很多,中间涉及到很多细节的处理,这篇文章仅仅是帮助大家对backtrader框架的核心部分有一个基础的理解,让大家在写策略的时候更轻松一些,更多的东西还是需要大家进一步去学习。
学习backtrader的一些资源
1.官方文档和博客
作为一个功能完善的量化框架,backtrader官方的文档与博客提供了非常详细的学习backtrader的资源。可以点击链接参考:官方文档与官方博客。
2. 官方论坛
学习过程中不可避免存在某些疑惑,可以去官方论坛,搜索一下,看一看别人有没有碰到过这个问题,是怎么解决的,如果没有类似问题,尝试在论坛进行提问,论坛里面有好多热心的使用者可能会回答大家的问题。
3. 网络一些资源
通过百度backtrader相关内容,也可以找到很多的学习资源。我自己本身也写了一个backtrader的付费专栏,
整个专栏包含的内容:backtrader中文教程(99元,已完成,结合我自己使用的经验,对backtrader官方文档有重点的分析讲解,并指出了一些官网上的错误与弯路,节省大家一部分学习与探索时间)+backtrader股票、期货、期权等策略实现(99元)+backtrader源码解读(99元)+backtrader实盘交易(99元)+3次免费咨询的机会=696元,目前专栏售价为299元