同列存储多债券历史价格场景下计算各债券历史波动率的问题求解
代码调整方案
问题根因
- 原代码最后一行直接对全列
log_return计算标准差,没有按ISIN分组,且标量无法正确匹配到每行,所以返回NaN - 滚动窗口代码参数设置错误:
window=1, freq='A'代表按年频率取窗口,每个窗口仅统计1个观测值的标准差,自然每个ISIN只有少量结果 - 不需要将ISIN转为宽表计算,长表分组计算是更节省内存的方案,完全适配9000只债券的计算需求
方案1:计算单只债券全时间段的静态历史波动率
如果你需要的是每只债券在整个数据集时间范围内的固定波动率,直接对log_return按ISIN分组后用transform回填结果即可:
import pandas as pd import numpy as np vol_df = pd.read_csv('hist_prices.csv') vol_df['BusinessDate'] = pd.to_datetime(vol_df['BusinessDate']) # 按ISIN+日期排序,避免收益率计算顺序错误 vol_df = vol_df.sort_values(['ISIN', 'BusinessDate']).reset_index(drop=True) vol_df['Mid Price'] = vol_df[['Bid', 'Ask']].mean(axis=1) vol_df['log_return'] = vol_df.groupby('ISIN')['Mid Price'].apply(lambda x: np.log(x) - np.log(x.shift(1))) # 分组计算标准差后回填到对应行 vol_df['hist_vol'] = vol_df.groupby('ISIN')['log_return'].transform('std') * np.sqrt(252)
方案2:计算单只债券的滚动历史波动率
如果需要按窗口滚动计算动态波动率,调整滚动窗口参数即可,支持按观测值数量或者时间范围两种窗口模式:
# 先将日期设为索引,适配时间窗口计算 vol_df = vol_df.set_index('BusinessDate') # 滚动波动率计算 rolling_vol = vol_df.groupby('ISIN')['log_return'].rolling( # 可选1:按观测值数量设窗口,适配不同债券交易日数不一致的场景,window=252代表取最近252个有效交易日的收益率 window=252, # 可选2:按时间范围设窗口,window='252D'代表取最近252个自然日内的所有有效收益率 # window='252D', min_periods=60, # 窗口内最少有60个有效收益率才计算,避免样本太少结果失真,可根据需求调整 closed='left' # 排除当前行的收益率,避免未来数据引用,可根据需求调整 ).std() * np.sqrt(252) # 结果回填到原表 vol_df = vol_df.reset_index() vol_df['rolling_hist_vol'] = rolling_vol.reset_index(drop=True)
注意事项
- 单只债券如果有效收益率记录少于
min_periods的设定值,对应波动率结果会返回NaN,属于正常情况 - 计算前务必按ISIN+交易日排序,避免收益率计算顺序错误导致结果偏差
内容的提问来源于stack exchange,提问作者user16708102
相关产品推荐
相关产品推荐

