3、波动率预测模型:GARCH模型、EWMA模型、波动率锥的构建与应用

做利率债做市,最怕什么?不是方向看错,而是波动率突然放大,你手里的头寸像坐过山车一样。我做了这么多年交易,有个深刻的体会:预测波动率,比预测方向更重要。方向错了可以止损,波动率没算对,仓位管理和对冲全都会乱套。

这一章,我们就来聊聊怎么预测波动率。我会重点讲三个工具:GARCH模型、EWMA模型,还有波动率锥。这三个东西,说白了就是帮你回答一个问题——“明天市场会动多大?”

核心逻辑:波动率预测不是算命,而是用历史数据去推断未来的“震荡幅度”。做市商靠的是双边报价赚差价,波动率一旦超出预期,你的报价可能被瞬间吃掉,或者你根本报不出有竞争力的价格。

波动率预测模型 GARCH模型 EWMA模型 波动率锥 ARCH效应检验 参数估计 衰减因子λ 多周期对比 分位数分析 应用:做市报价调整 · 仓位管理 · 对冲策略 · 压力测试

3.1 GARCH模型:捕捉波动率的“记忆效应”

GARCH模型,全称是广义自回归条件异方差模型。名字听着吓人,其实核心思想很简单:今天的波动率,跟昨天的波动率有关,也跟昨天的“意外”有关

我刚开始用GARCH的时候,总觉得它太学术。后来在实盘里跑了一次,发现它确实能抓到一些规律——比如市场大跌之后,波动率往往会持续高企一段时间。这就是所谓的“波动率聚集”现象。

3.1.1 模型公式

标准的GARCH(1,1)模型长这样:

σ²(t) = ω + α * ε²(t-1) + β * σ²(t-1)

其中:

  • σ²(t):今天的条件方差(波动率的平方)
  • ω:长期平均方差(常数项)
  • ε²(t-1):昨天的“冲击”或“残差”平方
  • σ²(t-1):昨天的条件方差
  • α + β < 1:平稳性条件,保证波动率不会发散

说白了,这个模型就是在说:今天的波动率 = 长期均值 + 昨天冲击的影响 + 昨天波动率的影响

我的经验:α和β的取值很有意思。α越大,说明市场对新鲜冲击反应越剧烈;β越大,说明波动率的“记忆”越长。我在国债期货上跑出来的参数,α通常在0.05-0.1之间,β在0.85-0.95之间。这意味着利率债的波动率有很强的持续性,一次冲击的影响会持续好几天。

3.1.2 Python实现

用Python实现GARCH模型,我推荐用arch库。下面是一个完整的示例:

import numpy as np
import pandas as pd
from arch import arch_model
import matplotlib.pyplot as plt

# 假设我们有一列收益率数据
# returns = pd.Series(...)

# 拟合GARCH(1,1)模型
model = arch_model(returns, vol='Garch', p=1, q=1)
result = model.fit(disp='off')

# 查看参数
print(result.params)

# 预测未来5天的波动率
forecast = result.forecast(horizon=5)
predicted_vol = np.sqrt(forecast.variance.values[-1, :])

# 可视化
plt.plot(np.sqrt(result.conditional_volatility), label='条件波动率')
plt.plot(predicted_vol, label='预测波动率', linestyle='--')
plt.legend()
plt.show()

注意:GARCH模型对数据频率很敏感。我建议用日频数据,不要用分钟级数据去拟合,否则参数估计会很不稳定。另外,记得先做ARCH效应检验——如果数据本身没有波动率聚集现象,用GARCH就是白费力气。

3.2 EWMA模型:简单粗暴但有效

EWMA,指数加权移动平均。这个模型比GARCH简单得多,但我在实盘里用得反而更多。为什么?因为它计算快、参数少、不容易过拟合

EWMA的核心思想是:越近的数据,权重越大;越远的数据,权重指数衰减

3.2.1 公式与实现

