← 返回目录
p4.1动手⏱ 约 17 分钟

引擎解剖:向量化 vs 事件驱动

我预期约束会让回测变差,实测推翻了它——而这个失败比结论更有用

🔎 最后验证 2026-07📚 来源:两种引擎对比、约束拆解与绑定条件于 2026-07-31 在 ECS 实测(8 只沪深300 成分股,2010-01-04~2026-07-29,31847 个交易日),输出见 code/outputs/stdout.txt🧰 Python 3.12.13、pandas 3.0.5、qlab.engine(本课自研)
为什么学这个

P4 章开始造东西。第一个问题就是选型:向量化,还是事件驱动?

向量化三行写完,快 371 倍。事件驱动要写事件、撮合、账户三层,慢得多。那为什么还要写?

标准答案是:"因为向量化表达不了 T+1、涨跌停、整手、资金约束——这些都会让回测比现实更好看。"

我带着这个预期做了实测,然后被推翻了。

8 只标的里,向量化只有 3 只是高估,平均反而低估 2.64pp。三条交易约束的影响,合计 -0.05pp

那真正吃掉收益的是什么?成本,+30.94pp。

这一节讲清楚:两种引擎到底差在哪,以及那三条约束什么时候才会绑定

💡 打个比方

汽车碰撞测试里有一堆安全装置:气囊、溃缩区、防抱死。

你在市区通勤测一年,它们一次都没触发。这不能证明它们没用——只能证明你的测试场景没覆盖到它们的作用域

回测引擎的约束也是这样。问题不是"要不要实现",而是"你知不知道它有没有绑定"。

一、速度:向量化确实快 371 倍

单标的:向量化 1.7ms | 事件驱动 616.3ms | 慢 371 倍

这个差距是决定性的:参数网格搜索时,你一天能试几次,取决于它。

所以本课的分工是:P5 用向量化做粗筛,用事件驱动做终验。先用快的把候选缩小到十几个,再用慢的严格验证。

二、两种引擎差多少:结果与预期相反

8 只个股,同一条 5/20 均线策略:

标的向量化累计%事件驱动累计%差(高估)
sh.60000026.3258.59-32.27
sh.600009-15.11-14.70-0.41
sh.60001032.9919.55+13.43
sh.60001121.0646.37-25.32
sh.6000152.25-8.90+11.15
sh.60001633.3918.31+15.09
sh.60001812.3714.09-1.72
sh.600019-33.51-32.45-1.07

平均 -2.64pp,8 只里只有 3 只是高估。

⚠️ 避坑

我预期的是"向量化必然高估",实测方向不一致。这个失败值得单独讲。

原因:两种引擎最大的差异不是约束,而是成交价假设

  • 向量化:默认按收盘价换仓(信号 shift 一位,乘以次日收益)
  • 事件驱动:按次日开盘价成交

开盘价高于还是低于昨收,是随机的。所以这个差异双向抵消,而且量级可以很大(单只标的差 32pp)。

教训:不要把"实现更精细"直接等同于"结果更保守"。你必须逐条拆开,才知道哪一条真的在起作用。

🔧 动手做:推翻"约束一定让回测变差"的直觉(6 分钟)

python vec_vs_event.py,盯【二】那张表最后一列「高估pp」。

你以为加了约束(资金/整手/T+1/涨跌停)的事件驱动,一定比向量化更悲观、更接近现实?

你会看到(实测):8 只标的里 5 只反而是事件驱动更高,方向根本不一致(从 -32pp 到 +15pp 都有)。

想明白:两个引擎最大的差异不是约束,是成交价假设(向量化用当日收盘、事件驱动用次日开盘),而这是双向的——有时帮你、有时坑你。真正单向吃你收益的是成本(下一节 p4.2 会量出来)。所以别默认"更严格的引擎 = 更保守的结果",先分清哪些差异是双向的、哪些是单向的。

三、逐条拆:哪条约束真的吃掉了收益

配置平均累计%相对基准平均成交平均被拒
全部约束(基准)12.61%427.20.0
关掉涨跌停12.61%+0.00pp427.20.0
关掉 T+112.61%+0.00pp427.20.0
关掉整手12.56%-0.05pp430.80.0
关掉三项约束12.56%-0.05pp430.80.0
再去掉成本43.55%+30.94pp442.80.0

结论很干脆:三条交易约束合计 -0.05pp,而成本一项就是 +30.94pp。

这与 p0.2 的死亡线完全一致:对大盘股 + 低频策略,成本是唯一真正吃掉收益的东西。

四、那三条约束什么时候才会绑定

被拒 0 笔——这不是引擎没实现约束,是这个设定下约束不绑定。我们逐条证明它确实实现了:

(a) 一字板:大盘蓝筹几乎没有

8 只标的共 31847 个交易日:一字涨停 8 天、一字跌停 4 天(合计占 0.038%)

万分之四。大盘蓝筹极少出现全天封死。但小盘股、ST 股、极端行情段完全是另一回事——2015 年千股跌停时,"想卖卖不掉"是压倒性的。

(b) T+1:日频引擎里结构上不可能绑定

