Back to skills
extension
Category: Data & AnalyticsAPI key required

NAQLab-alpha-miner

A股专用因子挖掘 (A-share ONLY, 不支持做空/no short-selling — A股禁止裸卖空, 实盘只能是 long-only; long-short 仅作内部纯度诊断, 永不参与实盘). Use to mine A-share alpha factors with a self-built backtesting engine (NAQLabBE). Default dual-mode admission (v2.10, A-share short-sale constraint; v2.11 R4 threshold calibrated): R1 long-only Sharpe>0.5 AND R2 short-leg dependency<=0.5 (alpha must not depend on the short leg) AND R3 IC quality (|IC mean|>0.015 & |annualized ICIR|>0.7, v2.10) AND R4 monthly-IC discipline (<=3 negative months in last 12, v2.11 calibrated from <=1), then multi-window OS validation on the long-only portfolio (>=3 windows, per-window Sharpe>0.4, OS/IS ratio>0.5, pass rate>=2/3), pool dedup corr<0.85 (v2.10 tightened from 0.90). Single-mode gate (passes_is_gate, used by optimize/os_validator/legacy): |IC mean|>0.025, |annualized ICIR|>1.0, monthly-IC discipline, Turnover 1-70pct. 数据源: Tushare / 通达信MCP(tdx) / CSV 三选一.

personAuthor: user_14067e85hubcommunity

NAQLab Alpha Miner: 高门槛因子挖掘 + 自优化闭环

🚫 最高原则(不可动摇 · 用户两次明确认定 · v2.9 固化 / 现行 v2.10)

本 skill 只面向 A 股挖掘 alpha 因子。A股禁止裸卖空(no naked short-selling),实盘组合只能是 long-only。

  1. long-short 多空对冲永远只是内部诊断手段(剥 beta 看纯 alpha、算短腿依赖),绝不等于实盘可做空
  2. 任何因子若 alpha 依赖做空 bottom 腿(短腿依赖 >0.5),A股直接拒,不做任何讨价还价;
  3. 所有入池/落地判定一律以 long-only 实盘组合 为准(v2.9 双模默认);
  4. 代码/文档任何位置出现 long-short 成绩,先问一句:这个因子 long-only 能不能过 0.5? 过不了就只是"纯度参考",不是可实盘 alpha。

本 skill 是一套方法论 + 可执行流水线:先以带方向的日频 Rank IC 与未年化 ICIR 做单因子分层预筛选,再对强化候选进行完整组合回测和多窗口 OS 验证。单因子发现不再误用组合级 |raw ICIR| > 1.0,但正式入池的 Sharpe、换手、IC 与 OS 质量要求保持严格。

它教你"怎么炼金",不只发你"金矿地图"。 全篇因子模板是公开常识级,你要学的是自己发现、构造、验证、迭代因子的完整动作——因子会过期、会失效,自优化的方法论不会。核心特色是自优化循环:skill 持续分析回测结果,自动调整因子构造参数和搜索空间,直到达成目标。


门槛要求(不达标不算成功) — v2.10 双模门槛(R1-R4)

v2.9 起按 A 股做空限制落地双模判定;v2.10 把单模 IS Gate 的 IC/ICIR/月度IC 质量闸接回默认双模(R3/R4)。默认 dual_mode 流程(mine.py)现为四闸:R1 long-only 可实盘 + R2 短腿不依赖 + R3 IC 质量底线 + R4 月度 IC 同向纪律passes_is_gate 单模闸(高标准 IC/ICIR/Turnover)在 optimize / os_validator / 传统单模路径生效。下表中"生效范围"一列区分三类:默认双模 / 仅单模 / 未接入——评估门槛高低前先看它在哪个路径生效。

| 指标 | 阈值 | 生效范围 | 含义/依据 | |---|---|---|---| | long-only Sharpe | > 0.5 | ✅ 默认双模(R1 硬门槛) | A股多头可实盘下限;0.7 系按 ls 实证 0.675 定标偏保守,v2.9 下调至 0.5 | | 短腿依赖 | ≤ 0.5 | ✅ 默认双模(R2 硬门槛) | 空头腿正贡献占比 ≤50%,A股不能裸卖空,防"靠预测跌赚钱"的假 alpha | | IC 质量底线 | |IC均值|>0.015 且 |年化ICIR|>0.7 | ✅ 默认双模(R3,v2.10 新增) | Discovery 级防噪音:防 IC≈0 因子靠 beta 凑 lo-Sharpe 0.55 入池 | | 月度 IC 同向纪律 | 12 月内 IC<0 月 ≤ 3(v2.11 由 ≤1 校准) | ✅ 默认双模(R4,v2.10 接入)+ 仅单模 | 防反向不防减弱;第十一轮 NI+FCT 踩雷复发防护;v2.11 校准:全历史负月率 22-23% 属统计正常,≤1=同向率91%+不可达 → ≤3=同向率≥75%行业惯例 | | ls Sharpe(纯度诊断) | > 1.2 | ✅ 默认双模(诊断不拦截) | long-short 中性化 alpha 纯度参考,ls_purity_ok 仅记录 | | OS 多窗口 | ≥3 窗;单窗 Sharpe>0.4;OS/IS 比>0.5;通过率≥2/3 | ✅ 默认双模(long-only 口径) | 实证校准(单年 OS 窗 Sharpe 1.3 不可达 → 0.4) | | 池内去重 | 与池内因子 corr < 0.85 | ✅ 全部路径 | v2.10 由 0.90 收紧(业界 0.7-0.85);ewm 族同 L 信号 0.96-0.99 已被拦截 | | 最终组合 IC | |IC均值|>0.025 | ⚠️ 仅单模 passes_is_gate | 高标准;双模前置用 Discovery 级 0.015(R3),高标准留给 OS 前 | | 年化 ICIR | > 1.0(统一,不再分频率) | ⚠️ 仅单模 passes_is_gate | v2.8 已删悬空的 0.8/0.9 频率区分;双模前置用宽松底线 0.7(R3) | | Turnover | 1% ~ 70% | ⚠️ 仅单模 passes_is_gate | 防僵尸/防高频摩擦 | | 单因子分层预筛 | Discovery 0.015/0.15、Enhanced 0.025/0.30 | ❌ 未接入(死代码) | classify_single_factor 零调用,候选直接进组合回测 | | 相关性破格录取 | avg corr<0.6 破格 | ❌ 未接入(deprecated 悬空) | 仅 _archive 引用,常量保留待接入 |

月度 IC 同向纪律(核心修改 v2.0 · ✅ v2.10 起双模入池 R4 生效,不再只是单模纸面纪律 · v2.11 阈值 1→3 校准)

只看方向,不看强度:因子在 12 个月窗口里,最多允许 3 个月 IC 为负(v2.11 校准前为 1)。这一规则的哲学是——

  • 不防"减弱":IC 从 0.04 降到 0.01 仍然允许通过(这是正常的信号衰减)
  • 只防"反向":IC 变负说明因子在某月反向了,这是结构性失效,必须拒收
  • 实操:以 IC 月度聚合(mean of daily ICs per month)计算负月份计数,统计窗口滚动 12 个月
  • v2.11 校准依据(2026-08-13 存量池复审实证):池内 3 条动量因子全历史负月率 22-23%(IC 同向率 77-78%)属统计正常;≤1 要求 12 个月内同向率 ≥91%,实测无法达成的因子 R1-R3 均远超底线(lo-Sharpe 0.54-0.60 / aICIR 3.0+ / 短腿依赖 0.41-0.46),仅因门槛过严被拒不合理 → 放宽至 ≤3(同向率 ≥75%,行业惯例),用户 2026-08-13 拍板

