新版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 目录下。



点击上图中的“开始回测”按钮 就会触发转换函数

  1. class DialogBackTest(QtWidgets.QDialog) 类的 GenerateBackTestFile(self)这个方法
复制代码

这样就由strategyfile下的talib_MA.py(实盘策略文件)生成了strategyfilebacktest 目录下的talib_MA.py(量化回测策略文件)



我们看一下这2个策略文件结构上有什么不同,我们以最简单的TALIB MA策略为例,来说明实盘策略代码和量化回测用的代码的区别。

(1)在def __init__(self, period, slippoint):方法内增加了以下代码:

  1.         self.TradingDay = []
  2.         self.klinetime = []
  3.         self.open = []
  4.         self.high = []
  5.         self.low = []
  6.         self.close = []
  7.         self.volume = []
  8.         self.money = []
  9.         self.open_interest = []
  10.         self.InstrumentID = []
复制代码


(2)将

  1. def OnKline(self, mddata, arg, strategyname):
复制代码


改为

  1. def OnKline(self, reportpath1, reportpath2, mddata, arg, strategyname):
复制代码




(3)在def OnKline(self, mddata, arg, strategyname):方法内增加了以下代码:

  1. super(MyStrategy, self).OnKline(reportpath1, reportpath2, arg, mddata)
复制代码



通过以上3处代码自动修改生成了strategyfilebacktest下的同名文件,就实现了量化交易的虚拟账号类来进行仿真柜台结算了,
下面这句表示,该类的父类是module_backtest.py文件里的VirtualAccount类,该类功能就是实现了一个量化回测用的仿真柜台。

  1. class MyStrategy(module_backtest.VirtualAccount, QtCore.QThread):
复制代码



这是实盘用的策略文件代码如下:


  1. # MA策略
  2. import talib
  3. import module_backtest
  4. from vnctptdType661 import *
  5. from PyQt5 import QtCore
  6. # CTP行情库
  7. from vnctpmd import *
  8. import numpy as np
  9. import globalType
  10. import globalvar
  11. # 策略参数定义 '名称,开始值,结束值,步长'
  12. parlist = [['short', 3, 10, 1], ['long', 10, 30, 1]]

  13. class MyStrategy(module_backtest.VirtualAccount, QtCore.QThread):
  14.     def __init__(self, period, slippoint):
  15.         super(MyStrategy, self).__init__(period, slippoint)

  16.     def OnKline(self, mddata, arg, strategyname):
  17.         if arg[0] <= 0 or arg[1] <= 0:
  18.             return
  19.         # TradingDay = klinedata.TradingDay.decode()
  20.         # klinetime = klinedata.klinetime.decode()
  21.         self.InstrumentID = mddata.InstrumentID.decode()
  22.         # self.exchange=mddata.exchange.decode()
  23.         self.close.append(float(mddata.close))
  24.         try:
  25.             float_close = [float(x) for x in self.close]
  26.         except Exception as e:
  27.             pass
  28.         self.MA_A = talib.MA(np.array(float_close), arg[0])
  29.         self.MA_B = talib.MA(np.array(float_close), arg[1])
  30.         # print('结果1:' + str(self.MA5))
  31.         # print('结果2:' + str(self.MA20))
  32.         if self.MA_A[len(self.MA_A) - 1] > self.MA_B[len(self.MA_B) - 1]:
  33.             if self.sellvol + self.sellvol_history > 0:
  34.                 self.InsertOrder(self.InstrumentID, '', THOST_FTDC_D_Buy, THOST_FTDC_OF_Close, VN_OPT_LimitPrice,
  35.                                  mddata.close + 1, 1)
  36.             if self.buyvol + self.buyvol_history < 10:
  37.                 self.InsertOrder(self.InstrumentID, '', THOST_FTDC_D_Buy, THOST_FTDC_OF_Open, VN_OPT_LimitPrice,
  38.                                  mddata.close + 1, 1)
  39.         elif self.MA_A[len(self.MA_A) - 1] < self.MA_B[len(self.MA_B) - 1]:
  40.             if self.buyvol + self.buyvol_history > 0:
  41.                 self.InsertOrder(self.InstrumentID, '', THOST_FTDC_D_Sell, THOST_FTDC_OF_Close, VN_OPT_LimitPrice,
  42.                                  mddata.close - 1, 1)
  43.             if self.sellvol + self.sellvol_history < 10:
  44.                 self.InsertOrder(self.InstrumentID, '', THOST_FTDC_D_Sell, THOST_FTDC_OF_Open, VN_OPT_LimitPrice,
  45.                                  mddata.close - 1, 1)

