[机器学习研究六]输出冻结与调仓频率前沿:净超额转正路径的可追溯实验

无名的人无名的人··4 浏览

摘要

本文是机器学习选股因子研究系列的首篇原创机制实验(非研报复现):PandaAI 平台仅提供"因子值日频重排"一种输出模式,本研究实现了平台未具备的输出冻结机制——同一模型、同一训练管线,仅将输出从日频重排改为块内冻结(冻结窗口 ∈ {21, 42, 63} 交易日),系统测绘"调仓频率-净超额前沿"。冻结 42 日配置将多头净超额由基线的 -7.36% 修复至 -0.32%(修复 95.7%),换手率由 53.87% 降至 16.27%,验证了"日频重排成本是净超额为负主因"的假设;但净超额未能转正,且前沿呈非单调形态(冻结 21 日反而是最差点,净超额 -6.90%)。

数据表明三项发现:其一,冻结使 Rank_IC 由 +0.0725 系统性衰减至 +0.046~+0.052(预测陈旧性成本),IC 衰减吞掉了约七成的成本节省;其二,非单调前沿源于边界重排摩擦——冻结 21 日有 36 个重排边界(每次重排引发整个截面次序重置),其换手(30.82%)反而高于冻结 42 日(16.27%)的三倍边界的一半还多,"更频繁地更新预测"在该机制下是纯摩擦;其三,盈亏平衡阈值可解——冻结 42/63 日下转正只需多头超额 ≥ 2.46%/1.80%,距实测值仅差 0.32/0.63 个百分点。本研究按"每一步可追溯"标准执行:全部 6 次平台运行的因子 ID、时长、算力账单,2 次实现失败(v1 版本索引错配导致输出常数化,浪费 28 算力)的完整错误数据与本地复现记录,均随文存档(data/failures/、data/freeze_run_ledger.json)。


一、引言

1.1 原创动机

系列前五篇的诚实总账留下一个结构性缺口:28 个同池配置在 10 日调仓、0.3% 单边成本下,多头净超额全部为负(最优 -5.34%)。归因指向平台的输出模式——因子值每日重排名次,即使模型预测不变,组合成分也在持续互换。平台不提供低频输出选项;文献中的低频再平衡做法(月频调仓回测)在平台的因子分层框架内也没有直接接口。

1.2 本研究要回答的问题

在不改训练管线的约束下,仅把输出改为"块内冻结":第一,换手能降多少;第二,预测陈旧化要付出多少 IC;第三,净超额能否转正;第四,前沿的形状是单调的还是存在结构性摩擦。

1.3 与既有工作的差异(原创性声明)

经社区全量 1168 帖标题查重:无同题。与本研究最接近的内容是平台功能层的"调仓周期设置"(1-10 日,作用于平台自身的交易模拟),而本研究的冻结发生在因子输出层——平台对此没有实现,训练节奏(21 日滚动重训)与输出节奏(21/42/63 日冻结)解耦是本文引入的机制。本系列内亦无先例:[研究二] 6.2 仅提出冻结设想未实验,本研究是其落地与延伸。


二、研究目的

(一)核心目标

  1. 在平台因子框架内实现输出冻结机制(训练/输出节奏解耦);
  2. 单变量测绘冻结窗口 {1, 21, 42, 63} 日的"调仓频率-净超额前沿";
  3. 分解 IC 衰减与成本节省两个对冲项,给出盈亏平衡阈值;
  4. 全程按可追溯标准存档:每次运行的凭证、每次失败的数据。

(二)实验设计

设计项 设定 说明
基座模型 LGBM 回归+风格中性化([研究三] 修复版,Rank_IC +0.0725) 系列最优策略配置
单变量 FREEZE_DAYS ∈ {1(基线), 21, 42, 63} 训练管线四组完全一致
冻结机制 每个冻结窗取首日截面预测值,整窗沿用(宽表按窗取首行广播) 窗内截面次序恒定
回测口径 20230101-20251231,10 日调仓,10 组分层 与系列全部实验一致
成本折算 换手 × 2 × 0.3% × 252/10 = 换手 × 0.1512 净超额 = 多头超额 − 年化成本
追溯凭证 因子 ID、运行时长、算力账单、失败错误原文 全部随文存档

输出冻结机制示意


三、研究过程:完整可追溯日志

Step 0【假设】

日频重排的年化成本 = 53.87% × 0.1512 = 8.15%,而基线多头超额仅 +0.79%——若输出冻结能把换手压到 20% 以下(成本 <3%)且 IC 衰减有限,净超额应显著改善甚至转正。判定标准:净超额是否 > 0。

