← 返回编程题库
coding-lopez-magnitude-loss-function-var-backtest中等免费版1000ms未尝试

Lopez I 量级损失函数:VaR 回溯检验

Lopez I Magnitude Loss Function for VaR Backtesting

开始编码

实现 solution(realized_pnls: list[float], var_forecasts: list[float]) -> float。某风险台 VaR 回溯检验看板把这一例程与 Kupiec POF 二项检验、Christoffersen 独立性/条件覆盖性检验并列运行,作为补充“仅计数”检验的 magnitude-aware 评分。给定长度均为 T 的两个序列——日已实现 PnL(带符号;负数为亏损)与日 VaR 预报(正的亏损数)——返回 Lopez (1999) Type-I 损失:

LopezLoss = sum_t L_t
  L_t = 1 + (loss_excess_t)^2  当 realized_pnls[t] < -var_forecasts[t]
  L_t = 0                       否则
  loss_excess_t = (-realized_pnls[t]) - var_forecasts[t]

基项 1 给每次突破固定的计数贡献(使模型也按失败次数受罚,与 Kupiec POF 同源),平方超额项给每次失败的量级处罚(突破越大、得分越快地变大)。规范实现是带累加器的 O(T) 单遍扫描。

算例

solution([50000.0, -120000.0, 30000.0, -180000.0, -60000.0], [100000.0, 100000.0, 100000.0, 100000.0, 100000.0]) 返回 6800000002.0。5 天窗口、VaR 恒为 10 万。第 1 日(+5 万)、第 3 日(+3 万)、第 5 日(-6 万)均未突破。第 2 日(-12 万 < -10 万)突破,超额 2 万,贡献 1 + 20000^2 = 400000001;第 4 日(-18 万 < -10 万)突破,超额 8 万,贡献 1 + 80000^2 = 6400000001。合计 6800000002。第 4 日单日贡献约为第 2 日的 16 倍,因为量级项是平方——这正是 Lopez I 想要刻画的非对称。

六个易错点

第一严格小于。规范用 <(严格小于),不是 <=。PnL 恰好等于负 VaR 时是突破——它在阈值上而非阈值下。边界自检 solution([-100.0], [100.0]) 必须返回 0.0;用 <= 的写法返回 1.0

第二超额符号。规范是 loss_excess = (-realized_pnls[t]) - var_forecasts[t]。已实现亏损量级为 -realized_pnls[t](亏损日为正);减去正 VaR 即低于 VaR 的程度。漏负号写成 realized_pnls[t] - var_forecasts[t] 得到符号反向的“超额”:平方后虽仍非负,但量级完全错位(结果等于 |loss| + VaR 而非 |loss| - VaR)。

第三,**1 + 基项**。Lopez I 同时含计数分量(每次突破 +1)和量级分量(excess^2)。漏掉 1+ 的写法只算平方超额合计,是另一种统计量——超额 0.001 的微小突破贡献约 0 而非约 1,计数信号丢失。

第四平方而非线性或立方。平方超额是 magnitude-aware 的设计选择:十次量级 1 的突破得 10·(1+1)=20,但单次量级 10 的突破得 1+100=101——五倍之差,尽管总量级相同。线性(|excess|,那是 Lopez II)会得 10 vs 10、丢失非对称;立方过度放大尾部事件、超出标定的 chi-square 解释。

第五符号约定var_forecasts[t]亏损数给出(1% 1 日 VaR $25 万传入 250000.0 而非 -250000.0);realized_pnls[t] 是带符号的。条件 realized_pnls[t] < -var_forecasts[t] 正确地把负号 PnL 与正阈值取负后比较;先把 var_forecasts[t] 取负的写法翻转方向,会把盈利日记成“突破”。

第六非突破日贡献 0。平静日、盈利日、刚好等于阈值的日,贡献都恰为 0,不是(可能为负的)excess、不是 |excess|、也不是 1。无条件累加 excess(在平静日上为负)的写法,对非突破日也得到了 1 + excess^2,整个窗口被双重计数。

哨兵与边界

T == 0(空窗口):返回 0.0(空求和约定)。两列表长度恒等,故 realized_pnls 为空时 var_forecasts 同样为空。

无突破:返回 0.0。窗口内零的累加。验证 solution([10.0]*100, [50.0]*100) == 0.0

每日都突破:合计为窗口内 1 + excess_t^2 之和。T=1500 且每日超额 100 时,合计 1500 * (1 + 10000) = 15001500——稳稳落在双精度内。

边界情形:realized_pnls[t] == -var_forecasts[t] 严格不算突破(严格小于)。与误用 <= 的写法(会得到非零贡献)截然不同。

微小突破:例如超额 0.01 贡献 1.00011+ 基项保证即便极小突破贡献也不低于 1,计数信号完整保留)。

灾难突破:例如超额 1000.0 贡献 1 + 1e6 = 1000001——平方项完全压倒基项,正是设计意图。

实践背景

