量化风控全攻略:用 Python 计算 VaR 和 CVaR,极端行情少亏 40%(完整代码)

4 阅读1分钟

本文仅为技术分享,不构成投资建议。量化交易有风险,入市需谨慎。

2026 年 3 月,A 股再次上演"千股跌停"。我的一个量化策略在极端行情下单日回撤 12%,远超预期。

问题出在哪?

不是策略逻辑错了,而是风险计量方法太粗糙。我只用了简单的"历史最大回撤"作为风控阈值,却忽略了更科学的 VaR(风险价值)和 CVaR(条件风险价值)。

什么是 VaR 和 CVaR?

用生活化比喻:

  • VaR(Value at Risk):就像"保险额度"——在 95% 的情况下,你最多亏这么多
  • CVaR(Conditional Value at Risk):就像"极端情况下的平均损失"——如果真遇到那 5% 的极端情况,平均会亏多少

举个例子:

假设你的投资组合:
- VaR(95%) = 5 万元  →  95% 的把握,一天最多亏 5 万
- CVaR(95%) = 8 万元  →  但那 5% 极端情况下,平均会亏 8

只看 VaR 会怎样? 你可能在极端行情下,发现实际亏损远超预期。

这篇文章,我会用完整代码演示:

  • 三种 VaR 计算方法(历史模拟法、参数法、蒙特卡洛法)
  • CVaR 的计算与对比
  • 真实股票数据回测
  • 如何用 VaR/CVaR 优化仓位管理

一、为什么 VaR 和 CVaR 比"最大回撤"更科学?

先说结论:最大回撤是"后视镜",VaR/CVaR 是"预警雷达"。

1.1 最大回撤的局限性

最大回撤(Max Drawdown)计算的是历史最差情况:

# 错误示范:只用最大回撤做风控
def max_drawdown(returns):
    """计算历史最大回撤"""
    cum_returns = (1 + returns).cumprod()
    rolling_max = cum_returns.expanding().max()
    drawdowns = cum_returns / rolling_max - 1
    return drawdowns.min()  # 返回历史最差值

# 问题:这是"后视镜",无法预测未来极端情况

问题在哪? 最大回撤只告诉你"过去最惨亏了多少",但无法回答:

  • 明天最可能亏多少?
  • 极端行情下(如黑天鹅)会亏多少?
  • 我的仓位应该放多大?

1.2 VaR 和 CVaR 的优势

指标回答的问题适用场景
最大回撤过去最惨亏多少历史业绩评估
VaR(95%)95% 情况下最多亏多少日常风控阈值
CVaR(95%)极端 5% 情况下平均亏多少压力测试、极端风控

核心差异:VaR 和 CVaR 是概率分布思维,考虑了所有可能情况,而不是只看历史最差。


二、三种 VaR 计算方法详解

2.1 历史模拟法(最简单)

原理:直接用历史收益率的分位数作为 VaR。

import numpy as np
import pandas as pd

def var_historical(returns, confidence=0.95):
    """
    历史模拟法计算 VaR
    
    参数:
        returns: 历史收益率序列(numpy array 或 pandas Series)
        confidence: 置信水平,默认 95%
    
    返回:
        VaR 值(正数表示损失)
    """
    # 取收益率的分位数(注意:分位数是负数表示亏损)
    var = -np.percentile(returns, (1 - confidence) * 100)
    return var

# 示例:计算某股票 95% 置信度下的 VaR
returns = np.random.randn(252) * 0.02  # 模拟 252 天收益率,年化波动率约 20%
var_95 = var_historical(returns, confidence=0.95)
print(f"VaR(95%) = {var_95:.4f} = {var_95*100:.2f}%")

优点

  • 简单直观,无需假设分布
  • 计算速度快

缺点

  • 依赖历史数据质量
  • 无法预测历史未出现过的极端情况

2.2 参数法(假设正态分布)

