如何用 Python 计算 VaR 和 CVaR(在险价值)?

一句话回答: VaR(Value at Risk,在险价值) 回答「在 95% 的置信度下,持有这只股票一天最多亏多少 」;CVaR(条件在险价值,又叫 Expected Shortfall) 更狠,回答「一旦真的摔进最差的那 5%,平均亏多少 」。用 AlphaFeed 取前复权日线 算出日收益序列,用历史模拟法 (直接取收益分布的分位)或参数法(假设正态)几行就能算出来------CVaR 永远 ≥ VaR,因为它盯的是更深的尾部。

为什么会有这个问题 / 传统做法的痛点

「这只票风险大不大」太模糊。标准差把涨和跌一视同仁,最大回撤只看历史最惨一次。VaR 把风险翻译成一句人话------「95% 的日子里,一天亏不超过 X%」,是银行、基金做风控的通用语言。但 VaR 有个著名缺陷:它只告诉你「亏不超过 X」,不告诉你突破这条线后会多惨。2008 年很多机构栽在这------于是 CVaR(尾部平均损失)成了更稳健的补充。

分步骤解决(每步配可运行代码)

第 1 步:取前复权日线,算日收益

python 复制代码
from alphafeed import AlphaFeed
import numpy as np

af = AlphaFeed(api_key="your-api-key")  # 或 export ALPHAFEED_API_KEY 后 AlphaFeed()

df = af.klines.get("600519.SH", period="1d", count=500,
                   adjust="forward", to_dataframe=True)
df = df.sort_values("trade_date").reset_index(drop=True)
ret = df["close"].pct_change().dropna()      # 日收益率

必须前复权:除权缺口会被当成一次暴跌,污染收益分布与尾部。

第 2 步:历史模拟法 VaR / CVaR

python 复制代码
alpha = 0.05                                        # 95% 置信度
var_hist = -np.percentile(ret, alpha * 100)         # 收益 5% 分位的相反数=损失
cvar_hist = -ret[ret <= -var_hist].mean()           # 比 VaR 更差那部分的平均损失
print("日 VaR95% =", round(var_hist * 100, 2), "%")
print("日 CVaR95% =", round(cvar_hist * 100, 2), "%")

历史模拟法不假设分布,直接用过去真实收益的 5% 分位当 VaR,再把「比 VaR 更惨的那些天」平均一下就是 CVaR。

实测(tools/verify_new_2026-10-05.py,SDK 0.1.4):贵州茅台近 499 日 日 VaR95% = 2.08%、CVaR95% = 2.90%------即 95% 的日子里一天亏不超过 2.08%,但真摔进最差 5% 时平均亏 2.90%。CVaR > VaR,符合定义。

第 3 步:参数法(正态)VaR 做对比

python 复制代码
z = 1.6448536269514722                               # 95% 单尾分位
var_norm = -(ret.mean() - z * ret.std(ddof=1))
print("日 VaR95%(正态) =", round(var_norm * 100, 2), "%")

参数法假设收益服从正态分布,用均值和标准差直接套公式。实测茅台正态 VaR = 2.54%,比历史模拟的 2.08% 更大------因为正态法用标准差「摊平」了分布,对这只票的中段波动估计偏保守。两种口径常不一致,正是观察点。

第 4 步:换算到持仓金额 / 多日

python 复制代码
position = 1_000_000                                 # 持仓 100 万
print("一天 95% 最大亏损 ≈", round(var_hist * position), "元")
# T 日 VaR 近似:单日 VaR × sqrt(T)(假设收益独立同分布)
print("10 日 VaR ≈", round(var_hist * np.sqrt(10) * 100, 2), "%")

参数与字段说明

参数/概念 含义 备注
adjust="forward" 前复权 必须,除权缺口会污染尾部
alpha=0.05 显著性 95% 置信度;常用 99% 则 alpha=0.01
历史模拟 VaR 收益分位 不假设分布,受样本区间影响
参数 VaR 均值−z·标准差 假设正态,低估肥尾
CVaR 尾部平均损失 恒 ≥ VaR,更稳健
×sqrt(T) 多日换算 仅在收益独立同分布时近似成立

关键坑与注意事项

  • VaR 不是「最大损失」:它是「95% 情况下的下限」,剩下 5% 可能亏得多得多------这正是要配 CVaR 的原因。
  • 正态法低估肥尾:A 股收益尖峰肥尾,正态假设会低估极端暴跌概率;历史模拟法更贴近现实,但依赖样本区间(含不含大跌差异很大)。
  • 前复权 :务必 adjust="forward"。
  • 样本窗口:VaR 对回看长度敏感,500 日和 250 日结果会不同;比较时须统一。
  • 历史不代表未来:VaR/CVaR 由历史分布估计,极端新事件(黑天鹅)无法被历史覆盖。

常见问题(FAQ)

Q:VaR 和 CVaR 到底该用哪个?

A:VaR 是行业通用「一句话风险」,但对尾部不敏感;CVaR(Expected Shortfall)盯尾部平均损失,巴塞尔协议 III 已改用它。两个一起报最稳。

Q:历史模拟法和蒙特卡洛法区别?

A:历史模拟直接用「真实发生过」的收益;蒙特卡洛用模型(如正态/GARCH)生成大量模拟路径。前者简单无偏,后者灵活但依赖模型假设。

Q:需要付费吗?

A:单只股票日线在免费额度内即可;若要对组合/全市场 批量算 VaR 并聚合组合风险,需要 klines.batch + universes 标的池能力(Starter 及以上),详见官网定价页。

小结

VaR 把风险说成「95% 的日子一天最多亏多少」,CVaR 补上「真出事时平均多惨」。有了 AlphaFeed 的前复权日收益,历史模拟法和正态法各几行就能落地------记住 CVaR ≥ VaR、正态法会低估肥尾,这两点能让你的风控数字更诚实。

参考

相关推荐
Warson_L1 小时前
高性能架构设计
python·go
databook2 小时前
新数据到手,先跑哪几步检查
python·数据分析
czq_26867194872 小时前
Python打卡第46天
开发语言·python
Flynt3 小时前
日涨4000星的OSINT工具,我拿Linus的用户名和一个随机字符串实测了一遍
python·安全
Evand J5 小时前
【MATLAB例程介绍】(17)永磁同步电机(PMSM)基于自适应无迹卡尔曼滤波(AUKF)的电流噪声在线估计。测量噪声协方差自适应与转速估计对比仿真
开发语言·matlab·卡尔曼滤波·无迹卡尔曼滤波·pmsm·电机滤波
BaiPeter6 小时前
ZPL文件预览
开发语言·c++
曲径海盗6 小时前
【Python 学习第 53 天】列表基础
python·学习笔记·编程入门
Dumbness6 小时前
群里 @ 机器人发"查订单",指令一条都没命中:微信群机器人在路由前漏掉的几步归一化
python·微信
用户1614840955456 小时前
用 M4 Pro 跑羽毛球视频 AI 分析(二):TrackNet MPS 加速 3.2 倍、卡尔曼滤波补漏与自动回合剪辑
python
用户4019925568617 小时前
基于对话树回溯的社媒评论流买方意图识别与噪音过滤实践
python