此纪律在第十一轮实战中已踩雷NI+FCT 因子 IS Sharpe 1.480 全场最高,但 12 月中有 4 个月 IC 反向(累计贡献了 -37.4% 的回撤),本质是"高 Sharpe 假象"。此规则可前置拦截此类风险。

相关性惩罚破格录取(新增 v2.0 · ❌ 未接入主流程,常量 deprecated 悬空)

低相关即正义:与现有入池因子的平均 Pearson/Spearman 相关性 < 0.6 时,可破格降低 ICIR 要求(≥ 0.7 即可入池)。理由:

  • 组合优化层面,正交性 > 单一强度:哪怕 ICIR 0.7,与池内平均相关性 0.4 的因子,对组合分散的边际贡献可能远大于 ICIR 1.2 但相关性 0.9 的因子
  • 实操:以入池池 alpha_pool.json 中所有已入池因子的 IS 信号截面为基准,新候选因子与各池内因子做行业分层 Spearman 相关,取均值
  • 阈值:< 0.6 触发破格窗口(允许 ICIR 0.7);0.6~0.8 走标准门槛;> 0.8 直接拒绝(与既有因子重复)

六维标签体系(新增 v2.4,2026-08-12 用户拍板)

入池必填六维标签:每个因子入库时必须在 alpha_pool.jsontags 字段填写六个维度的标签(对标因子分类学,让因子库"不变成一锅粥"):

| 维度 | 取值示例 | 用途 | |---|---|---| | data_source | 行情量价 / 基本面财务 / 资金流 / 事件公告 / 产业资本 / 筹码分布 / 另类 | 回答"这因子吃什么数据"——同源排查第一键 | | signal_freq | 日频 / 周频 / 10交易日 / 月频 | 调仓频率匹配检查 | | family | 流动性/反转 / 质量 / 价值 / 成长 / 动量 / 行为资金 / 事件 / 产业资本 / 拥挤度 | 回答"和谁同族"——B19 共享腿、B20 同源加权假象排查直接查标签 | | transform | 原始 / ts_rank / 市值中性 / 行业中性 / 复合加权 | 变换方式追溯 | | predict_target | 次日收益 / 多日收益 | 预测目标一致性 | | maturity | 实验 / OS验证中 / 实盘观察 / 已纳入组合 / 已退役 | 生命周期状态(与 GATE_LOG 状态机联动) |

规则:组合因子可多值(如 FC10 = 行情量价+基本面财务+事件公告);挖矿候选在 IS 破门后、入池前必须给出六维标签预填;入池时随 alpha_pool.json 落库;退役时 maturity 改"已退役"。

正交化残差检验(新增 v2.4,B30 判据工程化)

入池前必跑 scripts/ortho_check.py:新候选对池内全部活跃因子信号做逐截面回归取残差(施密特正交化思想),输出:

  1. 残差 IC / 残差 ICIR vs 原 IC——残差 IC ≥ 原 IC × 70% 才证明有真实增量(B30 决定性判据"组合 IC ≥ 母体 IC"的自动化版);残差 IC 大幅缩水 = 新因子只是已有因子的线性组合,直接排除
  2. 残差相关性矩阵——正交化后与池内因子的剩余相关性

流程:组合挖矿破门候选 → 先跑 ortho_check → 残差 IC 不达标直接排除(替代人工组合 IC 对比)。

候选数感知 IC 门槛(新增 v2.4,多重检验校正实务版)

每轮挖矿结果汇总时自动计算 N = 本轮候选总数,报告 IC 门槛修正值 = base × (1 + log10(N)/10)(示例:base 0.025,N=60 → 0.025×1.18 ≈ 0.0295)。同时记录本轮 候选 N : 入池 M 比值——比值 > 10:1 触发选择性过拟合警示(对应文章"样本外选因子本身也是过拟合")。N≤10 时不修正(小样本轮次维持原门槛)。

信号频率诊断:自相关 + IC 衰减曲线(新增 v2.4)

单因子/组合候选过门后,检验报告必须补两维诊断alpha_common.factor_autocorr / alpha_common.ic_decay_curve):

| 诊断 | 方法 | 判读 | |---|---|---| | lag-1 自相关 | 逐股信号序列 lag-1 Pearson 相关,全市场均值 | ≈0.95+ → 低频慢信号;0.7~0.9 → 中频;<0.5 → 高频快信号。与 signal_freq 标签核对 | | IC(k) 衰减曲线 | 因子对 k=1,5,10,20,40 日后累计收益的 Rank IC | 衰减拐点(IC 首次跌破峰值×50%)即最优持仓周期上界,直接决定调仓频率设计 |

联动规则:自相关高(低频)但 IC 在 k=5 就腰斩 → 信号慢但收益兑现快,持仓周期应缩短(换手与持仓周期错配预警);自相关低(高频)但 IC 在 k=20 仍稳 → 信号快但收益持续,可放宽持仓周期。最优持仓周期由数据决定,不拍脑袋定周频/月频。

实战判读细则(v2.4.1,第二十六轮 7 腿实测校准)

  1. IC 单调上升型 = 慢信号,持仓周期应更长:TO126(IC 1 日 0.048 → 40 日 0.057)、NI252(0.020 → 0.058)实测 IC 随 k 单调上升——optimal_holding_horizon 返回 k=40 只是测试窗口上界,真实最优持仓应 ≥40 日。此类因子配 10/20 日调仓反而是正向放大(10 日 IC 已高于 1 日)。
  2. 事件脉冲型 = 只适合短持仓 + 轻仓:FC 事件腿(autocorr≈0.997 低频)IC 却 k=10 起转负(+0.002 → -0.014)——自相关高 ≠ 持仓期长,事件信息瞬时兑现。作增益腿权重应 ≤0.3。
  3. 组合内增益腿单腿 IC 可负:MFLG(autocorr 0.09 高频)单腿 IC -0.013 为负,但在 TO+NI 组合内被扶正(组合 IC 正)——入池增益腿看组合级增量,单腿 IC 负不排除;此条仅适用于组合内增益腿,独立候选因子方向矛盾(B29.②)仍直接排除。

关于 IC / ICIR 的说明

IC (Information Coefficient) 是每日行业内因子值与前瞻收益的 Spearman 秩相关。IC均值必须保留正负方向;|IC均值|仅用于判断强度,不能在分层前取绝对值,否则无法验证训练期与保留期是否同向。

  • 原始 ICIRmean(IC_t) / std(IC_t),不年化,适合比较单因子在日度截面上的稳定性。
  • 年化 ICIRraw ICIR * sqrt(252),仅作为最终组合验证指标。
  • 发现层:只决定是否保留研究价值。
  • 强化层:是完整组合 IS/OS 验证的唯一入口。
  • 最终组合:同时要求 Sharpe、IC、年化 ICIR(按频率差异化)、月度 IC 同向、相关性惩罚与 OS 多窗口通过。