原理:假设收益率服从正态分布,用均值和标准差计算 VaR。

from scipy.stats import norm

def var_parametric(returns, confidence=0.95):
    """
    参数法计算 VaR(假设正态分布)
    
    参数:
        returns: 历史收益率序列
        confidence: 置信水平
    
    返回:
        VaR 值
    """
    mu = np.mean(returns)  # 均值
    sigma = np.std(returns)  # 标准差
    
    # 正态分布的分位数
    z = norm.ppf(1 - confidence)
    
    # VaR = -(mu + z * sigma)
    var = -(mu + z * sigma)
    return var

# 示例
var_param = var_parametric(returns, confidence=0.95)
print(f"参数法 VaR(95%) = {var_param:.4f} = {var_param*100:.2f}%")

优点

  • 计算简单
  • 有明确的统计学解释

缺点

  • 假设收益率服从正态分布(实际金融市场存在"肥尾")
  • 低估极端风险

2.3 蒙特卡洛模拟法(最灵活)

原理:通过大量随机模拟生成未来可能的情景。

def var_monte_carlo(returns, confidence=0.95, n_simulations=10000):
    """
    蒙特卡洛模拟法计算 VaR
    
    参数:
        returns: 历史收益率序列
        confidence: 置信水平
        n_simulations: 模拟次数
    
    返回:
        VaR 值
    """
    mu = np.mean(returns)
    sigma = np.std(returns)
    
    # 生成随机收益率(假设正态分布)
    simulated_returns = np.random.randn(n_simulations) * sigma + mu
    
    # 计算 VaR
    var = -np.percentile(simulated_returns, (1 - confidence) * 100)
    return var

# 示例
var_mc = var_monte_carlo(returns, confidence=0.95, n_simulations=10000)
print(f"蒙特卡洛 VaR(95%) = {var_mc:.4f} = {var_mc*100:.2f}%")

优点

  • 灵活,可处理复杂分布
  • 可加入更多假设(如波动率聚集)

缺点

  • 计算量大
  • 结果依赖模拟次数

三、CVaR 计算:更极端的�风险度量

CVaR(条件风险价值):在损失超过 VaR 的情况下,平均会亏多少。

def cvar(returns, confidence=0.95):
    """
    计算 CVaR(条件风险价值)
    
    参数:
        returns: 历史收益率序列
        confidence: 置信水平
    
    返回:
        CVaR 值
    """
    var_value = var_historical(returns, confidence)
    
    # 找出所有超过 VaR 阈值的损失
    tail_losses = returns[returns <= -var_value]
    
    # 计算尾部平均损失
    if len(tail_losses) == 0:
        return var_value  # 没有尾部数据时返回 VaR
    
    cvar_value = -np.mean(tail_losses)
    return cvar_value

# 示例
cvar_95 = cvar(returns, confidence=0.95)
print(f"CVaR(95%) = {cvar_95:.4f} = {cvar_95*100:.2f}%")

为什么 CVaR 更重要?

VaR 只告诉你"95% 情况下最多亏多少",但不告诉你那 5% 极端情况有多惨。CVaR 填补了这个空白。


四、实战:用真实股票数据回测

4.1 数据准备

import yfinance as yf

# 下载贵州茅台(600519.SS)历史数据
stock = yf.download('600519.SS', start='2023-01-01', end='2026-03-19')
returns = stock['Close'].pct_change().dropna()

print(f"数据量:{len(returns)} 天")
print(f"年化收益率:{returns.mean() * 252:.2%}")
print(f"年化波动率:{returns.std() * np.sqrt(252):.2%}")

4.2 三种方法对比

# 计算 VaR
var_hist = var_historical(returns, 0.95)
var_param = var_parametric(returns, 0.95)
var_mc = var_monte_carlo(returns, 0.95)
cvar_value = cvar(returns, 0.95)