我构造了一个信号天天翻转的策略来触发它:

开启 T+1:成交 3974,被拒 0 笔
关闭 T+1:成交 3974,被拒 0

完全相同。

原因是架构性的:本引擎每天只交易一次,今天买、最早也是明天卖——而 T+1 恰恰允许次日卖

T+1 只在日内多次交易时才绑定(早盘买入、尾盘想卖)。

所以在日频单次调仓的引擎里,enforce_t1 是一段正确但用不上的代码。它的价值出现在你把引擎扩展到分钟频、或一天内多次调仓的那一刻。

知道这一点,比让它默默躺在那里更重要——否则你会以为自己"已经处理了 T+1"。

(c) 资金/整手:小资金下立刻绑定

把本金从 100 万降到 5000 元:

成交 1 笔,被拒 131 笔
  被拒原因:资金不足一手,无法建仓 × 131
⚠️ 避坑

这 131 笔被拒,是我在写这一节时才补进引擎的。

原来的代码里有一条"目标差额不足一手就不动"的规则。它会静默吞掉一种真实情形:想建仓,但连一手都买不起

不记录的话,回测会显示"策略选择空仓"——而真相是"你没钱建仓"。两者在净值曲线上完全一样,在结论上天差地别:前者说明策略在规避风险,后者说明你的本金不够跑这个策略。

引擎的价值,一半在于它算得对,另一半在于它把"没做成的事"也记下来。

五、选型结论

向量化事件驱动
速度快 371 倍
资金/整手约束表达不了
涨跌停/停牌表达不了
被拒委托记录没有这个概念
适用参数粗筛终验、极端场景、小资金

本课的做法:两个都要,分工明确。P5 的参数搜索用向量化(否则搜不完),最终候选用事件驱动跑一遍(否则不知道约束绑没绑)。

❓ 测验
你用事件驱动引擎回测,全程「被拒委托 0 笔」。最合理的解读是?
✏️ 填空
本节实测:三条交易约束合计只影响 -0.05pp,而去掉 ___ 一项就带来 +30.94pp 的高估。

📌 免责:本课为技术教学,标的为沪深300 成分股按代码序取样(非精选),所有回测为历史模拟,不构成投资建议。

✅ 小结

这一节的结论,有一半和我预期的相反:

  • 速度:向量化快 371 倍 → 分工是"粗筛用向量化,终验用事件驱动"
  • 两种引擎的差距方向不一致(8 只里 3 只高估,平均 -2.64pp)——因为最大差异是成交价假设(收盘价 vs 次日开盘价),那是双向的
  • 三条交易约束合计 -0.05pp,成本一项 +30.94pp —— 与 p0.2 死亡线一致
  • 约束的绑定条件:一字板占 0.038%;T+1 在日频单次调仓的引擎里结构上不可能绑定;资金/整手在小资金下立刻绑定(5000 元本金 → 131 笔被拒)

外加一条工程纪律:引擎不仅要算得对,还要把"没做成的事"记下来。那 131 笔被拒是我写这一节时才补进引擎的——在此之前,"没钱建仓"会被伪装成"策略选择空仓"。

下一节把参数摆到明处:capital、commission、slippage、benchmark。每一个默认值都是一个假设,而假设不写出来,回测就没法被别人复核。

下一节 → 数据装配与参数:capital / commission / slippage / benchmark
🔎 来源与核验· 6 条,点开核对
本节每个关键论断都对应一个可追溯的来源 —— 这是本课程"靠谱、不过时"的底线。
「单标的 5/20 均线策略:向量化 1.7ms、事件驱动 616.3ms,慢 371 倍(4023 个交易日)」
📚 本节 code/vec_vs_event.py,2026-07-31 于 ECS 实测,输出见 code/outputs/stdout.txt✓ 已核验 2026-07
「8 只个股对比:向量化相对事件驱动平均 -2.64pp、中位 -0.74pp,仅 3/8 为高估;单只最大差异 -32.27pp(sh.600000)」
📚 同上实测✓ 已核验 2026-07
「约束拆解(8 只平均累计收益):全部约束 12.61%;关掉涨跌停 +0.00pp、关掉 T+1 +0.00pp、关掉整手 -0.05pp;再去掉成本 43.55%(+30.94pp)」
📚 同上实测✓ 已核验 2026-07
「8 只标的 31847 个交易日中,一字涨停 8 天、一字跌停 4 天,合计占 0.038%」
📚 同上实测(按前收盘 ±10% 判定,low≥涨停价 或 high≤跌停价)✓ 已核验 2026-07
「信号天天翻转的策略下,开启/关闭 T+1 的成交与被拒笔数完全相同(3974/0):日频单次调仓引擎中 T+1 结构上不绑定」
📚 同上实测✓ 已核验 2026-07
「本金降至 5000 元:成交 1 笔、被拒 131 笔,原因均为「资金不足一手,无法建仓」」
📚 同上实测✓ 已核验 2026-07
智图软件的赞赏码
都看到这了,打个赏呗!
接下来 · p4.2
数据装配与参数
继续读下一节 →