门槛调整说明 (v2.0.0):IS 年化 Sharpe 由 1.3 下调至 1.2(留 0.1 安全垫应对样本外衰减);最终组合 IC 由 0.03 恢复文档原值 0.025(避免池过窄失去分散意义);ICIR 由统一 1.0 拆分为高频 0.8 / 低频 0.9(区分信号频率特性);新增月度 IC 同向纪律(防反向)与相关性惩罚(破格录取低相关信号)。OS 实战阈值保持 Sharpe≥0.4、比≥0.5、IC 同号。


核心数据流

Tushare / 通达信MCP(tdx) / CSV → 因子构造(5组) → IS 回测 → 门槛筛选 → OS 多窗口验证 → 入池 → 自优化迭代
     ↑                                                                         ↓
     └────────────────── 参数调整 / 脚本改写 ←─── 结果分析 ←───────────────────┘

数据来源:Tushare / 通达信MCP(tdx) / 离线 CSV

通过以下任一数据源获取 A 股市场数据:

| 数据源 | 说明 | 费用 | |---|---|---| | Tushare | 免费 A 股数据接口,覆盖量价/基本面/估值及部分资金流与事件数据 | 免费(需注册 token) | | 通达信 MCP (tdx) | 通达信官方行情/基本面/F10/研报/公告/宏观;经 WorkBuddy 连接器「AI 会话桥接」拉取原始 JSON 落盘 data/tdx_raw/tdx_fetcher.py --normalize 规范化为标准 CSV | 免费(需连接器授权) | | 离线 CSV | 自备 CSV 数据文件 | 免费 |

数据字段需求:

  • 量价数据:open / high / low / close / volume / vwap / returns
  • 基本面数据:净利润 / 营收 / 净资产 / 总资产 / 现金流 / EBIT / EBITDA
  • 估值数据:PE / PB / PS / EV / 股息率
  • 分析师预期:一致预期 EPS / 营收 / 净利润
  • 宏观数据:利率 / 汇率 / 商品价格(可选)

详见 第1章 数据获取

因子构造:5 组 AI 自动分组

skill 不预设因子类别,而是根据数据字段特征自动识别 5 个因子族。典型分组:

| 组别 | 典型因子 | 数据来源 | |---|---|---| | 价值类 | E/P, B/P, EBIT/EV, S/P | 基本面 + 量价 | | 质量类 | ROE, ROA, 利润率, 现金流/资产 | 基本面 | | 成长类 | 营收增长, 利润增长, EPS 增长 | 基本面时序变化 | | 动量/反转类 | 过去 N 日收益, ts_rank(收益, d) | 量价 | | 另类/预期类 | 分析师预期修正, 波动率, 换手率 | 分析师 + 量价 |

详见 第2章 因子构造

因子表达式语言:DSL 嵌套表达式(新增 v2.5,对标文章第四章)

因子表达式从「参数分离的扁平字符串」升级为「表达式即代码」的嵌套 DSL:window/group/neutralization 全部内嵌进表达式,由 scripts/expression_engine.py(tokenize → parse → eval)解析执行,不再依赖外部参数拆解。

算子全集(79 个)

