单页 HTML 版:保留原报告正文、关键数据、表格、模型说明、危机事件、代码片段与参考来源说明;排版按手机端优先优化。
本文以“若未特别指定,则采用 1990 年至今”为默认样本窗口,对 VIX 与标普500之间的关系做日频实证分析;同时单独讨论 intraday 可得性,但没有把 intraday 作为主估计样本,因为公开、连续、免费且可长期回溯的一致性分钟级历史并不完整。
VIX 的定义来自基于 SPX 期权价格的 30 日前瞻隐含波动率。Cboe 公开提供 1990 年至今的 VIX 历史数据和 2006 年至今的 VVIX 历史数据。标普500方面,本文将 OpenIntro 文档注明源自 Yahoo Finance 的 1950–2018 日频序列,与由 St. Louis Fed/FRED 发布、原始来源为 S&P Dow Jones Indices 的 2016–2026 日频标普500序列拼接;这是因为 FRED 页面说明该官方日频接口受许可限制,仅保留最近 10 年日频历史。
第一,VIX 与标普500不是“长期均衡关系”,而是围绕收益冲击、波动预期和风险厌恶的短期—中期联动关系。在 1990-01-02 至 2026-04-24 的共同交易日样本中,标普500日对数收益与 VIX 日对数变化的当期相关系数约为 -0.714,252 日滚动相关的中位数约为 -0.795,说明这种负相关不是偶发,而是长期稳定、时变但高度持续的事实。
第二,这一关系显著非对称:负收益日对应的 VIX 上升幅度明显大于正收益日对应的 VIX 回落幅度。第三,这一关系存在双向预测性但并非长期协整:收益与 VIX 变化的 VAR(3) Granger 检验在两个方向上都显著,但 log(SPX) 与 log(VIX) 不满足共同 I(1) 前提,因而 VECM 不适用。第四,这一关系在尾部和危机时段更强:t-copula 显示正的上尾依赖,极端股指下跌与极端 VIX 飙升会同步聚集。
对投资者和风险管理者而言,最重要的含义是:VIX 不是简单的“股市反向价格”,而是一个带有凸性、状态依赖和尾部聚集特征的风险价格指标。把它当作“市场下跌的线性镜像”会低估高波动状态下的非线性放大;把它当作“稳定的长期均值回复交易工具”又会忽视危机中持续高位停留与 VVIX 放大的风险。更实际的做法,是把 VIX、VVIX、滚动相关和 DCC 动态相关一起纳入风险监控,而不是只盯一个静态阈值。
本研究的经验设计遵循“定义—拼接—预处理—建模—稳健性—危机复盘”的流程。VIX 采用 Cboe 官方历史收盘序列;VVIX 采用 Cboe 官方历史序列,作为“波动率的波动率”的直接代理。标普500采用两段式拼接:1990–2018 使用 OpenIntro 文档注明来源为 Yahoo Finance 的日频 S&P 500 序列;2016–2026 使用 FRED 中原始来源标注为 S&P Dow Jones Indices 的 SP500 日频收盘序列。
2016–2018 的重叠区在实际拼接中最大绝对差仅约 0.04 个指数点,缝合误差可以忽略。VIX 的方法论层面还要加一个关键注记:Cboe 页面说明,原始 1993 年 VIX 先基于 S&P 100 期权,2003 年更新为基于 S&P 500 期权的新版本方法;Cboe 同时另行提供旧方法的 VXO 历史数据,因此 1990 年以来的 VIX 序列应视为“新版方法的一致化历史”。
预处理步骤如下。首先,把标普500价格变成日对数收益 \(r_t = 100\ln(SPX_t/SPX_{t-1})\);其次,把 VIX 变成日对数变化 \(\Delta \ln VIX_t = 100\ln(VIX_t/VIX_{t-1})\),因为收益率与 VIX 变化是最自然的平稳配对;再次,构造 21 日年化实现波动率 \(RV21\) 与 21 日年化 VIX 变化波动 \(VoV21\),并在 2006 年后用官方 VVIX 做直接替代;最后,用共同交易日交集对齐,避免周末和节假日错位。
之所以把 intraday 放在补充层面,是因为 Cboe 的公开历史页主要提供日频收盘,而 intraday 连续历史更多通过仪表板与数据商渠道提供;现有文献则表明 5 分钟级别的 VIX 对 S&P 500 收益分布具有显著信息含量。
| 数据集 | 提供方 | 频率 | 覆盖期 | 本文用途 | 备注 |
|---|---|---|---|---|---|
| VIX_History.csv | Cboe | 日频收盘 | 1990–至今 | 主 VIX 序列 | 官方历史页直接下载 |
| VVIX_History.csv | Cboe | 日频 | 2006–至今 | 直接 vol-of-vol 代理 | 用于 OLS/分位数回归稳健性 |
| sp500_1950_2018 | Yahoo Finance 来源的 OpenIntro 数据集 | 日频 | 1950–2018 | 1990–2018 的 SPX 主序列 | 文档明示源自 Yahoo Finance |
| SP500 via FRED/Eco3min | FRED,原始来源 S&P Dow Jones | 日频收盘 | 2016–至今 | 2016–2026 的 SPX 扩展与交叉验证 | FRED 页面明示日频只保留最近 10 年 |
| Intraday dashboard/data products | Cboe 等 | 分钟级 | 非统一公开长样本 | 仅概念讨论 | 不纳入主回归样本 |
这套数据设计在可获得性、官方性与可复制性之间做了折中:VIX 与 VVIX 尽量坚持官方 Cboe;标普500则在长样本上采用 Yahoo Finance 来源序列,在最近十年与官方来源重叠验证后向现在延伸。对“若未说明则按 1990 年至今”的规则,本文已按该规则执行,并明确注明了因数据可得性而产生的拼接选择。
在 1990-01-02 至 2026-04-24 的共同样本中,共有 9,141 个交易日。标普500日对数收益的均值约 0.033%、标准差约 1.137%;VIX 日对数变化的均值接近零、标准差约 6.82;VIX 水平的均值约 19.46、标准差约 7.76、样本最大值 82.69;2006 年以后 VVIX 的均值约 93.47。几个分布都明显偏离正态:收益厚尾、VIX 变化右偏厚尾、VIX 水平强右偏;这正是后文使用分位数回归、copula 与 EVT 的原因。
Cboe 官方把 VIX 定义为由 SPX 期权价格提取的 30 日前瞻波动预期,因此它本来就应该对现货市场压力最敏感;Whaley、Giot 以及后续文献之所以把它称为“fear gauge”,正是因为这种同步性在危机中会被放大。
更严格地看,当期相关并不是全部。全样本当期相关 \(Corr(r_t,\Delta \ln VIX_t)\) 约 -0.714。把窗口扩展到 252 日滚动相关,其均值约 -0.759、中位数约 -0.795、5% 分位数约 -0.864、最负值约 -0.897。按波动状态分组,这种负相关会在高波动区进一步加强:当 VIX<20 时约 -0.713,20≤VIX<30 时约 -0.765,VIX≥30 时约 -0.776。
本文估计的 DCC 均值约 -0.766,5% 分位数约 -0.870,95% 分位数约 -0.591。换句话说,VIX 与股指收益的关系不是“有时正有时负”的松散联系,而是几乎永远为负,只是负得有多深的问题。Engle 的 DCC 框架本来就是为这种“相关性本身随时间波动”的资产关系设计的。
先说 VECM。对 level 变量做单位根与协整检查后,结论很清楚:log(SPX) 看起来是 I(1) 过程,而 log(VIX) 在长期样本中更接近均值回复的 I(0) 过程;二者不满足“都为 I(1)”这个进入 VECM 的前提。基于此,本文不把 VECM 当作主框架,而是使用以 \(r_t\) 和 \(\Delta \ln VIX_t\) 为核心的 VAR/Granger 与回归体系。
这一点在经济直觉上也合理:股价水平是带趋势的价格过程,VIX 是对未来一个月条件方差与风险厌恶的高频价格化指标,它们不是天然要在 level 上协同漂移。Bekaert 与 Hoerova 对 VIX 的分解也支持这一点:VIX 平方包含“预期实现方差”和“方差风险溢价”两部分,而不是简单的股票价格镜像。
在 VAR 里,按 BIC 选择的一个简洁设定是 VAR(3)。Granger 检验显示:标普收益 Granger 导致 VIX 变化 的 F 统计量约 4.35,p 值约 0.0045;反过来,VIX 变化 Granger 导致标普收益 的 F 统计量约 4.72,p 值约 0.0027。
这意味着存在统计意义上的双向反馈,但经济含义并不对称:从交叉相关看,真正巨大的效应集中在当期,lag 0 相关约 -0.714;而超前/滞后一天的相关都很小,约在 0.03–0.08 的量级。实务上,这通常应解释为“同一天的风险再定价 + 次日的轻微反身性/均值回复”,而不是某个方向存在很强、很稳定的线性预测优势。
| 模型 | 变量 | 目的 | 本文处理 |
|---|---|---|---|
| 滚动相关 | \(Corr_t(r_{SPX}, \Delta \ln VIX)\) | 查看时变线性联动 | 21/63/126/252 日,重点报告 252 日 |
| 交叉相关 | \(Corr(r_t,\Delta \ln VIX_{t+k})\) | 查看 lead-lag | 报告 \(k=-20,\dots,20\) |
| Granger / VAR | \([r_t,\Delta \ln VIX_t]\) | 判断短期反馈方向 | BIC 选 VAR(3) |
| VECM 可行性检查 | \(\ln SPX_t,\ln VIX_t\) | 判断是否存在 level 协整 | 因 \(\ln VIX\) 更接近 I(0),最终不采用 VECM |
| OLS | \(\Delta \ln VIX_t\) 对收益与 VVIX | 估计线性敏感度 | 2006+ 样本,HAC 标准误 |
| 分位数回归 | \(\Delta \ln VIX_t\) 对收益与 VVIX | 检验高压状态非线性 | 报告 τ=0.1/0.5/0.9 |
| DCC-GARCH | 标普收益与 VIX 变化 | 估计动态条件相关 | 报告均值和分位数 |
| Copula / EVT | \(-r_t\) 与 \(\Delta \ln VIX_t\) | 刻画极端共尾 | 比较 Gaussian 与 t-copula,并估计 GPD |
回归层面,最有解释力的规格是 2006 年以后使用官方 VVIX 的模型:
这个 OLS 的结果是:\(\beta_+ \approx -3.99\)、\(\beta_- \approx 5.07\)、\(\gamma \approx 0.0137\)、\(R^2 \approx 0.548\)。含义很直接:同样 1% 的标普正收益,对 VIX 是明显压低;同样 1% 的标普负收益,对 VIX 的抬升更强,而且方向相反、幅度更大;同时,VVIX 越高,VIX 当日变化越容易向上放大。
把同一模型放到分位数回归里,\(\beta_-\) 会从 τ=0.1 的 2.93 增强到 τ=0.5 的 5.71,再增强到 τ=0.9 的 9.30;而 VVIX 系数在高分位显著转正。这意味着:真正的“VIX 对负收益的弹性”是在高压状态里才被彻底释放出来。
| 指标 | 规格 | 结果 | 解读 |
|---|---|---|---|
| 当期相关 | \(Corr(r_t,\Delta \ln VIX_t)\) | -0.714 | 强烈同步负相关 |
| 252 日滚动相关中位数 | 滚动窗口 | -0.795 | 负相关高度持久 |
| 交叉相关峰值 | \(k=0\) | -0.714 | lead-lag 远弱于同步效应 |
| Granger:\(r \to \Delta \ln VIX\) | VAR(3) | p=0.0045 | 收益能预测短期 VIX 变化 |
| Granger:\(\Delta \ln VIX \to r\) | VAR(3) | p=0.0027 | 但反向也存在弱反馈 |
| 协整可行性 | \(\ln SPX,\ln VIX\) | 不适用 VECM | 因 \(\ln VIX\) 更接近 I(0) |
| OLS:正收益系数 | 2006+,含 VVIX | -3.99 | 上涨压低 VIX |
| OLS:负收益系数 | 2006+,含 VVIX | +5.07 | 下跌抬升 VIX,且更强 |
| OLS:VVIX 系数 | 2006+ | +0.0137 | vol-of-vol 放大 VIX |
| 分位数:负收益系数 | τ=0.1 / 0.5 / 0.9 | 2.93 / 5.71 / 9.30 | 高压分位非线性显著增强 |
| DCC 均值 | DCC-GARCH | -0.766 | 动态相关几乎始终为负 |
| t-copula 尾依赖 | 上尾 | ≈0.105 | 极端下跌与 VIX 飙升共尾 |
| 经验 \(\chi_{0.99}\) | 上尾 | ≈0.339 | 极端压力同步出现的条件概率很高 |
| BDS 检验 | OLS 残差 | p < 1e-30 | 线性模型后仍残留非线性结构 |
最能说明问题的,不是均值,而是尾部。把“市场压力”重写成 \(-r_{SPX}\) 与 \(\Delta \ln VIX\) 的联合分布后,Gaussian copula 估计的相关参数约 0.760;Student-t copula 估计的相关参数约 0.753,自由度约 8.85,并给出上尾依赖系数约 0.105。
用经验 copula 直接看,落在 99% 分位阈值以上的联合极端事件,其条件共尾概率约 0.339。这说明:在普通日子里,VIX 与股指收益可以被相关系数概括;但在真正极端的风险日里,必须用尾依赖而不是均值相关来思考。EVT 的 GPD 拟合也支持厚尾:\(-r_{SPX}\) 的 95% 阈值以上 GPD 形状参数约 0.214,\(\Delta \ln VIX\) 的对应形状参数约 0.183,都显示危机尾部比高斯世界更肥。
因此,把 VIX 仅仅作为“均值回复很强的波动指数”会低估它在尾部状态中的风险价格性质。Bekaert 与 Hoerova 对方差风险溢价的分解,与这里看到的尾部聚集现象在经济解释上是连贯的。
脉冲响应也支持“短而猛”的耦合特征。VAR(3) 的非正交 IRF 显示,标普收益冲击对 \(\Delta \ln VIX\) 的响应主要集中在前 1–3 个交易日,随后迅速衰减;反向从 VIX 冲击到收益的响应更弱、更短。这意味着:收益冲击首先在当日与次日通过风险再定价传导到 VIX,而不是以一个长滞后、平滑扩散的结构传递。对交易和对冲来说,VIX 更像是一个快速反应、但不稳定外推的风险温度计。
危机事件研究方面,本文没有强行选取外部“新闻日”为事件日,而是用样本内危机簇中的局部 VIX 峰值日做中心点,再报告前后 5 个交易日的标普累计对数收益与 VIX 变化。这样做的优点是:事件日与市场压力的内生度一致,避免“新闻发生日”和“价格峰值日”错位。
| 事件中心日 | 描述性标签 | 事件日 VIX | 事件日 SPX 对数收益 | 前5日累计收益 | 后5日累计收益 | [-5,+5] 累计收益 |
|---|---|---|---|---|---|---|
| 1998-08-31 | LTCM/Russia | 44.28 | -7.04% | -12.81% | 6.68% | -6.13% |
| 2001-09-21 | 9/11 aftermath | 42.66 | -1.92% | -12.33% | 7.49% | -4.84% |
| 2008-11-20 | GFC peak | 80.86 | -6.95% | -19.15% | 17.49% | -1.67% |
| 2011-08-08 | US downgrade/Euro crisis | 48.00 | -6.90% | -13.94% | 7.32% | -6.62% |
| 2015-08-24 | China devaluation shock | 40.74 | -4.02% | -10.48% | 4.09% | -6.40% |
| 2018-02-05 | Volmageddon | 37.32 | -4.18% | -7.44% | 0.27% | -7.17% |
| 2020-03-16 | COVID panic | 82.69 | -12.77% | -14.07% | -6.44% | -20.50% |
| 2023-03-13 | Regional bank shock | 26.52 | -0.15% | -4.88% | 2.45% | -2.42% |
| 2025-04-08 | 2025 tariff shock | 52.33 | -1.58% | -12.27% | 7.98% | -4.29% |
危机表有两个非常稳健的经验规律。其一,VIX 的峰值更多是对跌势与不确定性的峰值定价,并不总与最低点完全同日,因此后 5 日收益经常转正,这在 1998、2001、2008、2011、2015 和 2025 都能看到。其二,2020 是个例外:VIX 创下样本最高值 82.69 后,后 5 日收益仍继续为负,说明当不确定性同时伴随真实经济停摆和流动性枯竭时,VIX 高位并不立即意味着可机械抄底。
从投资实践看,本文最重要的结论有三条。第一,VIX 更适合做风险状态变量,而不是简单方向预测器。它与当期股指收益高度负相关,但这种关系是同步和状态依赖的,不意味着“高 VIX 之后必然上涨”。
第二,负收益冲击的 VIX 弹性显著大于正收益冲击的回落弹性,所以把 VIX 当作对冲工具时,真正有价值的是它的凸性,而不是线性 beta。
第三,VVIX 必须和 VIX 联合看:本文回归与尾部分析都表明,当 VVIX 升高时,VIX 本身更容易发生大幅变化;对风险经理来说,这意味着仅盯 VIX 水平而忽略“波动率的波动率”,会低估波动产品与尾部保证金风险。
VIX 低、VVIX 低、相关绝对值较小,市场更接近常态波动。此时 VIX 更多是风险温度计,而不是方向信号。
VIX 高、VVIX 高、相关绝对值迅速加深,上尾共尾概率抬升,风险从一般波动转向系统性应激。
从风险管理看,最实用的框架不是一个阈值,而是一张四宫格:VIX 水平、VVIX 水平、滚动相关、DCC 动态相关。当 VIX 低、VVIX 低、相关绝对值较小,市场更接近“低压—弱耦合”状态;当 VIX 高、VVIX 高、相关绝对值迅速加深,而且上尾共尾概率抬升时,风险已从一般波动转向系统性应激。此时,简单线性 VaR、静态相关矩阵和正态尾部假设都可能低估损失。
局限性也需要明确。本文的主样本是日频,因此没有把分钟级的微观结构、隔夜跳空和开盘集合竞价纳入主回归;intraday 只做可得性和文献层面的说明。其次,标普500长样本采用 Yahoo Finance 来源序列与官方最近十年序列拼接,虽然重叠区误差极小,但拼接本身仍然意味着“不同分发渠道的一致化处理”。再次,回归中的当期收益与当期 VIX 变化是同步关系,不应被过度解释为结构因果。最后,DCC、copula 与 EVT 的具体数值对分布假设、阈值选择和样本窗口敏感,因此这些模型更适合做压力识别和稳健排序,而不适合迷信到小数点后若干位。
如果把这份报告的方法论压缩成一句话,最准确的表述是:VIX 与标普500之间没有一个可用于 VECM 的稳定 level 协整关系,但存在一个极其稳定、显著非对称、时变且在尾部放大的“收益—波动预期—风险厌恶”耦合机制。
Whaley 把 VIX 定义为“investor fear gauge”,是理解 VIX 经济含义的起点。Giot 进一步证明了隐含波动率变化与股指收益之间显著、负向且对下跌敏感的关系。Bekaert 与 Hoerova 则把 VIX 平方分解为条件方差与方差风险溢价,为“为什么 VIX 不只是 realized vol 的预测器”提供了更深的资产定价解释。Engle 的 DCC 模型是本文时变相关部分的标准工具。Tapiero 之类的 intraday 研究则说明,VIX 的信息含量不仅存在于日频,也存在于更高频的收益分布预测里。
| 来源 | 用途 |
|---|---|
| Cboe VIX FAQ / VIX Historical Data / VIX Methodology | VIX 定义、历史数据与方法论 |
| Cboe VVIX 历史数据与相关文档 | VVIX 数据与 vol-of-vol 解释 |
| OpenIntro / Yahoo Finance 来源的 sp500_1950_2018 | 标普500长历史日频序列 |
| FRED / S&P Dow Jones Indices | 最近十年 SP500 官方来源日频序列 |
| Whaley (2000), The Investor Fear Gauge | VIX 作为恐惧指标的经典解释 |
| Giot (2005), Relationships Between Implied Volatility Indexes and Stock Index Returns | 隐含波动率指数与股指收益的负相关和非对称性 |
| Bekaert & Hoerova (2013/2014), The VIX, the Variance Premium and Stock Market Volatility | VIX 平方分解:预期方差与方差风险溢价 |
| Engle (2002), Dynamic Conditional Correlation | DCC-GARCH 动态相关方法 |
| Tapiero (2015), Information Content of Intraday VIX | intraday VIX 信息含量 |
import pandas as pd
import numpy as np
# Cboe official
vix = pd.read_csv("https://cdn.cboe.com/api/global/us_indices/daily_prices/VIX_History.csv")
vvix = pd.read_csv("https://cdn.cboe.com/api/global/us_indices/daily_prices/VVIX_History.csv")
# Yahoo Finance source via OpenIntro
spx_old = pd.read_csv("https://www.openintro.org/data/csv/sp500_1950_2018.csv")
# FRED / S&P Dow Jones recent history
spx_new = pd.read_csv("https://eco3min.fr/dataset/sp500-price-index.csv")
# parse and stitch
vix["date"] = pd.to_datetime(vix["DATE"], format="%m/%d/%Y")
vvix["date"] = pd.to_datetime(vvix["DATE"], format="%m/%d/%Y")
spx_old["date"] = pd.to_datetime(spx_old["Date"])
spx_new["date"] = pd.to_datetime(spx_new["date"])
spx_old = spx_old[["date", "Close"]].rename(columns={"Close": "spx"})
spx_new = spx_new[["date", "sp500_close"]].rename(columns={"sp500_close": "spx"})
spx = pd.concat([spx_old[spx_old["date"] < spx_new["date"].min()], spx_new], ignore_index=True)
spx = spx.drop_duplicates("date").sort_values("date")
vix = vix[["date", "CLOSE"]].rename(columns={"CLOSE": "vix"})
vvix = vvix[["date", "VVIX"]].rename(columns={"VVIX": "vvix"})
df = spx.merge(vix, on="date", how="inner").merge(vvix, on="date", how="left")
df = df[df["date"] >= "1990-01-02"].sort_values("date")
df["r_spx"] = 100 * np.log(df["spx"] / df["spx"].shift(1))
df["dln_vix"] = 100 * np.log(df["vix"] / df["vix"].shift(1))
df["pos_r"] = df["r_spx"].clip(lower=0)
df["neg_r_abs"] = -df["r_spx"].clip(upper=0)
# rolling correlation and cross-correlation
corr0 = df["r_spx"].corr(df["dln_vix"])
df["rollcorr_252"] = df["r_spx"].rolling(252).corr(df["dln_vix"])
lags = range(-20, 21)
xcc = {}
for k in lags:
xcc[k] = df["r_spx"].corr(df["dln_vix"].shift(-k))
print("contemporaneous corr:", corr0)
print("lag -1 / 0 / +1:", xcc[-1], xcc[0], xcc[1])
from statsmodels.tsa.api import VAR
var_df = df[["r_spx", "dln_vix"]].dropna()
var_mod = VAR(var_df)
lag_order = var_mod.select_order(10).bic # parsimonious choice
var_res = var_mod.fit(lag_order)
print(var_res.summary())
print(var_res.test_causality("dln_vix", ["r_spx"], kind="f").summary())
print(var_res.test_causality("r_spx", ["dln_vix"], kind="f").summary())
irf = var_res.irf(10)
# irf.plot(orth=False)
import statsmodels.api as sm
reg = df[["dln_vix", "pos_r", "neg_r_abs", "vvix"]].dropna()
X = sm.add_constant(reg[["pos_r", "neg_r_abs", "vvix"]])
ols = sm.OLS(reg["dln_vix"], X).fit(cov_type="HAC", cov_kwds={"maxlags": 5})
print(ols.summary())
for q in [0.1, 0.5, 0.9]:
qr = sm.QuantReg(reg["dln_vix"], X).fit(q=q)
print(f"\nquantile = {q}")
print(qr.params)
# simple empirical upper-tail dependence
stress = pd.DataFrame({
"x": -df["r_spx"], # market drop pressure
"y": df["dln_vix"] # VIX jump
}).dropna()
u = stress.rank(method="average") / (len(stress) + 1)
for q in [0.95, 0.99]:
mask_x = u["x"] > q
mask_y = u["y"] > q
cond_prob = (mask_x & mask_y).mean() / (1 - q)
print(f"empirical tail dependence at {q}: {cond_prob:.3f}")