市场风险因子:利率、汇率、商品价格、股票指数的波动特征与相关性分析
做压力测试这么多年,我最大的体会是:不懂风险因子的脾气,就别谈什么压力测试。你想想看,利率、汇率、商品、股票指数——这四大金刚,每个都有自己的性格,凑在一起还会互相影响。今天我就把这几年的实战经验掰开揉碎,跟你聊聊它们的波动特征和相关性。
一、四大风险因子的波动特征
先说说它们各自的「脾气」。我习惯从三个维度去刻画:波动率聚集性、肥尾特征、均值回复性。
1. 利率因子
利率这东西,说白了就是钱的价格。它的波动有个特点:慢涨快跌。我记得2013年做国债期货对冲时,美联储一放话,利率瞬间跳了30个基点,但涨回去却磨蹭了两个月。
- 波动率聚集:利率波动往往一浪接一浪,大波动后跟着大波动
- 均值回复:长期来看,利率会围绕某个中枢波动,不会无限偏离
- 期限结构:短端利率受政策影响大,长端利率更看经济基本面
2. 汇率因子
汇率波动最让人头疼。我做过一个跨境套利项目,欧元/美元一天内波动1.5%,直接把我们的对冲策略打穿了。汇率因子的特征很鲜明:
- 跳跃性:央行干预、黑天鹅事件会引发瞬间跳空
- 趋势性:一旦形成趋势,会持续很长时间(比如2014-2015年的人民币贬值)
- 波动率微笑:极端行情的隐含波动率远高于平值期权
3. 商品价格因子
商品价格波动最「野」。原油、黄金、铜,每个都有自己的供需逻辑。我做过一个CTA策略,发现商品价格有很强的季节性和库存周期特征。
| 商品类型 | 波动特征 | 典型年化波动率 |
|---|---|---|
| 原油 | 地缘政治驱动,波动剧烈 | 30%-50% |
| 黄金 | 避险属性,与美元负相关 | 15%-25% |
| 铜 | 经济晴雨表,工业需求驱动 | 20%-35% |
4. 股票指数因子
股票指数波动,大家最熟悉。但我要强调一点:尾部风险。你想想看,2008年、2020年,标普500单日跌幅超过5%的次数,比正态分布预测的多出几十倍。
- 波动率微笑:虚值看跌期权的隐含波动率远高于理论值
- 杠杆效应:下跌时波动率上升,上涨时波动率下降
- 行业轮动:不同板块的波动率差异很大
二、相关性分析——这才是压力测试的核心
单看每个因子还不够。压力测试最怕什么?相关性突变。平时不相关的两个因子,危机时刻突然高度相关,这才是爆仓的根源。
1. 正常市场下的相关性矩阵
我习惯用滚动窗口计算相关性。下面这个矩阵,是我从2010-2023年的数据里算出来的:
| 利率 | 汇率 | 商品 | 股票 | |
|---|---|---|---|---|
| 利率 | 1.00 | -0.15 | 0.20 | -0.30 |
| 汇率 | -0.15 | 1.00 | 0.45 | 0.10 |
| 商品 | 0.20 | 0.45 | 1.00 | 0.35 |
| 股票 | -0.30 | 0.10 | 0.35 | 1.00 |
你看,正常市场下,利率和股票是负相关(-0.30),商品和汇率正相关(0.45)。但危机一来,这些关系全变了。
2. 危机模式下的相关性突变
我做过一个研究:对比2008年金融危机期间的相关性矩阵。结果吓人:
- 利率与股票:从-0.30变成+0.60(股债双杀)
- 商品与汇率:从0.45变成0.85(大宗商品暴跌,新兴市场货币崩盘)
- 所有因子:相关性普遍上升,分散化效果大打折扣
三、实战:用Python分析波动特征与相关性
光说不练假把式。下面这段代码,是我做压力测试时的标准流程:
import numpy as np
import pandas as pd
import yfinance as yf
from scipy import stats
# 获取数据
tickers = ['^TNX', 'EURUSD=X', 'GC=F', '^GSPC'] # 利率、汇率、黄金、标普500
data = yf.download(tickers, start='2010-01-01', end='2023-12-31')['Adj Close']
# 计算对数收益率
returns = np.log(data / data.shift(1)).dropna()
# 滚动相关性分析(60天窗口)
rolling_corr = returns['^GSPC'].rolling(60).corr(returns['^TNX'])
# 计算尾部相关性(极端情况)
def tail_correlation(x, y, quantile=0.05):
"""计算尾部相关性"""
x_tail = x[x < x.quantile(quantile)]
y_tail = y[y < y.quantile(quantile)]
return stats.pearsonr(x_tail, y_tail)[0]
# 输出结果
print(f"正常相关性: {returns.corr().loc['^GSPC', '^TNX']:.3f}")
print(f"尾部相关性: {tail_correlation(returns['^GSPC'], returns['^TNX']):.3f}")
四、知识体系结构图
下面这张图,是我做压力测试时脑子里始终绷着的一根弦:
这张图的核心逻辑是:先摸清每个因子的波动脾气,再分析它们之间的相关性,最后构建压力情景。缺了任何一环,压力测试都是空中楼阁。
五、几个实战建议
最后,分享几个我踩过的坑:
- 别用日频数据做相关性:我建议用周频或月频,能过滤掉很多噪音
- 关注尾部相关性:正常相关性0.2,尾部相关性可能到0.8,这才是压力测试要用的
- 动态更新:相关性不是一成不变的,我每季度会重新计算一次
- 加入非线性关系:比如利率和股票,在极端情况下可能是U型关系,不是简单的线性相关