| 类别 | 算子 | 语义 | 分组维度 | |---|---|---|---| | 时序变换 | delay(X,K) | 取 K 日前值 | 按 stock | | 时序变换 | delta(X,K) | X - delay(X,K)(K 日变化量) | 按 stock | | 时序变换 | roc(X,K) | X/delay(X,K) - 1(K 日变化率) | 按 stock | | 时序变换 | rolling(func,W,X) | W 窗口滚动聚合(mean/sum/std/min/max/median) | 按 stock | | 时序变换 | ewm(X,H) | 指数加权平滑(半衰期 H) | 按 stock | | 时序变换 | rank_ts(X,T) | T 日时序分位排名(≈ 旧 ts_rank) | 按 stock | | 时序变换 | ts_decay_linear(X,W) | 线性衰减加权均线(最新权重最高,降换手,对标 WQ,§2.3 已承诺此前未实现) | 按 stock | | 时序变换 | ts_corr(A,B,W) | 两序列滚动时序相关(对标 WQ ts_corr,做领先-滞后/溢出因子) | 按 stock | | 时序变换 | ts_arg_max(X,W) | 窗口内最大值距今天数(0=今天最大,择时/距顶天数) | 按 stock | | 时序变换 | ts_arg_min(X,W) | 窗口内最小值距今天数(0=今天最小) | 按 stock | | 时序变换 | ts_zscore(X,W) | 逐股滚动标准化(保留符号/量级,区别于 rank_ts) | 按 stock | | 时序变换 | ts_mean/ts_sum/ts_std/ts_min/ts_max(X,W) | rolling 易读别名(均值/和/标准差/最小/最大),对标 WQ 直觉命名 | 按 stock | | 时序变换 | wma(X,W) | 线性加权移动平均(权重 1..W,最新最高,对标 WQ wma,降换手) | 按 stock | | 时序变换 | skewness(X,W) / kurtosis(X,W) | 滚动时序偏度/峰度(高阶矩,捕捉分布尾巴与非正态) | 按 stock | | 时序变换 | ts_backfill(X,W) | 窗口内向前回填缺失值(停牌/复牌缺口,限 W 日内) | 按 stock | | 时序变换 | ts_neutralize(X,W) | 减滚动均值去水平/趋势(平稳化,区别于截面 demean) | 按 stock | | 时序变换 | ts_decay_exp_window(X,W,[H]) | 指数衰减加权均线(权重 0.5^距今天数/H,区别于 ts_decay_linear 线性衰减) | 按 stock | | 时序变换 | ts_regression(Y,X,W) | 滚动 OLS beta 斜率(Y 对 X 滚动回归系数,做个股对参照序列的滚动暴露) | 按 stock | | 时序变换 | ts_cov(A,B,W) | 滚动协方差(对标 WQ ts_cov,做领先-滞后/溢出因子) | 按 stock | | 截面变换 | rank(X) | 当日截面百分比排名 | 按 date | | 截面变换 | zscore(X) | 当日截面标准化(减均值除标准差) | 按 date | | 截面变换 | demean(X) | 当日截面减均值 | 按 date | | 截面变换 | industry_neutralize(X,G) | 组内减均值(G=行业字段) | 按 date+G | | 截面变换 | market_neutralize(X,MC) | 对 log(MC) 回归取残差 | 按 date | | 截面变换 | winsorize(X,n) | 当日截面截尾去极值(限制 ±n·std,A 股涨跌停/ST/复牌极端值刚需) | 按 date | | 截面变换 | scale(X) | 截面缩放到 [-1,1](x / max|x|,保留符号,量级统一) | 按 date | | 截面变换 | bucket(X,n) | 截面分桶(按分位切 n 组,返回 0..n-1,做离散因子) | 按 date | | 中性化 | regression_neut(X,v1,[v2...]) | 多因子联合中性化(按 date 截面 OLS,支持连续变量与分类字段自动 one-hot,行业+市值+beta 一步到位) | 按 date | | 组内变换 | group_zscore(X,G) / group_scale(X,G) | 同日期同组内标准化 / 缩放到 [-1,1](对标 WQ group_zscore/group_scale,区别于行业去均值) | 按 date+G | | 组内变换 | group_neutralize(X,G) | 同日期同组去均值(通用版 industry_neutralize,可按任意分组字段:国家/板块/自定义) | 按 date+G | | 兼容保留 | ts_rank(X,W) / group_rank(X,G) / direct_rank(X,G) / cross_section_rank(X) / pearson(A,B) | 旧模板表达式不变 | — | | 条件逻辑 | greater(A,B) / less(A,B) / eq(A,B) | 比较,输出 1.0/0.0 布尔掩码(逐元素) | 逐元素 | | 条件逻辑 | if_else(cond,A,B) | cond>0 取 A 否则取 B(逐元素三目) | 逐元素 | | 条件逻辑 | trade_when(cond,signal,default) | cond>0 取 signal 否则取 default(条件暴露,避开涨跌停/停牌:trade_when(greater(is_limit,0),0,signal)) | 逐元素 | | 条件逻辑 | and_(A,B) / or_(A,B) / xor(A,B) / not_(A) | 布尔掩码组合(1.0/0.0),多条件叠加:and_(cond1,cond2) 同时满足,例「低波动且非涨跌停」 | 逐元素 | | 算术 | + - * / 与数字字面量 | 嵌套组合任意深度 | — | | 算术变换 | abs(X) / sign(X) / log(X) / sqrt(X) | 逐元素数学变换(对数/平方根负输入→nan,契合市值/波动非线性) | 逐元素 | | 算术变换 | power(X,k) / min(A,B) / max(A,B) | 逐元素幂次 / 取较小 / 取较大(区别于 ts_min/ts_max 滚动聚合) | 逐元素 | | 信号/状态 | cross(A,B) | A 上穿 B 当日=1 否则 0(金叉/突破信号生成核心) | 按 stock | | 信号/状态 | barslast(cond) | 距上次 cond 成立周期数(0=今天成立,「距上次涨停 N 天」类因子刚需) | 按 stock | | 信号/状态 | count(cond,N) | 最近 N 周期 cond 成立次数(「20 日涨停次数/阳线天数」) | 按 stock | | 信号/状态 | valuewhen(cond,X) | 上一次 cond 成立时 X 的值(状态跟随,记录突破价/量) | 按 stock | | 信号/状态 | exist(cond,N) | 最近 N 周期是否曾成立(「10 日内出现过涨停」) | 按 stock | | 信号/状态 | every(cond,N) | 最近 N 周期是否一直成立(「连涨/连跌 N 天」) | 按 stock | | 信号/状态 | filter(cond,N) | 信号 N 周期冷却去重(防重复信号/降换手,A 股实战) | 按 stock | | 信号/状态 | barscount(X) | 有效数据以来周期数(上市天数过滤,去次新股) | 按 stock | | 移动均线 | ema(X,N) | 通达信指数均线(平滑系数 2/(N+1),区别于 ewm 半衰期) | 按 stock | | 移动均线 | sma(X,N,M) | 通达信递归累积均 Y=(X·M+Y'·(N-M))/N(KDJ/经典指标基础) | 按 stock | | 移动均线 | dma(X,A) | 动态均线 Y=A·X+(1-A)·Y'(A 可为序列,如换手率) | 按 stock | | 滚动统计 | slope(X,N) | 对 bar 序号回归的便捷斜率(避免手拼序号序列) | 按 stock | | 滚动统计 | var(X,N) / avedev(X,N) | 滚动方差 / 平均绝对偏差(分布离散度) | 按 stock | | 标量数学 | exp / log10 / floor / ceiling / round / mod | 逐元素标量数学补全(对标 QMT EXP/MOD/FLOOR/ROUND…) | 逐元素 | | 复合指标 | macd(X[,fast=12,slow=26,signal=9]) | MACD 柱 = (DIF-DEA)*2,DIF=ema(X,fast)-ema(X,slow),DEA=ema(DIF,signal)(动量/背离/金叉判定,对标通达信 MACD) | 按 stock | | 复合指标 | rsi(X[,N=14]) | 相对强弱 RSI∈[0,100](均值(上涨)/均值(下跌) 比,无量下跌修正,超买超卖) | 按 stock | | 复合指标 | kdj(close,low,high[,N=9,M1=3,M2=3]) | KDJ 的 J=3K-2D(RSV 由 OHLC 算,超买超卖极值) | 按 stock | | 复合指标 | boll(X[,N=20,K=2]) | 布林带位置 %B=(X-下轨)/(上轨-下轨)(触下轨=0/上轨=1,突破带外越界) | 按 stock | | QMT 别名墙 | ref→delay / ma→ts_mean / sum→ts_sum / std→ts_std / hhv→ts_max / llv→ts_min / covar→ts_cov / relate→ts_corr | 存量 QMT 公式零改迁移(别名映射现有算子,解析层零改动) | — |

双轨求值(backtester compute_factor_value 自动分派):

  • legacy_simplefield/-field/num/den)→ 旧矢量化快路径,性能零回退
  • legacy_templategroup_rank(ts_rank(SIG,W),G)/direct_rank(SIG,G) 完整串)→ 解析回退旧路径
  • dsl(含 DSL 算子或嵌套算术,如旧 blend 模板)→ 表达式引擎执行

