2. 案例02:计算反转因子并分析其与未来收益的相关性

任务说明

本案例基于日线收盘价构造 5 日反转因子:rev5 = -(close / close.shift(5) - 1),即过去 5 日累计收益取负。随后计算未来 5 日收益 fwd5 = close.shift(-5) / close - 1,用 Spearman 相关系数检验因子值与未来收益的相关性。反转因子预期与未来收益正相关(过去跌得多,未来反弹概率大)。

环境与依赖

pip install pandas numpy scipy

完整实现

import numpy as np
import pandas as pd
from scipy.stats import spearmanr

# 1. 构造示例日线数据(真实使用时替换为读取行情数据)
np.random.seed(42)
dates = pd.bdate_range("2023-01-02", periods=300)
# 模拟带轻微均值回复的收益率序列
rets = np.random.normal(0, 0.02, len(dates))
for i in range(1, len(rets)):
    rets[i] -= 0.05 * rets[i - 1]  # 引入反转效应
close = pd.Series(100 * np.cumprod(1 + rets), index=dates, name="close")

# 2. 计算 5 日反转因子
rev5 = -(close / close.shift(5) - 1)
rev5.name = "rev5"

# 3. 计算未来 5 日收益
fwd5 = close.shift(-5) / close - 1
fwd5.name = "fwd5"

# 4. 对齐并剔除缺失值
df = pd.concat([rev5, fwd5], axis=1).dropna()

# 5. Spearman 相关性检验
rho, pval = spearmanr(df["rev5"], df["fwd5"])
print(f"样本数: {len(df)}")
print(f"Spearman rho = {rho:.4f}, p-value = {pval:.4f}")

# 6. 分组验证:按因子值分 5 组,观察各组未来收益均值
df["group"] = pd.qcut(df["rev5"], 5, labels=False)
group_mean = df.groupby("group")["fwd5"].mean()
print("\n分组未来5日收益均值:")
print(group_mean)

运行与验证

  • 运行脚本后观察 rho 与 p-value。若 rho > 0 且 p-value < 0.05,说明反转因子与未来 5 日收益显著正相关,因子方向符合预期。
  • 分组均值应呈现单调递增趋势(group 0 最低、group 4 最高),进一步佐证因子单调性。
  • 替换 close 为真实行情数据(如从 CSV 读取 pd.read_csv("xxx.csv", index_col="date", parse_dates=True)["close"])即可复用到实际标的。

关键点

  • 因子方向:取负号使"过去跌得多"对应因子值大,与未来收益正相关,便于统一解读。
  • Spearman 对异常值不敏感,适合因子与收益这类非线性单调关系的检验。
  • 必须用 shift(-5) 构造未来收益,避免使用未来信息污染因子计算。