σ²(t) = λ * σ²(t-1) + (1 - λ) * r²(t-1)

其中:

  • λ:衰减因子,通常取0.94(日频数据)或0.97(周频数据)
  • r²(t-1):昨天的收益率平方

你看,这个公式比GARCH少了一个参数。我个人的习惯是,做市报价的波动率调整用EWMA,因为快;做风险管理的压力测试用GARCH,因为准

避坑指南:我曾经在2017年用EWMA做国债期货的波动率预测,λ设成了0.99。结果市场突然波动,模型反应慢了两天,差点出大问题。后来我改成0.94,虽然短期波动大了点,但至少能跟上市场节奏。记住:做市交易,宁可反应过度,不要反应迟钝

3.2.2 代码示例

def ewma_vol(returns, lambda_=0.94):
    """
    计算EWMA波动率
    """
    vol = np.zeros_like(returns)
    vol[0] = np.var(returns[:20])  # 初始值用前20天方差
    
    for i in range(1, len(returns)):
        vol[i] = lambda_ * vol[i-1] + (1 - lambda_) * returns[i-1]**2
    
    return np.sqrt(vol)

# 使用
vol_series = ewma_vol(returns, lambda_=0.94)

3.3 波动率锥:多周期视角下的“正常范围”

波动率锥,是我个人最喜欢的工具。它不预测具体的波动率数值,而是告诉你:在当前市场环境下,不同持有期的波动率处于什么历史分位

你想想看,做市交易最怕什么?不是波动率大,而是波动率超出预期。波动率锥就是帮你建立这个“预期”的。

3.3.1 构建方法

构建波动率锥的步骤很简单:

  1. 计算不同持有期(1天、5天、20天、60天等)的历史波动率
  2. 对每个持有期,计算波动率的分位数(10%、25%、50%、75%、90%)
  3. 把这些分位数连成线,就形成了“锥”的形状
持有期 10%分位 25%分位 50%分位 75%分位 90%分位
1天 0.12% 0.18% 0.25% 0.35% 0.48%
5天 0.28% 0.38% 0.52% 0.68% 0.85%
20天 0.55% 0.72% 0.90% 1.10% 1.35%
60天 0.80% 1.00% 1.25% 1.55% 1.90%

怎么用?假设当前1天期波动率是0.30%,落在50%-75%分位之间。这说明市场处于正常偏高的状态。但如果1天期波动率突然跳到0.50%,超过了90%分位——嗯,这时候你要小心了,市场可能进入了异常状态。我一般会在这个时候收紧报价价差,或者降低持仓规模。

3.3.2 Python实现

def volatility_cone(returns, periods=[1, 5, 20, 60], quantiles=[0.1, 0.25, 0.5, 0.75, 0.9]):
    """
    构建波动率锥
    """
    cone = {}
    for period in periods:
        # 计算滚动波动率
        rolling_vol = returns.rolling(period).std() * np.sqrt(252/period)
        # 计算分位数
        cone[period] = rolling_vol.quantile(quantiles).values
    
    return pd.DataFrame(cone, index=quantiles)

# 使用
cone_df = volatility_cone(returns)
print(cone_df)

3.4 三个模型的对比与选择

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

  • 做市报价调整:用EWMA。快,参数少,适合高频调整。
  • 风险管理:用GARCH。准,能捕捉波动率的动态特征。
  • 情景分析:用波动率锥。直观,告诉你当前处于什么历史位置。

我的实战组合:每天早上开盘前,我会先看波动率锥,判断市场处于什么状态。然后用EWMA计算一个实时波动率,用于调整报价价差。最后用GARCH做一个未来5天的预测,用于决定今天的仓位规模。三个模型各司其职,配合起来效果很好。

嗯,这一章的内容就到这里。波动率预测不是万能的,但没有波动率预测是万万不能的。尤其是在利率债做市这种高频、低利差的环境里,算准波动率,就等于算准了利润


专注资料整理