Strasmore Research
Deep Dives · Matt ConnorBy Matt Connor · · Updated 2026-08-21

风险价值如何计算:3种方法

用固定SPY收益序列比较历史法、参数法和蒙特卡洛法,了解三种VaR结果为何不同,以及VaR完全忽略的尾部损失。

风险价值(VaR)的计算方法是:先确定持有期和置信水平,再根据收益率序列读取相应的分位数。1天、99%置信水平下的VaR为2%,意味着每100个交易日中,有99天的损失不超过2%,第100天则可能超过2%。对于相同的输入数据,三种标准方法都可以回答这个问题,但它们得出的结果差异往往超出多数人的预期。

VaR实际衡量的是什么

VaR是损失分布的分位数。将样本中的每日收益率从最差到最好排序,从损失端向内走百分之一,落点对应的收益率以正数损失表示,就是一天期百分之九十九历史VaR。这样的构造并不意味着它代表最坏情况,而是标志着估计结果不再描述的区域边界。

这是读者最常误解的性质。百分之九十九VaR表示,最差的百分之一交易日会落在该阈值之外,但不说明超出幅度。最大回撤回答的是另一个问题:某个投资组合实际经历过的峰值至谷值损失。两者对同一组投资组合的排序可能完全相反。

以下所有数据均基于同一条序列:从2010年初到2025年底的SPY每日收盘价,并换算为收盘价至收盘价的百分比变动。样本区间固定,不采用滚动窗口。每个面板都使用相同日期重新构建序列,因此不同运行结果之间的数字不会漂移。

查询按年固定收益序列:SPY按日收益,2010至2025年
每个数字背后的完整 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
Run this yourself

该序列覆盖16个日历年,其中仅2010包含252个交易日。以下两个特征对后续分析都很重要。在这一时间尺度上,单日平均收益率几乎无关紧要:20100.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。若改为对实际收益率进行重抽样,也就是自助法置信区间背后的方法,则可以保留真实尾部风险。

查询单一序列,三种方法:六个置信水平下的1日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)
Run this yourself

95.0%水平,三种方法的结果相差不到一个百分点:历史法为1.66%,参数法为1.74%,模拟法为1.71%。在99.9%水平,结果开始明显分化:历史法为5.85%,参数法为3.31%,使用相同数据时相差2.54个百分点。模拟法在每个水平上都接近参数法。这不是缺陷,而是该方法揭示的规律:模拟会复现所输入的分布。

沿列向下查看面板,可以看到置信水平每提高一级,阈值就会扩大。沿行横向查看,则会发现,在分布中部,方法选择的影响很小;到了尾部,方法选择便成为决定性因素。没有注明计算方法和样本窗口的VaR限额,其他人无法复现,也就不能算是一个完整的数字。

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)
Run this yourself

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已经显示出这一假设的后半部分并不成立。

查询时间平方根缩放与实测多交易时段损失对比,99%水平
每个数字背后的完整 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)
Run this yourself

第一行是恒等性检查:在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 中用自然语言提出请求。

#risk#value at risk#expected shortfall#quant#position sizing