← 返回编程题库
coding-christoffersen-independence-lr-test中等免费版1000ms未尝试

Christoffersen LR_ind 独立性统计量:VaR 回溯检验

Christoffersen LR_ind Independence Statistic for VaR Backtesting

开始编码

实现 solution(exceedance_indicator: list[int]) -> float。某风险台每日 VaR 回溯检验看板把这一例程与 Kupiec POF(无条件覆盖性)检验并列运行,作为 Christoffersen 联合检验的条件覆盖性分量。给定长度 T 的 0/1 指示序列(第 i 个元素为 1 当且仅当第 i 天发生 VaR 突破),返回 Christoffersen (1998) 独立性似然比统计量 LR_ind。在 i.i.d. 突破的零假设下 LR_ind 渐近服从 chi-square(1);当 LR_ind > 3.84 时按 95% 置信度拒绝 i.i.d. 假设。

闭式为

LR_ind = 2 * [ n00*ln(1 - p01) + n01*ln(p01)
             + n10*ln(1 - p11) + n11*ln(p11)
             - (n00 + n10)*ln(1 - p)
             - (n01 + n11)*ln(p) ]

其中四个转移计数对连续配对 i ∈ 1..T-1 求和:

  • n00 = #{ I[i-1]==0 且 I[i]==0 }
  • n01 = #{ I[i-1]==0 且 I[i]==1 }
  • n10 = #{ I[i-1]==1 且 I[i]==0 }
  • n11 = #{ I[i-1]==1 且 I[i]==1 }

无限制(一阶 Markov 链)MLE 为 p01 = n01 / (n00 + n01)p11 = n11 / (n10 + n11),受限(i.i.d. Bernoulli)MLE 为 p = (n01 + n11) / (n00 + n01 + n10 + n11)。约定 0 * ln(0) := 0(极限)适用于任何计数为 0 的项。

实现是 O(T) 单遍计数加 O(1) 统计量求值。

算例

solution([0, 0, 0, 0, 1, 1, 0, 0]) 返回 0.5991612825719415。逐步走七个连续配对:位置 (1,2,3) 给 (0,0);位置 4 给 (0,1);位置 5 给 (1,1);位置 6 给 (1,0);位置 7 给 (0,0)。计数:n00=4、n01=1、n10=1、n11=1。条件 MLE:p01 = 1/(4+1) = 0.2、p11 = 1/(1+1) = 0.5。无条件 MLE:p = (1+1)/(4+1+1+1) = 2/7。LR_ind = 2 * [4*ln(0.8) + 1*ln(0.2) + 1*ln(0.5) + 1*ln(0.5) - 5*ln(5/7) - 2*ln(2/7)] ≈ 0.5992。远低于 3.84——尽管视觉上明显聚集,样本太小仍无法拒绝独立性。

五个易错点

第一配对计数与边际计数。n00、n01、n10、n11 是连续配对的计数,不是 0 与 1 的总数。把 count_0 = sum(1 for x in arr if x==0) 塞进 Kupiec 风格闭式的写法复刻的是错的检验(无条件覆盖性,而非条件独立性)。LR_ind 的整个意义在于检测聚集——这是时序的属性,不是边际率的属性。

第二条件概率方向p01 = n01 / (n00 + n01),分母是 FROM-state 的总流出(所有以 0 起头的配对)。写成 p01 = n01 / total_pairs 得到的是联合概率 P(I_{t-1}=0, I_t=1),不是条件概率 P(I_t=1 | I_{t-1}=0),所得统计量在零假设下不收敛到 chi-square(1)。

第三,**计数边界处的 0 * ln(0)**。当 n00、n01、n10、n11 中任一为 0 时,对应 count * ln(p) 项即 0 * ln(0)。Python 直接算 0 * math.log(0) = 0 * (-inf) = NaN 把结果污染;须在计数为 0 时分支跳过。在完全无突破(已是稀疏哨兵)时受限项 (n01 + n11) * ln(p) 也会撞同一陷阱;在每天都突破(同样稀疏哨兵)时 (n00 + n10) * ln(1-p) 也会。

第四系数 2。与 Kupiec POF 姊妹同:LR_ind = 2 * [ ... ]。系数减半在正确阈值处无法越过 chi-square(1) 临界值;写 -2 * 产生负值并破坏 LR_ind >= 0 不变量。

第五求和符号混合。公式为 + 无限制 - 受限:四个 n_ij * ln(...) 项(无条件 Markov MLE 下)取正号,两个 (n_._ + n_._) * ln(...) 项(受限 i.i.d. MLE 下)取负号。翻转任一子集得到的是另一个(无意义的)统计量。

哨兵与边界

T < 2:连续配对不足;返回 float('nan')。覆盖空列表与单元素列表。

(n00 + n01) == 0(n10 + n11) == 0:至少一个 from-state 没有任何观测到的流出,其条件概率为 0/0。返回 float('nan')——数据过稀疏,无法检验独立性。这一分支同时覆盖全零(state 1 无流出)、全一(state 0 无流出)、仅末位为 1 的 [0,...,0,1](state 1 无流出)。注意非对称情形 [1, 0, ..., 0](长度 > 2):state 1 恰好贡献一个 (1,0) 转移,故 n10 + n11 = 1 > 0触发稀疏哨兵;该输入下 p01 = p11 = p = 0,所有 count*ln(...) 项要么计数为 0、要么对数为 ln(1) = 0,统计量 LR_ind = 0.0——见对应边界测试。

当无限制 MLE 与受限 MLE 重合(p01 == p11 == p)时,统计量恰为 0——无证据反对独立性。在 [0,0,1,1,0] 上验证:n00=n01=n10=n11=1,三个概率都等于 0.5,LR_ind = 0.0。

实践背景

