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.0001(1+ 基项保证即便极小突破贡献也不低于 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 可见样例;服务端提交会运行可见样例和隐藏测试。
默认展示公开样例。点击「运行样例」后会在这里显示实际输出;点击「提交评测」会进入隐藏测试。
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 设计意图所在。