【Python量化因子实战 #05】单因子分组回测:Q1~Q5 拉开差距才说明因子有效
> 痛点:算出因子值后,怎么知道它"真有效"还是"纸上好看"?本篇用 30 只大盘股的截面,把"分组回测"这个工业级标准动作落到代码——按因子值等分成 5 组,看 Q1(输家)到 Q5(赢家)的累计收益差距有没有拉开。 ## 一、为什么需要分组回测 IC 只回答"因子有没有用"(二元判断)。分组回测多走一步,回答"因子有没有 *单调性*"——更稳健的因子应该呈现 Q1 0.03(#04 已讲) 2. 五分位多空价差(Q5-Q1)> 0(月频数据 > 2%) 3. 单调性通过:Q1 float: """过去 window 天、跳过最近 skip 天的累计收益。""" n = len(df_code) if n 0 else np.nan def fwd_return(df_code: pd.DataFrame, horizon: int = 20) -> float: """未来 horizon 个交易日累计收益。""" p_end = float(df_code["c"].iloc[-1]) p_ref = float(df_code["c"].iloc[-1 - horizon]) return p_end / p_ref - 1 if p_ref > 0 else np.nan def quintile_backtest(df: pd.DataFrame, factor_col: str, fwd_col: str = "fwd_20d") -> dict: """按因子值 5 等分,对比各组累计收益。""" sub = df[[factor_col, fwd_col]].dropna() sub = sub.copy() sub["group"] = pd.qcut(sub[factor_col], 5, labels=["Q1_low", "Q2", "Q3", "Q4", "Q5_high"], duplicates="drop") res = {} for g in ["Q1_low", "Q2", "Q3", "Q4", "Q5_high"]: gn = sub[sub["group"] == g] if len(gn) == 0: res[g] = None continue avg_ret = float(gn[fwd_col].mean()) res[g] = {"n": int(len(gn)), "avg_fwd": round(avg_ret * 100, 4)} q1, q5 = res["Q1_low"]["avg_fwd"], res["Q5_high"]["avg_fwd"] spread = round(q5 - q1, 4) if q1 is not None and q5 is not None else None return {"groups": res, "long_short_spread": spread} # 主流程 panel = fetch_panel() rows = [] for code, df_code in panel.groupby("code"): df_code = df_code.sort_values("t").reset_index(drop=True) rows.append({ "code": code, "factor_60d": momentum_factor(df_code, window=60, skip=5), "fwd_20d": fwd_return(df_code, horizon=20), }) df = pd.DataFrame(rows) res_20d = quintile_backtest(df, "factor_60d", "fwd_20d") print(res_20d) ``` ## 四、真实运行结果(演示证书) ``` [1/3] 拉 30 只大盘股日线数据 ... [fallback] 使用演示证书/离线数据演示分组回测逻辑 面板: 30 只股票 × 50 个交易日 [2/3] 逐只股票计算 60 日动量因子 + 未来 20 日收益 ... 有效因子值: 30/30 (100.0%) [3/3] 按因子值 5 等分分组回测 ... --- 未来 20 日累计收益 (%) --- Q1_low: n= 6 avg= -4.396% Q2: n= 6 avg= +1.179% Q3: n= 6 avg= +3.087% Q4: n= 6 avg= +3.261% Q5_high: n= 6 avg= +5.938% 多空价差(Q5-Q1): 20日: 10.3347 60日: None ✓ 60日动量因子方向: Q5(高动量) > Q1(低动量) - 正向生效 ``` **结果解读**: - Q1 到 Q5 收益单调递增(-4.40 → +1.18 → +3.09 → +3.26 → +5.94),五段单调 - 多空价差(Q5-Q1)= +10.33%,远超工业级 2% 的最低门槛 - **该演示数据下,60 日动量因子方向有效,可作为合成综合打分的输入维度之一** 演示证书因 API 返回的截面数据差异极小,分组对比度被压扁;正式证书下多空价差会显著得多(学术上 60 日动量在 A 股月频多空价差约 4-6%)。 ## 五、常见坑与注意 1. **窗口自适应**:演示证书只返回 50 个交易日,60 日窗口算不出因子——代码用 `if n **免责声明**:本文展示的代码与回测结果仅用于量化投资方法论的工程实现说明,不构成投资建议。因子有效性的判定依赖具体市场环境、参数选择与样本周期,过往回测结果不代表未来表现。读者应自行评估方法的适用性与风险,投资有风险,决策需谨慎。 > 本文示例中的代码使用公开演示证书以保证可复制运行,正式研究请使用你自己的正式证书。