3. 案例03
任务说明
本案例基于多只股票的日线收盘价,计算每只股票过去20个交易日的收益率标准差作为波动率因子,再对同一交易日所有股票的波动率因子做横截面 Z-score 标准化,最后输出标准化结果。
环境与依赖
- Python 3.8+
- pandas、numpy
安装命令:pip install pandas numpy
实现思路
- 构造宽表:行索引为交易日,列名为股票代码,值为收盘价。
- 用
pct_change()计算日收益率。 - 用
rolling(20).std()得到20日收益率标准差,即波动率因子。 - 按行(axis=1)做 Z-score:
(x - mean) / std,得到横截面标准化结果。
完整代码
import numpy as np
import pandas as pd
np.random.seed(0)
# 1. 构造示例数据:5只股票、60个交易日的收盘价
dates = pd.date_range("2024-01-01", periods=60, freq="B")
codes = ["A", "B", "C", "D", "E"]
prices = pd.DataFrame(
np.cumprod(1 + np.random.normal(0, 0.02, size=(60, 5)), axis=0) * 100,
index=dates, columns=codes,
)
# 2. 日收益率
returns = prices.pct_change()
# 3. 20日收益率标准差 = 波动率因子
vol = returns.rolling(window=20).std()
# 4. 横截面 Z-score 标准化(按行)
cs_mean = vol.mean(axis=1)
cs_std = vol.std(axis=1, ddof=0)
vol_z = vol.sub(cs_mean, axis=0).div(cs_std, axis=0)
# 5. 输出结果
result = vol_z.dropna(how="all")
print(result.tail(5).round(4))
# 校验:每个有效交易日的横截面均值≈0、标准差≈1
check = pd.DataFrame({
"mean": result.mean(axis=1),
"std": result.std(axis=1, ddof=0),
})
print(check.tail(5).round(6))
运行方式
将代码保存为 vol_factor.py,执行:python vol_factor.py。
验证方法与通过条件
- 输出末尾5行应为一个 5×5 的标准化矩阵,数值量级大致在 -2 到 2 之间。
- 校验表中每个有效交易日的
mean应接近 0(浮点误差范围内),std应接近 1。 - 满足以上两点即说明波动率因子计算与横截面 Z-score 标准化均正确。
常见问题
- 若某交易日有效股票数少于2,
std为 NaN,标准化结果也为 NaN,属正常现象。 - 若需按行业或市值分组标准化,可将
mean/std替换为groupby分组统计后再做减法与除法。