VNPY应用入门/进行量化策略回测01(不谈理论,只谈应用)


(darcylike) #1

打开知乎发现居然有800粉丝关注了,惊到了我,真的有点慌,开专栏的本意是督促自己读书,记录。

量化交易的第一步就是回测,还记得我的一个回测程序就是简单的写一个双均线策略,里面用了一个很多个vector(C++)来记录交易数据、还有成交信息等等。基本上就是面向过程的编程方法,没有做太多的抽象,很长一段时间里写新策略回测的成本非常高(并非专业计算机专业出身,所以啊技术高手可以绕道~),后来用老师写的平台,因为非开源,很多bug调来调去就是本身底层代码的原因,又因为封装了,报个内存错误,真的是欲哭无泪,这里VNPY的逻辑和体系是比较完整和易懂的,我自己借用了很多VNPY的源代码,改出了适合自己数据和交易模式的回测平台。网上大部分文章都是基于结构去宏观分析,对于小白门入手还是有一定难度的,所以这篇文章会从应用,将从最小的一步开始讲起,不涉及到模块就不展开,希望每个看完整篇文章的人都能够基于VNPY做回测。

要了解一个系统,当然是手把手的去一步步调试看看。

首先去GITHUB上搜索VNPY,下载最新版本。然后按照官网的教程安装(贴不了链接,知乎会盾)。

