🪙金融波动率建模:GARCH模型实战

"""
金融波动率建模:GARCH模型实战
使用 Python 的 arch 库进行波动率建模
目标:对股票收益率序列建模,预测未来波动率
"""
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from datetime import datetime, timedelta
import warnings
warnings.filterwarnings('ignore')

# 1. 安装必要库(如果未安装)
# pip install arch yfinance

import yfinance as yf
from arch import arch_model
from arch.univariate import ConstantMean, GARCH, EGARCH, FIGARCH
import seaborn as sns

# 2. 获取金融数据(以苹果股票为例)
def get_stock_data(symbol='AAPL', period='2y'):
    """获取股票数据并计算收益率"""
    stock = yf.download(symbol, period=period)
    # 计算对数收益率
    stock['log_return'] = 100 * np.log(stock['Close'] / stock['Close'].shift(1))
    # 去除缺失值
    returns = stock['log_return'].dropna()
    return returns, stock

print("获取苹果股票数据...")
returns, stock_data = get_stock_data('AAPL', period='2y')
print(f"数据长度: {len(returns)}")
print(f"收益率统计:\n{returns.describe()}")

# 3. 数据可视化
fig, axes = plt.subplots(2, 1, figsize=(14, 10))

# 价格和收益率
axes[0].plot(stock_data.index, stock_data['Close'], label='收盘价', color='blue')
axes[0].set_title('苹果股票价格 (AAPL)')
axes[0].set_ylabel('价格 (USD)')
axes[0].grid(True, alpha=0.3)

axes[1].bar(returns.index, returns.values, alpha=0.6, width=1, label='日收益率', color='orange')
axes[1].set_title('日对数收益率 (%)')
axes[1].set_ylabel('收益率 (%)')
axes[1].grid(True, alpha=0.3)
axes[1].axhline(y=0, color='red', linestyle='--', alpha=0.5)

plt.tight_layout()
plt.show()

# 4. 检查波动率聚集性(ARCH 效应)
# 计算收益率的平方(波动率代理)
returns_squared = returns ** 2

plt.figure(figsize=(14, 5))
plt.plot(returns_squared.index, returns_squared.values, label='收益率平方', color='purple', alpha=0.7)
plt.title('收益率平方序列(显示波动率聚集性)')
plt.ylabel('收益率^2')
plt.grid(True, alpha=0.3)
plt.show()

# 5. 拟合 GARCH(1,1) 模型
print("\n拟合 GARCH(1,1) 模型...")

# 方法1: 使用 arch_model 的高级接口
garch_model = arch_model(returns, vol='Garch', p=1, o=0, q=1, dist='Normal')
garch_fitted = garch_model.fit(update_freq=0, disp='off')

print("GARCH(1,1) 模型参数估计:")
print(garch_fitted.summary())

# 提取条件波动率(标准差)
volatility = garch_fitted.conditional_volatility

# 6. 拟合 EGARCH(1,1) 模型(考虑杠杆效应)
print("\n拟合 EGARCH(1,1) 模型...")
egarch_model = arch_model(returns, vol='EGARCH', p=1, o=1, q=1, dist='Normal')
egarch_fitted = egarch_model.fit(update_freq=0, disp='off')

print("EGARCH(1,1) 模型参数估计:")
print(egarch_fitted.summary())

egarch_volatility = egarch_fitted.conditional_volatility

# 7. 预测未来波动率
print("\n预测未来5天波动率...")
# GARCH 模型预测
garch_forecast = garch_fitted.forecast(horizon=5)
garch_forecast_var = garch_forecast.variance.iloc[-1].values
garch_forecast_vol = np.sqrt(garch_forecast_var)  # 转换为波动率

# EGARCH 模型预测
egarch_forecast = egarch_fitted.forecast(horizon=5)
egarch_forecast_var = egarch_forecast.variance.iloc[-1].values
egarch_forecast_vol = np.sqrt(egarch_forecast_var)

print("GARCH(1,1) 预测波动率 (%):", garch_forecast_vol.round(3))
print("EGARCH(1,1) 预测波动率 (%):", egarch_forecast_vol.round(3))

# 8. 可视化结果
fig, axes = plt.subplots(2, 1, figsize=(14, 12))

# 原始收益率与 GARCH 波动率
axes[0].plot(returns.index, np.abs(returns.values), label='绝对收益率', color='lightblue', alpha=0.6)
axes[0].plot(volatility.index, volatility, label='GARCH(1,1) 波动率', color='red', linewidth=2)
axes[0].plot(egarch_volatility.index, egarch_volatility, label='EGARCH(1,1) 波动率', color='green', linewidth=2)
axes[0].set_title('收益率与条件波动率对比')
axes[0].set_ylabel('波动率')
axes[0].legend()
axes[0].grid(True, alpha=0.3)

# 滚动波动率对比
rolling_vol_20 = returns.rolling(window=20).std() * np.sqrt(252) * 100  # 年化滚动波动率
axes[1].plot(rolling_vol_20.index, rolling_vol_20.values, label='20日滚动波动率 (年化)', color='gray', linestyle='--')
axes[1].plot(volatility.index, volatility * np.sqrt(252), label='GARCH(1,1) 年化波动率', color='red')
axes[1].plot(egarch_volatility.index, egarch_volatility * np.sqrt(252), label='EGARCH(1,1) 年化波动率', color='green')
axes[1].set_title('年化波动率对比')
axes[1].set_ylabel('年化波动率 (%)')
axes[1].set_xlabel('日期')
axes[1].legend()
axes[1].grid(True, alpha=0.3)