引擎向量化后端(v2.5.2 工具函数优化):所有按股票分组的算子统一走两条通道—— _by_stock(单序列 groupby(stock_code).transform)+ _by_stock_df(多列/状态型 groupby(stock_code).apply,已抽离 cross/barslast/filter/dma/kdj/ts_corr/ts_regression 的模块级实现函数 _barslast_impl/_filter_impl/_dma_impl/_ts_corr_impl/_ts_reg_impl)。 旧代码 7 处手写 for _, g in df.groupby(...) 循环 + 临时 _code/_c/_d 列 + 手动 concat/sort_index 样板已合并为单一 helper;filter 内循环改为只遍历信号点(O(#信号) 而非 O(T));并以显式 _idx=arange(n) 还原行序,对输入索引类型免疫。 回测最热路径 compute_ic_series(alpha_common)由逐日 groupby.apply(corrcoef) 改为 解析法向量化(分组聚合 E[f]/E[r]/E[fr]/E[f²]/E[r²] 算 Pearson),数值与逐日 corrcoef 完全一致,大面板相对旧实现提速约 1.3x。

字段覆盖率护栏(v2.5.1):DSL 表达式回测前自动检查引用字段的覆盖率(非 NaN 比例),任一字段 <50% 即打印 [DSL 跳过] 告警并跳过该候选(error 字段记录"覆盖率不足")。低覆盖率字段(如 fundamentals 中 ebit 仅 1.6% 非 NaN)经算术传播会污染整列因子值,典型症状是 sharpe 爆成 ±1e16、IC 恒 0——护栏直接拦截,不再产生垃圾指标。

文章 4.3 原版示例(可直接使用)

zscore(industry_neutralize(ewm(zscore(roc(close,5))*0.4 + zscore(roc(close,60))*0.6, 20), sw_l1))

内置四大 DSL 候选形态族recipes.jsondsl_recipes 配置,默认 25 条/轮): | 家族 | 模板 | 语义 | |---|---|---| | pure_ts | zscore(rank_ts(roc(close,W),T)) | 纯时序动量(A股为反转,long-short 下 IC 强但 sharpe 卡 0.5) | | momentum_blend | zscore(industry_neutralize(rank_ts(roc(close,S),T)*0.3 + rank_ts(roc(close,L),T)*0.7, industry)) | 双期限动量+行业中性(中性化稀释 IC,long-short 下双崩) | | ewm_smooth | ewm(zscore(roc(close,S))*0.3 + zscore(roc(close,L))*0.7, H) | A股过 IS 1.2 唯一稳定族(短反转×长动量 ewm 平滑, 内置负号) | | fund_momentum | zscore(industry_neutralize(rank_ts(delta(F,K),T), industry)) | 基本面变化动量(sharpe 高但 IC<0.025 过不了门) |

注意:数据层预烘焙字段(returns_20d/volatility_60d 等,compute_derived_fields 15 块 v2 变换)与 DSL 算子等价(roc(close,20)returns_20d)。两者可混用;预烘焙字段省算力,DSL 算子更灵活(窗口参数化、嵌套组合)。

ewm_smooth 实战结论(2026-08-12 跨 5 轮全量实证, A股 3216 只/2020-2026)

这是 DSL miner 当前唯一能稳定产出过 IS 1.2 门槛 KEEPER 的家族, 沉淀如下避免下次从头踩坑:

  1. 三步复利链路(瓶颈定位闭环): long-only 卡 beta (0.675)long-short 剥 beta (0.995)十分位 n_quantiles=10 放大多空价差 (1.27) A股 long-only 组合的 top 五分位绝对收益天然被市场 beta 拖累(含 2022 熊市段), icir 0.2 级强信号转化不成组合收益; 多空对冲剥掉 beta 后纯 alpha 才浮现, 十分位进一步提高多空组合集中度放大 sharpe。其余族(pure_ts/momentum_blend/fund_momentum)在 long-short+十分位下仍 0 过门或 IC<0.025, 此路径非跨族普适, 是 ewm_smooth 专属 validated 路径。 ⚠️ v2.9 双模下此链路只是"纯度证明":上述 1.27 是 ls 十分位成绩,实盘准入仍需该因子 long-only Sharpe > 0.5(双模自动重跑 lo 判定);若 lo 不达标,该族即便 ls 再强也只进观察,不进实盘池。

  2. 独立 KEEPER 数由"长动量窗口"L 决定(去重机制): 池内去重阈值 0.9, 共享同一 L 的不同 (S,L) 配对互相相关 0.96–0.99 → 被拦; 不同 L 的类之间相关 0.87 → 可并存。当前 6 配对网格(roc5/10/20 × L60/120)最多产出 2 个独立 KEEPER(L=120 类 1 个如 roc5-120 + L=60 类 1 个如 roc20-60)。要扩产出须引入新 L(如 L=250, 但 IS 窗口 2020-2022 覆盖风险需验证)

  3. 半衰期 hl5 稳健, hl3 样本外脆弱: 同信号下 hl5 版 OS 通过率 100%, hl3 版 IS 踩线(S≈1.20)且 OS 0%(如 roc10-60 hl3 / roc20-60 hl3)。优先用 hl5, hl3 仅作同源补充(会被去重拦或 OS 筛掉)。

  4. ⚠️ 配置固化坑(必读): 改 factor_generator.pyDEFAULT_RECIPES 源码后, 已落盘的 alpha_workspace/recipes.json(首跑自动生成)不会自动同步, load_recipes() 仍读旧版 → 只给旧候选数。必须删 recipes.json 触发重写mine.py/data_loader.py 下次运行会自动用新 DEFAULT_RECIPES 重建)。同理 tried.txt 记录已试表达式, 旧表达式会被跳过(新网格的新 (S,L) 配对不受影响)。

  5. ⚠️ 候选被打乱, 须聚焦: generate_candidates 用固定种子 random.Random(20260102).shuffle 打乱 119 条候选, ewm_smooth 散落其中, 默认 limit=50 大概率碰不到。验证/扩产用 mine.py --only-family ewm_smooth 定向跑。

回测引擎(NAQLabBE):自建

不依赖任何外部平台,纯 Python + numpy/pandas 实现:

  1. 因子值 → 截面排名(rank)→ 分组排序(group_rank)→ 分位组合
  2. 日收益计算:双模默认(v2.9,--dual-mode)——先跑 long-only 实盘组合(硬门槛 LONG_ONLY_DEPLOY_SHARPE_MIN=0.5,A股多头现实可行下限),过门槛再跑 long-short 多空对冲做纯度诊断+短腿依赖判定;A股不可裸卖空,long-short 永远只是因子验证手段,不参与实盘。单模可选:--long-only(纯多头) / --long-short(只跑多空)
  3. 指标计算:Sharpe / IC / ICIR / Turnover / 最大回撤 / 胜率
  4. 中性化:行业中性 / 市值中性

⚠️ A股禁裸卖空,实盘只认 long-only(v2.9 双模):long-short 多空对冲是因子纯度诊断手段(剥掉市场 beta 后,icir 0.2 级的强信号才能兑现为纯 alpha Sharpe,实证:ewm_smooth 由 long-only 0.675 → long-short 0.995 → 十分位 1.27),绝不等于实盘可做空。双模下每条候选:① long-only Sharpe > 0.5 才准入(A股多头硬门槛) ② 短腿依赖 max(bottom_leg,0)/(max(top,0)+max(bottom,0)) ≤ 0.5 才可实盘——若因子 alpha 主要靠做空 bottom 腿赚钱(>0.5),A股纯多头直接拒。落地 QMT 时重建多头组合(§6.8 闸门),不可直接做空。

⚡ 大池性能红线(全A 3000+只/500万+行时必读):

  • groupby.apply(lambda...) / transform(lambda...) 是致命反模式:500万行上 industry_neutralize 曾耗时 74.6s、ts_rank 双循环 5 分钟/候选。全部改用矢量化:groupby.rank(pct=True)transform("mean")/("size")
  • ts_rank() 用"有序列表 + bisect"实现 O(n·log w),全量 500 万行 22.6s(比双循环快 13 倍),语义与旧版完全一致;一致性验证脚本见 scripts/bench_tsrank.py
  • compute_ic_seriesgroupby.rank 一次算秩,再逐日 Pearson,避免每天重复排名。
  • 优化后全A池单候选耗时:ts_rank ~35s、direct_rank ~16s(60 候选 ≈ 30-40 分钟)。

详见 第3章 回测引擎(NAQLabBE)

OS 验证:多窗口交叉验证

全样本:  |----IS1----|--OS1--|----IS2----|--OS2--|----IS3----|--OS3--|
         训练        验证    训练        验证    训练        验证
  • IS(样本内):挖掘和调参
  • OS(外场):验证因子在未见数据上的表现
  • 多窗口:至少 3 组 IS/OS 对,评估因子在不同市场环境下的稳健性
  • 通过标准:OS 年化 Sharpe > 1.3,OS/IS Sharpe 比 > 0.6,且至少 2/3 OS 窗口通过。

详见 第4章 OS 验证


自优化循环(本 skill 的核心特色)

skill 不只是"跑一遍出结果",而是一个持续迭代的闭环:

OBSERVE  → 读回测结果,汇总哪些因子族/参数组合命中率高
DECIDE   → AI 分析瓶颈,决定下一步:调参数?换信号源?改构造方式?
ACT      → 自动修改 recipes.json 参数 / 生成新候选 / 调整搜索空间
VERIFY   → 跑回测,严格读硬指标,过门槛才留
RECORD   → 把结论写进 log 和 PLAYBOOK,供下一轮 OBSERVE 读取

自优化的三种模式:

  1. 参数微调:窗口长度、分母选择、分组粒度、中性化方式
  2. 结构进化:从单信号 → 多信号 blend → 跨角色相乘 → 深层嵌套
  3. 脚本改写:当参数微调到达瓶颈,自动改写因子构造模板代码

详见 第5章 自优化循环


