← 返回编程题库
coding-weighted-historical-var-custom-weights中等免费版2000ms未尝试

自定义权重历史 VaR

Weighted Historical VaR with Custom Weights

开始编码

带调用方自定义权重的加权历史 VaR 是历史 VaR 家族的通用版——不再固定为等权重(每个观测 1/n)或固定的指数衰减表,而是让调用方传入任意非负权重方案。研究台可以按时间近度(类似 EWMA)、按流动性、按波动率体制、按事件重要性,乃至按隐藏状态的贝叶斯后验来加权;函数只负责接受通用的逐观测权重并返回加权分位数。请实现 solution(pnl_samples: list[float], weights: list[float], alpha: float) -> float。输入是未排序的 PnL 序列(带符号,正值=盈利)、长度相同的非负原始权重列表,以及 VaR 置信度 alpha。返回加权历史分位数 VaR,并以正的损失数值报告;序列为空或所有权重之和为零时返回 float('nan')

参考算法分四步。(1) 计算 total_w = sum(weights);若 n == 0total_w == 0 返回 NaN(无观测,或权重方案退化)。(2) 把每个 pnl_samples[i] 与归一化权重 w[i] = weights[i] / total_w 配对,使 sum(w) = 1。(3) 按 pnl 升序排序。(4) 从最小 pnl 开始累积权重,找最小的 k 使 cumulative_weight[k] >= (1 - alpha) - 1e-121e-12 epsilon 用于吸收加权和的 IEEE-754 漂移,与等权重历史 VaR 兄弟题口径一致)。输出 -sorted_pairs[k][0],让尾部为亏损时输出正数。整体复杂度是排序 O(n log n) 加上累积扫描的 O(n)。

solution([-0.05, 0.02, 0.01, -0.03, -0.02], [1.0, 1.0, 1.0, 4.0, 1.0], 0.8) 应返回 0.03。原始权重之和为 8.0,归一化后为 [0.125, 0.125, 0.125, 0.5, 0.125]。配对后按 pnl 升序排序得 (-0.05, 0.125), (-0.03, 0.5), (-0.02, 0.125), (0.01, 0.125), (0.02, 0.125),累积权重为 0.125, 0.625, 0.75, 0.875, 1.0alpha = 0.8 时阈值为 1 - 0.8 = 0.2k = 00.125 < 0.2 不够,k = 10.625 >= 0.2,所以阈值 pnl 是 -0.03,VaR 等于 0.03。注意:等权重下同一份数据的 VaR 是 0.05,因为最差的 -0.05 与其它观测同权重;这里把 -0.03 这笔的权重放大到 4.0,把分位数边界推到了它身上。

实践背景

自定义权重的实现里有四个常见正确性陷阱。第一,*必须归一化*:cum_w[k] >= 1 - alpha 这条阈值规则只有在总权重为 1 时成立;调用方传进来的权重和如果是 100,作者跳过 sum(weights) 这一除法,相当于在用 1 - 100*(1 - alpha_caller) 这个完全没有意义甚至自动满足的 alpha。框架无从猜测调用方的口径,所以必须由实现来归一化。第二,*排序方向*:pnl 必须升序——损失尾部是最左侧的累积切片。降序排序后再从顶部读取 (1 - alpha) 累积分位,会得到上方尾部,方向完全反了。

第三,1e-12 *epsilon 兜底* 与等权重兄弟题一致。在自定义权重下,累积和相对于闭式的 1 - alpha 可能漂移几个 ulp(尤其是大量小权重叠加时);少了 epsilon,cum_w[k] >= 1 - alpha 会在精确相等的边界判 false,让答案下标偏一。第四,*正损失输出*:返回值是 -sorted_pnls[k]k 是零基下标)。如果作者直接输出 sorted_pnls[k](少了负号),典型损失尾部就会得到一个负数,下游的红绿灯和违规检查会把它误判为盈利。

两个退化加权方案可以顺手当作 sanity check。所有权重相等(常数 c > 0)时,归一化得 1/n,问题退化为标准等权重历史 VaR——和等权重兄弟题给出的阈值完全一致。权重全部集中在某一个观测上时(仅一个正权重、其余为 0),累积扫描在那笔观测对应的排序位置就达标,结果完全由那笔观测的 pnl 决定。等值 PnL 的并列也无碍:并列簇内部顺序不影响簇末端的累积权重,因此阈值是良定的;Python 的稳定升序排序会取最小的那个 k

约束条件

  • 0 ≤ len(pnl_samples) == len(weights) ≤ 1500。当列表为空时返回 `float('nan')`。
  • |pnl_samples[i]| ≤ 1e6,均为有限浮点数。观测无需事先排序——你的排序步骤会把最差的损失放到最前。
  • 0.0 ≤ weights[i] ≤ 1e6。权重非负;函数内部归一化,所以任何正比例缩放都可接受。
  • 0.5 ≤ alpha < 1.0(常见 VaR 置信度:0.5、0.9、0.95、0.99、0.999)。
  • 阈值规则:按 pnl 升序排序后,从最小 pnl 累积归一化权重,取最小的 `k` 满足 `cumulative_weight[k] >= (1 - alpha) - 1e-12`。
  • VaR 输出为 `-sorted_pnls[k]`(`k` 是零基下标):阈值 pnl 是亏损时返回正的损失数值,阈值 pnl 是盈利时返回负数。`n == 0` 或 `sum(weights) == 0` 时返回 `float('nan')`。
  • 浮点容忍:rel_tol=1e-9,abs_tol=1e-9。

