多置信度历史 VaR 一次性计算
Historical VaR at Multiple Confidence Levels
开始编码风控部门的日终仪表板上,同一份组合 PnL 历史经常需要同时给出多个置信度的 VaR——例如 95%、97.5%、99%、99.9%——以满足不同监管口径与内部风险委员会的报告需要。请实现 solution(pnl_samples: list[float], alphas: list[float]) -> list[float]:给定有符号的 PnL 历史与一组置信度,对每个 alphas[k] 用历史模拟法返回对应的 VaR,输出顺序与 alphas 的输入顺序严格一致。
每个 alpha 的算法分三步。(a) 把 pnl_samples 升序排序得到 s[0..N-1];(b) 计算尾部下标 k = max(1, ceil(N * (1 - alpha) - 1e-12));(c) 报告 VaR = -s[k - 1],把负 PnL 翻为正损失。当 N == 0 时,每个 alpha 输出 float('nan');当输入的 alphas 为空,则返回空列表。-1e-12 是 IEEE-754 边界的「epsilon 收窄」:当 N*(1-alpha) 在浮点上算出来比真实整数大一点点时,去掉它就会多算一档。
举例:solution([0.012, -0.018, 0.005, -0.025, 0.014, -0.040, 0.002, -0.011, 0.008, -0.022], [0.95, 0.99])。N=10,升序排序为 [-0.040, -0.025, -0.022, -0.018, -0.011, 0.002, 0.005, 0.008, 0.012, 0.014]。alpha=0.95 时 k = ceil(10*0.05 - 1e-12) = 1,VaR = -sorted[0] = 0.040;alpha=0.99 时 k = ceil(10*0.01 - 1e-12) = 1,VaR 同样是 0.040。两个 alpha 共用同一份排序结果,复杂度 O(N log N + K)。
实现层面有三个反复出现的坑。第一,*别把排序写进 alpha 循环*:那是 O(N log N · K),虽然不会出错但浪费明显。第二,*输出顺序要保留*:内部把 alphas 排序后再按升序输出会破坏接口契约——下游会按 alphas[k] 的位置读取 VaR。第三,*重复 alpha 各自给一份*:如果输入是 [0.95, 0.95, 0.99],输出应是三个值,前两位相同;不能去重再补回。再加上 epsilon 收窄那一档,VaR 用正数报告(负的 PnL 取相反数),就齐了。
约束条件
- 0 ≤ len(pnl_samples) ≤ 1500,每个样本满足 |pnl_samples[t]| ≤ 1e6。
- 0 ≤ len(alphas) ≤ 20,每个 alpha 满足 0.5 ≤ alpha < 1.0,可以乱序、可以有重复。
- 当 len(pnl_samples) == 0 时,输出长度等于 len(alphas),每个元素都是 `float('nan')`。
- 当 len(alphas) == 0 时,输出为空列表 `[]`,无论 pnl_samples 是否为空。
- VaR 以正损失约定报告:`VaR = -sorted_pnl[k-1]`,损失档位是负 PnL,取相反数得到正数。
- 浮点容忍:rel_tol=1e-9,abs_tol=1e-9。
样例
Case 1 · worked example, two alphas
输入: [[0.012,-0.018,0.005,-0.025,0.014,-0.04,0.002,-0.011,0.008,-0.022],[0.95,0.99]]
期望: [0.04,0.04]
N=10。升序排序后 sorted = [-0.040, -0.025, -0.022, -0.018, -0.011, 0.002, 0.005, 0.008, 0.012, 0.014]。对 alpha=0.95:k = ceil(10*0.05 - 1e-12) = 1,VaR = -sorted[0] = 0.040。对 alpha=0.99:k = ceil(10*0.01 - 1e-12) = 1,VaR = -sorted[0] = 0.040。排序仅做一次,两个 alpha 共享。
Case 2 · dashboard alphas N=20
输入: [[0.005,-0.012,0.018,-0.035,0.022,-0.008,0.011,-0.044,0.029,-0.017,0.006,-0.025,0.014,-0.031,0.019,-0.009,0.024,-0.052,0.013,-0.021],[0.95,0.975,0.99,0.999]]
期望: [0.052,0.052,0.052,0.052]
N=20。排序后最差损失(最小 PnL)为 -0.052。对 alpha=0.95:k = ceil(20*0.05 - 1e-12) = 1,VaR = 0.052。对 alpha=0.975:k = ceil(20*0.025 - 1e-12) = 1,仍是 0.052。对 alpha=0.99:k = ceil(20*0.01 - 1e-12) = 1,仍是 0.052。对 alpha=0.999:k = ceil(20*0.001 - 1e-12) = 1,依然取最差档损失。保持输入顺序输出。
最近提交
还没有提交记录。
编码区
实现 solution(...)。本地运行当前支持 Python 可见样例;服务端提交会运行可见样例和隐藏测试。
默认展示公开样例。点击「运行样例」后会在这里显示实际输出;点击「提交评测」会进入隐藏测试。
Case 1 · worked example, two alphas
输入: [[0.012,-0.018,0.005,-0.025,0.014,-0.04,0.002,-0.011,0.008,-0.022],[0.95,0.99]]
期望: [0.04,0.04]
N=10。升序排序后 sorted = [-0.040, -0.025, -0.022, -0.018, -0.011, 0.002, 0.005, 0.008, 0.012, 0.014]。对 alpha=0.95:k = ceil(10*0.05 - 1e-12) = 1,VaR = -sorted[0] = 0.040。对 alpha=0.99:k = ceil(10*0.01 - 1e-12) = 1,VaR = -sorted[0] = 0.040。排序仅做一次,两个 alpha 共享。
Case 2 · dashboard alphas N=20
输入: [[0.005,-0.012,0.018,-0.035,0.022,-0.008,0.011,-0.044,0.029,-0.017,0.006,-0.025,0.014,-0.031,0.019,-0.009,0.024,-0.052,0.013,-0.021],[0.95,0.975,0.99,0.999]]
期望: [0.052,0.052,0.052,0.052]
N=20。排序后最差损失(最小 PnL)为 -0.052。对 alpha=0.95:k = ceil(20*0.05 - 1e-12) = 1,VaR = 0.052。对 alpha=0.975:k = ceil(20*0.025 - 1e-12) = 1,仍是 0.052。对 alpha=0.99:k = ceil(20*0.01 - 1e-12) = 1,仍是 0.052。对 alpha=0.999:k = ceil(20*0.001 - 1e-12) = 1,依然取最差档损失。保持输入顺序输出。