风险价值如何计算:3种方法
用固定SPY收益序列比较历史法、参数法和蒙特卡洛法,了解三种VaR结果为何不同,以及VaR完全忽略的尾部损失。
风险价值(VaR)的计算方法是:先确定持有期和置信水平,再根据收益率序列读取相应的分位数。1天、99%置信水平下的VaR为2%,意味着每100个交易日中,有99天的损失不超过2%,第100天则可能超过2%。对于相同的输入数据,三种标准方法都可以回答这个问题,但它们得出的结果差异往往超出多数人的预期。
VaR实际衡量的是什么
VaR是损失分布的分位数。将样本中的每日收益率从最差到最好排序,从损失端向内走百分之一,落点对应的收益率以正数损失表示,就是一天期百分之九十九历史VaR。这样的构造并不意味着它代表最坏情况,而是标志着估计结果不再描述的区域边界。
这是读者最常误解的性质。百分之九十九VaR表示,最差的百分之一交易日会落在该阈值之外,但不说明超出幅度。最大回撤回答的是另一个问题:某个投资组合实际经历过的峰值至谷值损失。两者对同一组投资组合的排序可能完全相反。
以下所有数据均基于同一条序列:从2010年初到2025年底的SPY每日收盘价,并换算为收盘价至收盘价的百分比变动。样本区间固定,不采用滚动窗口。每个面板都使用相同日期重新构建序列,因此不同运行结果之间的数字不会漂移。
每个数字背后的完整 SQL
WITH
px AS
(
SELECT date, max(toFloat64(close)) AS close_px
FROM global_markets.stocks_daily_aggs
WHERE ticker = 'SPY'
AND date >= '2009-12-01'
AND date < '2026-01-01'
GROUP BY date
),
rets AS
(
SELECT date, 100 * (close_px / prev_close - 1) AS ret_pct
FROM
(
SELECT date, close_px,
lagInFrame(close_px, 1) OVER (ORDER BY date ROWS BETWEEN 1 PRECEDING AND CURRENT ROW) AS prev_close
FROM px
)
WHERE date >= '2010-01-01' AND prev_close > 0
)
SELECT
toString(toYear(date)) AS year,
count() AS sessions,
round(avg(ret_pct), 3) AS mean_return_pct,
round(stddevSamp(ret_pct), 2) AS daily_sigma_pct
FROM rets
GROUP BY year
ORDER BY year该序列覆盖16个日历年,其中仅2010包含252个交易日。以下两个特征对后续分析都很重要。在这一时间尺度上,单日平均收益率几乎无关紧要:2010为0.054%,而每日标准差sigma为1.13%。此外,sigma并非恒定不变。2020的每日波动率为2.11%,2017则为0.43%。一个sigma无法同时描述这两种情况。
风险价值的三种计算方法
历史VaR:从实际结果中读取分位数
将实际收益率排序,然后取相应分位数。这种方法不假设收益率服从某种分布,这正是其优势所在。但它假设样本中已经包含估计值所要覆盖的那类交易日。将置信水平推得足够高后,整个样本窗口中最差的几个交易日就会决定结果。
参数VaR:均值减去z乘以sigma
先用均值和sigma概括收益率序列,再假设收益率服从正态分布。VaR等于z乘以sigma再减去均值。其中,z为标准正态分布分位数:95%置信水平对应1.645,99%对应2.326,99.9%对应3.090。计算速度很快,但这一假设会在特定方向上失效。股票日收益率在分布中部往往比正态曲线更集中,而在极端位置则延伸得更远。这里的sigma也是计算夏普比率时使用的分母,因此面对肥尾数据时存在同样的盲点。
蒙特卡洛VaR:固定随机种子进行模拟
根据假设的过程生成大量合成样本,然后从这些模拟结果中读取分位数。下方面板使用4万次标准正态抽样。这些抽样由Box-Muller变换基于经过哈希播种的均匀序列生成,再按收益率序列的均值和sigma进行缩放。随机种子写在SQL中,因此每次重新运行都会得到完全相同的抽样结果。模拟可以支持更灵活的设定、路径依赖和多资产相关性,但不会自动带来更强的现实性:如果输入正态分布,输出的就是叠加抽样噪声的参数VaR。若改为对实际收益率进行重抽样,也就是自助法置信区间背后的方法,则可以保留真实尾部风险。
每个数字背后的完整 SQL
WITH
px AS
(
SELECT date, max(toFloat64(close)) AS close_px
FROM global_markets.stocks_daily_aggs
WHERE ticker = 'SPY'
AND date >= '2009-12-01'
AND date < '2026-01-01'
GROUP BY date
),
rets AS
(
SELECT date, 100 * (close_px / prev_close - 1) AS ret_pct
FROM
(
SELECT date, close_px,
lagInFrame(close_px, 1) OVER (ORDER BY date ROWS BETWEEN 1 PRECEDING AND CURRENT ROW) AS prev_close
FROM px
)
WHERE date >= '2010-01-01' AND prev_close > 0
),
emp AS
(
SELECT
avg(ret_pct) AS mu,
stddevSamp(ret_pct) AS sd,
quantileExact(0.100)(ret_pct) AS h90,
quantileExact(0.050)(ret_pct) AS h95,
quantileExact(0.025)(ret_pct) AS h975,
quantileExact(0.010)(ret_pct) AS h99,
quantileExact(0.005)(ret_pct) AS h995,
quantileExact(0.001)(ret_pct) AS h999
FROM rets
),
draws AS
(
SELECT
quantileExact(0.100)(z) AS z90,
quantileExact(0.050)(z) AS z95,
quantileExact(0.025)(z) AS z975,
quantileExact(0.010)(z) AS z99,
quantileExact(0.005)(z) AS z995,
quantileExact(0.001)(z) AS z999
FROM
(
SELECT sqrt(-2 * log(u1)) * cos(2 * pi() * u2) AS z
FROM
(
SELECT
(cityHash64('var-seed-u1', i) % 999999937 + 1) / 999999938.0 AS u1,
(cityHash64('var-seed-u2', i) % 999999937 + 1) / 999999938.0 AS u2
FROM (SELECT arrayJoin(range(40000)) AS i)
)
)
)
SELECT
tupleElement(lvl, 1) AS confidence,
round(-1 * tupleElement(lvl, 2), 2) AS historical_var_pct,
round(tupleElement(lvl, 3) * sd - mu, 2) AS parametric_var_pct,
round(-1 * (mu + sd * tupleElement(lvl, 4)), 2) AS monte_carlo_var_pct,
round(-1 * tupleElement(lvl, 2) - (tupleElement(lvl, 3) * sd - mu), 2) AS method_spread
FROM
(
SELECT
mu,
sd,
arrayJoin([
('90.0%', h90, 1.281552, z90, 1),
('95.0%', h95, 1.644854, z95, 2),
('97.5%', h975, 1.959964, z975, 3),
('99.0%', h99, 2.326348, z99, 4),
('99.5%', h995, 2.575829, z995, 5),
('99.9%', h999, 3.090232, z999, 6)
]) AS lvl
FROM emp
CROSS JOIN draws
)
ORDER BY tupleElement(lvl, 5)在95.0%水平,三种方法的结果相差不到一个百分点:历史法为1.66%,参数法为1.74%,模拟法为1.71%。在99.9%水平,结果开始明显分化:历史法为5.85%,参数法为3.31%,使用相同数据时相差2.54个百分点。模拟法在每个水平上都接近参数法。这不是缺陷,而是该方法揭示的规律:模拟会复现所输入的分布。
沿列向下查看面板,可以看到置信水平每提高一级,阈值就会扩大。沿行横向查看,则会发现,在分布中部,方法选择的影响很小;到了尾部,方法选择便成为决定性因素。没有注明计算方法和样本窗口的VaR限额,其他人无法复现,也就不能算是一个完整的数字。
VaR无法告诉你的信息:预期损失
预期损失也称条件VaR。它计算突破VaR的交易日的平均损失。VaR标示尾部风险的起点。预期损失衡量的是尾部风险内部的损失程度。
每个数字背后的完整 SQL
WITH
px AS
(
SELECT date, max(toFloat64(close)) AS close_px
FROM global_markets.stocks_daily_aggs
WHERE ticker = 'SPY'
AND date >= '2009-12-01'
AND date < '2026-01-01'
GROUP BY date
),
rets AS
(
SELECT date, 100 * (close_px / prev_close - 1) AS ret_pct
FROM
(
SELECT date, close_px,
lagInFrame(close_px, 1) OVER (ORDER BY date ROWS BETWEEN 1 PRECEDING AND CURRENT ROW) AS prev_close
FROM px
)
WHERE date >= '2010-01-01' AND prev_close > 0
),
qs AS
(
SELECT
quantileExact(0.100)(ret_pct) AS q90,
quantileExact(0.050)(ret_pct) AS q95,
quantileExact(0.025)(ret_pct) AS q975,
quantileExact(0.010)(ret_pct) AS q99,
quantileExact(0.005)(ret_pct) AS q995,
quantileExact(0.001)(ret_pct) AS q999
FROM rets
),
tails AS
(
SELECT
any(q90) AS var90,
any(q95) AS var95,
any(q975) AS var975,
any(q99) AS var99,
any(q995) AS var995,
any(q999) AS var999,
avgIf(ret_pct, ret_pct <= q90) AS es90,
avgIf(ret_pct, ret_pct <= q95) AS es95,
avgIf(ret_pct, ret_pct <= q975) AS es975,
avgIf(ret_pct, ret_pct <= q99) AS es99,
avgIf(ret_pct, ret_pct <= q995) AS es995,
avgIf(ret_pct, ret_pct <= q999) AS es999
FROM rets
CROSS JOIN qs
HAVING countIf(ret_pct <= q999) > 0
)
SELECT
tupleElement(lvl, 1) AS confidence,
round(-1 * tupleElement(lvl, 2), 2) AS historical_var_pct,
round(-1 * tupleElement(lvl, 3), 2) AS expected_shortfall_pct,
round(tupleElement(lvl, 3) / tupleElement(lvl, 2), 2) AS es_to_var_ratio
FROM
(
SELECT
arrayJoin([
('90.0%', var90, es90, 1),
('95.0%', var95, es95, 2),
('97.5%', var975, es975, 3),
('99.0%', var99, es99, 4),
('99.5%', var995, es995, 5),
('99.9%', var999, es999, 6)
]) AS lvl
FROM tails
)
ORDER BY tupleElement(lvl, 4)在99.0%,该序列的VaR为3.09%,预期损失为4.43%,相当于阈值的1.44倍。在相同置信水平下,若收益服从正态分布,该比率应接近1.15。即使在99.9%,此时阈值已经达到5.85%,突破阈值交易日的平均损失仍为8.14%。仅依据VaR设定的限额,会将每次突破都视为相同事件;比率列则显示这种假设与实际情况相差多远。
机构与交易员理解的一日99% VaR是否相同?
不相同,差异主要在于持有期限。隔夜不持仓的交易员只承担数小时的风险,因此一交易时段阈值与其持有期限基本匹配。但盘中价格路径可能远远超出收盘至收盘的变动幅度。为长期负债提供资金的机构则持有期限为数年,其风险敞口跨越多个季度。因此,机构的一日99% VaR更多是资本计量和风险监控工具,而不是对其实际承担风险的描述。多年来,银行资本规则一直采用一日99% VaR。此后,《巴塞尔市场风险框架》将指标调整为97.5%的预期损失。
不同期限之间的标准转换方法,是按时间平方根进行缩放:将单个交易时段的数值乘以期限内交易时段数量的平方根。该方法假设收益相互独立,且波动率sigma保持不变。上方逐年列示的sigma已经显示出这一假设的后半部分并不成立。
每个数字背后的完整 SQL
WITH
px AS
(
SELECT date, max(toFloat64(close)) AS close_px
FROM global_markets.stocks_daily_aggs
WHERE ticker = 'SPY'
AND date >= '2009-11-01'
AND date < '2026-01-01'
GROUP BY date
),
multi AS
(
SELECT
date,
100 * (close_px / p1 - 1) AS r1,
100 * (close_px / p5 - 1) AS r5,
100 * (close_px / p10 - 1) AS r10,
100 * (close_px / p20 - 1) AS r20
FROM
(
SELECT
date,
close_px,
lagInFrame(close_px, 1) OVER (ORDER BY date ROWS BETWEEN 20 PRECEDING AND CURRENT ROW) AS p1,
lagInFrame(close_px, 5) OVER (ORDER BY date ROWS BETWEEN 20 PRECEDING AND CURRENT ROW) AS p5,
lagInFrame(close_px, 10) OVER (ORDER BY date ROWS BETWEEN 20 PRECEDING AND CURRENT ROW) AS p10,
lagInFrame(close_px, 20) OVER (ORDER BY date ROWS BETWEEN 20 PRECEDING AND CURRENT ROW) AS p20
FROM px
)
WHERE date >= '2010-01-01' AND p20 > 0
),
q AS
(
SELECT
quantileExact(0.01)(r1) AS q1,
quantileExact(0.01)(r5) AS q5,
quantileExact(0.01)(r10) AS q10,
quantileExact(0.01)(r20) AS q20
FROM multi
)
SELECT
tupleElement(h, 1) AS horizon,
round(-1 * tupleElement(h, 3), 2) AS actual_var_pct,
round(-1 * q1 * sqrt(tupleElement(h, 2)), 2) AS sqrt_scaled_var_pct,
round(tupleElement(h, 3) / (q1 * sqrt(tupleElement(h, 2))), 2) AS actual_to_scaled_ratio
FROM
(
SELECT
q1,
arrayJoin([
('1 session', 1.0, q1, 1),
('5 sessions', 5.0, q5, 2),
('10 sessions', 10.0, q10, 3),
('20 sessions', 20.0, q20, 4)
]) AS h
FROM q
)
ORDER BY tupleElement(h, 4)第一行是恒等性检查:在1 session,缩放后的数值等于实测数值,比例为1。到了20 sessions,两者开始分离,而且方向并非通常所警示的那样:将单个交易时段的数值进行缩放后得到13.8%,而该期限内实测收益显示为10.7%,比例为0.78。在这段窗口期内,缩放后的数值高于多时段尾部的实测值。
这里有两种相互拉扯的模式。单个交易时段的厚尾分布在收益累加后会变薄,因此,聚合后的99%分位数扩大的速度会慢于期限平方根。波动率聚类则相反,会将剧烈波动的交易时段集中在同一窗口内。在这组序列中,前一种模式影响更大。但换一个窗口或资产,结果未必相同,关键就在于:这个乘数是一个假设,而不是一项测量结果。波动率聚类也是波动率目标策略据以调整持仓规模的特征。
还存在一个需要明确说明的限制。以上全部内容都是针对广泛指数基金的单一资产VaR。由十只相互关联的股票构成的组合还承担集中度风险。投资组合VaR会通过相关性估计来处理这一风险,而相关性往往在估计最重要的时刻发生最大变化。
方法说明与约定
- 分位数采用精确分位数,而不是抽样估计。蒙特卡洛抽样来自写入SQL的哈希种子均匀序列,因此这里的每个数值都能重新计算出相同结果。
- 收益采用收盘至收盘的价格变动,不进行股息再投资。这是一交易时段VaR的常用约定。
- 期限面板采用重叠窗口:连续的20个交易时段收益共享19天,因此其尾部所依据的独立观测数量远少于行数所暗示的数量。
常见问题
一日99% VaR 是什么?
这是在单个交易日内,只有最差的100个交易日中的1个会超过的损失水平。根据上方序列,历史法估算值为 3.09%。该数值表示一个阈值,并不说明超过这一阈值后的损失规模。
哪种 VaR 计算方法最准确?
抽象地说,三种方法都不能称为最准确,因为它们基于不同假设回答不同问题。历史 VaR 忠实反映给定样本,但无法说明样本未涵盖的情况。参数 VaR 成本较低,但会低估股票尾部风险。蒙特卡洛法的准确性取决于输入的分布。
VaR 与预期短缺有什么区别?
VaR 是特定置信水平下的损失阈值。预期短缺则计算超过该阈值的交易日的平均损失。在这一序列中,99%置信水平下的预期短缺是 VaR 的 1.44 倍;在正态分布下,该比例约为1.15倍。
能否将一日 VaR 换算为十日 VaR?
将一日 VaR 乘以10的平方根是标准的简化方法。该方法假设收益相互独立,且波动率保持不变。期限面板显示了两者的差距:按此方法换算,20个交易日的数值为 13.8%,而实际测得的数值为 10.7%。
上方每个面板都附有生成相应结果的 SQL。若要对不同 ticker 或时间窗口执行同样的三种计算,请在 Strasmore terminal 中用自然语言提出请求。