历史波动率计算:从对数收益率到EWMA模型
聊到历史波动率,很多新手第一反应就是「拿标准差算一下不就完了?」。嗯,理论上没错,但实际做起来,坑比想象中多。我最早做波动率交易的时候,就因为算错了一个分母,导致整个策略回测数据全偏了。今天咱们就把这块彻底捋清楚。
一、对数收益率:为什么不用普通收益率?
先问个问题:股票今天涨10%,明天跌10%,你回本了吗?没有。因为(1+10%)×(1-10%)=0.99,亏了1%。这就是普通收益率的致命问题——它不对称。
对数收益率就不一样了。它天然具有时间可加性,而且分布更接近正态。公式很简单:
r_t = ln(P_t / P_{t-1})
其中P_t是今天的收盘价,P_{t-1}是昨天的。
我个人习惯用对数收益率做所有波动率计算。为什么?因为当你把多个时间段的收益率加起来,对数收益率直接相加就等于总收益率,而普通收益率需要连乘。这在做滚动窗口计算时,能省不少事。
二、样本标准差 vs 总体标准差:差一个自由度
这个坑我踩过。当年写第一个波动率计算器,直接用Excel的STDEV.P(总体标准差),结果算出来的隐含波动率总是对不上市场报价。后来才发现,应该用STDEV.S(样本标准差)。
区别在哪?看公式:
样本标准差:σ = √[ Σ(r_i - r̄)² / (n-1) ]
总体标准差:σ = √[ Σ(r_i - r̄)² / n ]
分母差了个1。n是样本数量。为什么用n-1?因为样本均值r̄是从数据里估计出来的,损失了一个自由度。用n-1做无偏估计,更准。
| 类型 | 分母 | 适用场景 |
|---|---|---|
| 样本标准差 | n-1 | 用历史数据估计未来波动率 |
| 总体标准差 | n | 已知全部数据,只描述过去 |
做交易的人,99%的情况用样本标准差。记住这一点。
三、年化处理:把日波动率变成年波动率
算出来的日波动率是0.02,那一年是多少?直接乘以√252。为什么是252?因为一年大概有252个交易日。
σ_年 = σ_日 × √252
这里有个细节:如果你用的是周数据,就乘以√52;月数据乘以√12。关键是保持一致性。
我曾经见过有人用365天做年化,结果波动率直接虚高20%。你想想看,周末和节假日又不交易,用365天不是自己骗自己吗?
四、滚动窗口计算:让波动率动起来
静态波动率只能告诉你过去一段时间的平均波动水平。但市场是活的,我们需要看到波动率怎么随时间变化。滚动窗口就是干这个的。
做法很简单:固定一个窗口长度(比如20天),每天往前滑动一天,重新算一次标准差。这样你就能得到一条波动率曲线。
# Python伪代码
window = 20
rolling_vol = []
for i in range(window, len(returns)):
window_data = returns[i-window:i]
vol = np.std(window_data, ddof=1) * np.sqrt(252)
rolling_vol.append(vol)
窗口长度怎么选?没有标准答案。我个人习惯:
- 短线交易:10-20天窗口
- 中线交易:30-60天窗口
- 长线持仓:90-120天窗口
窗口越短,波动率曲线越敏感,但噪音也大。窗口越长,曲线越平滑,但反应滞后。这是个取舍问题。
五、EWMA模型:给数据加权重
滚动窗口有个问题:20天前的数据和昨天的数据,权重一样。这合理吗?显然不合理。昨天的价格波动对今天的影响,肯定比20天前的大。
EWMA(指数加权移动平均)就是来解决这个问题的。它给近期的数据更高的权重,权重随时间指数衰减。
σ²_t = λ × σ²_{t-1} + (1-λ) × r²_t
其中λ是衰减因子,通常在0.9到0.99之间。λ越大,历史数据衰减越慢;λ越小,模型对近期数据越敏感。
| λ值 | 半衰期(天) | 适用场景 |
|---|---|---|
| 0.94 | 约11天 | RiskMetrics标准模型 |
| 0.97 | 约23天 | 中等波动市场 |
| 0.99 | 约69天 | 低波动、趋势市场 |
RiskMetrics(摩根大通的风险管理模型)用的就是λ=0.94。我自己的经验是,做期权交易用0.94-0.96比较合适,既能捕捉到波动率突变,又不会太敏感。
- 滚动窗口:等权重,简单粗暴
- EWMA:指数衰减权重,更符合市场记忆特征
六、知识体系框架
下面这张图把整个历史波动率计算的逻辑串起来了。从原始价格数据开始,一步步走到EWMA模型。建议保存下来,写代码的时候对照着看。
七、实战中的避坑指南
最后分享几个我踩过的坑:
- 数据频率要统一:别把日数据和周数据混在一起算。我见过有人用日收益率算标准差,然后乘以√252,但数据里混了周数据——结果波动率忽高忽低。
- 异常值处理:遇到停牌、涨跌停板,收益率会是0或者极端值。我习惯把这些数据剔除或者用前值填充,不然波动率会被严重扭曲。
- EWMA的初始值:第一天没有σ²_{t-1}怎么办?我一般用前20天的样本方差做初始值,等模型跑一段时间后,初始值的影响就衰减没了。
- 不要过度优化λ:有人为了拟合历史数据,把λ调到0.9999。结果模型对市场突变毫无反应。记住,EWMA是用来预测的,不是用来拟合的。
好了,历史波动率计算这块就聊到这。把这些基础打牢,后面讲隐含波动率的时候,你才能理解为什么市场报价有时候会「不合理」——其实不是市场错了,是你用的模型不对。
公众号:蓝海资料掘金营,微信deep3321