复制代码



转换后的回测用的策略文件代码如下:

  1. # MA策略
  2. import talib
  3. import module_backtest
  4. from vnctptdType661 import *
  5. from PyQt5 import QtCore
  6. # CTP行情库
  7. from vnctpmd import *
  8. import numpy as np
  9. import globalType
  10. import globalvar
  11. # 策略参数定义 '名称,开始值,结束值,步长'
  12. parlist = [['short', 3, 10, 1], ['long', 10, 30, 1]]

  13. class MyStrategy(module_backtest.VirtualAccount, QtCore.QThread):
  14.     def __init__(self, period, slippoint):
  15.         super(MyStrategy, self).__init__(period, slippoint)
  16.         self.TradingDay = []
  17.         self.klinetime = []
  18.         self.open = []
  19.         self.high = []
  20.         self.low = []
  21.         self.close = []
  22.         self.volume = []
  23.         self.money = []
  24.         self.open_interest = []
  25.         self.InstrumentID = []
  26.     def InsertOrder(self, InstrumentID, exchangeid, direction, offside, VN_OPT_LimitPrice, price, vol):
  27.         self.InsertOrder_backtest(InstrumentID, exchangeid, direction, offside, VN_OPT_LimitPrice, price, vol)

  28.     def OnKline(self, reportpath1, reportpath2, mddata, arg, strategyname):
  29.         super(MyStrategy, self).OnKline(reportpath1, reportpath2, arg, mddata)
  30.         if arg[0] <= 0 or arg[1] <= 0:
  31.             return
  32.         # TradingDay = klinedata.TradingDay.decode()
  33.         # klinetime = klinedata.klinetime.decode()
  34.         self.InstrumentID = mddata.InstrumentID.decode()
  35.         # self.exchange=mddata.exchange.decode()
  36.         self.close.append(float(mddata.close))
  37.         try:
  38.             float_close = [float(x) for x in self.close]
  39.         except Exception as e:
  40.             pass
  41.         self.MA_A = talib.MA(np.array(float_close), arg[0])
  42.         self.MA_B = talib.MA(np.array(float_close), arg[1])
  43.         # print('结果1:' + str(self.MA5))
  44.         # print('结果2:' + str(self.MA20))
  45.         if self.MA_A[len(self.MA_A) - 1] > self.MA_B[len(self.MA_B) - 1]:
  46.             if self.sellvol + self.sellvol_history > 0:
  47.                 self.InsertOrder(self.InstrumentID, '', THOST_FTDC_D_Buy, THOST_FTDC_OF_Close, VN_OPT_LimitPrice,
  48.                                  mddata.close + 1, 1)
  49.             if self.buyvol + self.buyvol_history < 10:
  50.                 self.InsertOrder(self.InstrumentID, '', THOST_FTDC_D_Buy, THOST_FTDC_OF_Open, VN_OPT_LimitPrice,
  51.                                  mddata.close + 1, 1)
  52.         elif self.MA_A[len(self.MA_A) - 1] < self.MA_B[len(self.MA_B) - 1]:
  53.             if self.buyvol + self.buyvol_history > 0:
  54.                 self.InsertOrder(self.InstrumentID, '', THOST_FTDC_D_Sell, THOST_FTDC_OF_Close, VN_OPT_LimitPrice,
  55.                                  mddata.close - 1, 1)
  56.             if self.sellvol + self.sellvol_history < 10:
  57.                 self.InsertOrder(self.InstrumentID, '', THOST_FTDC_D_Sell, THOST_FTDC_OF_Open, VN_OPT_LimitPrice,
  58.                                  mddata.close - 1, 1)


复制代码











 

posted @   wka6890  阅读(586)  评论(0编辑  收藏  举报
编辑推荐:
· 开发者必知的日志记录最佳实践
· 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
点击右上角即可分享
微信分享提示