15、风险管理(下):VaR与CVaR计算、尾部风险对冲、组合保险策略
风险管理这个话题,说实话,很多交易员一开始都不太爱听。觉得那是风控部门的事,自己只管赚钱就行。我以前也这么想,直到有一次……嗯,那笔交易让我亏得有点惨。从那以后,我养成了一个习惯:每次开仓前,先算算最坏情况下会亏多少。
这一章,我们聊聊VaR、CVaR,还有尾部风险怎么对冲。说白了,就是怎么在极端行情下保住你的本金。
15.1 VaR:最常用的风险度量,但有个坑
VaR,全称是Value at Risk,风险价值。它的定义很简单:在给定的置信水平和持有期内,最大可能损失是多少。
举个例子:95%置信水平下,日VaR是100万。意思是,有95%的概率,你一天最多亏100万。剩下的5%呢?亏多少都有可能,VaR不告诉你。
这就是VaR最大的问题——它不关心尾部风险。我见过不少交易员,只看VaR觉得风险可控,结果一次黑天鹅事件直接爆仓。
计算VaR,常用的方法有三种:
- 参数法(方差-协方差法):假设收益率服从正态分布。计算简单,但现实中的收益率分布往往有厚尾,这个方法会低估风险。
- 历史模拟法:直接用过去的数据,找分位数。不依赖分布假设,但历史不一定会重演。
- 蒙特卡洛模拟法:随机生成大量路径,模拟未来价格变化。最灵活,但计算量大。
我个人习惯用历史模拟法,简单直接。但要注意,样本窗口的选择很关键。窗口太短,捕捉不到极端事件;窗口太长,又可能包含过时的市场结构。
避坑指南:我曾经用250天的历史窗口算VaR,觉得挺合理。结果那年市场结构变了,历史数据完全失效。后来我改用加权历史模拟法,给近期的数据更高的权重,效果好了不少。
下面是一个简单的Python实现,用历史模拟法计算期权组合的VaR:
import numpy as np
import pandas as pd
def calculate_var_historical(returns, confidence_level=0.95):
"""
历史模拟法计算VaR
returns: 收益率序列
confidence_level: 置信水平,默认95%
"""
sorted_returns = np.sort(returns)
index = int((1 - confidence_level) * len(sorted_returns))
var = -sorted_returns[index]
return var
# 假设我们有一个期权组合的日收益率数据
# 实际项目中,这些数据来自持仓的每日盯市盈亏
np.random.seed(42)
daily_returns = np.random.normal(0, 0.02, 1000) # 模拟数据
var_95 = calculate_var_historical(daily_returns, 0.95)
var_99 = calculate_var_historical(daily_returns, 0.99)
print(f"95% VaR: {var_95:.4f}")
print(f"99% VaR: {var_99:.4f}")
15.2 CVaR:比VaR更诚实
CVaR,也叫Expected Shortfall,条件风险价值。它回答的是VaR没回答的问题:当损失超过VaR时,平均会亏多少?
你想想看,VaR告诉你95%的情况下最多亏100万,但剩下的5%呢?可能是亏110万,也可能是亏500万。CVaR会告诉你,那5%的平均损失是多少。
计算CVaR也很直接:
def calculate_cvar_historical(returns, confidence_level=0.95):
"""
历史模拟法计算CVaR
"""
sorted_returns = np.sort(returns)
index = int((1 - confidence_level) * len(sorted_returns))
# 取尾部所有损失的平均值
tail_returns = sorted_returns[:index]
cvar = -np.mean(tail_returns)
return cvar
cvar_95 = calculate_cvar_historical(daily_returns, 0.95)
print(f"95% CVaR: {cvar_95:.4f}")
在实际项目中,我通常同时看VaR和CVaR。如果两者差距很大,说明尾部风险很高,需要格外小心。
小技巧:在回测时,可以统计实际损失超过VaR的次数。如果超过的次数明显多于理论值(比如95%置信水平下,超过比例大于5%),说明你的VaR模型有问题,需要调整。
15.3 尾部风险对冲:别等黑天鹅来了才后悔
尾部风险,就是那些概率很小、但一旦发生就损失巨大的事件。比如2008年金融危机、2020年疫情暴跌。
怎么对冲?常用的方法有:
- 买入虚值看跌期权:最直接的方法。平时付点保费,极端行情下能大赚一笔。
- 波动率曲面套利:当市场恐慌时,波动率会飙升。做多波动率可以在尾部事件中获利。
- 风险逆转策略(Risk Reversal):卖出虚值看涨期权,买入虚值看跌期权。既能降低对冲成本,又能保护下行风险。
我记得有一次,市场连续低波动了三个月,大家都觉得没事了。我坚持买了一些虚值看跌期权,成本不高。结果一个月后出了个黑天鹅,那些期权翻了十几倍,把整个组合的亏损都补回来了。
注意:尾部风险对冲不是免费的。保费会持续侵蚀你的收益。关键在于找到平衡点——既不能完全不保护,也不能过度保护导致收益太低。
15.4 组合保险策略:给投资组合上保险
组合保险策略,说白了就是给整个投资组合买个保险。最经典的是CPPI(Constant Proportion Portfolio Insurance,固定比例投资组合保险)策略。
CPPI的核心思想很简单:
- 设定一个保底金额(比如不能亏超过10%)
- 计算安全垫 = 组合净值 - 保底金额
- 根据乘数(通常2-5倍),将安全垫的一部分投资于风险资产(比如期权)
- 剩余部分投资于无风险资产
举个例子:
- 组合净值:1000万
- 保底金额:900万(最多亏10%)
- 安全垫:100万
- 乘数:3
- 风险资产配置:100万 × 3 = 300万
- 无风险资产:700万
当组合上涨时,安全垫变大,风险资产配置增加;当组合下跌时,安全垫缩小,风险资产配置减少。这样就能自动实现「涨时加仓、跌时减仓」的效果。
下面是一个简单的CPPI实现:
def cppi_strategy(portfolio_value, floor_ratio=0.9, multiplier=3, risk_free_rate=0.03):
"""
CPPI策略计算
portfolio_value: 当前组合净值
floor_ratio: 保底比例
multiplier: 乘数
risk_free_rate: 无风险利率
"""
floor = portfolio_value * floor_ratio
cushion = portfolio_value - floor
risk_allocation = cushion * multiplier
risk_allocation = min(risk_allocation, portfolio_value) # 不能超过总资产
safe_allocation = portfolio_value - risk_allocation
return risk_allocation, safe_allocation
# 模拟CPPI策略
portfolio_value = 1000
floor_ratio = 0.9
multiplier = 3
risk_alloc, safe_alloc = cppi_strategy(portfolio_value, floor_ratio, multiplier)
print(f"风险资产配置: {risk_alloc:.2f}万")
print(f"无风险资产配置: {safe_alloc:.2f}万")
实战经验:CPPI策略在趋势行情中表现很好,但在震荡市中容易反复止损。我建议结合波动率指标来动态调整乘数——波动率高时降低乘数,波动率低时提高乘数。
15.5 知识体系总览
这一章的内容比较多,我画了张图帮你理清思路:
风险管理不是一劳永逸的事。市场在变,策略在变,风险也在变。我建议你每周至少做一次VaR和CVaR的复盘,看看实际损失和模型预测是否一致。如果偏差太大,赶紧找原因。
好了,这一章就到这里。记住:赚钱靠策略,活下来靠风控。