![](data:image/svg+xml;utf8,<svg%20xmlns=‘http://www.w3.org/2000/svg’%20width=‘266’%20height='251’>)

大家可以看一下,如果把回测相关的模块抽出来(没有加风控、优化等,其中数据读取是重新写了)出现其实只涉及到很少的几个py文件,所以回测改起来没有那么难,但是本篇文章还是基于最原始的VNPY回测去写,写完之后大家自己去改动。

所有量化交易的第一步都是看数据。打开\vnpy-master\examples\CtaBacktesting文件夹。

![](data:image/svg+xml;utf8,<svg%20xmlns=‘http://www.w3.org/2000/svg’%20width=‘258’%20height='215’>)

打开其中的loadCsv.py:

![](data:image/svg+xml;utf8,<svg%20xmlns=‘http://www.w3.org/2000/svg’%20width=‘548’%20height='94’>)

再看看loadMcCsv函数在做什么,于是乎跳转到ctaHistoryData.py,是将我们本地的IF0000_1MIN.CSV和RB0000_1MIN.CSV的数据导入到MONGODB本地数据库中。

这个时候下载一下stodio 3T这个软件,我们可以看到本地数据库可视化。

![](data:image/svg+xml;utf8,<svg%20xmlns=‘http://www.w3.org/2000/svg’%20width=‘228’%20height='249’>)

里面就有了VnTrader_1MIN的数据啦,再进一步打开看看

![](data:image/svg+xml;utf8,<svg%20xmlns=‘http://www.w3.org/2000/svg’%20width=‘1109’%20height='151’>)

![](data:image/svg+xml;utf8,<svg%20xmlns=‘http://www.w3.org/2000/svg’%20width=‘1108’%20height='174’>)

可以看到数据有这么多关键字:交易时间、交易量、交易合约标的、最高价、最低价、收盘价等。

runBacktesting.py

from vnpy.trader.app.ctaStrategy.strategy.strategyKingKeltner import KkStrategy

这里是你要回测的策略引入,打开\vnpy-master\vnpy\trader\app\ctaStrategy\strategy文件夹

![](data:image/svg+xml;utf8,<svg%20xmlns=‘http://www.w3.org/2000/svg’%20width=‘261’%20height='175’>)

我们只需要把import后面的策略名改掉就可以引入其他策略,所以你的其他新策略也都放在这个文件夹里就行。接着回到runBacktesting.py文件:engine = BacktestingEngine()

这里创建回测引擎,我们看看回测引擎对象有什么,打开看看ctaBacktesting.py.

![](data:image/svg+xml;utf8,<svg%20xmlns=‘http://www.w3.org/2000/svg’%20width=‘332’%20height='566’>)

基本上与回测相关的基本参数初始化、函数都在回测引擎类中定义了,接着回到runBacktesting.py文件。

![](data:image/svg+xml;utf8,<svg%20xmlns=‘http://www.w3.org/2000/svg’%20width=‘459’%20height='392’>)

对回测的相关参数进行了设置,大家可以看看回测引擎类,里面有很多参数设置的函数,可以根据自己的需要调配,这里设置了回测数据的起始日期,滑点(用于策略表现计算),合约大小,最小tick等。

![](data:image/svg+xml;utf8,<svg%20xmlns=‘http://www.w3.org/2000/svg’%20width=‘453’%20height='96’>)

接着初始化策略对象,又回到ctaBacktesting.py,找到这个initStrategy函数,没什么东

![](data:image/svg+xml;utf8,<svg%20xmlns=‘http://www.w3.org/2000/svg’%20width=‘669’%20height='219’>)

接下来重中之重来了!

![](data:image/svg+xml;utf8,<svg%20xmlns=‘http://www.w3.org/2000/svg’%20width=‘478’%20height='75’>)

我们跳转到ctaBacktesting.py,找到里面的runBacktesting()函数

![](data:image/svg+xml;utf8,<svg%20xmlns=‘http://www.w3.org/2000/svg’%20width=‘492’%20height='125’>)

接着打开loadHistoryData()这个函数,我们如果要修改读取数据的路径的话,就在这个函数里做修改。

接着载入需要的回测数据:

![](data:image/svg+xml;utf8,<svg%20xmlns=‘http://www.w3.org/2000/svg’%20width=‘756’%20height='298’>)

flt就是选取回测最开始的日期到策略开始日期间的数据,并且按照日期顺序排列

![](data:image/svg+xml;utf8,<svg%20xmlns=‘http://www.w3.org/2000/svg’%20width=‘803’%20height='202’>)

将读取的数据都存入initData列表中,这个是策略初始化所需要的数据,比如说双均线策略中,你的快均线和慢均线的第一个值是需要一定初始数据量测算的,比如说需要20天之类。

![](data:image/svg+xml;utf8,<svg%20xmlns=‘http://www.w3.org/2000/svg’%20width=‘768’%20height='368’>)

这里就是载入回测交易所需要的数据,可以说是真正交易的回测数据。

![](data:image/svg+xml;utf8,<svg%20xmlns=‘http://www.w3.org/2000/svg’%20width=‘491’%20height='293’>)

这里根据我们在runBacktesting里面设置的回测模式(tick还是bar模式),dataClass记录回测数据类型,func记录回测读取的数据函数。这里我们深入看一下回测数据类型,数据类全部定义在vtObject.py中,包括tick类数据,bar,成交、订单数据类等,如果我们要根据我们自己的数据类型定义的话,就可以在这个py文件中去增加写就行了,比如说为了方便价差交易回测,我就自己增加了一个spreaddata类,我们可以具体看看其中bar类的数据,定义了最高、最低、收盘价等,里面用了很多像EMPTY_FLOAT的常量定义,这些常量都在vnpy.trader.vtConstant.py文件里,如果你有什么新的常量都可以在里面添加定义。

![](data:image/svg+xml;utf8,<svg%20xmlns=‘http://www.w3.org/2000/svg’%20width=‘322’%20height='321’>)

![](data:image/svg+xml;utf8,<svg%20xmlns=‘http://www.w3.org/2000/svg’%20width=‘621’%20height='520’>)

继续我们回到runBacktesting函数里,继续执行。

![](data:image/svg+xml;utf8,<svg%20xmlns=‘http://www.w3.org/2000/svg’%20width=‘543’%20height='137’>)

这里进行策略初始化,我们看看都初始化了什么,打开strategyKingKeltner.py。

![](data:image/svg+xml;utf8,<svg%20xmlns=‘http://www.w3.org/2000/svg’%20width=‘669’%20height='271’>)

这里通过回放initData初始化策略参数,打开self.onBar

![](data:image/svg+xml;utf8,<svg%20xmlns=‘http://www.w3.org/2000/svg’%20width=‘565’%20height='97’>)

看看bg的初始化:self.bg = BarGenerator(self.onBar, 5, self.onFiveBar)

![](data:image/svg+xml;utf8,<svg%20xmlns=‘http://www.w3.org/2000/svg’%20width=‘689’%20height='489’>)

BarGenerator就是K线合成器,可以合成N分钟K线。

打开def updateBar(self, bar)函数

我们可以看到如果self.xminbar == None的时候,就用第一个BAR去初始化它,接着如果X分钟已经走完的时候。

![](data:image/svg+xml;utf8,<svg%20xmlns=‘http://www.w3.org/2000/svg’%20width=‘416’%20height='166’>)

我们向onXminBar函数去推送一个X分钟BAR数据,然后再吧xminBar设置为None.因为前面初始化bg时传入的onXminBar的函数为KKstrategy的onFiveBar。

今天就到这里吧,希望接下来能尽快更新完。