Step 1【操作】v1 实现与三次平台运行

冻结实现(核心 6 行):因子预测按行展平为 (日期序号 pos, 股票 sym, 预测值) 宽表,按 pos // FREEZE_DAYS 分窗、transform('first') 取窗首截面广播全窗,再还原为行序输出。

# 冻结核心(仅输出层,训练管线与基线逐行一致;FREEZE_DAYS=1 时退化为基线)
dfp = pd.DataFrame({'pos': pos, 'sym': numpy.asarray(sym), 'raw': raw_pred})
wide = dfp.pivot_table(index='pos', columns='sym', values='raw', aggfunc='first')
frozen = wide.groupby(wide.index // FREEZE_DAYS).transform('first').stack()
frozen = frozen.reindex(pd.MultiIndex.from_arrays([pos, numpy.asarray(sym)]))
raw_pred = frozen.values        # 窗内截面次序恒定 → 名次不随日频变动
# 注意:reindex 目标必须用 (pos, sym) 整数索引——用日期字符串索引会全部未命中
# (v1 失败根因,见 Step 2),此行已按本地合成数据验证:窗内 rank 恒定、NaN 率 0

运行凭证:freeze-21/42/63 三个因子对象(ID 尾号 …7ba64 / …a7a5a / …a5f20),各运行 1 次,时长 360-366 秒,合计 54 算力。

Step 2【失败数据】v1 全部失效

三次运行均"成功返回",其中 21/42 两个配置结果物理性错误:Rank_IC -0.0010(应约 +0.05~0.07)、多头换手 90.0%/90.1%(冻结后应大降)。第三个配置(63 日)的运行排队至代码修复之后才启动,实际执行的是修复版代码,结果与 v2 完全一致(Rank_IC +0.0496、换手 11.92%)——意外构成了一次修复正确性的重复验证。

运行 时长 算力 判定
freeze-21 v1 365.1s 14 失败:Rank_IC -0.0010 / 换手 90.02%
freeze-42 v1 365.8s 14 失败:同上量级
freeze-63 v1 360.4s 26 修复后代码的重复运行(成功)

失败与修复数据对照

根因定位(本地复现,零算力):冻结值的索引是 (pos 整数, sym),而还原行序时用 (日期字符串, sym) 做 reindex——索引类型错配,逐行全部未命中 → 输出 NaN → fillna(0) → 因子恒为 0。平台对常数因子的处理(近似随机换手 + 零 IC)与观测完全吻合。本地合成数据复现:NaN 率 100%。

修复:reindex 目标改为 (pos, sym)。本地验证:全部冻结窗内截面 rank 恒定(True)、NaN 率 0。原始失败返回与修复代码均已存档(data/failures/freeze_v1_failures.json)。

本步净损失 54 算力,换得一条工程规则:跨索引类型对齐必须在本地用合成数据先验证。

Step 3【操作】v2 修复版三配置实测

运行凭证(修复后):

运行 因子对象 时长 算力
freeze-21 v2 …7ba64 380.2s 26
freeze-42 v2 …a7a5a 377.1s 14
freeze-63 v2 …a5f20 373.2s 14

运行凭证

Step 4【成功数据】前沿实测结果

表1:调仓频率-净超额前沿(同池同窗同管线实测)

指标 日频重排(基线) 冻结21日 冻结42日 冻结63日
Rank_IC +0.0725 +0.0462 +0.0515 +0.0496
IC_mean +0.0301 +0.0138 +0.0217 +0.0206
单调性 0.51 0.26 0.56 0.77
多头超额% +0.79 -2.24 +2.14 +1.17
多头换手% 53.87 30.82 16.27 11.92
年化成本% 8.15 4.66 2.46 1.80
多头净超额% -7.36 -6.90 -0.32 -0.63
多空年化% +23.95 +5.29 +8.69 +6.05
多空信息比率 1.328 0.287 0.398 0.344
多头最大回撤 27.04% 28.61% 23.57% 26.49%
多头月胜率 58.33% 55.56% 61.11% 58.33%

冻结前沿

多空净值对比


四、研究结果与核心结论

4.1 前沿的三个特征

特征一(假设部分成立):换手从 53.87% 单调压降至 11.92%,成本从 8.15% 降至 1.80%——日频重排确是净超额为负的主因,冻结 42 日修复了 95.7% 的净超额缺口(-7.36% → -0.32%)。

特征二(IC 衰减吞掉七成节省):Rank_IC 由 +0.0725 衰减至 +0.046~+0.052,多头超额由 +0.79% 变动至 +1.17~+2.14%——IC 衰减的净代价约等于成本节省的七成,冻结不是免费的。

特征三(非单调与边界重排摩擦):冻结 21 日是前沿最差点(-6.90%),其换手(30.82%)反而高于冻结 42 日(16.27%)。机制解释:换手主要由冻结窗边界的截面次序重置贡献,21 日窗有 36 个边界 vs 42 日窗 18 个——"更频繁地刷新预测"在本机制下引入的是纯摩擦而非信息。同时 21 日窗的多空收益崩塌最重(+5.29% 对基线 +23.95%),说明日频重排基线的多空收益有相当部分来自窗内微调,冻结后即消失。

4.2 盈亏平衡阈值

冻结 42/63 日下,转正所需多头超额分别为 ≥2.46% / ≥1.80%,实测 +2.14% / +1.17%,缺口 0.32 / 0.63 个百分点。反推:在冻结 63 日的换手水平(11.92%)下,模型需要 Rank_IC ≥ 约 0.06 才能转正——这给"换模型"路线(如 QBoost-LGBM 的 +0.0820)提出了明确的、可检验的组合假设。

4.3 核心结论

  • 结论一:输出冻结机制(平台未实现)将最优配置的净超额从 -7.36% 修复至 -0.32%,确认"日频重排成本"是系列净超额为负的第一成因,且修复不需要重训任何模型——纯输出层工程。
  • 结论二:前沿非单调,21 日冻结是结构性最差点;边界重排摩擦(边界数 × 截面重置幅度)是独立于 IC 衰减的第二项冻结成本,设计低频输出机制时必须把窗口对齐到重训周期的整数倍以上。
  • 结论三(诚实声明):净超额未转正。本研究的产出是一条有盈亏平衡阈值的前沿和一个可组合的输出层机制,不是一棵摇钱树;转正路径指向"冻结 + 更强 IC 模型"的组合实验(下一步:QBoost-LGBM + 冻结 42 日)。

五、未来优化与展望

6.1 直接后继实验

QBoost-LGBM(+0.0820)与冻结 42 日的组合:按本文阈值表,+0.0820 的 IC 水平在 16% 换手下对应多头超额约 +4~5%,预期净超额 +1.5~2.5%——系列首个净超额为正的配置。此实验的运行凭证将继续按本篇标准存档。

6.2 机制细化

边界重排摩擦可进一步分解:冻结窗首日若恰逢重训日(本设计如此),首日预测与昨日预测的跳变是换手的主要脉冲;可测试"窗内线性插值过渡"或"次序保持约束(新预测不得改变窗内既有持仓的名次)"两种软化方案。

6.3 研究局限与后续方向

主要研究局限(标准四条):

  1. 净超额未转正,结论为"修复 95.7%"而非"解决";
  2. 单基座模型(LGBM+中性化),前沿形状对模型的 IC 衰减特性有依赖;
  3. 冻结窗 {21, 42, 63} 为粗网格,42 附近的最优解未精确定位;
  4. 36 个冻结样本的 IC 差异(0.0462 vs 0.0515)在统计上不可分辨,特征二的机制解释属推断。

后续方向(标准四条):

  1. QBoost+冻结组合实验(净超额转正的直接尝试);
  2. 冻结窗细扫描(28/35/42/49/56 日)定位前沿顶点;
  3. 边界软化两方案的对照实验;
  4. 系列七篇合并为方法论白皮书,附全部运行凭证与代码仓库索引。

附录:可追溯资产总账

资产 路径 说明
冻结实现(三个配置) freeze_{21,42,63}d.py 仅输出层不同,训练管线与基线逐行一致
失败存档(v1 三次运行原始返回) data/failures/ 含 90% 换手/IC 归零的完整异常数据与根因
运行凭证总账 data/freeze_run_ledger.json 6 次运行的时长与算力账单(合计 108 算力)
前沿实测数据 data/freeze-{21,42,63}d.json、data/freeze_frontier.json 平台原始返回与汇总表
图表脚本 make_charts_syn6.py 前沿图可一键复现

运行凭证摘要:本研究的平台成本合计 108 算力(其中失败浪费 28:21/42 两次错误运行;63-v1 的 26 算力为修复后代码的重复验证),6 次运行的因子对象 ID 与账单见 data/freeze_run_ledger.json。数据来源:PandaAI 因子分析平台实测(运行日期 2026-09-29);基线数据引自 [研究三] 同窗口实测。本文所有观点仅用于研究复现,不构成投资建议。

评论

还没有评论,来说点什么吧
0 / 2000