从 0 到 1 搭一套期货量化系统:广发仿真 + vnpy + CTP 接入踩坑全记录
写在前面
我一直想有一套属于自己的、能自动买卖的期货量化系统——不是买别人的软件,而是从框架、策略、接入到界面全部自己掌握。
这篇文章记录我用一个周末把"玉米双均线趋势跟踪策略"跑通在广发期货 CTP 仿真环境上的全过程。重点不是炫技,而是把过程中最折磨人的 CTP 握手失败(错误码 4040 / 4097) 从现象到根因彻底讲清楚——这部分在网上的资料非常零散,踩过的坑希望你能直接跳过。
所有代码、配置、界面都已实际跑通,截图里的黑窗口日志都是真实输出。
一、整体方案与技术选型
| 层 | 选型 | 说明 |
|---|---|---|
| 量化框架 | VeighNa(vnpy)4.4.0 | 开源、社区大、CTA 模块成熟 |
| CTP 接口 | vnpy_ctp 6.7.11.4(自带 6.7.11 API) | 接上期所 CTP 协议 |
| 券商环境 | 广发期货仿真 CTP2358 | 仿真账号免门槛,先验证再上实盘 |
| 策略 | 玉米双均线趋势跟踪 v1.0(增强版) | 金叉多 / 死叉空 + ATR 止损 + 移动止盈 |
| 运行 | 虚拟环境 + 一键 .bat 启动器 | 双击即跑,不用敲命令 |
| 品种 | 玉米 / 橡胶 / 白糖 / PTA(多实例) | 一个品种一份策略实例 |
为什么选 vnpy:CTA 模块原生支持策略的"初始化 / 启动 / 停止",有图形界面可以看盘,也有无界面模式适合常驻运行。对新手最友好。
为什么先跑仿真:仿真环境和实盘用的是同一套 CTP 协议、同一套看穿式认证流程,但不需要真金白银。先把连接和策略在仿真里验证稳了,再填实盘配置(BrokerID 换成 9000、换生产授权码)即可。
二、策略:玉米双均线趋势跟踪 v1.0
策略本身不难,核心是趋势跟踪 + 风控,而不是预测涨跌:
- 进场:快线(10 周期)上穿慢线(30 周期)且呈多头排列 → 买开;反之下穿 → 卖开(可关空单)。
- 出场:ATR 动态止损(止损距离 = 3 × ATR,波动大自动放宽)+ 移动止盈(盈利后回撤 2% 自动落袋)。
- 仓位:按账户权益和 ATR 自动算手数,单品种最多 5 手,避免一把梭。
- 多品种:每个品种单独起一份策略实例,互不影响,各自管自己的仓位和止损。
双均线是"右侧"策略,震荡市会反复被打脸,所以加了均线排列过滤 + ATR 止损来控回撤。v1.0 阶段目标就是"能稳定自动跑、不爆仓",不是追求高收益。
三、界面与运行效果
启动图形界面(python run_vnpy.py --gui)后,窗口标题显示为"果壳 1.0 玉米交易系统":左侧有交易/委托/持仓面板,右侧和底部是行情、活动、成交、日志区。底部的"日志"区域会实时打印 CTP 连接状态,不用依赖被列宽截断的界面提示。
如果想完全自动、不需要看盘,直接双击 启动玉米自动策略.bat(无界面模式),会在黑窗口里看到每个品种的连接、订阅和交易信号日志。
四、最硬的一关:CTP 仿真接入的 4040 / 4097
这是整篇最值得看的部分。
3.1 现象
双击启动器,黑窗口卡在:
行情接口:4040 CTP:API Front shake hand err: decode err
交易服务器:4097 连接断开
连锁反应:收不到合约列表 → 订阅 c2609 失败 → 策略初始化失败。
4040 / 4097 的本质是"握手认证失败"——CTP 前置在建立连接时校验你的身份信息(账号、密码、AppID、授权码、运行模式)没通过,直接断开。它发生在"下单"之前,所以和策略逻辑毫无关系。
3.2 三个根因(逐个排除)
我前后折腾了很久,最后定位到三个叠加因素,缺一不可:
根因 1:vnpy 根本不读你写的 production_mode 字段 ⭐(最大的坑)
我们最初在配置里写:
GF_SIM = {
"production_mode": True, # 以为这个控制实盘/仿真
...
}
翻 vnpy_ctp 源码才发现,网关 connect() 实际只读一个叫 柜台环境 的键:
# vnpy_ctp/gateway/ctp_gateway.py
envrionment = setting.get("柜台环境", "实盘")
production_mode = envrionment == "实盘" # 只有"实盘"才是 True
我们的配置里压根没有 柜台环境 这个键,于是 vnpy 默认当成 "实盘" —— 也就是一直用生产模式去连仿真前置。之前我反复改 production_mode 那几次,对 vnpy 来说完全是无效操作,这也是"怎么改都不行"的真正原因。
根因 2:仿真环境必须 production_mode = false(测评模式)
广发下载的 CTP API 包里有一份官方《接入仿真环境须知》,白纸黑字:
交易 TraderAPI 和行情 MdAPI,有一个 bool 类型的默认参数
blsProductionMode,表示 api 是否使用生产模式,true 为生产模式(默认值),false 为测评模式。即,接入评测(仿真)环境时,需留意配置blsProductionMode为 false。
也就是说,连仿真必须显式传 false。我们之前一直按"实盘 / true"连,握手必然失败。
✅ 正确写法:
GF_SIM = {
"柜台环境": "评测", # 关键!让 vnpy 传 production_mode=false
...
}
根因 3:CTP API 版本不匹配(6.7.11 vs 6.7.13)
vnpy_ctp 自带的底层 DLL 是 6.7.11,而广发仿真要求 V6.7.13。客户经理让从官网"软件下载"页下 CTP 仿真评测 API 包,里面 Win_Linux_v6.7.13_20260225_trader.zip 解压出 64 位 thosttraderapi_se.dll / thostmduserapi_se.dll,直接覆盖进:
vnpy_env/Lib/site-packages/vnpy_ctp/api/
覆盖前记得备份旧 DLL(建个 _backup_6.7.11/ 目录),万一要回滚。Python 是 64 位,所以一定要用包里的 64 位 se 版本。
4.3 解决后的样子
三个坑全填上之后,黑窗口出现如下日志:
行情服务器连接成功
交易服务器连接成功
行情服务器登录成功
交易服务器登录成功
交易服务器授权验证成功
4040 / 4097 彻底消失。复盘一下:握手失败基本只有两条路——要么"模式/认证"配错,要么"版本"不对。按上面三点逐一核对,基本都能过。
五、另一个差点让我放弃的坑:改错文件
4040 修好之后又报了一轮"找不到合约"。排查一圈,发现我前面把配置改在了根目录 ctp_config.py,但 run_vnpy.py 实际 from config.ctp_config import ... 读的是 config/ctp_config.py。
教训:Python 的导入路径和文件实际位置必须一致。改完配置一定用一行
python -c "from config.ctp_config import get_ctp_config; ..."验证"真正被加载的那个文件"内容对不对,而不是只看自己改的那个。
六、从单品种到多品种
量化不可能只做玉米。加上橡胶、白糖、PTA 时,架构上做了个清晰的决定:
vnpy 的 CTA 策略,每个实例绑定一个合约(vt_symbol)。多品种 = 每个品种起一份策略实例。 它们各自管自己的仓位、止损、信号,互不干扰。
实现上只是在入口维护一张表:
STRATEGY_SYMBOLS = {
"玉米": "c2609.DCE", # 大商所,乘数 10
"橡胶": "ru2609.SHF", # 上期所,乘数 10
"白糖": "SR2609.CZCE", # 郑商所,乘数 10
"PTA": "TA2609.CZCE", # 郑商所,乘数 5
}
然后遍历这张表,逐个 add_strategy → init → start。同时给策略加了个 multiplier 参数(玉米/橡胶/白糖 10 吨每手,PTA 5 吨每手),仓位计算才不会算错手数。
换月也很简单:把 c2609 改成 c2611 之类即可,仿真里哪个合约有行情就用哪个。
七、踩坑清单(Cheat Sheet)
给想自己搭的朋友一份速查:
- 握手 4040/4097:先查
柜台环境是否为"评测"(仿真),再查 DLL 版本是否和券商要求一致。 - vnpy 不读
production_mode:它读的是柜台环境这个键,"实盘"= 生产模式。 - DLL 必须 64 位且和 Python 位数一致:
import struct; print(struct.calcsize('P')*8)看位数。 - 改完配置验证的是"被加载的那个文件",不是你手改的那个。
- 非交易时间(午休 11:30–13:30、夜盘外)仿真不推送合约/行情,连上了也可能 30 秒收不到合约——这不是 bug,等开盘。
- 授权码有 T+1 生效:报备后第二天才可用,当天连会一直握手失败。
- 仿真账号首次登录必须改一次密码,改完同步到配置。
- 启动 ≠ 立刻下单:策略只在出现信号且空仓时才交易;停止也不会自动平仓,持仓需手动处理。
八、写在最后
这套系统现在能:双击启动器 → 自动连广发仿真 → 4 个品种各自跑双均线策略 → 自动买卖 + 止损止盈,图形界面也能实时看盘。
下一步计划:
- 在仿真里跑够 1–2 周,统计胜率、回撤、夏普;
- 把策略 v1.0 的几个参数(快慢线周期、ATR 倍数)做一轮参数优化;
- 验证稳定后再走广发实盘报备,填生产环境配置上实盘。
量化最有意思的地方,不是某次赚了多少,而是把"凭感觉"变成"可复现、可验证、可改进"的系统。这套骨架搭好之后,换策略、加品种、上实盘都是增量工作。
如果你也在用 vnpy 接券商仿真,希望这篇能帮你省下那几天和那几次"为什么就是不行"的崩溃。
附录:关键配置脱敏示例
# config/ctp_config.py(已脱敏)
GF_SIM = {
"用户名": "6000****", # 广发下发的仿真资金账号(已打码)
"密码": "********", # 首次登录改过的密码
"经纪商代码": "2358", # 广发仿真 BrokerID
"交易服务器": "183.62.252.251:42405",
"行情服务器": "183.62.252.251:42413",
"产品名称": "client_999071860_1.0", # 报备的 AppID
"授权编码": "********", # 广发下发的看穿式授权码(勿外泄)
"柜台环境": "评测", # 仿真必须为"评测"
}
⚠️ 授权码、密码、账号属于敏感信息,切勿发到公网。文中的图片和代码示例里的
****都是发布前必须打码的位置。AppID 和前置地址一般可公开,但建议也视券商要求处理。
本文为个人搭建经验记录,不构成任何投资建议。期货交易有杠杆风险,仿真验证充分后再考虑实盘。