Christoffersen (1998) 提出 LR_ind 来与 Kupiec POF 检验互补,置于 VaR 回溯检验看板上。即便边际突破率与理论率匹配(Kupiec 通过),突破仍可能在时间上聚集——例如全年的突破额度集中在某个糟糕的一周,违反 VaR 内置的 i.i.d. 假设。LR_ind 通过检验 P(I_t=1 | I_{t-1}=0) ≠ P(I_t=1 | I_{t-1}=1) 来检测聚集。组合后的 Christoffersen Conditional Coverage 统计量 LR_cc = LR_uc + LR_ind(自由度 2 的 chi-square)是标准联合回溯检验。本题是题库的独立性检验姊妹——区别于 Basel 红绿灯分区分类器(分类、无统计检验)、突破集群计数例程(仅描述)、Kupiec POF 似然比(无条件覆盖性、边际率)。

约束条件

  • 0 <= len(exceedance_indicator) <= 1500(T ∈ [0, 1500])
  • exceedance_indicator[i] in {0, 1}(每个元素严格为 0 或 1)
  • 输出:float —— 非负 LR_ind 统计量,或 `float('nan')`(T<2 或某 from-state 流出为 0,即数据过稀疏);rel_tol=1e-9、abs_tol=1e-9;NaN 与 NaN 视为相等

样例

Case 1 · statement-example: clustered window with 2 exceedances

输入: [[0,0,0,0,1,1,0,0]]

期望: 0.5991612825719415

8 天窗口里有一段连续 2 个突破。配对计数:n00=4、n01=1、n10=1、n11=1。p01=1/5=0.2,p11=1/2=0.5,p=2/7。LR_ind=2*[4*ln(0.8)+1*ln(0.2)+1*ln(0.5)+1*ln(0.5)-(4+1)*ln(5/7)-(1+1)*ln(2/7)] 约 0.5992。低于 chi-square(1) 95% 临界值 3.84——样本太小,无法拒绝独立性。

Case 2 · visible: T=1 below minimum pair count

输入: [[1]]

期望: "NaN"

T=1 没有任何连续配对,无限制 MLE 为 0/0。返回 float('nan')。空列表返回同样的 NaN。

Case 3 · visible: all-zeros 50-day window

输入: [[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]]

期望: "NaN"

完全没有突破:n10+n11=0(state 1 无任何流出),p11 为 0/0。返回 float('nan')——数据过稀疏,无法检验独立性。漏掉该哨兵的写法要么除零崩溃,要么把 0*ln(0) 喂进 math.log 误打误撞返回 NaN(对的答案、错的原因;后面的对抗测试会抓到)。

Case 4 · visible: independence collapse p01==p11==p yields LR_ind=0

输入: [[0,0,1,1,0]]

期望: 0

配对计数:n00=1、n01=1、n10=1、n11=1。则 p01=1/2、p11=1/2、p=2/4=1/2——三个概率重合,无限制与受限对数似然相等,LR_ind 严格塌缩为 0.0。校验独立性零假设的不动点。

Case 5 · visible: alternating 0,1,0,1,0,1,0,1 anti-clustered

输入: [[0,1,0,1,0,1,0,1]]

期望: 9.560713465806604

完全反聚集。配对计数:n00=0、n01=4、n10=3、n11=0。p01=1、p11=0、p=4/7。无限制似然恰好(链是确定性的),受限似然远离:LR_ind 约 9.561。超过 3.84——尽管边际突破率正好 50%,检验仍正确拒绝 i.i.d. 零假设。

最近提交

还没有提交记录。

编码区

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

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

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

Case 1 · statement-example: clustered window with 2 exceedances

输入: [[0,0,0,0,1,1,0,0]]

期望: 0.5991612825719415

8 天窗口里有一段连续 2 个突破。配对计数:n00=4、n01=1、n10=1、n11=1。p01=1/5=0.2,p11=1/2=0.5,p=2/7。LR_ind=2*[4*ln(0.8)+1*ln(0.2)+1*ln(0.5)+1*ln(0.5)-(4+1)*ln(5/7)-(1+1)*ln(2/7)] 约 0.5992。低于 chi-square(1) 95% 临界值 3.84——样本太小,无法拒绝独立性。

Case 2 · visible: T=1 below minimum pair count

输入: [[1]]

期望: "NaN"

T=1 没有任何连续配对,无限制 MLE 为 0/0。返回 float('nan')。空列表返回同样的 NaN。

Case 3 · visible: all-zeros 50-day window

输入: [[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]]

期望: "NaN"

完全没有突破:n10+n11=0(state 1 无任何流出),p11 为 0/0。返回 float('nan')——数据过稀疏,无法检验独立性。漏掉该哨兵的写法要么除零崩溃,要么把 0*ln(0) 喂进 math.log 误打误撞返回 NaN(对的答案、错的原因;后面的对抗测试会抓到)。

Case 4 · visible: independence collapse p01==p11==p yields LR_ind=0

输入: [[0,0,1,1,0]]

期望: 0

配对计数:n00=1、n01=1、n10=1、n11=1。则 p01=1/2、p11=1/2、p=2/4=1/2——三个概率重合,无限制与受限对数似然相等,LR_ind 严格塌缩为 0.0。校验独立性零假设的不动点。

Case 5 · visible: alternating 0,1,0,1,0,1,0,1 anti-clustered

输入: [[0,1,0,1,0,1,0,1]]

期望: 9.560713465806604

完全反聚集。配对计数:n00=0、n01=4、n10=3、n11=0。p01=1、p11=0、p=4/7。无限制似然恰好(链是确定性的),受限似然远离:LR_ind 约 9.561。超过 3.84——尽管边际突破率正好 50%,检验仍正确拒绝 i.i.d. 零假设。