4. 截面回测引擎
回测框架应匹配问题形态:截面选股用矩阵驱动而非事件驱动;信号与风控和实盘同源。
作用:用「日期 for-loop + 截面矩阵运算」逐日模拟组合净值,输出绩效与报告。
输入与输出的契约
输入是信号层的每日合成分截面和预处理层的 returns 面板。输出是净值曲线、绩效指标(Sharpe / 最大回撤 / Calmar / 胜率 / 盈亏比)和图表报告。
这一层对上下游的承诺:T 日的每一个决策只用 T-1 及更早的信息;信号、风控、因子筛选与实盘走同一套实现。回测数字的意义完全建立在这两条之上——破坏任何一条,Sharpe 再高也只是自欺。
决策一:矩阵驱动,而不是事件驱动
Alpha101 是每日对 500 只标的进行截面评分排序的截面问题,而非针对单只标的的突破交易。Backtrader 等事件驱动框架把每根 K 线当事件逐个处理,在此场景下性能开销过高;自研矩阵驱动引擎约 300 行代码,执行效率更优,且更容易从结构上杜绝未来函数。
一般化的判据:回测框架应匹配问题形态。逐标的的时序策略适合事件驱动;逐日全截面的选股策略适合矩阵驱动。
决策二:防未来函数靠物理隔离,不靠逐处检查
信号矩阵在进入主循环之前,就对每个标的整体后移一天——T 日行上放的是 T-1 收盘后就能算出的分数。主循环里没有任何「这个数据是不是未来的」的时间判断,因为被后移过的矩阵在结构上就不可能包含未来。
这个设计的好处是审计成本低:要验证回测无未来函数,只需要检查一处(入口的 shift),而不需要逐行审查整个循环体。
决策三:成本显式建模,调仓频率是一等参数
换手成本不是事后估算,而是每个调仓日精确计入:
换手率 = Σ|新权重 − 旧权重| / 2
当日成本 = 换手率 × 单边费率 × 2(双边)算个例子:旧组合 {A: 50%, B: 50%},新组合 {B: 50%, C: 50%}。A 清仓 50%、C 建仓 50%、B 不动,换手率 = (50% + 0 + 50%) / 2 = 50%,按单边费率 0.1% 计,当日成本 = 50% × 0.1% × 2 = 0.1%,直接从当日收益里扣。
这个算术直接解释了为什么调仓频率必须与实盘一致:同样的组合,每日调仓的摩擦成本约是 5 日调仓的 5 倍。回测按 5 日、实盘按每日,亏损的主因就不是因子失效而是摩擦 → 事故档案 · 调仓频率不一致导致摩擦放大。
调仓相位(首次调仓落在第几天)同样是显式参数:同一策略把相位从 0 拨到 4,净值曲线可能差出一截。这就是 timing luck——好策略应该对相位不敏感,所以它必须可测。
一次调仓日发生了什么
以默认参数(Top 10、5 日调仓、单边成本 0.1%)为例,设今天是 T 日且距上次调仓已满 5 个交易日:
- 取信号:取出 T 日行的截面分数(实际是 T-1 的信息,见决策二)
- 截面排序:去掉缺失值后取前 10 名。有效分数不足 10 个就有多少取多少,小样本日降级持仓
- 等权分配:每只 1/10(评分加权作为备选口径预留,当前实际走等权)
- 风控过滤(顺序敏感):单票超 10% 封顶 → 持仓数超 30 按权重截断 → 当前回撤 ≥ 15% 时全体权重乘 0.5 → 总仓超 95% 整体缩放 → 丢掉 < 0.01% 的粉尘权重。注意回撤状态来自昨天日终的记账(第 6 步),不引入当日信息
- 算换手与成本:按决策三的公式,从当日收益里扣
- 记收益、滚净值:日收益 = Σ 权重 × 当日 returns − 成本,净值累乘。当日缺 returns 的持仓按 0 收益处理——这是停牌 / 缺数据的简化口径,与预处理层的
tradable_mask缺口是同一件事 - 日终风控记账:更新历史峰值、算当前回撤,供下一个调仓日的第 4 步使用。回测路径的「回撤止损」就在这里——执行路径恰恰缺的就是这一步(见下方缺口)
非调仓日只有第 6、7 步:持仓不动、换手为 0,净值随市场漂。
常见错误
- 止损公式语义错误(
max()保底导致净值不跌破本金就永不触发),风控规则上线前未经自动化测试验证 → 事故档案 · 止损逻辑失效 - 回测与实盘的信号 / 风控 / 因子筛选三条路径各自独立实现,结果无法复现 → 强制统一到唯一实现,事故档案 · 回测实盘路径分叉
当前状态
历史回测在特定区间与参数下得到 Sharpe 1.3–1.8 量级的结果。口径不一、均为局部拟合,须与 SPY/QQQ 基准对比才有意义——详见指标口径与免责声明。
主要缺口:回撤止损只在回测路径生效。权重类风控(单票 / 持仓数 / 总仓上限)已通过复用同一个风控模块接入执行路径,但回撤状态只有回测的日终记账在维护,实盘路径没有喂入回撤数据,回撤降仓不会触发。
实现对照
上一层:3. 因子与信号 DWS · 下一层:5. 交易执行层 ADS