第三节 波动率计算与建模:从历史数据到预测模型

波动率这东西,说白了就是市场的心跳。做商品波动率交易,你首先得知道怎么测量这个心跳,然后才能谈得上交易。今天我就把HV的计算方法、IV的提取方式,还有预测模型这块,掰开了揉碎了讲清楚。

核心要点:波动率计算不是简单的数学题,它直接决定了你的交易信号是否可靠。我见过太多人用错了参数,结果策略回测漂亮,实盘一塌糊涂。

3.1 历史波动率(HV)的计算方法

历史波动率,就是看过去价格波动得有多剧烈。计算方式有好几种,我一个个说。

3.1.1 简单标准差法

这是最基础的方法。取过去N天的收益率,算标准差,再年化。公式长这样:

# 简单标准差计算HV
import numpy as np
import pandas as pd

def calculate_hv_simple(price_series, window=20, trading_days=252):
    # 计算对数收益率
    log_returns = np.log(price_series / price_series.shift(1))
    # 滚动标准差
    rolling_std = log_returns.rolling(window=window).std()
    # 年化
    hv = rolling_std * np.sqrt(trading_days)
    return hv

# 举个例子
prices = pd.Series([100, 102, 101, 103, 105, 104, 106])
hv = calculate_hv_simple(prices)
print(f"年化HV: {hv.iloc[-1]:.4f}")

嗯,这里要注意:窗口期选多少?我个人习惯用20个交易日,对应一个月。但如果你做短线,5天也行。长线的话,60天更稳。

我的经验:窗口期太短,波动率会跳来跳去,信号太多假突破。窗口期太长,反应太慢,等你进场行情都走完了。20天是个不错的折中。

3.1.2 EWMA(指数加权移动平均)

简单标准差有个问题:它给每一天的权重都一样。但你想啊,昨天的波动肯定比30天前的波动更有参考价值。EWMA就是解决这个问题的。

def calculate_hv_ewma(price_series, lambda_param=0.94, trading_days=252):
    log_returns = np.log(price_series / price_series.shift(1))
    # EWMA方差
    variance = log_returns.ewm(alpha=1-lambda_param).var()
    hv = np.sqrt(variance) * np.sqrt(trading_days)
    return hv

# lambda=0.94是RiskMetrics的经典参数
hv_ewma = calculate_hv_ewma(prices)
print(f"EWMA年化HV: {hv_ewma.iloc[-1]:.4f}")

lambda取0.94,这是摩根大通当年做风险管理时用的参数。我试过很多组合,说实话0.94确实好用,但也不是万能。如果你做的是农产品,波动率变化快,可以试试0.92。

避坑指南:我曾经在玉米期货上用EWMA,lambda设了0.99,结果波动率几乎不动,完全没捕捉到一次天气炒作行情。EWMA对lambda很敏感,一定要根据品种特性调参。

3.1.3 GARCH模型

GARCH(广义自回归条件异方差模型)是更高级的玩法。它假设波动率不是常数,而是有聚集效应的——大波动后面跟着大波动,小波动后面跟着小波动。

from arch import arch_model

def calculate_hv_garch(price_series, p=1, q=1):
    log_returns = np.log(price_series / price_series.shift(1)).dropna()
    # 拟合GARCH(1,1)
    model = arch_model(log_returns * 100, vol='Garch', p=p, q=q)
    result = model.fit(disp='off')
    # 获取条件波动率
    conditional_vol = result.conditional_volatility / 100
    hv = conditional_vol * np.sqrt(252)
    return hv

# GARCH(1,1)是最常用的
hv_garch = calculate_hv_garch(prices)
print(f"GARCH年化HV: {hv_garch.iloc[-1]:.4f}")

GARCH(1,1)为什么最常用?说白了就是简单有效。p=1表示用上一期的方差,q=1表示用上一期的残差。这两个参数组合起来,就能很好地描述波动率的聚集效应。

三种方法对比:

方法 优点 缺点 适用场景
简单标准差 计算快,容易理解 对异常值敏感 快速估算
EWMA 反应灵敏,权重合理 需要调lambda 中短期交易
GARCH 捕捉波动聚集效应 计算复杂,参数多 量化研究

3.2 隐含波动率(IV)的提取方法

IV和HV不一样。HV是回头看,IV是向前看——它是市场参与者对未来波动率的预期,藏在期权价格里。

提取IV,说白了就是解方程。期权定价公式(比如Black-Scholes)里,除了波动率,其他参数都是已知的。把市场价格代入,反解出波动率就行。

