3. Python环境准备与数据获取:安装arch库、获取股票/指数收益率数据、数据预处理与可视化
好,咱们正式开始动手了。这一章我带你搭好环境、拿到数据、做预处理,最后画几张图看看收益率长什么样。说白了,这是整个GARCH建模的“地基”。地基不稳,后面再漂亮的模型也是白搭。
3.1 环境准备:安装arch库
做波动率建模,Python里最顺手的库就是arch。我个人习惯用pip安装,一行命令搞定:
pip install arch
如果你用的是Anaconda环境,也可以:
conda install -c conda-forge arch
嗯,这里要注意。arch库依赖numpy、pandas、scipy这些基础库。如果你之前没装过,建议先更新一下:
pip install --upgrade numpy pandas scipy matplotlib
小提示: 我在项目中遇到过因为numpy版本太老导致arch报错的情况。建议用
pip list | grep numpy 检查一下版本,至少1.20以上。
3.2 获取股票/指数收益率数据
数据源我推荐用yfinance,免费、稳定、覆盖全球主要市场。先装一下:
pip install yfinance
然后我们拿沪深300指数(代码 000300.SS)来演示。为什么选它?因为A股市场波动率聚集效应特别明显——你想想看,牛市的时候天天涨,熊市的时候连续暴跌,这种“扎堆”现象正是GARCH要捕捉的。
import yfinance as yf
import pandas as pd
import numpy as np
# 下载沪深300指数数据
ticker = "000300.SS"
data = yf.download(ticker, start="2015-01-01", end="2023-12-31")
# 只看收盘价
close = data['Close']
# 计算对数收益率
returns = np.log(close / close.shift(1))
# 删除缺失值
returns = returns.dropna()
print(returns.head())
print(f"样本量: {len(returns)}")
避坑指南: 我曾经直接用简单收益率(
(close - close.shift(1)) / close.shift(1))做GARCH,结果模型收敛性很差。后来换成对数收益率,效果立竿见影。原因是对数收益率在时间上可加,且近似正态分布,更符合GARCH的假设。
3.3 数据预处理:清洗与检查
拿到收益率数据后,别急着建模。先做三件事:
- 检查缺失值——停牌、节假日会导致数据空洞
- 检查异常值——比如某天突然涨跌停,可能是数据错误
- 检查平稳性——GARCH要求收益率序列是平稳的
代码实现:
# 1. 缺失值检查
print(f"缺失值数量: {returns.isnull().sum()}")
# 2. 异常值检查(用3倍标准差法)
mean = returns.mean()
std = returns.std()
outliers = returns[(returns > mean + 3*std) | (returns < mean - 3*std)]
print(f"异常值数量: {len(outliers)}")
# 3. 平稳性检验(ADF检验)
from statsmodels.tsa.stattools import adfuller
result = adfuller(returns)
print(f"ADF统计量: {result[0]:.4f}")
print(f"p值: {result[1]:.4f}")
if result[1] < 0.05:
print("序列平稳,可以继续")
else:
print("序列不平稳,需要差分处理")
核心要点: 我做了上百次GARCH建模,总结出一条铁律——数据预处理花的时间,至少占整个项目的一半。很多同学上来就调参,结果模型不收敛,回头一看,原来是数据里有几个异常值在捣乱。
3.4 可视化:看波动率聚集效应
数据准备好了,画图看看。波动率聚集效应说白了就是:大的波动后面跟着大的波动,小的波动后面跟着小的波动。用图说话:
import matplotlib.pyplot as plt
fig, axes = plt.subplots(2, 1, figsize=(12, 8))
# 上图:收盘价走势
axes[0].plot(close.index, close.values, color='#2E86AB', linewidth=0.8)
axes[0].set_title('沪深300指数收盘价 (2015-2023)', fontsize=14)
axes[0].set_ylabel('价格')
axes[0].grid(True, alpha=0.3)
# 下图:收益率序列
axes[1].plot(returns.index, returns.values, color='#A23B72', linewidth=0.6)
axes[1].set_title('沪深300指数日收益率', fontsize=14)
axes[1].set_ylabel('收益率')
axes[1].set_xlabel('日期')
axes[1].grid(True, alpha=0.3)
plt.tight_layout()
plt.show()
你仔细看收益率图。2015年股灾那会儿,收益率上下乱跳,波动幅度特别大。到了2017年慢牛行情,收益率就变得很“温顺”。这就是典型的波动率聚集——高波动时期和低波动时期会扎堆出现。
3.5 本章知识体系
下面这张图帮你理清本章的核心逻辑:
我的经验: 刚开始做GARCH的时候,我总想跳过数据预处理这一步,觉得“差不多就行了”。结果模型跑出来,参数估计的p值全都不显著。后来老老实实把异常值剔除、缺失值填充,模型一下子就收敛了。所以——别偷懒,预处理做扎实了,后面事半功倍。
好了,环境搭好了,数据也拿到手了。下一章咱们正式进入GARCH模型的世界,看看怎么用arch库拟合一个最简单的GARCH(1,1)模型。