章节地图

| 何时读 | 章节 | |---|---| | 数据接口配置、字段映射、数据质量检查 | 第1章 数据获取 | | 因子构造模板、信号设计、AI 自动分组算法 | 第2章 因子构造 | | NAQLabBE 回测引擎:组合构建、指标计算、中性化 | 第3章 回测引擎(NAQLabBE) | | OS 多窗口交叉验证、稳健性评估、过拟合检测 | 第4章 OS 验证 | | 自优化循环、参数搜索、脚本进化、提示词模板 | 第5章 自优化循环 | | 入池因子转 QMT 策略:GBK 转码、字段映射、API 规范、交易规则、落地闸门(§6.8 族级落地原则) | 第6章 QMT 策略落地 |


目录结构

(skill 根目录与 scripts/ 子目录地图, 与「因子工厂挖矿落地全流程」各阶段一一对应)

NAQLab-alpha-miner/
├── SKILL.md / references/     # 方法论 + 6 章文档
├── builds/                   # 打包产物 (NAQLab-alpha-miner_v<VERSION>_YYYY-MM-DD.zip)
├── alpha_workspace -> D:\…    # 数据/信号/池 (NTFS 接合点)
└── scripts/
    ├── 根层: 核心引擎 + 流水线 + 编排层
    │   alpha_common.py  expression_engine.py(79 算子 DSL)  backtester.py(NAQLabBE)
    │   data_loader.py  factor_generator.py  optimize.py
    │   mine.py  os_validator.py  combination_mining_v23.py  corr_check_v22.py
    │   ortho_check.py  ic_decay_analysis.py  combo_lockin_ewm.py
    │   os_track.py  refresh_daily_signal.py   # 编排层, 按文件名调用下方子目录
    │   update_market_data.py  tdx_fetcher.py  tushare_full_a_fetcher.py  # 数据基础设施
    ├── data_sources/   (37) build_*/fetch_*/probe_*  → 阶段 S0 数据源
    ├── qmt/            (9)  gen_qmt_signal_* + qmt_embed_tools + qmt_feasibility_* + gen_qmt_backtest  → 阶段 S8 实盘
    ├── tests/          (5)  test_*  → 引擎/IC 回归 (185+9 全过)
    ├── _scratch/       (5)  tmp_* 一次性临时脚本 (打包排除)
    ├── _archive/            版本快照 (可还原)
    └── pack_skill.py        打包工具

阶段映射: S0 数据源 → data_sources/ · S2–S7 挖矿/验证/组合/质检 → 根层核心脚本 · S8 实盘部署 → qmt/ · 候选池/正式池产物 → alpha_workspace/active/pool/。 目录重构于 v2.7.0 (2026-08-13): 原扁平 80+ 脚本按阶段归入 data_sources/ qmt/ tests/ _scratch/, 核心 28 个留根层。

快速开始

-1. 首次数据拉取

本 skill 提供三个数据源,按 detect_data_source 优先级 Tushare > 通达信MCP(tdx) > CSV 自动选择;用户也可 --source 显式指定。

使用 Tushare 时(推荐,加载即拉取,一步完成):

export TUSHARE_TOKEN="你的token"
python scripts/data_loader.py --source tushare --n-stocks 150

使用通达信 MCP(tdx) 时,三步分开:会话内 MCP 拉取 → 规范化 → 加载。

  1. 在会话内调用已授权的通达信连接器 MCP 工具(如 tdx_quotes/tdx_kline/tdx_api_data)批量拉取,把返回的原始 JSON 落盘到 data/tdx_raw/
  2. python scripts/tdx_fetcher.py --normalize 规范化 → 标准 CSV 输出到 data/tdx/
  3. python scripts/data_loader.py --source tdx --n-stocks 150 加载并生成武器库

详见 第1章 §1.10 通达信 MCP 数据源

使用离线 CSV 时,自备数据后加载:

export DATA_DIR="你的CSV数据目录"
python scripts/data_loader.py --source csv

0. 数据源选择门(必须先完成)

三个数据源按 Tushare > 通达信MCP(tdx) > CSV 自动选择,用户也可 --source 显式指定;未检测到任何数据源时,挖矿流水线不得启动。

第一步:数据源检查清单(AI 依次执行)

| 步骤 | 检查内容 | 方法 | |---|---|---| | ① | Tushare token 是否配置 | 检查环境变量 TUSHARE_TOKEN 是否设置 | | ② | 通达信 MCP 规范化数据是否就绪 | 检查 alpha_workspace/data/tdx/daily_prices/ 是否存在规范化 CSV(tdx 来源, 已跑过 tdx_fetcher.py --normalize) | | ③ | 离线 CSV 数据是否就绪 | 检查环境变量 DATA_DIRalpha_workspace/data/ 目录 | | ④ | alpha_workspace/ 是否已有 arsenal.json | 如已有,说明数据已加载过,可直接进入挖矿 |

AI 行为规则

  • 用户未指定来源时,按 Tushare → tdx → CSV 优先级自动选择;用户显式指定时优先服从。
  • 用户选择 Tushare 但未配置 token 时,引导设置 TUSHARE_TOKEN
  • 用户选择通达信 MCP(tdx) 时,走三步流程:会话内 MCP 拉取落盘 data/tdx_raw/tdx_fetcher.py --normalizedata_loader.py --source tdx;连接器未授权时先引导连接 tdx-connector。
  • 未检测到任何数据源时,必须停下来询问用户,而不能运行 data_loader.pymine.py

环境准备

# Python 3.8+ 环境
pip install numpy pandas scipy

# 数据接口(三选一)
# 方式1: Tushare —— 在 https://tushare.pro 注册获取 token(推荐,detect 优先级最高)
pip install tushare
export TUSHARE_TOKEN="你的token"

# 方式2: 通达信 MCP(tdx) —— 官方行情/基本面/F10, 经 WorkBuddy 连接器 AI 会话桥接
# 会话内调 MCP 工具拉取 → 原始 JSON 落盘 data/tdx_raw/ → tdx_fetcher.py --normalize
# 详见 references/01-data-acquisition.md §1.10

# 方式3: 离线 CSV 数据
# 准备 CSV 文件: date, stock_code, open, high, low, close, volume + 基本面字段
# 目录结构详见 references/01-data-acquisition.md §1.4

1. 完整命令序列

# ① 数据加载 (Tushare 模式 — 一次完成拉取+加载,推荐)
export TUSHARE_TOKEN="你的token"
python scripts/data_loader.py --source tushare --n-stocks 150

# ① 数据加载 (通达信 MCP 模式 — 先会话内拉取规范化,再加载)
#    会话内 MCP 拉取落盘 data/tdx_raw/ → tdx_fetcher.py --normalize → 加载
python scripts/tdx_fetcher.py --normalize
python scripts/data_loader.py --source tdx --n-stocks 150

# ① 数据加载 (CSV 模式 — 自备数据)
export DATA_DIR="你的CSV数据目录"
python scripts/data_loader.py --source csv

# ⚠️ 首次使用需安装 Python 依赖 (numpy, pandas, scipy)
# 推荐使用 venv:
#   python -m venv .venv && .venv/Scripts/pip install numpy pandas scipy
#   .venv/Scripts/python scripts/...

