波动率度量方法:从标准差到Yang-Zhang
做固收量化交易这些年,我越来越觉得波动率这东西,就像债券市场的脉搏。你摸不准它,策略就容易翻车。今天咱们聊聊几种主流的波动率度量方法——标准差法、Parkinson法、Garman-Klass法、Yang-Zhang法,以及它们各自该用在什么场景下。
说白了,波动率度量就是回答一个问题:价格到底有多“跳”?但不同场景下,“跳”的定义不一样。有的只看收盘价,有的要把最高最低价都算进去,有的还得考虑开盘跳空。嗯,这里头门道不少。
1. 标准差法:最朴素的度量
标准差法,也叫Close-to-Close法。它只盯着收盘价看。公式很简单:
import numpy as np
def close_to_close_volatility(prices):
# prices: 收盘价序列
log_returns = np.log(prices[1:] / prices[:-1])
return np.std(log_returns, ddof=1) * np.sqrt(252) # 年化
我个人习惯用这个做快速筛查。为什么?因为它计算量最小,数据也最容易拿到。但你要注意——它有个致命缺陷:忽略了日内价格波动。
避坑指南:我曾经在国债期货上吃过亏。某天盘中波动剧烈,但收盘价跟前一天几乎一样。标准差法算出来波动率很低,可实际上那天做市商都被打爆了。所以,别只看收盘价。
适用场景:
- 数据频率低(日线、周线)
- 市场流动性好,收盘价有代表性
- 做长期趋势跟踪策略
2. Parkinson法:把最高最低价用起来
Parkinson法比标准差法进了一步。它用最高价和最低价来估算波动率。你想想看,一天之内价格从低到高走了多远,这本身就包含了波动信息。
def parkinson_volatility(high, low):
# high, low: 最高价和最低价序列
n = len(high)
sum_squared = np.sum(np.log(high / low) ** 2)
return np.sqrt(sum_squared / (4 * n * np.log(2))) * np.sqrt(252)
我在做利率互换波动率交易时,特别喜欢用这个方法。为什么?因为利率互换的日内数据往往只有最高最低价,没有完整的tick数据。Parkinson法刚好派上用场。
小技巧:Parkinson法假设价格是连续运动的,没有跳空。如果市场开盘就跳空,这个方法会低估真实波动率。我一般会先检查一下开盘价和前一天收盘价的差距,如果跳空超过1%,就换别的方法。
适用场景:
- 只有OHLC数据(开盘、最高、最低、收盘)
- 市场连续交易,没有跳空
- 做日内高频策略的回测
3. Garman-Klass法:更精细的估计
Garman-Klass法在Parkinson的基础上,把开盘价和收盘价也加了进来。它认为,开盘价和收盘价之间的差距,以及它们相对于最高最低价的位置,都包含了波动信息。
def garman_klass_volatility(open, high, low, close):
# 经典的Garman-Klass公式
log_hl = np.log(high / low) ** 2
log_co = np.log(close / open) ** 2
n = len(open)
variance = np.sum(0.5 * log_hl - (2 * np.log(2) - 1) * log_co) / n
return np.sqrt(variance) * np.sqrt(252)
说实话,这个方法是我在实盘中最常用的。它兼顾了日内波动和开盘收盘的跳空信息。我记得有一次做国债期货的波动率套利,用Garman-Klass算出来的波动率,跟实际期权隐含波动率的拟合度特别好。
核心优势:Garman-Klass法比标准差法效率高得多。理论上,它的估计方差只有标准差法的1/4左右。也就是说,用同样的数据量,它能给出更精确的估计。
适用场景:
- 有完整的OHLC数据
- 需要高精度波动率估计
- 做波动率衍生品定价
4. Yang-Zhang法:处理跳空的高手
Yang-Zhang法是目前公认最稳健的波动率估计方法之一。它把波动率分解成三部分:隔夜波动(开盘跳空)、日内波动(最高最低)、收盘波动(收盘相对开盘)。
def yang_zhang_volatility(open, high, low, close):
n = len(open)
# 隔夜波动
overnight = np.log(open[1:] / close[:-1])
overnight_var = np.var(overnight, ddof=1)
# 日内波动(用Parkinson)
intraday = np.log(high / low)
intraday_var = np.mean(intraday ** 2) / (4 * np.log(2))
# 收盘波动
close_to_open = np.log(close / open)
close_var = np.var(close_to_open, ddof=1)
# 加权组合
k = 0.34 / (1.34 + (n + 1) / (n - 1))
variance = overnight_var + k * intraday_var + (1 - k) * close_var
return np.sqrt(variance) * np.sqrt(252)
为什么说它稳健?因为它把跳空单独拎出来处理了。你想想看,债券市场经常有隔夜跳空——央行突然降息、经济数据超预期,第二天开盘直接跳。这时候标准差法和Parkinson法都会失真,但Yang-Zhang法能扛住。
注意:Yang-Zhang法虽然好,但计算稍微复杂一点。而且它需要足够多的样本量(至少20个交易日),不然估计结果不稳定。我一般至少用60个交易日的数据。
适用场景:
- 市场有显著跳空(债券、外汇)
- 需要最准确的波动率估计
- 做波动率预测模型的特征工程
5. 四种方法对比
我把这四种方法的核心差异整理成了一张表,方便你对照:
| 方法 | 所需数据 | 跳空处理 | 估计效率 | 我最常用的场景 |
|---|---|---|---|---|
| 标准差法 | 收盘价 | 忽略 | 低 | 快速筛查、长期趋势 |
| Parkinson法 | 最高、最低价 | 忽略 | 中 | 利率互换、只有OHLC数据 |
| Garman-Klass法 | OHLC | 部分处理 | 高 | 国债期货、波动率套利 |
| Yang-Zhang法 | OHLC | 完全处理 | 最高 | 信用债、有跳空的市场 |
6. 知识体系总览
下面这张图,帮你理清这四种方法的关系和选择逻辑:
7. 实战中的选择建议
说了这么多,到底该用哪个?我个人的经验是:
- 做回测时:用Garman-Klass法。它效率高,对大多数固收品种都适用。
- 做实盘监控时:用Yang-Zhang法。虽然计算慢一点,但准确度最高,能帮你及时发现波动率突变。
- 数据有限时:用标准差法。别嫌弃它简单,总比没有强。
- 做跨品种比较时:统一用一种方法,别混着用。我习惯用Garman-Klass,因为它对数据要求适中,结果也稳定。
一个小建议:不管你用哪种方法,都建议同时算一个“滚动窗口”的波动率。比如用20天、60天、120天的窗口分别算。这样你能看到短期和长期的波动率变化趋势,对策略调整很有帮助。
好了,波动率度量这块就聊到这儿。记住,没有最好的方法,只有最合适的方法。关键是你得理解每种方法的假设和局限,然后根据你的数据和场景去选。下次咱们聊聊怎么把这些波动率用到实际策略里去。