新版VNPY策略自动生成回测文件功能代码解析
VNPY3.0客户端开源代码 VNPY3.0是VNPY官方提供的CTP开源项目客户端源代码,支持国内149家期货公司的CTP接入,支持股指期货,股指期权、商品期货、商品期权的程序化交易和量化交易的仿真回测。
VNPY开源下载
https://gitee.com/vnpypro/vnpy
2022年1月2日版本,实现了策略文件生成模块,本文就是介绍回测机制。
在VNPY3.0项目目录下有strategyfile和strategyfilebacktest目录。
strategyfile 是实盘策略文件目录
strategyfilebacktest 是量化回测策略文件目录
在VNPY主界面点击红圈中的“回测”按钮,即可打开图3界面
回测是由module_backtest.py文件实现的
图2:VNPY窗口界面
图3:进入到回测界面
其中我们开发策略的时候是修改strategyfile下的策略文件,回测时会自动生成回测专用的策略文件,存在strategyfilebacktest 目录下。
点击上图中的“开始回测”按钮 就会触发转换函数
- class DialogBackTest(QtWidgets.QDialog) 类的 GenerateBackTestFile(self)这个方法
这样就由strategyfile下的talib_MA.py(实盘策略文件)生成了strategyfilebacktest 目录下的talib_MA.py(量化回测策略文件)
我们看一下这2个策略文件结构上有什么不同,我们以最简单的TALIB MA策略为例,来说明实盘策略代码和量化回测用的代码的区别。
(1)在def __init__(self, period, slippoint):方法内增加了以下代码:
- self.TradingDay = []
- self.klinetime = []
- self.open = []
- self.high = []
- self.low = []
- self.close = []
- self.volume = []
- self.money = []
- self.open_interest = []
- self.InstrumentID = []
(2)将
- def OnKline(self, mddata, arg, strategyname):
改为
- def OnKline(self, reportpath1, reportpath2, mddata, arg, strategyname):
(3)在def OnKline(self, mddata, arg, strategyname):方法内增加了以下代码:
- super(MyStrategy, self).OnKline(reportpath1, reportpath2, arg, mddata)
通过以上3处代码自动修改生成了strategyfilebacktest下的同名文件,就实现了量化交易的虚拟账号类来进行仿真柜台结算了,
下面这句表示,该类的父类是module_backtest.py文件里的VirtualAccount类,该类功能就是实现了一个量化回测用的仿真柜台。
- class MyStrategy(module_backtest.VirtualAccount, QtCore.QThread):
这是实盘用的策略文件代码如下:
- # MA策略
- import talib
- import module_backtest
- from vnctptdType661 import *
- from PyQt5 import QtCore
- # CTP行情库
- from vnctpmd import *
- import numpy as np
- import globalType
- import globalvar
- # 策略参数定义 '名称,开始值,结束值,步长'
- parlist = [['short', 3, 10, 1], ['long', 10, 30, 1]]
- class MyStrategy(module_backtest.VirtualAccount, QtCore.QThread):
- def __init__(self, period, slippoint):
- super(MyStrategy, self).__init__(period, slippoint)
- def OnKline(self, mddata, arg, strategyname):
- if arg[0] <= 0 or arg[1] <= 0:
- return
- # TradingDay = klinedata.TradingDay.decode()
- # klinetime = klinedata.klinetime.decode()
- self.InstrumentID = mddata.InstrumentID.decode()
- # self.exchange=mddata.exchange.decode()
- self.close.append(float(mddata.close))
- try:
- float_close = [float(x) for x in self.close]
- except Exception as e:
- pass
- self.MA_A = talib.MA(np.array(float_close), arg[0])
- self.MA_B = talib.MA(np.array(float_close), arg[1])
- # print('结果1:' + str(self.MA5))
- # print('结果2:' + str(self.MA20))
- if self.MA_A[len(self.MA_A) - 1] > self.MA_B[len(self.MA_B) - 1]:
- if self.sellvol + self.sellvol_history > 0:
- self.InsertOrder(self.InstrumentID, '', THOST_FTDC_D_Buy, THOST_FTDC_OF_Close, VN_OPT_LimitPrice,
- mddata.close + 1, 1)
- if self.buyvol + self.buyvol_history < 10:
- self.InsertOrder(self.InstrumentID, '', THOST_FTDC_D_Buy, THOST_FTDC_OF_Open, VN_OPT_LimitPrice,
- mddata.close + 1, 1)
- elif self.MA_A[len(self.MA_A) - 1] < self.MA_B[len(self.MA_B) - 1]:
- if self.buyvol + self.buyvol_history > 0:
- self.InsertOrder(self.InstrumentID, '', THOST_FTDC_D_Sell, THOST_FTDC_OF_Close, VN_OPT_LimitPrice,
- mddata.close - 1, 1)
- if self.sellvol + self.sellvol_history < 10:
- self.InsertOrder(self.InstrumentID, '', THOST_FTDC_D_Sell, THOST_FTDC_OF_Open, VN_OPT_LimitPrice,
- mddata.close - 1, 1)
-
转换后的回测用的策略文件代码如下:
- # MA策略
- import talib
- import module_backtest
- from vnctptdType661 import *
- from PyQt5 import QtCore
- # CTP行情库
- from vnctpmd import *
- import numpy as np
- import globalType
- import globalvar
- # 策略参数定义 '名称,开始值,结束值,步长'
- parlist = [['short', 3, 10, 1], ['long', 10, 30, 1]]
- class MyStrategy(module_backtest.VirtualAccount, QtCore.QThread):
- def __init__(self, period, slippoint):
- super(MyStrategy, self).__init__(period, slippoint)
- self.TradingDay = []
- self.klinetime = []
- self.open = []
- self.high = []
- self.low = []
- self.close = []
- self.volume = []
- self.money = []
- self.open_interest = []
- self.InstrumentID = []
- def InsertOrder(self, InstrumentID, exchangeid, direction, offside, VN_OPT_LimitPrice, price, vol):
- self.InsertOrder_backtest(InstrumentID, exchangeid, direction, offside, VN_OPT_LimitPrice, price, vol)
- def OnKline(self, reportpath1, reportpath2, mddata, arg, strategyname):
- super(MyStrategy, self).OnKline(reportpath1, reportpath2, arg, mddata)
- if arg[0] <= 0 or arg[1] <= 0:
- return
- # TradingDay = klinedata.TradingDay.decode()
- # klinetime = klinedata.klinetime.decode()
- self.InstrumentID = mddata.InstrumentID.decode()
- # self.exchange=mddata.exchange.decode()
- self.close.append(float(mddata.close))
- try:
- float_close = [float(x) for x in self.close]
- except Exception as e:
- pass
- self.MA_A = talib.MA(np.array(float_close), arg[0])
- self.MA_B = talib.MA(np.array(float_close), arg[1])
- # print('结果1:' + str(self.MA5))
- # print('结果2:' + str(self.MA20))
- if self.MA_A[len(self.MA_A) - 1] > self.MA_B[len(self.MA_B) - 1]:
- if self.sellvol + self.sellvol_history > 0:
- self.InsertOrder(self.InstrumentID, '', THOST_FTDC_D_Buy, THOST_FTDC_OF_Close, VN_OPT_LimitPrice,
- mddata.close + 1, 1)
- if self.buyvol + self.buyvol_history < 10:
- self.InsertOrder(self.InstrumentID, '', THOST_FTDC_D_Buy, THOST_FTDC_OF_Open, VN_OPT_LimitPrice,
- mddata.close + 1, 1)
- elif self.MA_A[len(self.MA_A) - 1] < self.MA_B[len(self.MA_B) - 1]:
- if self.buyvol + self.buyvol_history > 0:
- self.InsertOrder(self.InstrumentID, '', THOST_FTDC_D_Sell, THOST_FTDC_OF_Close, VN_OPT_LimitPrice,
- mddata.close - 1, 1)
- if self.sellvol + self.sellvol_history < 10:
- self.InsertOrder(self.InstrumentID, '', THOST_FTDC_D_Sell, THOST_FTDC_OF_Open, VN_OPT_LimitPrice,
- mddata.close - 1, 1)
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 【自荐】一款简洁、开源的在线白板工具 Drawnix