# ② 挖矿流水线:生成5组因子 → IS回测 → 门槛筛选 → OS验证 → 入池
#    双模默认(v2.10):long-only 实盘硬门槛(>0.5) + ls 纯度/短腿诊断(R1-R4),A股推荐:
python scripts/mine.py --groups 5 --limit 50
#    单模可选:
python scripts/mine.py --groups 5 --limit 50 --long-only    # 只跑纯多头
python scripts/mine.py --groups 5 --limit 50 --long-short   # 只跑多空(仅纯度诊断用)

# ③ 自优化:分析结果,调整参数,重跑(循环直到达成)
python scripts/optimize.py --rounds 10

# ④ 查看结果:因子池、OS验证报告、优化历史
python scripts/mine.py --report

2. 运行时产物(alpha_workspace/,自动创建)

| 文件 | 内容 | |---|---| | arsenal.json | 数据字段清单 + AI 自动分组结果 | | recipes.json | 因子构造搜索空间(可编辑,自优化会自动调整) | | pool.jsonl | 过门槛 + OS 验证的因子池 | | is_results.jsonl | IS 回测全量结果(含失败因子,供分析) | | os_results.jsonl | OS 验证结果 | | optimization_log.jsonl | 自优化历史:每轮调了什么、效果如何 | | PLAYBOOK.md | 你的活页手册(从模板复制,蒸馏重写) | | <策略>_src.py + <策略>.py | QMT 落地:UTF-8 编辑源 + GBK 部署版(见第6章) |

2.1 产物归档规范(2026-08-11 起强制,每次运行后执行)

用户约定(2026-08-11 拍板):所有成果文件不再平铺在 alpha_workspace/ 根目录,一律按「处理日期 + 流程」两级目录生成存放。每次挖矿/OS验证/回测/落地跑完,产物必须当场归位,不得留在根目录。

目录结构(两级)

alpha_workspace/
├── active/                          ← 活资产(跨日期持续引用,不按日期拆)
│   ├── scripts/   执行端/回测/生成工具 .py(GBK 部署版 + UTF-8 源; 含 *_embedded.py 纯内嵌信号单文件版)
│   ├── signals/   全量日频得分 CSV(qmt_signal_*.csv, 可选, 审计用); 调仓目标已内嵌进 embedded 策略不再单独落盘
│   ├── docs/      PLAYBOOK、策略说明、执行指南
│   └── pool/      alpha_pool.json(当前活跃因子池)
├── archive/                         ← 历史产物(按 处理日期/流程 两级)
│   └── YYYY-MM-DD/                  ← 当天处理日期(以 mtime 或当天日期为准)
│       ├── 挖矿/      mining/combination 日志、is_results*.jsonl、recipes/arsenal/tried
│       ├── OS验证/    os_validation*.jsonl、combination_os_*.log、optimization_log
│       ├── 相关性/    corr_check*.jsonl、corr 运行日志
│       ├── 频率扫描/  qmt_feasibility*.jsonl、数据源探针日志
│       ├── 报告/      第 N 轮挖矿结果报告.md、评估报告
│       └── 备份/      backup_* 目录、旧版 pool/jsonl 备份
└── data/                            ← 行情/事件数据(原地不动)

分类规则(判断放哪)