from scipy.optimize import brentq
import numpy as np

def implied_volatility(option_price, S, K, T, r, option_type='call'):
    """
    用二分法反解隐含波动率
    """
    def bs_price(sigma):
        d1 = (np.log(S/K) + (r + 0.5*sigma**2)*T) / (sigma*np.sqrt(T))
        d2 = d1 - sigma*np.sqrt(T)
        if option_type == 'call':
            price = S*norm.cdf(d1) - K*np.exp(-r*T)*norm.cdf(d2)
        else:
            price = K*np.exp(-r*T)*norm.cdf(-d2) - S*norm.cdf(-d1)
        return price - option_price
    
    try:
        iv = brentq(bs_price, 0.01, 5.0)
        return iv
    except:
        return np.nan

# 举个例子:某商品期权市价2.5,标的价格100,行权价105,剩余30天,利率3%
iv = implied_volatility(2.5, 100, 105, 30/365, 0.03)
print(f"隐含波动率: {iv:.4f} ({iv*100:.2f}%)")

这里有个坑:不同行权价、不同到期日的期权,算出来的IV不一样。这就形成了波动率微笑或偏斜。我建议你取平值期权的IV作为基准,或者用VIX那种方法,把多个IV加权平均。

我的习惯:提取IV时,我会同时看近月和远月合约。近月IV反映短期情绪,远月IV反映长期预期。两者差值大了,往往意味着市场在酝酿大行情。

3.3 波动率预测模型

预测波动率,是波动率交易的核心。你不能光看过去,得猜未来。常用的预测模型有这么几种:

3.3.1 简单回归模型

用历史波动率去预测未来波动率。比如:

# 用过去20天的HV预测未来5天的HV
def predict_hv_simple(hv_series, lookback=20, forecast_horizon=5):
    # 简单移动平均预测
    predicted = hv_series.rolling(window=lookback).mean().shift(1)
    return predicted

这个方法简单,但精度有限。说白了就是假设历史会重演,但市场往往不按套路出牌。

3.3.2 GARCH预测

GARCH模型不仅能算历史波动率,还能做预测。拟合好模型后,直接调用预测函数:

def predict_hv_garch(price_series, steps=5):
    log_returns = np.log(price_series / price_series.shift(1)).dropna()
    model = arch_model(log_returns * 100, vol='Garch', p=1, q=1)
    result = model.fit(disp='off')
    # 预测未来steps天的波动率
    forecasts = result.forecast(horizon=steps)
    predicted_vol = np.sqrt(forecasts.variance.iloc[-1] / 10000) * np.sqrt(252)
    return predicted_vol.values

GARCH预测有个特点:它会向长期均值回归。如果当前波动率很高,预测值会逐渐下降;如果很低,会逐渐上升。这个特性在交易中很有用。

3.3.3 隐含波动率预测

有些研究表明,IV比HV更能预测未来波动率。毕竟IV是市场真金白银交易出来的预期。

def predict_with_iv(iv_series, hv_series):
    # 简单加权:IV占70%,HV占30%
    predicted = 0.7 * iv_series + 0.3 * hv_series
    return predicted

我个人更倾向于把IV和HV结合起来。IV反映市场情绪,HV反映历史规律,两者互补。

曾经踩过的坑:有一年我做原油波动率交易,完全依赖GARCH预测。结果中东局势突变,波动率瞬间翻倍,GARCH模型根本来不及反应。后来我加了IV作为预警指标,情况好多了。

3.4 知识体系总览

说了这么多,我画张图帮你理清思路:

波动率计算与建模知识体系 波动率 历史波动率 (HV) 简单标准差 EWMA GARCH 隐含波动率 (IV) BS反解 波动率微笑 期限结构 波动率预测 回归模型 GARCH预测 IV预测 三种方法各有优劣,实际交易中建议组合使用 实战应用建议 • 短线交易:EWMA + IV 组合 • 中长线交易:GARCH + 简单标准差

你看,波动率计算和建模,说白了就是三个步骤:算历史、提隐含、做预测。每一步都有多种方法,没有绝对的好坏,关键看你的交易周期和品种特性。

最后说一句:别迷信模型。再好的模型也只是工具,市场永远比模型复杂。我见过太多人把GARCH当圣杯,结果亏得底朝天。波动率交易的核心,是理解波动率为什么会变,而不是怎么算它。

专注资料整理