样例

Case 1 · statement-example, n=5 alpha=0.8 weight on -0.03

输入: [[-0.05,0.02,0.01,-0.03,-0.02],[1,1,1,4,1],0.8]

期望: 0.03

权重之和=8,归一化后 [0.125,0.125,0.125,0.5,0.125]。按 pnl 升序得 (-0.05,0.125),(-0.03,0.5),(-0.02,0.125),(0.01,0.125),(0.02,0.125);累积 0.125,0.625,0.75,0.875,1.0。alpha=0.8 -> 阈值 0.2,第一个满足的 k=1 对应 pnl=-0.03,VaR=0.03。

Case 2 · visible, n=4 alpha=0.95 equal weights collapse to equal-weighted historical VaR

输入: [[-0.04,-0.02,0.01,0.005],[3,3,3,3],0.95]

期望: 0.04

等权重 weights=[3,3,3,3],归一化后 1/4=0.25。排序后累积 0.25,0.5,0.75,1.0;alpha=0.95、阈值=0.05,第一个 k=0 处 0.25>=0.05 满足,对应 pnl=-0.04,VaR=0.04。

Case 3 · visible, n=4 alpha=0.95 weight concentrated on profitable obs

输入: [[-0.04,-0.02,0.01,0.005],[0,0,0,5],0.95]

期望: -0.005

权重全集中在 pnl=0.005 上;归一化后那笔权重=1,其余=0。排序后累积权重在 pnl=0.005 处第一次达到 0.05 阈值,VaR=-0.005。

Case 4 · visible, n=4 alpha=0.95 weight concentrated on worst loss

输入: [[-0.04,-0.02,0.01,0.005],[10,0,0,0],0.95]

期望: 0.04

权重全集中在最差损失 -0.04 上;归一化后该笔权重=1。排序后第一笔 pnl=-0.04 累积权重直接=1>=0.05,VaR=0.04。

Case 5 · boundary, n=0 empty returns NaN

输入: [[],[],0.95]

期望: "NaN"

n=0 时返回 NaN。

Case 6 · boundary, all-zero weights returns NaN

输入: [[-0.04,-0.02,0.01,0.005],[0,0,0,0],0.95]

期望: "NaN"

所有权重均为 0,归一化分母为 0,返回 NaN。

最近提交

还没有提交记录。

编码区

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

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

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

Case 1 · statement-example, n=5 alpha=0.8 weight on -0.03

输入: [[-0.05,0.02,0.01,-0.03,-0.02],[1,1,1,4,1],0.8]

期望: 0.03

权重之和=8,归一化后 [0.125,0.125,0.125,0.5,0.125]。按 pnl 升序得 (-0.05,0.125),(-0.03,0.5),(-0.02,0.125),(0.01,0.125),(0.02,0.125);累积 0.125,0.625,0.75,0.875,1.0。alpha=0.8 -> 阈值 0.2,第一个满足的 k=1 对应 pnl=-0.03,VaR=0.03。

Case 2 · visible, n=4 alpha=0.95 equal weights collapse to equal-weighted historical VaR

输入: [[-0.04,-0.02,0.01,0.005],[3,3,3,3],0.95]

期望: 0.04

等权重 weights=[3,3,3,3],归一化后 1/4=0.25。排序后累积 0.25,0.5,0.75,1.0;alpha=0.95、阈值=0.05,第一个 k=0 处 0.25>=0.05 满足,对应 pnl=-0.04,VaR=0.04。

Case 3 · visible, n=4 alpha=0.95 weight concentrated on profitable obs

输入: [[-0.04,-0.02,0.01,0.005],[0,0,0,5],0.95]

期望: -0.005

权重全集中在 pnl=0.005 上;归一化后那笔权重=1,其余=0。排序后累积权重在 pnl=0.005 处第一次达到 0.05 阈值,VaR=-0.005。

Case 4 · visible, n=4 alpha=0.95 weight concentrated on worst loss

输入: [[-0.04,-0.02,0.01,0.005],[10,0,0,0],0.95]

期望: 0.04

权重全集中在最差损失 -0.04 上;归一化后该笔权重=1。排序后第一笔 pnl=-0.04 累积权重直接=1>=0.05,VaR=0.04。

Case 5 · boundary, n=0 empty returns NaN

输入: [[],[],0.95]

期望: "NaN"

n=0 时返回 NaN。

Case 6 · boundary, all-zero weights returns NaN

输入: [[-0.04,-0.02,0.01,0.005],[0,0,0,0],0.95]

期望: "NaN"

所有权重均为 0,归一化分母为 0,返回 NaN。