波动率度量方法:从标准差到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. 知识体系总览

下面这张图,帮你理清这四种方法的关系和选择逻辑:

波动率度量方法选择框架 波动率度量 简单方法 高级方法 标准差法 Parkinson法 Garman-Klass法 Yang-Zhang法 选择条件:数据质量 + 市场特征 只有收盘价 → 标准差法 有OHLC + 无跳空 → Parkinson / Garman-Klass 有OHLC + 有跳空 → Yang-Zhang

7. 实战中的选择建议

说了这么多,到底该用哪个?我个人的经验是:

  1. 做回测时:用Garman-Klass法。它效率高,对大多数固收品种都适用。
  2. 做实盘监控时:用Yang-Zhang法。虽然计算慢一点,但准确度最高,能帮你及时发现波动率突变。
  3. 数据有限时:用标准差法。别嫌弃它简单,总比没有强。
  4. 做跨品种比较时:统一用一种方法,别混着用。我习惯用Garman-Klass,因为它对数据要求适中,结果也稳定。

一个小建议:不管你用哪种方法,都建议同时算一个“滚动窗口”的波动率。比如用20天、60天、120天的窗口分别算。这样你能看到短期和长期的波动率变化趋势,对策略调整很有帮助。

好了,波动率度量这块就聊到这儿。记住,没有最好的方法,只有最合适的方法。关键是你得理解每种方法的假设和局限,然后根据你的数据和场景去选。下次咱们聊聊怎么把这些波动率用到实际策略里去。

专注资料整理