跳到主要内容

因子的定义与构造

直觉

因子(factor)是一个「能给股票打分」的数值——分数高的股票,未来收益平均更好(或更差)。经典因子有四大类:价值(便宜的)、动量(涨得猛的)、质量(好公司)、低波(波动小的)。这一节我们用横截面数据,亲手把其中三种构造出来。

四大经典因子

因子直觉典型度量
价值便宜的股票被低估市净率倒数、盈利收益率
动量强者恒强过去 6–12 月收益
质量好公司值得溢价ROE、利润稳定性
低波低波动有异常收益过去波动率的倒数

:::note 本节的数据 sp500_metadata.csv 直接给了每只股票固定的 quality(质量) 分;动量与低波我们从 sp500_universe_daily.csv 的价格历史构造。价值因子需要基本面数据,本数据集没有,故概念讲解、不实现。 :::

因子的标准化

不同因子的量纲差很多(动量是百分比,质量可能是 z-score)。比较前通常做横截面标准化

f~i=fifˉσf\tilde f_i = \frac{f_i - \bar f}{\sigma_f}

这样每个因子都变成「均值 0、标准差 1」,方便叠加成多因子打分。

可运行案例:构造并标准化三个因子

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

prices = pd.read_csv('/data/sp500_universe_daily.csv', parse_dates=['date']).set_index('date')
meta = pd.read_csv('/data/sp500_metadata.csv').set_index('ticker').loc[prices.columns]

ret = np.log(prices / prices.shift(1))

# —— 因子1 动量: 过去 6 个月(126 日)累计收益, 最新一期截面 ——
momentum = np.log(prices / prices.shift(126)).iloc[-1]

# —— 因子2 低波: 过去 60 日波动率的倒数(波动越小分越高) ——
lowvol = 1.0 / ret.tail(60).std(ddof=0)

# —— 因子3 质量: 元数据里的 quality ——
quality = meta['quality']

factors = pd.DataFrame({'动量': momentum, '低波': lowvol, '质量': quality})

# 横截面标准化
factors_z = (factors - factors.mean()) / factors.std(ddof=0)

print("原始因子描述:"); print(factors.describe().round(3))
print("\n因子间相关(标准化后):"); print(factors_z.corr().round(2))

factors_z.boxplot(figsize=(6, 3.6))
plt.title("三个标准化因子的横截面分布"); plt.ylabel("z-score")
plt.tight_layout(); plt.show()

动手改一改

把动量窗口从 126 改成 21(短期)——它会变成「反转」因子(短期涨多的反而回调),相关结构也随之改变。因子不是死的,窗口和定义变了,含义就变。

小结

  • 因子 = 给股票打分的数值;经典四类:价值、动量、质量、低波;
  • 量纲不同,比较前要横截面标准化
  • 因子定义(窗口、算法)直接决定含义,改参数等于换因子。

下一节我们用 IC/IR 检验一个因子到底「有没有预测力」。