回测很快实盘很慢:除滑点外的执行层差异清单 前言用天勤TqBacktest做历史回测时常见体验是同一段 Python 代码几分钟跑完两三年螺纹钢 5 分钟线CPU 占用也不高。换上TqKq模拟或TqAccount实盘同一台机器夜盘风扇转起来循环体感“变慢”成交节奏也和回测曲线对不上。很多人第一反应是“回测滑点设小了”其实除滑点外还有一整类执行层差异数据推送密度、报单撤单次数、网络等待、拒单与部分成交回测里要么没有、要么被简化。下面用对照方式说明这些差异各自指什么、在代码里对应天勤的哪些接口、转模拟盘前建议做哪些检查。目的不是否定回测而是让你知道回测快往往因为“环境更理想”实盘慢并不一定是程序写坏了。一、数据密度回测帧少、实盘 tick 多回测由历史数据按时间推进若策略用is_changing(kl.iloc[-1], datetime)过滤只有新 K 线出现时才进信号逻辑一秒内可能只处理几次。实盘订阅get_quote后盘口last_price、买卖价量每个 tick 都可能变若误写成is_changing(kl)或is_changing(quote)且不指定字段主循环会在一秒内跑几十上百次完整策略CPU 自然远高于回测。检查项实盘与回测是否同一套触发规则quote 仅在做盘口过滤时读取不要用它驱动整段 K 线均线计算。二、成交模型ACTIVE、PASSIVE 在实盘才“疼”TargetPosTask的price参数ACTIVE表示对价买用卖一、卖用买一PASSIVE表示排队买用买一、卖用卖一。回测里模拟成交往往较干脆实盘 PASSIVE 可能整夜挂着不成交ACTIVE 在薄盘口会吃大滑点。部分成交时volume_left大于零、pos.pos只变一部分回测曲线常假设一次到位。检查项模拟盘用get_trade()统计成交笔数、均价与信号价的差拒单时读order.last_msg。三、TargetPosTask 撤单改价带来的“慢”官方文档写明task 在行情变化时会更新报价价格变则先撤再挂。夜盘波动大时单次wait_update内 task 工作量增加两次wait_update间隔若还夹了大段计算会表现为“程序变慢、行情处理迟”。这不是网络带宽不够而是执行层在频繁撤单。检查项统计每小时报单与撤单次数若过高考虑降低信号频率或不用 PASSIVE。四、网络与 wait_update 在实盘才真等回测的wait_update吃的是本地已下载的历史包几乎不等待广域网。实盘的wait_update要真连行情与交易网关若在两次调用之间写大文件、同步调 HTTP、或time.sleep会推迟收包表现为quote.datetime落后。回测里同样的 sleep 可能不明显因为数据照样按历史节奏灌入。检查项在循环末尾打单次耗时超过数百毫秒就要 profile 哪一行阻塞。五、合约与换月underlying_symbol 仅实盘会变回测若订KQ.m主连序列连续。实盘下单必须落到具体月份主连 quote 上的underlying_symbol字段指向当前主力合约换月时会变。若策略仍对旧月份set_target_volume会出现订错合约、持仓对不上执行层表现就像“变慢、乱套”。检查项换月日前后打印underlying_symbol与get_position的合约是否一致。六、交易时段、夜盘与人工回测历史已含休市实盘在夜盘结束到日盘开盘的衔接分钟若缺少quote.trading_time一类过滤可能多报几次废单。人工在 APP 改仓、多进程误开两个TqApi连接同一账户都是回测不会出现的现象。七、建议的对照实验选与回测相同的一个月区间用TqKq跑模拟不能要求逐笔相同对比成交次数、平均持仓时间、报单拒单率、主循环平均耗时。差异表写下来比口头说“回测骗人”更能指导改代码。总结回测与实盘的差距很多时候并不在策略逻辑本身而在执行环境把同一逻辑放大成了不同节奏回测里数据推进节奏可控、成交模型相对理想而实盘里触发更细密、成交路径更复杂、拒单和撤单会把系统拖进额外开销。想把这部分衔接好需要把触发频率、成交路径、撤单行为和网络等待逐项对齐例如 K 线 datetime 触发是否一致、quote 字段是否被误用来驱动全量计算、ACTIVE/PASSIVE 的假设是否匹配等。再用结构化日志统计成交笔数、volume_left 与失败原因判断慢是正常的工程代价还是逻辑错误放大。把执行层差异当成可验收的工程指标对待实盘的稳定性才会随着你迭代而提升。FAQ1回测把手续费调高就够吗不够还要在模拟盘看成交率与部分成交。2回测里 CPU 也很高同样查 is_changing 是否过宽与实盘同一套过滤。3tick 级回测和 K 线策略能比速度吗数据帧密度不同不可直接比循环耗时。4多账户回测与实盘每个账户独立做成交统计对照。风险提示以上内容用于研发预期管理不构成投资建议。