滚动标准差即金融中“滚动波动率”,用pandas.Series.rolling().std()计算,默认样本标准差(ddof=1),可设ddof=0得总体标准差;需确保收益率等频、无缺失,推荐用'252D'时间偏移窗口以匹配真实交易日。

用 pandas.Series.rolling() 计算滚动标准差就是波动率
金融中常说的“滚动波动率”,本质就是对收益率序列做固定窗口的滚动标准差。不需要额外库,pandas 的 .rolling() 方法直接支持,但要注意它默认计算的是**样本标准差**(除以 n-1),而部分风控场景要求总体标准差(除以 n)。可通过 ddof=0 参数切换:
-
returns.rolling(window=252).std(ddof=0)→ 年化波动率常用分母为n的总体标准差 -
returns.rolling(window=252).std()→ 默认ddof=1,即样本标准差,更常见于统计推断 - 若需年化,乘以
np.sqrt(252)(日频)或np.sqrt(12)(月频),别忘了先确认收益率是日度还是月度
收益率序列必须是等间隔且无缺失值,否则滚动结果会失真
滚动计算对时间连续性敏感。如果原始价格数据有交易日缺失(比如节假日跳空)、或你用了 resample('D').last() 但没填充,.rolling() 仍按行数而非实际天数滑动窗口——这会导致 252 行 ≠ 252 个交易日。
- 正确做法:用
returns.asfreq('D').fillna(0)或returns.reindex(pd.date_range(...), fill_value=0)对齐日历 - 更稳妥:用
returns.rolling('252D')(注意是字符串,如'252D'),它基于真实日期偏移,自动跳过非交易日(前提是索引是DatetimeIndex且含实际日期) - 检查缺失:运行
returns.isna().sum(),若有缺失,.rolling().std()在窗口内遇到NaN会直接返回NaN,不是插值
使用 numpy 手动实现时,np.std 的 axis 和 ddof 容易设错
有人为控制细节改用 numpy + sliding_window_view,但容易在维度和自由度上出错。例如:
from numpy.lib.stride_tricks import sliding_window_view windows = sliding_window_view(returns, window_shape=252) vol_manual = np.std(windows, axis=1, ddof=0) # 必须指定 axis=1,否则压平整个数组
-
sliding_window_view返回 shape 为(n-251, 252)的二维数组,np.std需对每行(即每个窗口)求标准差 →axis=1 -
ddof不写默认为 0,但pandas默认是 1,混用时数值不一致 - 该方式无法处理
NaN,遇到含NaN的窗口会返回nan;而pandas的.std()默认skipna=True
高频场景下,滚动波动率的性能瓶颈常在索引类型而非计算本身
当处理万级股票、十年日频数据时,.rolling().std() 本身很快,但如果你的 DatetimeIndex 是 object 类型(比如从字符串解析失败),或未排序、含重复日期,pandas 会降级到慢路径。
- 检查索引类型:
type(df.index)应为pandas.core.indexes.datetimes.DatetimeIndex - 强制转换:
df.index = pd.to_datetime(df.index),再df = df.sort_index() - 避免重复日期:
df = df[~df.index.duplicated(keep='last')],否则.rolling()可能行为异常
真正卡住的往往是后续画图或导出——滚动波动率结果是 Series,但索引若为不规则时间戳,matplotlib 绘图可能崩或极慢。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











