从 vn.py 迁到天勤:事件引擎与 wait_update 怎么转
前言
vn.py 那套我熟:EventEngine一转,on_tick、on_bar、on_order各自注册,CtaTemplate 里写逻辑,挺有「正规军」的感觉。第一次用天勤时,我下意识又建了一个EventEngine,把天勤的 quote 往里面塞,结果双引擎并行——tick 进 vn、也进天勤,下单有时走 MainEngine、有时又在天勤 循环里insert_order,模拟盘一天下了双倍单,风控当场叫停。
后来才明白:天勤自己已经是引擎,while True: api.wait_update()就是主事件泵,你要做的是把原来的on_xxx改成「在这一帧里,如果 is_changing 了就调用」。不是天勤缺功能,是调度权只能有一个老大。
下面是我带同事迁 vn 时的对照表和 class 模板,算法(均线、通道)可以原样搬,BarGenerator 的思想也能留,但数据源和循环必须换天勤的。
一、结构对照:别找一一等价,找职责等价
| vn.py 里你熟悉的 | 天勤里建议 |
|---|---|
| EventEngine | while True: api.wait_update() |
| on_tick | if api.is_changing(quote): ... |
| on_bar | if api.is_changing(klines.iloc[-1], "datetime"): ... |
| MainEngine.send_order | insert_order/TargetPosTask |
| CtaTemplate | 自写class+on_update() |
vn 的「事件类型字符串」在天勤里没有对应物——不必硬造,用is_changing的字段参数就能达到「只在价格变时算」「只在新 K 线时算」的效果。
二、把 CtaTemplate 收成 class(我用的模板)
classMyStrategy:def__init__(self,api):self.api=api self.quote=api.get_quote("SHFE.rb2510")self.klines=api.get_kline_serial("SHFE.rb2510",60)defon_update(self):api=self.apiifapi.is_changing(self.klines.iloc[-1],"datetime"):self.on_bar_close()ifapi.is_changing(self.quote,"last_price"):self.on_tick()defon_bar_close(self):passdefon_tick(self):passapi=TqApi(TqSim(),auth=TqAuth("账户","密码"))s=MyStrategy(api)whileTrue:api.wait_update()s.on_update()多策略就多个 instance,禁止多个策略共用一个全局target_pos。vn 里你可能习惯每个 Strategy 独立,天勤也一样,只是共用一个wait_update。
三、数据容器:BarGenerator 可以留,引擎别留
vn.py 的 BarGenerator、ArrayManager 继续服务你的指标计算没问题,但 K 线来源改成get_kline_serial的 DataFrame。我踩过的坑是:仍在 vn 里合成 bar,天勤也订了 kline,两套 bar 差一根,信号差一分钟,能纠结一整天。
不要在 vn 的MainEngine里嵌TqApi,选一条主循环。研究阶段可以在 Jupyter 里用 vn 算因子、天勤只负责执行,但生产环境尽量一条线,否则出问题不知道信谁。
四、迁移顺序(我要求新人按周走)
- 第一周:只迁行情和指标,模拟盘对价格、对 K 线收盘时间,不下单。
- 第二周:迁
TargetPosTask或insert_order,1 手来回,对持仓和 order 日志。 - 第三周:迁风控、多品种、夜盘时段过滤。
跳步的人往往在第三周才暴露「bar 差一根」这种基础问题,返工更痛。
五、常见坑
- vn 线程 + 天勤 单线程:二选一。
- 全局变量在多个策略间共享:状态进 class。
- 回调里下单、主循环里也下单:统一从一个
on_bar_close出口下单。
总结
vn.py 迁天勤,我花最多时间的不是学 API,是克制再包一层 EventEngine 的冲动。天勤的wait_update已经帮你阻塞到「有更新」了,is_changing帮你过滤「谁更新」,这和 vn 的 emit 本质是同一件事。你把 CtaTemplate 改成 class + on_update,算法留、调度换,通常两三周能平稳过渡。文档advanced/for_vnpy_user.rst建议团队一起读,有争议时以文档为准,别以「我以前 vn 是这么写的」为准——两个框架的脾气不一样。
FAQ
1)能否长期两套并存?
不建议,维护成本和幽灵 bug 都会上去。
2)回测怎么迁?
用TqBacktest替换 vn 回测模块,策略类尽量复用。
3)多策略怎么写?
多 class,一个wait_update,各自is_changing早返回。
4)性能会变差吗?
看你是不是 tick 级全算;vn 也一样怕这个。
5)官方迁移说明在哪?
advanced/for_vnpy_user.rst。
风险提示
本文用于期货量化技术实践讨论,不构成投资建议。
