简介:wtpy 是基于 WonderTrader 的 Python3 适配子框架,附完整源代码与文档说明,面向量化交易开发者、Python 工程师及计算机相关专业学生,也适合作为毕业设计或课程设计参考。资源共 417 个文件,压缩包约 64.66MB,主体为 136 个 Python 源码文件、83 个 YAML 配置、81 个 DLL 与 40 个 SO 原生库,另含 JSON 数据、CSV 样本及少量前端资源,按 apps、wrapper、monitor 等模块清晰组织。其中 apps 子模块提供回测指标分析与 CTA 并行优化器,wrapper 子模块封装与 C++ 底层对接的合约加载、数据转换、实盘交易等接口,monitor 子模块内置 HTTP 与 WebSocket 监控服务,覆盖从合约管理、策略回测到实盘执行的完整链路。代码经测试运行成功,内含 README 与构建脚本,用户可结合示例配置与数据文件快速部署,便于学习框架原理和二次开发。目前已有 221 人查看学习,适合需要系统性了解量化交易子框架的进阶者。
1. wtpy:把 C++ 量化框架包装成 Python 能用的子框架
WonderTrader 的核心是用 C++ 写的,速度快但上手门槛高。wtpy 就是针对 Python3 适配出来的子框架,把底层 C++ 模块封装成 Python 可调用的接口,同时保留回测、实盘、数据管理、监控服务这些核心能力。拿到这份源代码,你会发现它不只是简单绑定,而是把常用流程拆成了 apps、wrapper、monitor 三个层次,适合做 CTA 策略研究、毕业设计或者课程设计时快速落地。它最大的价值是你不必深入 C++,也能在 Python 里完成从数据清洗、策略回测到参数搜索的完整链条。下面我会按模块拆解、编译安装、回测优化、报告输出这几个维度一步步讲,最后补几个实际踩过的坑。
2. 模块结构拆解:wrapper、apps、monitor 各层都干了什么
2.1 wrapper 子模块:与 C++ 核心对接的接口层
wrapper 是 wtpy 里最容易让人看不懂、但最关键的部分。它做的是把 C++ 的回测引擎、实盘交易引擎、数据组件一个个包装成 Python 可以 import 的模块。比如WtBtWrapper.py负责和回测引擎的 C++ 核心对接,WtWrapper.py负责和实盘交易引擎对接,WtDtWrapper.py负责和数据组件对接。这一层的存在让上层的 Python 策略不需要关心 C++ 对象生命周期和内存释放的问题。
实际使用中,你很少直接去 new 这些 Wrapper,而是通过根目录下的ContractMgr、ProductMgr等辅助模块间接使用它们。以合约加载为例:
from wtpy import ContractMgr # 实例化合约管理器 mgr = ContractMgr() # 加载交易所合约文件 mgr.load("config/contracts.json") # 查询某个合约 contract = mgr.get_contract("rb.HOT") if contract: print(contract.exchange, contract.code, contract.expiredate)ContractMgr内部会调用ContractLoader.py去读取contracts.json,然后把合约信息缓存起来。contract.exchange返回交易所代码,contract.code返回合约代码,contract.expiredate返回到期日。这个查询在策略里经常用来校验当前主力合约是否临近交割月,避免在移仓换月时产生错误信号。
wrapper 层还有一个容易忽略的模块WtDtHelper.py。它提供的是用户数据和 WonderTrader 内部数据格式之间的转换能力。你从交易所或第三方数据商拿到 CSV 格式的 K 线后,要进入回测引擎,几乎都要先走这一层转换,后文会用具体代码演示。
2.2 apps 子模块:回测分析与 CTA 优化器
apps 是 wtpy 里最容易出成果的部分。WtBtAnalyst.py主要负责把回测生成的原始数据换算成年化收益、夏普比率、最大回撤、卡玛比率等指标,并输出到 Excel 文件。WtCtaOptimizer则是一个基于multiprocessing的 CTA 参数优化器,它会并行跑多组参数回测,把所有组合的交易指标汇总成 CSV。
WtHotPicker是另一个实用的辅助模块,专门处理国内期货换月规则。它可以从交易所网站爬取页面来确定换月规则,也可以解析 datakit 每日收盘生成的snapshot.csv来确定规则。做主力连续合约回测时,换月规则直接决定了你用的连续 K 线是否平滑,这模块能省掉不少手工处理时间。
2.3 monitor 子模块:回测管理、进程调度与 Web UI
monitor 子模块是很多人做毕设时忽略掉的一部分。它提供的不是单次回测能力,而是回测任务、实盘进程、事件推送的服务化管理。WtMonSvr.py是监控服务的核心,基于 Flask 实现了 HTTP 接口;PushSvr.py提供 WebSocket 服务,把组合运行中的事件实时推给前端页面。WatchDog.py负责自动调度服务端进程,DataMgr.py读取并缓存组合数据。
你在资源包中看到的app.1e35bbc7fa3d20b13f7ab241eec33b3b.css、style_black.css这类静态文件,就是 monitor 自带 Web UI 的前端资源。这说明 wtpy 在打包时把回测管理和实盘监控的界面也一起给了。如果要把这套框架扩展成多人可用的回测平台,monitor 子模块是最值得改的地方。
2.4 根目录下的基础模块:策略基类与交易上下文
根目录下这几个文件决定了策略怎么写。WtCoreDefs.py定义了 Python 版本的策略基类,CtaContext.py、HftContext.py、SelContext.py分别对应 CTA、高频、选股三种策略的上下文。ProductMgr.py负责品种属性和合约属性查询,SessionMgr.py负责交易时段模板管理。
写策略时,你一般会从WtCoreDefs.BaseCtaStrategy继承,然后在on_bar回调里调用context提供的方法完成开平仓。这里的关键是理解Context和Strategy的关系:一个策略实例对应一个Context,而Context负责和底层引擎通信。SessionMgr则让你避免手动处理节假日、夜盘时间段这些复杂规则。
下表列出常用模块的分类和典型使用场景:
| 模块文件 | 分类 | 典型使用场景 |
|---|---|---|
| WtBtWrapper.py | wrapper | 与回测引擎对接的回调入口 |
| ContractMgr.py | 根目录辅助 | 加载和查询 contracts.json |
| WtCtaOptimizer | apps | 多进程并行搜索 CTA 参数 |
| WtBtAnalyst.py | apps | 把回测结果输出为 Excel 报告 |
| WtMonSvr.py | monitor | 启动 HTTP 回测管理服务 |
| WtHotPicker | apps | 确定主力连续合约换月规则 |
3. 从 build.bat 到 Python 调用:wtpy 的编译与安装
3.1 先看 build.bat 和 setup.cfg 在做什么
wtpy 不是纯 Python 项目,底层 C++ 需要先编译成 Python 扩展。资源包里的build.bat就是 Windows 下的一键编译脚本,setup.cfg则是 Python 扩展的构建配置文件。你拿到源码后第一件事不是直接import wtpy,而是先把扩展编译出来。
setup.cfg里通常会指定 C++ 头文件路径、库路径和包名。一个典型的配置片段类似:
[metadata] name = wtpy version = 1.0.0 license = MIT [options] package_dir = =src packages = find: [build_ext] include_dirs = include library_dirs = libinclude_dirs指向 C++ 头文件所在目录,library_dirs指向编译好的静态库或动态库目录。build.bat在后台执行的实际上是类似python setup.py build_ext --inplace的流程,最终生成可以被当前 Python 环境直接 import 的.pyd文件。
3.2 在 Windows 上构建 wtpy 扩展
假设你已经把源码解压到D:\wtpy-dev目录下,打开命令行进入该目录,执行:
build.bat编译前需要确认三件事:Python 必须是 3.7 以上的 64 位版本;系统安装了 Visual Studio 2019 或更高版本,并且勾选了“使用 C++ 的桌面开发”工作负载;环境变量PYTHON_HOME指向当前 Python 安装目录。
如果编译报错Cannot open include file: 'Python.h',说明 Python 开发头文件没有安装。在 Windows 上重新运行 Python 安装包,勾选“Download development tools”即可;在 Linux 上则是安装python3-dev。如果报错Unable to find vcvarsall.bat,说明 VS 的 C++ 组件没装全,回到 Visual Studio Installer 里补装。
3.3 安装到你的 Python 环境
编译成功后,进入源码根目录,用 pip 完成剩余安装:
pip install -r requirements.txt pip install -e .requirements.txt通常至少会包含numpy、pandas、flask、websockets这几个,具体以当前项目实际依赖为准。pip install -e .是以可编辑模式安装,之后你对 wtpy 源码做的修改会被立即加载,调试策略时不用反复重新安装。
安装完成后,在任意路径下验证是否可用:
import wtpy print(wtpy.__version__) from wtpy import WtDtHelper print(WtDtHelper)如果导入失败,先确认当前 Python 是 64 位。wtpy 的 C++ 扩展基本不会编译 32 位版本,32 位环境下会直接报“module not found”或者找不到指定模块。
3.4 常见编译安装错误排查
下表是实际中最常见的几类问题:
| 现象 | 可能原因 | 处理方式 |
|---|---|---|
| build.bat 一闪而过 | 命令行里缺少错误暂停 | 在 cmd 中手动执行python setup.py build_ext --inplace查看日志 |
| 找不到 Python.h | 缺少 Python 开发工具 | 重装 Python,勾选 Development Tools |
| 找不到 vcvarsall.bat | VS 未安装 C++ 桌面组件 | 安装“使用 C++ 的桌面开发”负载 |
| import 时找不到 pyd | 扩展未生成到当前环境 | 执行pip install -e .后重试 |
| 运行时报缺少 DLL | 缺少 VC 运行库 | 安装 Visual C++ Redistributable for Visual Studio |
4. 实战:用 WtCtaOptimizer 并行搜索最优 CTA 参数
4.1 准备数据:把 CSV 换成 WonderTrader 能识别的格式
资源包里的SHFE.rb.HOT_m5.csv是螺纹钢 5 分钟 K 线,DCE.i.HOT_m5.csv是铁矿石 5 分钟 K 线,SSE.ETF.510300_m5.csv是沪深 300 ETF 的 5 分钟 K 线。WonderTrader 内部回测引擎直接读取的是二进制数据格式,所以 CSV 要先经过WtDtHelper转换。
以转换螺纹钢数据为例:
from wtpy import WtDtHelper helper = WtDtHelper() # 将csv转换为WonderTrader的dsb格式 helper.csv_to_dsb( file="SHFE.rb.HOT_m5.csv", # 原始csv路径 code="rb.HOT", # 合约代码 exchange="SHFE", # 交易所代码 period="m5" # K线周期 )这里code是 WonderTrader 内部的合约标识,rb.HOT表示螺纹钢主力连续合约;exchange必须是 SHFE、DCE、CZCE、CFFEX 这种标准交易所代码;period支持m1、m5、m15、m30、h1、h4、d等常见周期。转换完成后会在数据目录下生成.dsb文件,回测引擎会按这个文件名去加载数据。
要注意的是,csv文件里的字段名和顺序最好和模板一致,一般至少包含date、time、open、high、low、close、volume七列。如果你自己的数据多了一列openinterest或turnover,转换接口通常也能识别,但我更建议先只保留核心字段,等流程跑通后再逐步加。
4.2 写一个可被优化器调用的双均线策略
使用WtCtaOptimizer的前提是策略类能从外部接收参数。下面这个双均线策略就是典型的可优化结构:
from wtpy import WtCoreDefs class DualMaStrategy(WtCoreDefs.BaseCtaStrategy): def __init__(self, name, fast, slow): super().__init__(name) self.fast = fast self.slow = slow self.ctx = None def on_init(self, ctx): self.ctx = ctx ctx.straight_do_init() def on_bar(self, ctx, bar): if self.ctx is None: self.ctx = ctx hold = ctx.stra_get_position() close = bar["close"] fast_ma = ctx.stra_get_indicator("MA", self.fast, close) slow_ma = ctx.stra_get_indicator("MA", self.slow, close) if fast_ma > slow_ma and hold <= 0: ctx.stra_enter_long(1) elif fast_ma < slow_ma and hold >= 0: ctx.stra_exit_long(1)stra_get_position返回当前未平仓手数,stra_get_indicator是行情指标接口,第一个参数是指标名,第二个是指标周期。stra_enter_long(1)表示开多 1 手,stra_exit_long(1)表示平多 1 手。self.fast和self.slow会被优化器替换成不同数值。
回测中一个常见误区是在on_init里只订阅一次行情,然后在on_bar里不去判空。实际上,某些数据周期下内核会先推第一根历史的 bar 来做初始状态,这时候ctx可能还没有完全就绪,所以我在上面做了self.ctx的判空并缓存,避免第一根 bar 直接报空引用。
4.3 配置并启动 WtCtaOptimizer
WtCtaOptimizer的工作方式是笛卡尔积遍历所有参数组合,然后通过multiprocessing并行回测。下面是一个典型启动方式:
from wtpy.apps import WtCtaOptimizer optimizer = WtCtaOptimizer( basefiles_dir="config", # 存放contracts.json等 datadir="data", # 放置dsb数据的目录 outdir="output", # 优化结果输出目录 workers=8 # 并行进程数 ) optimizer.set_code("rb.HOT", "SHFE") optimizer.set_period("m5") optimizer.set_strategy(DualMaStrategy, "双均线示例") optimizer.add_param("fast", 5, 30, 5) optimizer.add_param("slow", 20, 100, 10) optimizer.run()参数说明如下:
| 方法/参数 | 含义 | 建议 |
|---|---|---|
basefiles_dir | 保存 contracts.json、commodities.json 等基础文件的目录 | 不要放到源码目录,容易混淆 |
datadir | 回测数据所在目录,存储转换好的 dsb/bin 文件 | 与 CSV 原始目录分开 |
outdir | 优化结果 CSV 输出目录 | 每次优化前清理旧结果 |
workers | 并行进程数 | 建议设为物理核心数或减半 |
set_code | 设置回测合约和交易所 | 合约代码必须和 dsb 文件名匹配 |
set_period | 设置 K 线周期 | 周期必须和数据文件后缀一致 |
add_param | 依次为参数名、起始值、结束值、步长 | 参数范围不要过大,避免组合爆炸 |
add_param("fast", 5, 30, 5)代表fast从 5 到 30 每次加 5,即 5、10、15、20、25、30 共 6 个值;slow从 20 到 100 每次加 10。两个参数组合起来是 6 乘 9 共 54 组回测。workers=8会同时启动 8 个进程,54 组回测通常几十秒能跑完,但如果换成分钟级数据并加入止损参数,组合数很容易膨胀到几千组,这时要控制workers数量,避免内存不够。
4.4 读取优化结果并判断参数稳健性
优化器运行完后,outdir下会生成汇总 CSV,里面至少包含每组参数对应的总收益、最大回撤、夏普比率、交易次数等。用 pandas 做简单分析:
import pandas as pd res = pd.read_csv("output/optimize_result.csv") # 按夏普比率排序 res_sorted = res.sort_values("sharpe", ascending=False) print(res_sorted.head(10))按夏普排序后,你会发现收益最高的一组往往不是夏普最高的一组,通常收益最高伴随较大回撤。我一般会先看夏普大于 1 的组合里,哪个参数区域的交易次数比较稳定,再用样本外数据去验证。比如用 2023 年的数据选出的参数,拿到 2024 年的数据上跑一遍,如果收益和回撤变化太大,说明参数过拟合了。
5. 回测报告的最后一公里:WtBtAnalyst 计算指标与几个必须避开的坑
5.1 把回测结果变成一份可以答辩的 Excel 报告
完成了参数选择,最后一步是用WtBtAnalyst生成一份规范的绩效报告。这个模块会读取回测输出的 dsb 文件,计算年化收益率、夏普比率、最大回撤、卡玛比率、盈亏比等指标,并输出到 Excel。
from wtpy.apps import WtBtAnalyst analyst = WtBtAnalyst() analyst.set_parsed_local("log/bt_result_20240101.dsb", "rb.HOT", "SHFE", "m5") analyst.set_benchmark("SHFE.rb.HOT") analyst.calc_and_dump("report.xlsx")set_parsed_local的第一个参数是回测引擎生成的原始结果文件,后面依次是合约代码、交易所、周期;set_benchmark用来设置基准,建议选择同一品种的指数或主力连续;calc_and_dump执行计算并导出 Excel。生成的报告里,我最常用的是“月度收益”工作表和“逐笔交易”工作表,前者能看出策略收益是否集中在某个时间段,后者能检查单笔亏损的来源。
5.2 常见的坑和排查思路
根据实际的排错经验,回测结果异常时先查这几个点:
| 症状 | 排查方向 | 处理建议 |
|---|---|---|
| 数据加载失败 | dsb 文件路径和合约代码不匹配 | 检查set_code的代码和文件名是否一致 |
| 成交全部在开盘瞬间 | 没有设置合理的手续费和滑点 | 在策略初始化中设置好费率 |
| 结果全为 0 | 仓位方向反了 | 查看逐笔交易列表,确认买卖方向 |
| 连续合约跳空明显 | 没有处理换月规则 | 用WtHotPicker生成换月策略 |
| 优化结果和单次回测不一致 | 上下文被多个进程共享 | 确认策略中没有全局可变状态 |
5.3 一个小技巧:用 WtHotPicker 处理主力连续合约换月
如果你的标的用的是rb.HOT这种主力连续合约,换月时的价格跳空会被系统当成真实波动,策略很容易在换月点产生假信号。WtHotPicker能自动根据 datakit 的snapshot.csv推导出换月日期和换月方式,然后将换月规则应用到回测数据上。用法上不需要自己手动解析换月信息,只需把 datakit 生成的数据目录传给WtHotPicker,它会输出一组规则,再把这组规则注册到回测环境里,之后的连续合约 K 线就会按规则做拼接处理。这个步骤看起来不起眼,但它直接决定了日线策略在主力连续合约上的回测可信度。
本文还有配套的精品资源,点击获取