4、VaR(在险价值):三种核心计算方法与局限性
VaR,全称Value at Risk,中文叫在险价值。
说白了,它就是回答一个问题:“在给定的置信水平下,我的投资组合在未来一段时间内,最大可能亏损是多少?”
举个例子:95%置信水平下,日VaR为100万。意思是,有95%的把握,明天亏损不超过100万。反过来,有5%的概率,亏损会超过100万。
这个指标在风控领域太常见了。我早期做量化的时候,每天开盘前第一件事就是看VaR。它就像一个风险仪表盘,告诉你今天油门能不能踩到底。
4.1 参数法(方差-协方差法)
参数法是最经典的方法。它假设资产收益率服从正态分布。
既然是正态分布,那只需要知道均值和标准差,就能算出VaR。
计算公式:
VaR = - (μ × t + Z_α × σ × √t) × P
其中:
- μ:收益率均值
- σ:收益率标准差
- Z_α:置信水平对应的分位数(95%对应1.645,99%对应2.326)
- t:持有期(天)
- P:投资组合市值
Python实现:
import numpy as np
def parametric_var(returns, confidence=0.95, portfolio_value=1_000_000):
mu = np.mean(returns)
sigma = np.std(returns)
z_score = {
0.90: 1.282,
0.95: 1.645,
0.99: 2.326
}[confidence]
var = - (mu + z_score * sigma) * portfolio_value
return var
# 示例
daily_returns = np.random.normal(0.001, 0.02, 252)
var_95 = parametric_var(daily_returns, 0.95)
print(f"95%置信水平下,日VaR为:{var_95:.2f}元")
我的经验:参数法计算快,适合大盘蓝筹股。但有个坑——金融数据往往有厚尾特征。我见过太多人直接用正态假设,结果VaR严重低估了极端风险。2015年股灾时,很多机构的参数法VaR完全失效,就是因为尾部风险被忽略了。
4.2 历史模拟法
历史模拟法不假设任何分布。它直接用过去N天的收益率数据,排序后取分位数。
你想想看,这方法多直观:过去100天里,最差的第5天亏损是多少?那就是95%置信水平的VaR。
计算步骤:
- 收集过去N天的历史收益率
- 对收益率从小到大排序
- 取第 (1-置信水平) × N 个位置的数值
- 乘以投资组合市值
Python实现:
def historical_var(returns, confidence=0.95, portfolio_value=1_000_000):
sorted_returns = np.sort(returns)
index = int((1 - confidence) * len(sorted_returns))
var = - sorted_returns[index] * portfolio_value
return var
# 示例
var_95_hist = historical_var(daily_returns, 0.95)
print(f"历史模拟法:95% VaR = {var_95_hist:.2f}元")
注意:历史模拟法依赖历史数据。如果市场结构变了,历史会骗人。我曾经用2018年的数据去预测2020年疫情下的VaR,结果差了3倍。历史不会简单重复,但历史模拟法假设它会。
4.3 蒙特卡洛模拟法
蒙特卡洛模拟法,说白了就是“暴力枚举”。
它生成成千上万条可能的未来价格路径,然后看最坏的情况。
核心思路:
- 假设收益率服从某种随机过程(通常是几何布朗运动)
- 随机生成大量路径(比如10000条)
- 对每条路径计算最终损益
- 取分位数作为VaR
Python实现:
def monte_carlo_var(initial_price, mu, sigma, days=1,
n_simulations=10000, confidence=0.95,
portfolio_value=1_000_000):
dt = 1/252 # 日频
final_prices = []
for _ in range(n_simulations):
price = initial_price
for _ in range(days):
epsilon = np.random.normal(0, 1)
price *= np.exp((mu - 0.5 * sigma**2) * dt + sigma * np.sqrt(dt) * epsilon)
final_prices.append(price)
returns = (np.array(final_prices) - initial_price) / initial_price
var = - np.percentile(returns, (1 - confidence) * 100) * portfolio_value
return var
# 示例
var_95_mc = monte_carlo_var(100, 0.08, 0.2, 1, 10000, 0.95)
print(f"蒙特卡洛模拟:95% VaR = {var_95_mc:.2f}元")
我的建议:蒙特卡洛最灵活,可以加入跳跃、波动率聚集等复杂特征。但计算量大,不适合高频场景。我一般用它做压力测试,或者验证参数法和历史模拟法的结果是否合理。
4.4 三种方法对比
| 方法 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| 参数法 | 计算快,公式简单 | 正态假设不现实 | 流动性好的大盘股 |
| 历史模拟法 | 无分布假设,直观 | 依赖历史,无法预测新风险 | 数据充足、市场稳定时 |
| 蒙特卡洛模拟 | 灵活,可模拟复杂情况 | 计算慢,依赖模型假设 | 压力测试、衍生品定价 |
4.5 VaR的局限性
VaR虽然好用,但坑也不少。我踩过几个,分享给你:
- 不满足次可加性:组合的VaR可能大于各部分VaR之和。这违反了风险分散化的直觉。
- 忽略尾部风险:VaR只告诉你“最差5%的边界”,但边界之外有多惨?它不说。2008年金融危机,很多机构的VaR显示正常,但实际亏损远超VaR。
- 对参数敏感:历史窗口选100天还是250天,结果可能差30%。我见过有人为了好看,故意选一个低VaR的窗口期。
- 无法处理非线性风险:期权等衍生品的损益是非线性的,VaR很难准确刻画。
避坑指南:我曾经用VaR管理一个期权组合,结果连续三天VaR都正常,第四天市场波动率飙升,组合直接爆仓。后来我改用CVaR(条件在险价值)来补充,它关注的是尾部损失的均值,比VaR更保守。
4.6 知识体系图
核心总结:VaR是风控的起点,不是终点。三种方法各有优劣,我建议你根据数据特征和业务场景灵活选择。记住,任何模型都有假设,而市场永远在打破假设。