Lopez (1999, "Methods for Evaluating Value-at-Risk Estimates") 提出量级损失族,是因为 Kupiec POF 与 Christoffersen 独立性检验只按突破次数与时序独立性给 VaR 模型评分,忽略每次突破的大小。两家银行年内各 10 次突破——一家全部 10 万、另一家全部 100 万——在 POF 与独立性检验上同分。Lopez I 把它们按 100 倍区分(因 excess^2 大 100 倍),故为日 VaR 看板上的标准 magnitude-aware 评分。本题是题库中 magnitude-aware 的姊妹——区别于 Basel 红绿灯分区分类器(分类、仅计数)、突破集群计数例程(描述性、计数与最长集群)、Kupiec POF 似然比(二项 LR、边际率)、Christoffersen 独立性 LR(聚集)、Christoffersen 条件覆盖性 LR(联合检验)。这五者各自对应 VaR 回溯检验看板上的不同部件。

约束条件

  • 0 <= len(realized_pnls) == len(var_forecasts) <= 1500
  • 对所有 t,|realized_pnls[t]| <= 1e6
  • 对所有 t,0.0 <= var_forecasts[t] <= 1e6
  • 输出:float —— 非负 Lopez I 合计;rel_tol=1e-9、abs_tol=1e-9

样例

Case 1 · statement-example: 5-day window with two exceedances of differing magnitude

输入: [[50000,-120000,30000,-180000,-60000],[100000,100000,100000,100000,100000]]

期望: 6800000002

5 天窗口,VaR 恒为 10 万;第 2 天(-12 万)与第 4 天(-18 万)触发突破。超额分别为 2 万与 8 万。L_2 = 1 + 20000^2 = 400000001;L_4 = 1 + 80000^2 = 6400000001。第 1、3、5 天各贡献 0。合计 6800000002.0。第 4 天的贡献占主导:同样是两次突破,但单一严重日远远盖过两个温和日——这正是 Lopez I 想要刻画的非对称。

Case 2 · visible: empty backtest window

输入: [[],[]]

期望: 0

T=0:空求和返回 0.0。无任何日,无突破,无损失。

Case 3 · visible: realized_pnl exactly equals minus VaR is NOT an exceedance

输入: [[-100,-100,-50],[100,100,100]]

期望: 0

三日,全部满足 realized_pnl >= -var_forecast(第 1、2 日恰好等号)。规范明确突破条件为严格小于,故等号不算突破。合计 0.0。

Case 4 · visible: single tiny exceedance produces 1 + epsilon

输入: [[-100.01],[100]]

期望: 1.0001000000000002

仅一日,超额仅 0.01:L = 1 + 0.0001 = 1.0001(浮点意义下)。陷阱演示:漏掉 `1+` 基项的写法返回 0.0001——相差 1 万倍。

Case 5 · visible: single severe exceedance dominated by squared term

输入: [[-1100],[100]]

期望: 1000001

一日,超额 1000,贡献 = 1 + 1e6 = 1000001。平方项以 6 个数量级压倒 +1 基项——magnitude-aware 设计意图所在。

最近提交

还没有提交记录。

编码区

实现 solution(...)。本地运行当前支持 Python 可见样例;服务端提交会运行可见样例和隐藏测试。

加载编辑器...
计时0:00

默认展示公开样例。点击「运行样例」后会在这里显示实际输出;点击「提交评测」会进入隐藏测试。

Case 1 · statement-example: 5-day window with two exceedances of differing magnitude

输入: [[50000,-120000,30000,-180000,-60000],[100000,100000,100000,100000,100000]]

期望: 6800000002

5 天窗口,VaR 恒为 10 万;第 2 天(-12 万)与第 4 天(-18 万)触发突破。超额分别为 2 万与 8 万。L_2 = 1 + 20000^2 = 400000001;L_4 = 1 + 80000^2 = 6400000001。第 1、3、5 天各贡献 0。合计 6800000002.0。第 4 天的贡献占主导:同样是两次突破,但单一严重日远远盖过两个温和日——这正是 Lopez I 想要刻画的非对称。

Case 2 · visible: empty backtest window

输入: [[],[]]

期望: 0

T=0:空求和返回 0.0。无任何日,无突破,无损失。

Case 3 · visible: realized_pnl exactly equals minus VaR is NOT an exceedance

输入: [[-100,-100,-50],[100,100,100]]

期望: 0

三日,全部满足 realized_pnl >= -var_forecast(第 1、2 日恰好等号)。规范明确突破条件为严格小于,故等号不算突破。合计 0.0。

Case 4 · visible: single tiny exceedance produces 1 + epsilon

输入: [[-100.01],[100]]

期望: 1.0001000000000002

仅一日,超额仅 0.01:L = 1 + 0.0001 = 1.0001(浮点意义下)。陷阱演示:漏掉 `1+` 基项的写法返回 0.0001——相差 1 万倍。

Case 5 · visible: single severe exceedance dominated by squared term

输入: [[-1100],[100]]

期望: 1000001

一日,超额 1000,贡献 = 1 + 1e6 = 1000001。平方项以 6 个数量级压倒 +1 基项——magnitude-aware 设计意图所在。