前言
国内期货量化程序常 7×24 挂在服务器或工位电脑上:日盘、夜盘连续运行,中间只依赖程序自己收行情、下单。运行几小时或几天后,有人发现日志不再刷新、get_quote里的时间字段停在很久以前,但进程还在——俗称“卡住不收行情”。也可能是交易所休市,K 线本就不该动,需要先排除正常休市再查故障。
本文从期货程序化实盘与模拟常见场景出发,说明可能原因、如何用天勤TqSdk的wait_update模型排查与恢复。不默认你懂网络协议,会解释“行情时间从哪来”“为什么 sleep 会导致假死”。
一、先确认:是故障还是休市
期货品种有交易时段表(日盘、夜盘、小节休息)。休市时没有新的 tick 聚合,5 分钟、1 分钟 K 线的datetime不会向前跳,quote 的最新价也可能长时间不变。此时程序若仍在wait_update里阻塞等待,属于正常,不是“断了”。
判断方法:对照交易所当日公告或行情软件,是否处于休市;若仅quote.datetime不动但账户、委托仍能通过其他渠道更新,再进入故障排查。
二、行情里的“时间”指什么
天勤get_quote("SHFE.rb2510")返回的 quote 对象带有datetime等业务字段(由行情服务写入,表示该行情快照对应的交易所时间)。策略里打印quote.datetime可观察行情是否在推进。K 线表get_kline_serial里每一行也有datetime,表示那根 bar 的时间标签。
这些时间都不是本机time.time()自己造的;本机时钟快慢与行情是否推进无直接关系。
若长时间不推进,要么是市场无成交/休市,要么是程序没再收到包,要么是收到了但没调用wait_update合并进内存。
三、原因一:主循环阻塞,wait_update 调用太少
天勤模型下,wait_update()负责收包、更新内存截面、并给TargetPosTask等后台任务发单机会。官方文档说明:若在两次wait_update之间sleep(5)、做同步 HTTP、跑大型机器学习推理,则这段时间内行情与回报都会滞后,表现为quote.datetime“卡住”。
错误示例:用time.sleep(60)等下一根 1 分钟 K 线——应改为等 K 线表datetime变化(is_changing),否则 sleep 期间无法收包。
恢复思路:缩短循环体、去掉 sleep、把 IO 移到别的线程;在循环末尾打单次耗时,超过数百毫秒就要优化。
四、原因二:网络、休眠、多 Api 未关闭
笔记本合盖休眠、VPN 断线、机房网络抖动,会导致 TCP 连接僵死。另:Jupyter 或脚本多次TqApi(...)而不api.close(),多个连接叠加以致异常——表现也可能是行情乱跳或停更。
恢复:对运行中的进程api.close()后重启单实例;检查是否只应有一个策略进程连同一交易账户。
可选:对wait_update(deadline=...)设超时,超时打告警(文档提醒 deadline 用法非简单场景需谨慎,避免任务堆积)。
五、原因三:合约订错或只有部分合约停更
若十个品种只有一个datetime不动,优先查该 symbol 是否写错交易所前缀、是否已到期摘牌、是否未订阅夜盘合约。刚订阅后文档提示quote.datetime可能暂时为空,需区分“从未收到”与“中途停收”。
六、协程里误用 wait_update
若在 asyncio 协程里直接调用wait_update,天勤会报错“不能在协程中调用 wait_update”。若异常被吞掉,表面像“程序挂着没数据”。Notebook 异步 demo 应使用register_update_notify,与同步while True分开。
七、恢复操作清单(建议打印)
- 确认是否休市。
api.close(),确认旧进程结束。- 重启策略,打印各合约
quote.datetime。 get_position与策略持久化记录对照(若有)。get_order看在途单,必要时人工撤单。
断线重连专题可与持仓核对、状态持久化一并做。
总结
期货量化程序长时间运行后“不收行情”,要先区分休市与故障。行情时间来自天勤业务对象上的datetime等字段,依赖wait_update持续合并数据包。最常见故障是主循环阻塞和网络/连接问题;其次是合约订阅错误和多 Api 未关闭。
恢复以单实例重启、重订阅、持仓与委托核对为主。预防靠避免 sleep 等 bar、控制循环耗时、进程守护与日志记录quote.datetime便于画图定位。
FAQ
1)wait_update 一直阻塞算卡死吗?
无 deadline 时会等数据,休市时可能长时间无包,属正常。
2)TargetPosTask 会导致行情停吗?
不会直接停行情,但频繁撤单会增加循环负担,间接拖慢处理。
3)回测会“停行情”吗?
历史数据播完抛BacktestFinished,是正常结束。
4)是否需要单独行情线程?
天勤默认单线程wait_update模型,不要再开线程抢 CTP 式回调。
风险提示
本文用于运维排查,不构成投资建议。