| 类型 | 去处 | 例子 | |---|---|---| | 日志 / 中间结果 / 轮次报告 / 备份 | archive/今天/流程/ | 挖矿日志、is_results.jsonl、第十二轮报告、pre_fix 备份 | | 脚本(.py) | active/scripts/ | 执行端、回测、embed、verify、*_embedded.py(纯内嵌信号单文件版) | | 调仓目标 | 内嵌于 active/scripts/*_embedded.pyEMBEDDED_SIGNAL 常量 | qmt_combo_to_ni_fc_strategy_embedded.py | | 日频得分 CSV(可选) | active/signals/ | qmt_signal_fc.csv | | 长期文档 | active/docs/ | PLAYBOOK.md、策略说明、执行指南 | | 因子池 | active/pool/ | alpha_pool.json | | 行情/事件数据 | data/ 原地 | daily_prices、event_factors.csv |

AI 行为规则

  1. 当天跑完当天归档:每轮挖矿/OS验证/回测/落地产物生成后,立即 mv 到对应 archive/YYYY-MM-DD/流程/,根目录不允许堆积。
  2. 日期取处理日期:跨天运行(如 23:50 开始 00:10 结束)按结束日归档;单文件以 mtime 日期为准。
  3. 活资产原地更新:active/ 下的脚本/CSV/文档是"活的",更新时直接覆盖,不要复制一份进 archive(archive 只收历史产物和备份)。
  4. 路径断裂检查:移动脚本涉及硬编码路径时,先 grep 目标文件的引用(如 SRC_CSV/SIGNAL_FILE),移动后必须同步修复并跑一次验证。
  5. skill 目录镜像:NAQLab-alpha-miner/alpha_workspace/ 是 D 盘工作区的镜像(挖矿/回测实际读写它),归档时两边保持同结构。

3. 入池后落地 QMT(每次入池后)

先过落地闸门,再谈落地(2026-08-11 用户拍板固化,详见 第6章 §6.8):入池 ≠ 可以上实盘。每个因子落地前必须过「落地闸门三问」——① 是否新信息源族?② 与实盘组合 corr < 0.6?③ 容量与可维护性过关?一个信息源族只落地 1 条代表策略,同族变体一律归档。过闸结论必须追加 alpha_workspace/active/pool/GATE_LOG.md 留档。

入池 alpha 需转成 QMT 可执行策略时,按 第6章 QMT 策略落地 执行:落地闸门(§6.8)→ 三维护航(§6.7.3:频率×成本×集中度)→ UTF-8 src 逐行注释 → GBK 转码 + 双端 SHA256 校验 → 字段映射(公告日取数防未来函数/换手四通道/行业三档降级)→ 生成策略说明文档 → PLAYBOOK 记录落地。


日常刷新(收盘后实盘信号, 2026-08-11 起)

实盘策略文件 (active/scripts/qmt_combo_to_ni_fc_strategy_embedded.py + qmt_combo_to_ni_mflg_tl_strategy_embedded.py) 的每日更新走一键链路, 一条命令完成 数据更新 → 信号端(4 因子) → 自动校验 → 摘要/回滚:

python scripts/refresh_daily_signal.py            # 全流程 (数据更新 + 信号 + 校验)
python scripts/refresh_daily_signal.py --skip-data # 跳过数据更新 (仅信号端 + 校验)
python scripts/refresh_daily_signal.py --dry-run   # 只打印计划

链路内部步骤: [0] 环境自检 (6 项, 含行为数据面板) → [1] 备份全部 embedded (逐个) → [2] 数据更新 (2a 行情增量 Tushare 按交易日 + 2b 事件因子滞后重建 + 2c 行为数据检查: 龙虎榜/股东增减持/资金流面板滞后于行情时自动 fetch 增量 + build 重建) → [3] 信号端 4 因子 (DEPLOYED: FC10/MFLG_TL 生成 embedded; OBSERVING_GEN: TL_HT/HT_in60 仅信号 CSV 供 os_track 消费) → [4] 硬校验遍历全部 DEPLOYED (GBK/语法/load_targets/最新调仓日≥今天/权重和=1/6位代码) → [5] 通过出摘要+SHA256, 失败逐个回滚。

退出码: 0 = 新文件就绪; 1 = 校验未通过已回滚 (非交易日"无事可做"也走此码, 属正常); 2 = 环境/流程异常。

已配置定时任务: 交易日 18:30 自动触发 (WorkBuddy automation, 工作目录 = skill 根目录), 已扩展为两步: ① refresh_daily_signal.py 信号刷新 → ② os_track.py --all 实时 OS 跟踪。A 股 15:00 收盘后 Tushare 日线/估值约 17-18 点齐备, 18:30 触发留足缓冲; 非交易日自动无事可做, 无需维护交易日历。

实时 OS 跟踪(轨道 B): 因子入池(OBSERVING)后进入落地前观察期, 每日记录当日 IC(信号 vs T+1 收益 Spearman), 满约 21 个交易日自动判定(IC 同号率≥60% + 累计IC>0 + 连续负IC≤5天 + 累计IC回撤>-20%), PASS 后才走落地闸门三问(§6.8)。方法与脚本见 第4章 §4.8scripts/os_track.py; 跟踪记录在 active/os_track/os_track_<因子>.jsonl, 状态机在 GATE_LOG 台账维护。已落地策略也持续跟踪作为 OS 衰减监控(同号率持续<60% 或累计IC转负 → 替换预警)。

⚠️ fetch 断点续传陷阱 (2026-08-11 事故修复): moneyflow 面板曾缺 7 天 (2023-10-30~11-06、12-04), 根因是 fetch_moneyflow_par.py 把「Tushare 返回空 DataFrame」的日期也标记 done → 永久缺口 (实测 Tushare 有数据)。已修: 空结果记 failed 不标 done + 运行前自愈剔除坏标记 (对比 progress done vs csv 实际日期) + failed 汇总提示; fetch_top_list_par.py(双输出, 两表都非空才标 done) / fetch_stk_holdertrade_par.py 同隐患一并修。通用规则: 断点续传以「实际写入数据」为准, 不以「API 调用成功」为准。详见 第1章 §1.8.1

⚠️ 调仓日前瞻追加 (2026-08-11 修复, 信号生成脚本必看): all_dates[::REBAL_INTERVAL] 从全量序列首日对齐取调仓日, 尾部不足一个周期的交易日永远进不了执行端 (MFLG_TL 最新调仓日曾卡在 07-28, 刷新后滞后 1~9 天)。修复=从 FC10 移植 _next_trading_day + 前瞻追加: 最新交易日不是调仓日时, 补一个「下一个调仓日」(用最新收盘信号, T+1 生效)。凡用 [::interval] 生成调仓日的脚本, 都必须带前瞻追加逻辑

⚠️ Tushare API 变更记录 (2026-08-11): forecast(业绩预告)接口不再接受 period 参数 (报错 "ann_date和ts_code至少输入一个参数"), 实测仅支持 ann_date(单日) 或 ts_code(单票); express(业绩快报)仍支持 periodfetch_forecast_express.py 已改为: forecast 按公告日逐日增量 (进度存 data/forecast_progress.json, 失败日不推进进度下次自动补), express 保持按报告期拉取 (自愈)。若再遇参数校验类报错, 优先怀疑 Tushare 上游接口参数变更, 用 pro.forecast/express 实测参数矩阵后再改。

⚠️ 行情数据 schema 契约 (2026-08-11 全量实测, 改数据脚本前必读):

  • daily_prices/{code}.csv9 列: date,stock_code,open,high,low,close,volume,amount,returns (returns = Tushare pct_chg, 单位 %; 消费端 data_loader FIELD_MAP 依赖 returns 列做动量因子, 不可删)。主池 3000 文件自创建即 9 列; 另有 216 个文件 (0012xx 等) 原为 8 列, 已于 2026-08-11 升级为 9 列 (returns 由 close.pct_change()*100 补算)。
  • amount 单位 = 千元 (Tushare 原值, 与存量一致; 实测 000001 08/05 amount=1703942.5 千元 ≈ 17 亿成交额)。严禁 ×1000 换算成元, 否则与存量不一致。
  • stock_code 必须 6 位补零字符串 (str.zfill(6)); 未补零 (如 1) 会破坏与 valuation/stock_list 的字符串匹配。
  • valuation.csv 是 6 列 date,stock_code,pe,pb,market_cap,ps,turnover_rate, 只追加股票池内股票 (append_valuation 已按 daily_prices 文件集合过滤), 每天 ~3000 行; market_cap 万元、turnover_rate %。
  • 追加全部幂等: daily 逐文件查最后一行日期、valuation 查最后一行日期, 半途重跑不会重复追加。
  • 事故教训 (2026-08-11): 旧版 update_market_data.py 用 9 列 DAILY_COLS 对 8 列文件追加 → 216 文件行/表头列数混合 → build_event_factors 报 ParserError: expected 8 fields, saw 9; 同时 stock_code 未补零 + valuation 追了全市场 (5533 行/天 vs 存量 2998)。修复=回滚 08/06+ 行 + 216 文件升级 9 列 + zfill(6) + 估值池过滤, 已全部落地并端到端验证 (最新调仓日 20260811, SHA256 校验 PASS)。判断 schema 以消费端 (data_loader.py / build_event_factors.py 的 pd.read_csv header 读取) 为准, 勿凭文档臆测

红线(任何模式下都生效)

  • OS 数据不可参与 IS 挖掘:OS 窗口的数据在 IS 阶段必须"不可见",否则验证无效。
  • 过拟合警惕:IS/OS Sharpe>1.3 加上 IC/ICIR 双指标交叉验证能有效识别过拟合,单凭高 Sharpe 的候选仍必须通过 IC 检验。
  • 凭证安全:Tushare token 只进环境变量,绝不硬编码、绝不进 Git。
  • 自优化不等于盲目搜索:每次参数调整必须记录理由和预期,不带预测的随机搜索不算优化。
  • 结果以硬指标为准:AI 的形容词不算数,只有 Sharpe/IC/ICIR/Turnover 的数字算数。
  • 产物必须归档(2026-08-11 起):根目录不允许平铺堆积产物,一律按 §2.1 归入 archive/今天/流程/active/;移动/重命名前先 grep 硬编码路径引用。
  • 落地必须过闸(2026-08-11 起):入池因子落地 QMT 前必须过 §6.8 落地闸门三问,结论追加 active/pool/GATE_LOG.md;同族变体一律归档不落地,每个信息源族只留 1 条代表策略

产出哲学:起步相同,演化不同

这个 skill 不发因子(清单会过期、会撞车),它发的是一个会自进化的方法:

  1. recipes.json(首跑自动生成)——你的搜索空间:因子模板、窗口、分组、信号组合方式。自优化循环会根据回测结果自动调整它。改这里 = 你的搜索空间开始分叉。
  2. 你的活页手册(从 PLAYBOOK.template.md 复制)——你的信念、教训、待验假设。改这里 = 你的判断开始独特。
  3. optimization_log.jsonl——自优化的轨迹:每轮改了什么、为什么改、效果如何。这是你方法的"进化化石"。

三个人用同一个 skill 跑一个月,应该挖出完全不同的因子——如果没有,说明你只在"跑",没在"迭代"。


免责声明:本 skill 不含任何账号/凭证/专有因子,仅教方法。IS/OS Sharpe>1.3 + |IC|>0.035 + |ICIR|>1.0 的三重门槛在实盘中具有较高区分度,但任何回测指标均不能保证未来收益。OS 验证和 IC/ICIR 交叉验证是识别"真 alpha"的关键工具,不是保证盈利的手段。不构成投资建议。