主题切换
11.7 隐含波动率与历史波动率
概念详解
期权定价中,波动率是最关键的不可观测输入。在 Black-Scholes 模型中,标的资产价格、行权价、到期时间、利率都可以直接观测,唯独波动率 σ 必须通过期权市场价格反推得到。这个反推出来的 σ 就是隐含波动率(IV)。
但市场参与者还关心另一个波动率:历史波动率(HV),即过去 N 天内实际实现的波动率,它是对未来的"前瞻性预测"。传统上,HV 通过对数收益率的标准差来估算;研究者提出了多种改进方法,试图在 HV 计算中加入隔夜波动、日内高低价信息等。
IV 与 HV 的关系是期权策略的核心:
- IV > HV:期权被高估,适合卖出期权(收权利金)
- IV < HV:期权被低估,适合买入期权(获取潜在波动)
- IV ≈ HV:市场定价"合理",适合价差(做市方向中性)
名词解释:隐含波动率(Implied Volatility, IV)
将期权的市场价格反向代入 Black-Scholes 公式,反推出来的波动率参数。IV 本质上代表了市场对未来波动率的预期,以及风险溢价(对承担风险的补偿)。IV 是期权市场对未来 30/60/90 天的"集体投票"。
名词解释:历史波动率(Historical Volatility, HV)
过去 N 天内(常用 10/20/60 天)对数收益率的标准差,年化后得到的波动率指标。HV 是"后视镜",反映过去已经发生的波动。
名词解释:IV-HV 差(Volatility Risk Premium)
IV 与 HV 的差值。学术研究表明,这是市场结构性风险溢价,长期为正(IV 长期 > HV),即期权买方长期"吃亏"。Easley, O'Hara 和 Srinivas (2002) 以及 Carr 和 Wu (2009) 等多篇论文证实 VRP 长期为正,平均年化 2-3 个百分点。
概念定义与差异
历史波动率(HV)的五种计算方法
不同的 HV 计算方法利用不同精度的价格信息:
| 方法 | 数据 | 计算公式 | 估计效率 |
|---|---|---|---|
| 简单标准差 | Close | 1x | |
| EWMA (RiskMetrics) | Close | 比简单 ~1.2x | |
| Parkinson | High/Low | 比简单 1.5-2x | |
| Garman-Klass | OHLC | 综合 HL 范围 + 收盘走向 | 比简单 2-3x |
| Yang-Zhang | OHLC + 隔夜 | 综合隔夜跳空 + 日内 + HL | 比简单 4-5x |
Yang-Zhang 是当前学界认为最有效的 HV 估算方法,其核心在于综合三部分:
$$\hat{\sigma}^2_{YZ} = \hat{\sigma}^2_{OC} + k \cdot \hat{\sigma}^2_{CO} + (1-k) \cdot \hat{\sigma}^2_{RS}$$
其中:
: 当日 open-to-close 的方差(反映日内行为) : 前收-今开的方差(反映隔夜跳空) : Rogers-Satchell 项(综合 HL 范围) : 最优权重
此处有展示代码展开 ▼
python
import numpy as np
import pandas as pd
np.random.seed(42)
# 模拟 252 天的 50ETF 收盘价
n_days = 252
daily_vol = 0.014
returns = np.random.randn(n_days) * daily_vol
prices = 2.800 * np.exp(np.cumsum(returns))
log_returns = np.log(prices[1:] / prices[:-1])
print(f"数据集: {n_days} 天, 年化 vol ≈ {log_returns.std()*np.sqrt(252)*100:.2f}%")点击展开可浏览运行结果
数据集: 252 天, 年化 vol ≈ 21.48%
📌 五种 HV 的 Python 实现
此处有展示代码展开 ▼
python
def hv_simple(returns, window=20):
"""方法 1: 简单滚动标准差"""
return returns.rolling(window).std() * np.sqrt(252)
def hv_ewma(returns, lam=0.94):
"""方法 2: RiskMetrics EWMA (λ=0.94 是业界标准)"""
var = returns.var()
vars_list = [var]
for r in returns[1:]:
var = lam * vars_list[-1] + (1-lam) * r**2
vars_list.append(var)
return pd.Series(np.sqrt(vars_list) * np.sqrt(252), index=returns.index)
def hv_parkinson(high, low, window=20):
"""方法 3: Parkinson (high-low)"""
n = (np.log(high/low))**2 / (4*np.log(2))
return np.sqrt(n.rolling(window).mean() * 252)
def hv_garman_klass(open_, high, low, close, window=20):
"""方法 4: Garman-Klass (OHLC)"""
n = 0.5*(np.log(high/low))**2 - (2*np.log(2)-1)*(np.log(close/open_))**2
return np.sqrt(n.rolling(window).mean() * 252)
def hv_yang_zhang(open_, high, low, close, window=20):
"""方法 5: Yang-Zhang (OHLC, 完整)"""
k = 0.34 / (1.34 + (window+1)/(window-1))
log_oc = np.log(close/open_)
log_co = np.log(close/open_.shift(1))
log_ho = np.log(high/open_)
log_lo = np.log(low/open_)
oc_var = (log_oc**2).rolling(window).mean()
co_var = (log_co**2).rolling(window).mean()
rs = log_ho*(log_ho-log_oc) + log_lo*(log_lo-log_oc)
rs_var = rs.rolling(window).mean()
var = oc_var + k*co_var + (1-k)*rs_var
return np.sqrt(var * 252)
# 用 close 模拟 OHLC(实际应用应使用真实 K 线)
idx = pd.date_range("2024-01-01", periods=n_days)
close = pd.Series(np.asarray(prices).ravel(), index=idx)
noise = lambda size: np.abs(np.random.randn(size)) * 0.003 * pd.Series(prices['close'].iloc[:size].values if size<n_days else prices['close'].values, index=idx[:size] if size<n_days else idx)
# 简化:用 close 构造伪 OHLC
def synth_ohlc(close):
n = len(close)
open_ = close.shift(1) * (1 + np.random.randn(n)*0.005)
high = close * (1 + np.abs(np.random.randn(n))*0.005) # 保留 close 的 DatetimeIndex,避免 index 错位
low = close * (1 - np.abs(np.random.randn(n))*0.005)
return open_, high, low, close
open_, high, low, close = synth_ohlc(close)
results = pd.DataFrame()
results["simple"] = hv_simple(pd.Series(log_returns, index=idx[1:]), 20)
results["ewma"] = hv_ewma(pd.Series(log_returns, index=idx[1:]))
results["parkinson"] = hv_parkinson(high, low, 20)
results["garman_k"] = hv_garman_klass(open_, high, low, close, 20)
results["yang_z"] = hv_yang_zhang(open_, high, low, close, 20)
print("\n最新一天的 5 种 HV (年化):")
print("-" * 50)
for name in results.columns:
val = results[name].iloc[-1] * 100
print(f" {name:<12}: {val:6.2f}%")点击展开可浏览运行结果
最新一天的 5 种 HV (年化): -------------------------------------------------- simple : 22.71% ewma : 27.91% parkinson : 9.29% garman_k : 9.90% yang_z : 14.85%
隐含波动率(IV)的构造与提取
IV 的获取方式与 HV 完全不同——IV 不依赖历史价格,而依赖当前期权市场价格。将期权市价代入 BS 公式,反推 σ:
$$C_{\text{market}} = S\Phi(d_1) - Ke^{-rT}\Phi(d_2) \quad \Rightarrow \quad \sigma_{IV}$$
反推通常用牛顿迭代法:从初始猜测 σ₀ = 0.2 开始,利用 BS 价格的近似线性求 ∂C/∂σ = Vega,逐步调整 σ 直至 |C_market - C_BS| < ε。
此处有展示代码展开 ▼
python
def bs_call(S, K, T, r, sigma):
if T <= 0:
return max(S-K, 0)
d1 = (np.log(S/K) + (r+sigma**2/2)*T) / (sigma*np.sqrt(T))
d2 = d1 - sigma*np.sqrt(T)
return S*norm.cdf(d1) - K*np.exp(-r*T)*norm.cdf(d2)
def implied_vol(market_price, S, K, T, r, sigma_init=0.2):
"""牛顿迭代反推隐含波动率"""
sigma = sigma_init
for i in range(100):
bs_val = bs_call(S, K, T, r, sigma)
diff = bs_val - market_price
if abs(diff) < 1e-6:
return sigma
# Vega 解析
d1 = (np.log(S/K) + (r+sigma**2/2)*T) / (sigma*np.sqrt(T))
vega = S*np.exp(-d1**2/2)/np.sqrt(2*np.pi)*np.sqrt(T)
sigma -= diff/vega
if sigma <= 0:
sigma = 0.001
return sigma
# 示例
S, K, T, r = 100, 100, 0.5, 0.03
opt_market = 4.5
iv = implied_vol(opt_market, S, K, T, r)
print(f"市价 {opt_market} 对应的隐含波动率: {iv*100:.2f}%")点击展开可浏览运行结果
📘 本段代码定义了 2 个函数/类:函数 `implied_vol`(牛顿迭代反推隐含波动率),以及 函数 `bs_call`。该片段为教学展示(未包含独立运行的输入数据),可在实战练习中结合真实数据调用。
名词解释:VIX 指数
VIX 是由 CBOE 推出的"标普 500 指数未来 30 天波动率的市场预期"。它通过对一系列 OTM Put/Call 进行加权计算得出,核心公式见下文。VIX 不依赖于任何模型假设,纯粹从市场价格提炼,因此被广泛用作"市场恐慌温度计"。
VIX 指数的构造公式
VIX 通过对不同行权价的 OTM 期权价格加权,得出未来 30 天的年化波动率:
$$VIX^2 = \frac{2}{T} \sum_i \frac{\Delta K_i}{K_i^2} e^{rT} Q(K_i) \Delta K_i - \frac{1}{T}\left(\frac{F}{K_0} - 1\right)^2$$
其中:
: 行权价 的 OTM 期权价格(Put 或 Call,取 OTM 的那一边) : 相邻两个行权价的间隔 : 前向指数水平(由 Put-Call 平价推出) : 第一个高于 的行权价 : 到期时间(年)
计算步骤:
- 选取 30 天以内的最近两个到期月份
- 在每个到期月,选出 OTM 期权(对低于 F 的行权价用 Put,高于 F 的用 Call)
- 用
确定权重 - 插值得出每个到期月的 VIX 子值,再加权到 30 天
此处有展示代码展开 ▼
python
def vix_calc(otm_options_near, otm_options_far, T1, T2, F, r):
"""
otm_options: list of tuples (K, mid_price)
T1, T2: 近月、远月到期时间(年)
F: 前向指数水平
"""
K0 = min([k for k,_ in otm_options_near if k > F])
K1_min = min([k for k,_ in otm_options_near])
K2_max = max([k for k,_ in otm_options_near])
def contrib(otm_options, T):
sigma2 = 0
n = len(otm_options)
for i, (K, Q) in enumerate(otm_options):
# 计算 Delta K (中心差分)
K_minus = otm_options[i-1][0] if i > 0 else K1_min
K_plus = otm_options[i+1][0] if i < n-1 else K2_max
dK = (K_plus - K_minus) / 2
sigma2 += dK * Q / K**2
return (2/T) * np.exp(r*T) * sigma2 - (1/T) * (F/K0 - 1)**2
sigma2_1 = contrib(otm_options_near, T1)
sigma2_2 = contrib(otm_options_far, T2)
# 加权到 30 天
N1, N2 = int(T1*365), int(T2*365)
N30 = 30
VIX2 = sigma2_1 * (N2-N30)/(N2-N1) + sigma2_2 * (N30-N1)/(N2-N1)
return np.sqrt(VIX2) * 100
# 示例
otm_near = [(95,0.20),(96,0.50),(97,1.00),(98,1.80),(99,2.80),
(100,4.20),(101,5.50),(102,7.00),(103,8.50),(105,11.50)]
# 注: 实际应该只保留 OTM 的部分, 即 Put 用 K<F, Call 用 K>F
otm_near_clean = [(95,0.20),(96,0.50),(97,1.00),(98,1.80),(99,2.80),
(101,5.50),(102,7.00),(103,8.50),(105,11.50)]
otm_far = [(93,0.40),(95,0.80),(97,1.50),(99,2.50),(100,3.60),
(101,4.90),(103,7.20),(105,9.50),(107,12.00)]
vix_now = vix_calc(otm_near_clean, otm_far, 1/12, 2/12, F=99.5, r=0.05)
print(f"VIX 构造结果: {vix_now:.2f}")
print(f"分位数(<15:极低 / 15-20:正常 / 20-30:略高 / >30:恐慌): {'恐慌' if vix_now>30 else '略高' if vix_now>20 else '正常' if vix_now>15 else '极低'}")点击展开可浏览运行结果
VIX 构造结果: 32.58 分位数(<15:极低 / 15-20:正常 / 20-30:略高 / >30:恐慌): 恐慌
波动率锥(Volatility Cone)
波动率锥(Vol Cone) 是衡量"不同时间窗口下,HV 的历史分布"的工具。绘制方法:
- 计算不同窗口的 HV(10/20/30/60/90/120/250 天)
- 对每个窗口,统计它在过去 X 年的分位数(5%, 25%, 50%, 75%, 95%)
- 绘制锥形图,横轴为窗口天数,纵轴为 HV 值
当当前 IV 显著高于同窗口历史中位数时,意味着期权相对昂贵。
此处有展示代码展开 ▼
python
def vol_cone(prices, windows=[10,20,30,60,90,120,250]):
"""计算不同窗口 HV,并统计分位数"""
log_returns = np.log(prices[1:] / prices[:-1])
df = pd.DataFrame()
for w in windows:
df[f"HV_{w}"] = log_returns.rolling(w).std() * np.sqrt(252)
# 各列分位数
quantiles = df.describe(percentiles=[0.05,0.25,0.50,0.75,0.95]).T
return df, quantiles
# 示例输出
df, q = vol_cone(prices)
print("波动率锥统计(年化):")
print(q[["mean","5%","25%","50%","75%","95%"]].applymap(lambda x: f"{x*100:.1f}%"))点击展开可浏览运行结果
📘 本段代码定义了 1 个函数/类:函数 `vol_cone`(计算不同窗口 HV,并统计分位数)。该片段为教学展示(未包含独立运行的输入数据),可在实战练习中结合真实数据调用。
输出形如:
mean 5% 25% 50% 75% 95%
HV_10 18.2% 11.5% 14.8% 17.6% 20.5% 28.1%
HV_20 19.5% 13.2% 16.5% 19.0% 21.8% 27.5%
HV_30 19.8% 14.0% 17.1% 19.5% 22.0% 27.0%
HV_60 20.1% 15.0% 17.8% 19.8% 22.1% 26.5%
HV_90 20.2% 15.5% 18.1% 20.0% 22.2% 26.2%
HV_120 20.3% 15.8% 18.4% 20.2% 22.3% 26.0%
HV_250 20.4% 16.0% 18.5% 20.3% 22.4% 26.0%如果当前 IV-HV 差 = 5%,意味着 IV 比 90% 分位数的 HV 还要高,此时做空跨式的胜率显著增大。
实盘信号:IV-HV 差作为择时工具
学术研究(Long, Timmermann & Wohar, 2014; Carr & Wu, 2009)一致发现:IV-HV 差为正且扩大时,卖出跨式的未来收益为正。简单逻辑:
- IV > HV → 市场过于乐观(为不确定性"付费过多"),预期 IV 回归 HV → 卖期权赚钱
- IV < HV → 市场过于低估不确定性,买入期权做波动率扩张更合理
此处有展示代码展开 ▼
python
def vrp_signal(iv, hv_20d, lookahead="revert"):
"""波动率风险溢价信号"""
vrp = iv - hv_20d
if vrp > 0.04: # >4个百分点
return "SELL_VOL"
elif vrp < -0.02: # 负2个百分点
return "BUY_VOL"
else:
return "NEUTRAL"
# 模拟:用 252 天历史数据回看信号分布
signals = []
for i in range(60, len(prices)):
hv_20 = pd.Series(log_returns).iloc[i-20:i].std()*np.sqrt(252)
# 假设 IV 是观测到的值 (用 1.2 倍 HV 模拟)
iv = hv_20 * 1.10 + np.random.normal(0, 0.02)
sig = vrp_signal(iv, hv_20)
signals.append(sig)
from collections import Counter
print("信号分布:", Counter(signals))点击展开可浏览运行结果
信号分布: Counter({'NEUTRAL': 132, 'SELL_VOL': 58, 'BUY_VOL': 2})VIX 历史分位与择时
| VIX 区间 | 市场状态 | 历史百分位(自 1990) |
|---|---|---|
| 0-12 | 极度平静 | 0-10% |
| 12-20 | 正常偏低 | 10-50% |
| 20-30 | 偏高 | 50-85% |
| 30-40 | 紧张 | 85-95% |
| 40-60 | 恐慌 | 95-99% |
| >60 | 危机级别 | >99% |
VIX 触及 80 + 时(如 2008/10、2020/03)是历史上极少的"危机时刻",之后做多波动率(如买入跨式)通常会在 1-3 个月内获得数倍收益,但前提是仓位控制极严格(因为中间可能继续亏)。
IV-HV 时序图与波动率锥(互动组件)
18.2
VIX 当前19.5
VIX 历史均值42%
VIX 当前分位+3.2%
IV-HV 差
常见误区
误区 1:"IV 越高越好,卖出期权能赚更多"
IV 高确实意味着权利金充足,但风险也按比例放大。卖出裸跨式时,IV 高时遭遇暴跌事件的损失可能是平时的 5-10 倍。2018 年 2 月,做空 VIX 的 XIV ETN 因 1 天暴跌 96% 而清盘,根本原因是 VIX 在一天内从 17 飙升至 50+。
误区 2:"HV 高就意味着未来 IV 也会高"
不。HV 与 IV 的关系并非简单同步。HV 是"已实现的",IV 是"预期的"。两者可能背离多年——例如 2018 年全年 HV 不高,但 50ETF 期权 IV 长期在 25-35% 之间,VRP 持续偏高。
误区 3:"VIX 与 SPX 完全负相关"
统计上相关,但有显著例外。在 2018 年 2 月、2020 年 3 月、2022 年某些时段,VIX 与 SPX 同向 移动——VIX 在 SPX 上涨时也下跌不明显,在 SPX 下跌时更剧烈地上涨。这意味着 VIX 的对冲效果并非"完美负相关"。
误区 4:"波动率锥的历史分位数可以外推"
历史分位数基于"过去 N 年"的经验,但市场结构性变化可能让历史分布不再适用。例如,2020 年之前,VIX 触及 30+ 通常对应"小危机",但 2020 年后 VIX 30+ 已经常态化。
误区 5:"用 IV 反推的 σ 直接用于预测"
IV 是市场预期,含有"风险溢价"。如果要估计"未来真实 σ",需要用 HV 作为参考,或者用衍生品定价模型(随机波动率)反推"无风险中性" σ。
题目 1
小测验
题目 1:当 IV > HV 时,市场参与者倾向于?
题目 1:当 IV > HV 时,市场参与者倾向于?
- AA. 大量买入期权,因为预期未来波动放大
- BB. 卖期权更有利,因为市场"付了过多"的预期波动
- CC. 与策略无关,主要看方向
- DD. 加杠杆买入,放大收益
查看答案与解析展开 ▼
正确答案:B
IV 高于 HV 说明市场为未来不确定性"付了过多"的钱,期权相对昂贵,即波动率风险溢价(VRP)为正。卖方收下的权利金里隐含的波动率高于随后实际实现值,长期期望收益为正,所以倾向卖出跨式这类收租策略。A 方向相反,IV 已经偏高时追买等于溢价接盘;C 错,IV-HV 差正是波动率策略择时的核心变量;D 加杠杆买更是在 VRP 为正时站在错误一边。
题目 2
Yang-Zhang HV 估计方法相比简单标准差的优势在于?
- AA. 计算更快
- BB. 只用 close 数据
- CC. 充分利用日内信息(HL + 隔夜跳空 + OC),估计效率更高
- DD. 适合加密货币
查看答案与解析展开 ▼
正确答案:C
Yang-Zhang 用 ,同时纳入 open-to-close(日内行为)、close-to-open(隔夜跳空)与 Rogers-Satchell(高低价范围)三项,信息利用最充分,估计效率约为简单标准差的 4-5 倍。A 错:它计算更复杂而非更快;B 恰好说反,只用 close 的正是简单标准差;D 只是使用场景,并非方法论上的优势。
题目 3
50ETF 期权市场上,通常 30 天 ATM 期权的隐含波动率?
- AA. 比 20 天历史波动率略高(2-5 个百分点),反映风险溢价
- BB. 与 HV 完全相等
- CC. 总是低于 HV
- DD. 没有相关性
查看答案与解析展开 ▼
正确答案:A
50ETF 上 30 天 ATM 期权的 IV 通常比 20 天 HV 高出 2-5 个百分点,这个系统性正偏就是波动率风险溢价(VRP)。它解释了为什么 Long Straddle 长期亏损、Covered Call 与 Iron Condor 等卖方策略长期占优。B、C、D 都不成立:IV 是含风险溢价的市场预期,HV 是已实现值,两者高度相关但有稳定正偏,既不会完全相等,也不存在固定低于或毫无关系。
实战练习
HV 五种对比:下载 50ETF 2023 年的日 K 线(用 akshare:
ak.fund_etf_hist_em("510050")),分别用 5 种方法计算 20 天 HV,观察它们的差异及其背后的原因。在波动大的时段(如 8 月底),哪种方法对日间跳空最敏感?IV-HV 差回测:取 50ETF 期权某月合约每日收盘价,反推每个交易日的 IV(假设 ATM),与同期 20 天 HV 比较,统计 IV-HV 差的分布。在差值 > 5% 时,持有"卖出跨式"组合 5 天后收益如何?
波动率锥绘制:用 2020-2024 年 50ETF 日线数据,绘制 7/30/60/90/120/250 天窗口的 HV 锥图,用 5%/25%/50%/75%/95% 五条分位数带展现。标注当下 HV 在锥图中的位置,以及对应 IV 的位置。
VIX 历史分位:下载 SPX 1990-2024 年日线,计算 20 天 HV,对比 VIX 收盘价的 5 年滚动分位数。观察 VIX 在 80+ 的历史时点(2008/10、2020/03、2022/01)。
延伸阅读
- Carr, P. & Wu, L. (2009). "Variance Risk Premiums." Review of Financial Studies. 关于 IV-HV 长期为正的最经典研究。
- Gatheral, J. (2006). The Volatility Surface. Wiley. 第 1-2 章讲解 IV 提取和 HV 计算方法。
- Cont, R. (2001). "Empirical Properties of Asset Returns: Stylized Facts and Statistical Issues." Quantitative Finance. 关于 HV 的统计学性质。
- Brandt, M. & Diecidue, E. (2014). "Volatility Forecasting." Handbook of Volatility Models. 多种 HV 方法的对比。
- 波动率锥实战可参见 tastytrade 团队的研究报告(https://www.tastytrade.com/research)。
本章要点
- HV 反映过去,IV 反映预期。两者永远存在差异,这个差异叫波动率风险溢价(VRP),长期为正。
- 5 种 HV 计算方法中,YZ (Yang-Zhang) 利用 OHLC 信息最充分,效率最高;EWMA 适合动态风险管理;简单标准差用于在线计算最方便。
- IV 通过 BS 反推得到:从期权市场价格反解 σ,核心是牛顿迭代法 + Vega 数值。
- VIX 是市场对未来 30 天波动率的预期,由一系列 OTM 期权价格加权得出,不是模型假设的产物,完全从市场提炼。
- 波动率锥 是策略制定的"地图":当前 IV 处于历史锥体的哪个分位数,直接决定了策略方向。
- IV-HV 差为正时倾向卖期权,为负时倾向买期权,这是学术界和市场广泛证实的规律。
- 波动率交易的核心是均值回归思维:VRP 长期为正提供了统计优势,但极端尾部事件(如 VIX 突破 50)可能摧毁"看起来稳赚"的策略。
接下来 11.8 章将基于本章的波动率视角,介绍 波动率交易策略(跨式、宽跨式、蝶式、铁鹰式等)的实战构建。