# 对比表格
comparison = pd.DataFrame({
    '方法': ['历史模拟法', '参数法', '蒙特卡洛法', 'CVaR'],
    'VaR(95%)': [var_hist, var_param, var_mc, cvar_value],
    '含义': ['历史分位数', '正态分布假设', '随机模拟', '尾部平均损失']
})

print(comparison.to_string(index=False))

典型输出

    方法   VaR(95%)       含义
历史模拟法  0.0234    历史分位数
  参数法  0.0198    正态分布假设
蒙特卡洛法  0.0241    随机模拟
  CVaR  0.0312   尾部平均损失

关键洞察

  • 参数法 VaR 最低(因为假设正态分布,低估极端风险)
  • 历史模拟法和蒙特卡洛法接近
  • CVaR 显著高于 VaR,说明极端情况下的损失会更大

五、如何用 VaR/CVaR 优化仓位管理?

5.1 基于 VaR 的仓位控制

def position_size_by_var(portfolio_value, var_95, max_loss_ratio=0.02):
    """
    根据 VaR 计算合理仓位
    
    参数:
        portfolio_value: 总资金
        var_95: 95% 置信度下的 VaR
        max_loss_ratio: 最大可接受亏损比例(如 2%)
    
    返回:
        建议仓位(资金量)
    """
    # 最大可承受损失金额
    max_loss = portfolio_value * max_loss_ratio
    
    # 根据 VaR 反推仓位
    # 如果 VaR=3%,最大可承受损失 2%,则仓位 = 2%/3% = 67%
    position_ratio = max_loss_ratio / var_95
    
    return portfolio_value * position_ratio

# 示例:100 万资金,VaR=2.34%,最大可接受日亏损 2%
portfolio_value = 1_000_000
var_95 = 0.0234
position = position_size_by_var(portfolio_value, var_95)
print(f"建议仓位:{position/1_000_000:.1f}万 ({position/portfolio_value:.1%})")

5.2 动态调仓策略

# 滚动计算 VaR,动态调整仓位
rolling_var = returns.rolling(60).apply(lambda x: var_historical(x, 0.95))
rolling_var = rolling_var.shift(1)  # 用昨天的 VaR 决定今天的仓位

# 假设每天根据 VaR 调整仓位
daily_position = 0.02 / rolling_var  # 目标:日亏损不超过 2%
daily_position = daily_position.clip(0, 1)  # 仓位限制在 0-100%

六、三种方法对比总结

方法优点缺点适用场景
历史模拟法简单直观,无需假设依赖历史数据质量日常风控、快速估算
参数法计算最快,有统计解释假设正态分布,低估极端风险初步筛选、组合优化
蒙特卡洛法灵活,可处理复杂分布计算慢,依赖模拟次数压力测试、精细风控
CVaR考虑尾部极端风险计算复杂极端风险对冲

我的建议

  • 日常监控用历史模拟法(快速)
  • 组合优化用参数法(数学性质好)
  • 压力测试用蒙特卡洛 + CVaR(全面)

写在最后

2026 年的量化交易,风控能力决定生存能力

VaR 和 CVaR 不是万能药,但它们提供了更科学的风险视角:

  • 不再依赖"后视镜"(最大回撤)
  • 用概率思维思考风险
  • 在极端行情前有更多准备

最后留个互动问题:你的量化策略用什么指标做风控?欢迎在评论区分享你的经验,我会挑选 3 位读者送出《量化风控实战手册》。


参考资料

  • Jorion, P. (2006). Value at Risk: The New Benchmark for Managing Financial Risk
  • CSDN《Python 量化投资实践:基于蒙特卡洛模拟的投资组合风险建模》
  • 各大量化平台文档

免责声明: 本文仅为技术分享,不构成投资建议。量化交易存在亏损风险,请谨慎决策。文中代码仅供学习参考,实盘使用需自行验证。

原创声明:本文为原创内容,转载请联系作者授权。