原本想开始讲策略类的编写,后来觉得,结合回测代码其实能够更好的理解,所以先解读一下vnpy回测的代码吧,后续自己也想把vnpy回测的部分优化一下,毕竟我觉得可视化和回测结果方提高还有很多空间。
我们解读的代码从runbacktesting.py开始。首先,和实盘中一样导入了一个策略。
from vnpy.trader.app.ctaStrategy.strategy.strategyDoubleMa import DoubleMaStrategy
紧接着,就获得了一个回测引擎的对象:
engine = BacktestingEngine()
我们先不管这个引擎,继续往下看,发现后面与engine有关的操作有这些:
# 设置引擎的回测模式为K线
engine.setBacktestingMode(engine.BAR_MODE)
# 设置回测用的数据起始日期
engine.setStartDate('20120101')
# 设置产品相关参数
engine.setSlippage(0.2) # 股指1跳
engine.setRate(0.3/10000) # 万0.3
engine.setSize(300) # 股指合约大小
engine.setPriceTick(0.2) # 股指最小价格变动
# 设置使用的历史数据库
engine.setDatabase(MINUTE_DB_NAME, 'IF0000')
# 在引擎中创建策略对象
d = {}
engine.initStrategy(DoubleMaStrategy, d)
# 开始跑回测
engine.runBacktesting()
# 显示回测结果
engine.showBacktestingResult()
那么我们就一个一个来看吧。
1.回测模式
我们进入BacktestingEngine类的定义,然后把和mode有关的全部看一下:
def setBacktestingMode(self, mode):
"""设置回测模式"""
self.mode = mode
首先,在外面调用的就是这个函数,然后,我们可以注意到,其实这个函数就是修改了一下mode变量。那么我们继续追杀这个变量出现过的地方。
在初始化函数当中,对这个变量做了初始化设置。
self.mode = self.BAR_MODE # 回测模式,默认为K线
然后是在loadHistoryData函数汇总,根据mode变量来判断。
# 首先根据回测模式,确认要使用的数据类
if self.mode == self.BAR_MODE:
dataClass = VtBarData
func = self.newBar
else:
dataClass = VtTickData
func = self.newTick
也就是,根据不同的回测模式,tick回测还是bar回测,我们在从数据库读取数据的时候,需要不同的数据的类。
在runBacktesting函数中,也有这段代码。个人觉得,这里略微啰嗦了,为什么不用工厂模式来生产呢?
然后是crossLimitOrder函数,也是就限价单撮合函数中,根据回测类型判断成交价格。
# 先确定会撮合成交的价格,这里和限价单规则相反
if self.mode == self.BAR_MODE:
buyCrossPrice = self.bar.high # 若买入方向停止单价格低于该价格,则会成交
sellCrossPrice = self.bar.low # 若卖出方向限价单价