plt.tight_layout()
plt.show()

# 9. 模型诊断:残差分析
residuals = garch_fitted.resid
std_resid = residuals / garch_fitted.conditional_volatility

fig, axes = plt.subplots(2, 2, figsize=(14, 10))

# 残差图
axes[0, 0].plot(std_resid.index, std_resid.values, label='标准化残差', color='blue')
axes[0, 0].set_title('标准化残差')
axes[0, 0].axhline(y=0, color='red', linestyle='--')
axes[0, 0].grid(True, alpha=0.3)

# 残差ACF
from statsmodels.tsa.stattools import acf
from statsmodels.graphics.tsaplots import plot_acf
plot_acf(std_resid, ax=axes[0, 1], lags=20, title='标准化残差 ACF')
axes[0, 1].grid(True, alpha=0.3)

# 残差平方ACF (检验ARCH效应是否消除)
plot_acf(std_resid**2, ax=axes[1, 0], lags=20, title='标准化残差平方 ACF')
axes[1, 0].grid(True, alpha=0.3)

# 残差分布直方图
sns.histplot(std_resid.dropna(), kde=True, ax=axes[1, 1])
axes[1, 1].set_title('标准化残差分布')
axes[1, 1].grid(True, alpha=0.3)

plt.tight_layout()
plt.show()

# 10. VaR 计算(Value at Risk)
confidence_level = 0.05  # 95% 置信水平
print(f"\n计算 {int((1-confidence_level)*100)}% VaR...")

# 基于正态分布假设
var_normal = garch_forecast_vol * norm.ppf(confidence_level)
print(f"GARCH VaR (正态分布, 未来5天, %): {var_normal.round(3)}")

# 基于历史模拟
historical_var = returns.quantile(confidence_level)
print(f"历史VaR (样本分位数, %): {historical_var:.3f}")

# 11. 模型比较
print("\n模型比较:")
models = {
    'GARCH(1,1)': garch_fitted,
    'EGARCH(1,1)': egarch_fitted
}

comparison_data = []
for name, model in models.items():
    aic = model.aic
    bic = model.bic
    log_likelihood = model.loglikelihood
    comparison_data.append({
        'Model': name,
        'AIC': aic,
        'BIC': bic,
        'Log-Likelihood': log_likelihood
    })

comparison_df = pd.DataFrame(comparison_data)
print(comparison_df)

# 12. 模型解释与应用
print("\n=== 模型解释 ===")
print("1. GARCH(1,1) 参数:")
print(f"   - Omega (常数项): {garch_fitted.params['omega']:.6f}")
print(f"   - Alpha (ARCH项): {garch_fitted.params['alpha[1]']:.4f}")
print(f"   - Beta (GARCH项): {garch_fitted.params['beta[1]']:.4f}")
print(f"   - Alpha + Beta = {garch_fitted.params['alpha[1]'] + garch_fitted.params['beta[1]']:.4f} (接近1表示高持久性)")

print("\n2. 模型应用:")
print("   - 期权定价 (如 Black-Scholes 模型需要波动率输入)")
print("   - 风险管理 (如 VaR 计算)")
print("   - 资产配置 (基于波动率调整权重)")
print("   - 高频交易 (预测短期波动率)")

print(f"\n3. 预测摘要:")
print(f"   - GARCH 预测未来5天平均波动率: {np.mean(garch_forecast_vol):.3f}%")
print(f"   - EGARCH 预测未来5天平均波动率: {np.mean(egarch_forecast_vol):.3f}%")
print(f"   - 历史平均波动率: {returns.std() * 100:.3f}%")

代码说明:

  1. 数据获取: 使用 yfinance 获取苹果股票数据,并计算对数收益率。
  2. 数据探索: 可视化价格和收益率,展示波动率聚集性(大波动后往往跟着大波动)。
  3. GARCH 模型: 拟合经典的 GARCH(1,1) 模型,这是金融领域最常用的波动率模型。
  4. EGARCH 模型: 拟合 EGARCH(1,1) 模型,考虑杠杆效应(负收益对波动率的影响可能更大)。
  5. 预测: 使用拟合好的模型预测未来几天的波动率。
  6. 可视化: 对比 GARCH/EGARCH 波动率与滚动波动率,展示模型拟合效果。
  7. 模型诊断: 检查标准化残差是否符合模型假设(白噪声、正态分布)。
  8. VaR 计算: 基于 GARCH 模型预测的波动率计算风险价值(Value at Risk)。
  9. 模型比较: 使用 AIC/BIC 等信息准则比较不同模型的优劣。
  10. 应用解释: 说明 GARCH 模型在金融实践中的具体用途。

扩展建议:

  • 其他模型: 尝试 FIGARCH、HAR-RV、Realized GARCH 等。
  • 协变量: 在均值方程或波动率方程中加入宏观经济指标。
  • 多元 GARCH: 对多个资产建模,考虑相关性(如 DCC-GARCH)。
  • 高频数据: 使用分钟级或秒级数据建模已实现波动率(Realized Volatility)。
  • 风险指标: 计算 CVaR、预期短缺 (Expected Shortfall) 等更高级风险指标。

添加新评论