标准化 VaR 预测残差流:先去均值再除以波动率
Standardized VaR-Forecast Residual Stream — De-Mean Then Divide By Vol
开始编码实现 solution(realized_pnls: list[float], mean_forecast: list[float], vol_forecast: list[float]) -> list[float]。给定三条等长的日级序列——已实现 PnL、当日均值预测、当日波动率预测(注意是标准差,不是方差)——输出标准化残差序列
> z[t] = (realized_pnls[t] − mean_forecast[t]) / vol_forecast[t]
当 vol_forecast[t] == 0 时该索引的标准化无定义;合约是仅在该索引输出 float('nan'),其余索引按公式正常计算。空输入返回空列表。
例:solution([0.5, 1.2, -0.3], [0.0, 0.2, -0.1], [1.0, 2.0, 0.5]) 返回 [0.5, 0.5, -0.4]。第一日均值预测为 0、波动率为 1,所以 z_0 = 0.5;第二日把 1.2 去均值到 1.0,再除以 2.0 得 0.5;第三日把 −0.3 去均值到 −0.2,再除以 0.5 得 −0.4。把第二日的波动率换成 0,即 vol_forecast = [1.0, 0.0, 0.5],则返回 [0.5, nan, -0.4],只有索引 1 变成 NaN。
区分点都是合约性的,而非算法性的。(1) 先去均值再除:分子是 realized − mean,不是裸 realized;漏掉这一步得到的不是零均值序列,下游任何 PIT(概率积分变换)或 Berkowitz LR 检验都不会把它当作标准正态。(2) 除以波动率而非方差:vol_forecast[t] 是标准差,平方后会把残差再缩 vol 倍。(3) 零波动率是逐元素 NaN:仅在该索引输出 float('nan'),绝不能为了"稳定"把分母 clamp 到极小常数(这会掩盖"模型认为今天退化"的有意义信号),也绝不能全局传播或跳过该索引。(4) 输入顺序保持:output[t] 仅由 inputs[t] 决定;不排序、不重排、不去重。复杂度为 O(T) 时间、O(T) 输出空间。
函数骨架见 stubs/stub.py。
实践背景
标准化残差是 VaR 预测诊断里最基础的原语:PIT 检验、Kolmogorov–Smirnov 拟合优度检验、以及无条件 Berkowitz 似然比检验都从同一步骤起手——先用当日均值预测对已实现 PnL 做去均值,再除以当日波动率预测;在均值+波动率模型校准正确且新息服从高斯的前提下,得到的 z 序列应当是 i.i.d. N(0,1)。本题的四个陷阱恰好对应真实风控管线里最常见的四种 bug:漏掉去均值这一步(z 不再以零为中心)、把分母错写成方差(z 被过度收缩、看起来"过分漂亮")、用 epsilon clamp 把零波动率"修补"掉(诊断丢掉了"模型崩了"的真实告警)、把序列做了某种排序(下游自相关检验看到的不再是按日历对齐的序列)。把这条原语写对,是后续所有 VaR backtesting 套件能够开动的第一道兼容性检查。
约束条件
- 0 <= len(realized_pnls) == len(mean_forecast) == len(vol_forecast) <= 1500
- 每个 |realized_pnls[t]|, |mean_forecast[t]| <= 1e6
- 0.0 <= vol_forecast[t] <= 1e6(允许为 0,零波动率会触发逐元素 NaN 哨兵)
- 输出是与输入等长的浮点列表;每个元素或为有限带符号浮点数,或为 float('nan');空输入返回空列表
- 比较器:rel_tol = abs_tol = 1e-9;预期输出在某索引为 NaN 时,参与者输出在同一索引为 NaN 即视为匹配
样例
Case 1 · statement-example: zero-mean unit-vol day, plus demean and divide-by-2
输入: [[0.5,1.2,-0.3],[0,0.2,-0.1],[1,2,0.5]]
期望: [0.5,0.5,-0.39999999999999997]
第一日均值为 0、波动率为 1:z_0=0.5;第二日去均值得 1.0,再除以 2.0:z_1=0.5;第三日去均值得 -0.2,再除以 0.5:z_2=-0.4。
Case 2 · statement-example: zero-vol day -> per-element NaN sentinel only at that index
输入: [[0.5,1.2,-0.3],[0,0.2,-0.1],[1,0,0.5]]
期望: [0.5,"NaN",-0.39999999999999997]
索引 1 的 vol_forecast=0,仅该索引输出 NaN,其余索引按公式正常计算(0.5 与 -0.4)。
Case 3 · statement-example: empty inputs return empty list
输入: [[],[],[]]
期望: []
空输入直接返回空列表。
最近提交
还没有提交记录。
编码区
实现 solution(...)。本地运行当前支持 Python 可见样例;服务端提交会运行可见样例和隐藏测试。
默认展示公开样例。点击「运行样例」后会在这里显示实际输出;点击「提交评测」会进入隐藏测试。
Case 1 · statement-example: zero-mean unit-vol day, plus demean and divide-by-2
输入: [[0.5,1.2,-0.3],[0,0.2,-0.1],[1,2,0.5]]
期望: [0.5,0.5,-0.39999999999999997]
第一日均值为 0、波动率为 1:z_0=0.5;第二日去均值得 1.0,再除以 2.0:z_1=0.5;第三日去均值得 -0.2,再除以 0.5:z_2=-0.4。
Case 2 · statement-example: zero-vol day -> per-element NaN sentinel only at that index
输入: [[0.5,1.2,-0.3],[0,0.2,-0.1],[1,0,0.5]]
期望: [0.5,"NaN",-0.39999999999999997]
索引 1 的 vol_forecast=0,仅该索引输出 NaN,其余索引按公式正常计算(0.5 与 -0.4)。
Case 3 · statement-example: empty inputs return empty list
输入: [[],[],[]]
期望: []
空输入直接返回空列表。