由一因子高斯 Copula 的二元正态 CDF 计算两户违约相关系数
Pairwise Default Correlation from One-Factor Gaussian-Copula Bivariate-CDF Inputs
开始编码实现 solution(pd_a: float, pd_b: float, bivariate_normal_cdf_value: float) -> float。信贷风险台对每对对手方调用一次此函数,把预先算好的一因子高斯 Copula 联合违约概率转换成两户的违约相关系数,进而喂给组合级 Monte Carlo 与解析集中度调整。
输入:
pd_a—— 对手方 A 的单期无条件违约概率,落在[0, 1]。pd_b—— 对手方 B 的单期无条件违约概率,落在[0, 1]。bivariate_normal_cdf_value—— 一因子高斯 Copula 下的联合违约概率P[A 违约 且 B 违约],等于Phi_2(Phi^-1(pd_a), Phi^-1(pd_b); rho_asset)。调用方已经基于自己的资产相关性参数rho_asset算好这个二元正态 CDF;本函数只消费这个标量。
输出由如下可观测公式定义:
- 分子 —— 违约指示变量的协方差:
numerator = bivariate_normal_cdf_value - pd_a * pd_b。 - 分母 —— 两个单名伯努利标准差的乘积:
denominator = sqrt(pd_a * (1 - pd_a) * pd_b * (1 - pd_b))。 - 违约相关系数:
default_corr = numerator / denominator。带符号。
退化单名分布的哨兵:
- 若
pd_a == 0、pd_a == 1、pd_b == 0或pd_b == 1,对应的违约指示变量为常数,方差为零,分母为零,违约相关系数数学上未定义。返回float('nan')。
只要 pd_a 与 pd_b 都严格在 (0, 1) 区间内,分母严格为正,除法良定义。
例
solution(0.02, 0.03, 0.0006) 返回 0.0。pd_a = 0.02、pd_b = 0.03 而 bivariate_normal_cdf_value = 0.0006 = pd_a * pd_b,联合违约概率等于独立乘积,分子恰好为零,违约相关系数为零。这就是独立性基准——若调用方把 rho_asset = 0 传给自家 Phi_2,返回值就是 pd_a * pd_b,solution(...) 据此报出零违约相关。
同行业典型的正违约相关算例:solution(0.02, 0.03, 0.0012) 返回 (0.0012 - 0.0006) / sqrt(0.02 * 0.98 * 0.03 * 0.97) = 0.0006 / sqrt(0.000570360) = 0.0006 / 0.0238822... ≈ 0.025123...。即使联合概率相对独立的基准翻了一倍(从 6e-4 到 1.2e-3),违约相关系数也只有约 0.025——百分之二点五。这正是经典的高斯 Copula 效应:当 PD 很小时,一个温和的资产相关性只会驱动出小得多的违约相关性。结果为正,因为联合违约比独立基准更频繁。
**pd_a = 0 哨兵**算例:solution(0.0, 0.05, 0.0) 返回 float('nan')。对手方 A 违约概率为零,A 的违约指示变量恒为零,方差为零,分母为零,违约相关系数未定义。注意此时 bivariate_normal_cdf_value 必为零(因为 P[A 且 B] <= P[A] = 0),但即便输入互洽,函数也必须返回 NaN——哨兵是基于退化的单名分布,不是基于分子。
边界:pd_a 恰为 0 或 1 返回 NaN。pd_b 恰为 0 或 1 返回 NaN。当两个 PD 严格在 (0, 1) 时:bivariate_normal_cdf_value = pd_a * pd_b 返回 0(独立)。bivariate_normal_cdf_value > pd_a * pd_b 返回正数(正违约相关——典型情形)。bivariate_normal_cdf_value < pd_a * pd_b 返回负数(负违约相关——罕见的反周期情形)。本函数对约束区间内任何输入都不抛异常;NaN 哨兵是退化 pd in {0, 1} 四种情形的合同输出。
实现细节由 stubs/stub.py 提供。
实践背景
在一因子高斯 Copula 信贷模型——监管 IRB 资本和大多数解析与 Monte Carlo 组合信贷风险引擎背后的核心架构——里,资产相关性 rho_asset 通过二元正态 CDF Phi_2(Phi^-1(pd_a), Phi^-1(pd_b); rho_asset) 参数化联合违约概率。然而风险官并不在资产相关性空间里推理。他们在违约相关性空间里推理——也就是违约二元指示变量的相关系数,这才是真正控制组合违约损失方差的量。两者是非常不同的数:典型 0.20 的资产相关性(许多公司敞口的监管锚),在 PD 处于个位数百分比时,往往只对应 0.02 到 0.10 的违约相关性,因为伯努利方差 p*(1-p) 很小,二元正态 CDF 远比单看资产相关性所暗示的离独立乘积 pd_a * pd_b 更近。solution(pd_a, pd_b, bivariate_normal_cdf_value) 是这一转换的原语:它把调用方对 Phi_2 的求值结果作为标量吃进来(Phi_2 真正的数值积分留给调用方自己信赖的二元正态例程),返回违约相关系数;该值再喂给解析栈的下一阶段——组合损失方差、大组合渐近分布、一因子集中度调整,或者全程 Monte Carlo 用的两两相关矩阵。本函数刻意把以下几条概念约定显式化——分子是联合概率减去独立乘积(指示变量的协方差,不是联合概率本身)、分母是单名标准差而非方差的乘积、答案带符号且对反周期资产对可以为负、pd in {0, 1} 是数学 NaN 而不是 0——这些正是生产信贷风控代码反复抓到的方向性错误。纯 O(1) 实现(三次乘法、一次开方、一次减法、一次除法)就是标准原语;面对几百万对手方对的生产系统按同一递推式做向量广播,但每对的合同完全相同。
约束条件
- 0.0 <= pd_a <= 1.0
- 0.0 <= pd_b <= 1.0
- 0.0 <= bivariate_normal_cdf_value <= 1.0
- 输出:float ——带符号的违约相关系数,或当 pd_a in {0,1} 或 pd_b in {0,1} 时为 NaN
- 浮点比较器使用 rel_tol=1e-9, abs_tol=1e-9, nan_equals_nan=true
样例
Case 1 · statement-example: independence yields zero default correlation
输入: [0.02,0.03,0.0006]
期望: 0
pd_a*pd_b = 0.0006 = bivariate_cdf,分子 = 0,违约相关系数 = 0。独立性基准。
Case 2 · statement-example: positive default correlation typical of same-sector pair
输入: [0.02,0.03,0.0012]
期望: 0.025123302075452107
分子 = 0.0012 - 0.0006 = 0.0006;分母 = sqrt(0.02*0.98*0.03*0.97) = sqrt(0.000570360) ≈ 0.0238822;违约相关系数 ≈ 0.025123。
Case 3 · statement-example: pd_a equals zero returns NaN sentinel
输入: [0,0.05,0]
期望: "NaN"
pd_a = 0 -> A 的违约指示变量恒为零,方差为零,分母为零,违约相关系数未定义 -> NaN。
Case 4 · typical: equal-pd Frechet upper bound default_corr equals one
输入: [0.5,0.5,0.5]
期望: 1
pd_a = pd_b = 0.5 且 bivariate_cdf = 0.5 = min(pd_a, pd_b);A 与 B 完全同向,违约相关系数 = 1。
Case 5 · typical: equal-pd Frechet lower bound default_corr equals minus one
输入: [0.5,0.5,0]
期望: -1
pd_a = pd_b = 0.5 且 bivariate_cdf = 0;A 与 B 从不同时违约(Frechet 下界),违约相关系数 = -1。
Case 6 · typical: equal-pd independence yields zero default correlation
输入: [0.5,0.5,0.25]
期望: 0
pd_a*pd_b = 0.25 = bivariate_cdf;分子 = 0;违约相关系数 = 0。
Case 7 · typical: asymmetric pds joint twice the independent product
输入: [0.1,0.2,0.04]
期望: 0.1666666666666666
分子 = 0.04 - 0.02 = 0.02;分母 = sqrt(0.1*0.9*0.2*0.8) = sqrt(0.0144) = 0.12;违约相关系数 = 0.02/0.12 = 1/6。
Case 8 · typical: asymmetric pds at Frechet upper bound
输入: [0.1,0.2,0.1]
期望: 0.6666666666666665
min(pd_a, pd_b) = 0.1 = bivariate_cdf(Frechet 上界)。分子 = 0.1 - 0.02 = 0.08;分母 = sqrt(0.0144) = 0.12;违约相关系数 = 0.08/0.12 = 2/3。
Case 9 · typical: asymmetric pds independence
输入: [0.1,0.2,0.02]
期望: -2.891205793294678e-17
pd_a*pd_b = 0.02 = bivariate_cdf;违约相关系数 = 0(浮点残差在容差以内)。
Case 10 · typical: low pds with multiple-of-independence joint default
输入: [0.01,0.02,0.001]
期望: 0.05743073230052641
分子 = 0.001 - 0.0002 = 0.0008;分母 = sqrt(0.01*0.99*0.02*0.98) = sqrt(0.00019404) ≈ 0.01393;违约相关系数 ≈ 0.0574。
Case 11 · typical: negative default correlation counter-cyclical sector pair
输入: [0.3,0.4,0.05]
期望: -0.31180478223116176
分子 = 0.05 - 0.12 = -0.07;分母 = sqrt(0.3*0.7*0.4*0.6) = sqrt(0.0504) ≈ 0.22450;违约相关系数 ≈ -0.3118。
Case 12 · typical: high pds with negative default correlation
输入: [0.7,0.8,0.5]
期望: -0.32732683535398827
分子 = 0.5 - 0.56 = -0.06;分母 = sqrt(0.7*0.3*0.8*0.2) = sqrt(0.0336) ≈ 0.1833;违约相关系数 ≈ -0.3273。
Case 13 · typical: high pds with positive default correlation
输入: [0.7,0.8,0.65]
期望: 0.4909902530309833
分子 = 0.65 - 0.56 = 0.09;分母 = sqrt(0.0336) ≈ 0.1833;违约相关系数 ≈ 0.4910。
Case 14 · typical: high pds independence
输入: [0.7,0.8,0.56]
期望: 6.056763153128097e-16
pd_a*pd_b = 0.56 = bivariate_cdf;违约相关系数 = 0(浮点残差在容差以内)。
Case 15 · typical: very small pds joint five-times the independent product
输入: [0.001,0.002,0.00001]
期望: 0.00566535298820771
分子 = 1e-5 - 2e-6 = 8e-6;分母 = sqrt(0.001*0.999*0.002*0.998) ≈ 0.001412;违约相关系数 ≈ 0.005665。
Case 16 · boundary: pd_a equals one returns NaN sentinel
输入: [1,0.05,0.05]
期望: "NaN"
pd_a = 1 -> A 的违约指示变量恒为 1,方差为零,分母为零 -> NaN。
Case 17 · boundary: pd_b equals zero returns NaN sentinel
输入: [0.05,0,0]
期望: "NaN"
pd_b = 0 -> B 的违约指示变量恒为零,方差为零,分母为零 -> NaN。
Case 18 · boundary: pd_b equals one returns NaN sentinel
输入: [0.05,1,0.05]
期望: "NaN"
pd_b = 1 -> B 的违约指示变量恒为 1,方差为零 -> NaN。
Case 19 · boundary: both pds zero returns NaN sentinel
输入: [0,0,0]
期望: "NaN"
两个 pd 都为 0;两个指示变量都退化;NaN。
Case 20 · boundary: both pds one returns NaN sentinel
输入: [1,1,1]
期望: "NaN"
两个 pd 都为 1;两个指示变量都恒为 1;NaN。
最近提交
还没有提交记录。
编码区
实现 solution(...)。本地运行当前支持 Python 可见样例;服务端提交会运行可见样例和隐藏测试。
默认展示公开样例。点击「运行样例」后会在这里显示实际输出;点击「提交评测」会进入隐藏测试。
Case 1 · statement-example: independence yields zero default correlation
输入: [0.02,0.03,0.0006]
期望: 0
pd_a*pd_b = 0.0006 = bivariate_cdf,分子 = 0,违约相关系数 = 0。独立性基准。
Case 2 · statement-example: positive default correlation typical of same-sector pair
输入: [0.02,0.03,0.0012]
期望: 0.025123302075452107
分子 = 0.0012 - 0.0006 = 0.0006;分母 = sqrt(0.02*0.98*0.03*0.97) = sqrt(0.000570360) ≈ 0.0238822;违约相关系数 ≈ 0.025123。
Case 3 · statement-example: pd_a equals zero returns NaN sentinel
输入: [0,0.05,0]
期望: "NaN"
pd_a = 0 -> A 的违约指示变量恒为零,方差为零,分母为零,违约相关系数未定义 -> NaN。
Case 4 · typical: equal-pd Frechet upper bound default_corr equals one
输入: [0.5,0.5,0.5]
期望: 1
pd_a = pd_b = 0.5 且 bivariate_cdf = 0.5 = min(pd_a, pd_b);A 与 B 完全同向,违约相关系数 = 1。
Case 5 · typical: equal-pd Frechet lower bound default_corr equals minus one
输入: [0.5,0.5,0]
期望: -1
pd_a = pd_b = 0.5 且 bivariate_cdf = 0;A 与 B 从不同时违约(Frechet 下界),违约相关系数 = -1。
Case 6 · typical: equal-pd independence yields zero default correlation
输入: [0.5,0.5,0.25]
期望: 0
pd_a*pd_b = 0.25 = bivariate_cdf;分子 = 0;违约相关系数 = 0。
Case 7 · typical: asymmetric pds joint twice the independent product
输入: [0.1,0.2,0.04]
期望: 0.1666666666666666
分子 = 0.04 - 0.02 = 0.02;分母 = sqrt(0.1*0.9*0.2*0.8) = sqrt(0.0144) = 0.12;违约相关系数 = 0.02/0.12 = 1/6。
Case 8 · typical: asymmetric pds at Frechet upper bound
输入: [0.1,0.2,0.1]
期望: 0.6666666666666665
min(pd_a, pd_b) = 0.1 = bivariate_cdf(Frechet 上界)。分子 = 0.1 - 0.02 = 0.08;分母 = sqrt(0.0144) = 0.12;违约相关系数 = 0.08/0.12 = 2/3。
Case 9 · typical: asymmetric pds independence
输入: [0.1,0.2,0.02]
期望: -2.891205793294678e-17
pd_a*pd_b = 0.02 = bivariate_cdf;违约相关系数 = 0(浮点残差在容差以内)。
Case 10 · typical: low pds with multiple-of-independence joint default
输入: [0.01,0.02,0.001]
期望: 0.05743073230052641
分子 = 0.001 - 0.0002 = 0.0008;分母 = sqrt(0.01*0.99*0.02*0.98) = sqrt(0.00019404) ≈ 0.01393;违约相关系数 ≈ 0.0574。
Case 11 · typical: negative default correlation counter-cyclical sector pair
输入: [0.3,0.4,0.05]
期望: -0.31180478223116176
分子 = 0.05 - 0.12 = -0.07;分母 = sqrt(0.3*0.7*0.4*0.6) = sqrt(0.0504) ≈ 0.22450;违约相关系数 ≈ -0.3118。
Case 12 · typical: high pds with negative default correlation
输入: [0.7,0.8,0.5]
期望: -0.32732683535398827
分子 = 0.5 - 0.56 = -0.06;分母 = sqrt(0.7*0.3*0.8*0.2) = sqrt(0.0336) ≈ 0.1833;违约相关系数 ≈ -0.3273。
Case 13 · typical: high pds with positive default correlation
输入: [0.7,0.8,0.65]
期望: 0.4909902530309833
分子 = 0.65 - 0.56 = 0.09;分母 = sqrt(0.0336) ≈ 0.1833;违约相关系数 ≈ 0.4910。
Case 14 · typical: high pds independence
输入: [0.7,0.8,0.56]
期望: 6.056763153128097e-16
pd_a*pd_b = 0.56 = bivariate_cdf;违约相关系数 = 0(浮点残差在容差以内)。
Case 15 · typical: very small pds joint five-times the independent product
输入: [0.001,0.002,0.00001]
期望: 0.00566535298820771
分子 = 1e-5 - 2e-6 = 8e-6;分母 = sqrt(0.001*0.999*0.002*0.998) ≈ 0.001412;违约相关系数 ≈ 0.005665。
Case 16 · boundary: pd_a equals one returns NaN sentinel
输入: [1,0.05,0.05]
期望: "NaN"
pd_a = 1 -> A 的违约指示变量恒为 1,方差为零,分母为零 -> NaN。
Case 17 · boundary: pd_b equals zero returns NaN sentinel
输入: [0.05,0,0]
期望: "NaN"
pd_b = 0 -> B 的违约指示变量恒为零,方差为零,分母为零 -> NaN。
Case 18 · boundary: pd_b equals one returns NaN sentinel
输入: [0.05,1,0.05]
期望: "NaN"
pd_b = 1 -> B 的违约指示变量恒为 1,方差为零 -> NaN。
Case 19 · boundary: both pds zero returns NaN sentinel
输入: [0,0,0]
期望: "NaN"
两个 pd 都为 0;两个指示变量都退化;NaN。
Case 20 · boundary: both pds one returns NaN sentinel
输入: [1,1,1]
期望: "NaN"
两个 pd 都为 1;两个指示变量都恒为 1;NaN。