独立性假设下的双边 CVA 与 DVA:两条折现时间剖面求和
Bilateral CVA and DVA Under Independence: Two Discounted Time-Profile Sums
开始编码实现 solution(expected_exposure_profile: list[float], expected_negative_exposure_profile: list[float], counterparty_marginal_pd: list[float], own_marginal_pd: list[float], lgd_counterparty: float, lgd_own: float, discount_factors: list[float]) -> list[float]。某衍生品交易台对每个交易对手交易计算双边信用估值调整对:CVA(针对交易对手违约风险的费用)与 DVA(针对银行自身违约风险影响其负债的回加)。在 PD 与敞口独立(无错向风险)的假设下,
cva = lgd_counterparty * sum_{t=0..T-1} counterparty_marginal_pd[t] * expected_exposure_profile[t] * discount_factors[t]
dva = lgd_own * sum_{t=0..T-1} own_marginal_pd[t] * expected_negative_exposure_profile[t] * discount_factors[t]返回长度为 2 的 float 列表 [cva, dva]。CVA 反映的是当交易对手违约、交易对银行而言 MtM 为正(即对手欠银行)时银行的预期损失(EE 一侧、对手 PD 驱动时点);DVA 反映的是当银行自身违约、交易对银行而言 MtM 为负(即银行欠对手)时银行会计意义上的收益(ENE 一侧、自身 PD 驱动时点)。两条腿共享折现因子曲线和同一独立性假设,但其余部分平行计算。
输入有七个:expected_exposure_profile 是长度 T 的 per-period 美元 Expected POSITIVE Exposure 列表(若交易对手在第 t 期违约,对手会欠银行多少钱);expected_negative_exposure_profile 是对应的 Expected NEGATIVE Exposure 列表(若银行在第 t 期违约,银行会欠对手多少钱)—— 两者都是非负美元数(EE 与 ENE 的方向由名称区分、不由输入符号体现)。counterparty_marginal_pd 与 own_marginal_pd 是长度 T 的无条件边际违约概率列表,分别对应交易对手与银行自身(存活到 t-1 已内嵌)。lgd_counterparty 与 lgd_own 分别是两侧跨期保持常数的违约损失率。discount_factors 是长度 T 的 per-period 折现因子列表。返回 [cva, dva]。
DVA 以正数返回 —— 即 DVA 收益的美元金额。在 IFRS 13 / 现代会计下,当银行自身信用恶化(违约概率上升使所欠负债现值下降),DVA 作为一笔正的 PnL 入账。双边总公允价值调整是 cva - dva(CVA 为扣减、DVA 为回加),但本函数返回两条腿的原始值、不做净值;调用方可通过 result[0] - result[1] 自行净值。
算例
考虑一笔 3 期合约:expected_exposure_profile = [1_000_000, 900_000, 800_000]、expected_negative_exposure_profile = [600_000, 700_000, 500_000]、counterparty_marginal_pd = [0.02, 0.018, 0.016]、own_marginal_pd = [0.005, 0.006, 0.007]、lgd_counterparty = 0.6、lgd_own = 0.4、discount_factors = [exp(-0.05*1), exp(-0.05*2), exp(-0.05*3)] ≈ [0.95123, 0.90484, 0.86071]。
CVA 一侧(对手 PD 乘以 EE):
t=0:贡献= 0.02 * 1,000,000 * 0.95123 ≈ 19,024.59。t=1:贡献= 0.018 * 900,000 * 0.90484 ≈ 14,658.37。t=2:贡献= 0.016 * 800,000 * 0.86071 ≈ 11,017.06。- 求和
≈ 44,700.02,乘LGD_cp = 0.6→cva ≈ 26,820.01。
DVA 一侧(自身 PD 乘以 ENE):
t=0:贡献= 0.005 * 600,000 * 0.95123 ≈ 2,853.69。t=1:贡献= 0.006 * 700,000 * 0.90484 ≈ 3,800.32。t=2:贡献= 0.007 * 500,000 * 0.86071 ≈ 3,012.48。- 求和
≈ 9,666.48,乘LGD_own = 0.4→dva ≈ 3,866.59。
所以 solution(...) 返回 [26820.01, 3866.59]。双边净调整为 cva - dva ≈ 22,953.42,但函数返回原始 [cva, dva] 对、净值由调用方处理。
五个易错点
第一个易错点是 CVA 用对手 PD 与 EE;DVA 用自身 PD 与 ENE —— 不要混用。CVA 反映交易对手违约、交易对银行而言 MtM 为正(即对手欠银行)时的银行预期损失(EE 一侧、由对手 PD 驱动时点);DVA 反映银行自身违约、交易对银行而言 MtM 为负(即银行欠对手)时的会计收益(ENE 一侧、由自身 PD 驱动时点)。把 own_marginal_pd 用到 CVA 一侧、或把 counterparty_marginal_pd 用到 DVA 一侧都会得到语义反向的值。算例中,把 own_marginal_pd 误用到 CVA 一侧得到 ~8,677 而非 ~26,820 —— 在交易台日度费用上接近 3 倍偏差。
第二个易错点是 DVA 是收益、以正数返回。在 IFRS 13 / 现代会计下,当银行自身信用恶化(违约概率上升使所欠负债现值下降),DVA 作为一笔正的 PnL 入账。本函数返回 DVA 美元金额(非负 float),不返回带号 -dva、也不返回单标量净值 cva - dva。调用方可在外部用 bilateral_adjustment = result[0] - result[1] 净值。预先取负或预先做净值都违反契约。
第三个易错点是 **输出顺序为 [cva, dva]**。函数返回长度 2 的列表,CVA 在前、DVA 在后。把顺序翻成 [dva, cva] 会得到一对结构上看起来一样但语义错误的非负数 —— 是个隐蔽错误。
第四个易错点是 独立性假设 —— 无错向 / 正向风险。E[loss_t] = LGD_cp * PD_cp_t * EE_t 的因子分解要求 PD 与敞口独立,即无错向风险(DVA 一侧同理用自身 PD 与 ENE)。若两者相关(错向:某 FX 互换在交易对手本币信用恶化时敞口正好上升;正向:某对冲在交易对手违约时正好兑付),需加错向调整因子 —— 本题不建模错向 / 正向风险,独立性假设正是两条腿 per-period 乘积形式得以成立的依据。
第五个易错点是 每个 LGD 跨期常数、对整段求和统一相乘 —— 提到循环外,不要取幂。lgd_counterparty 跨期常数、乘到整个 CVA 求和上;lgd_own 跨期常数、乘到整个 DVA 求和上。把 LGD 当作每期取幂(如 LGD ** t,与折现混淆)或每期变化都会得到错的 CVA/DVA。最简形式为两条平行一行式:cva = LGD_cp * sum_t(PD_cp_t * EE_t * DF_t)、dva = LGD_own * sum_t(PD_own_t * ENE_t * DF_t)。
边界
T == 0返回[0.0, 0.0](空合约 —— 没有期可求和)。lgd_counterparty == 0.0返回[0.0, dva](对手全额回收 —— 无 CVA —— 但 DVA 仍照常算)。lgd_own == 0.0返回[cva, 0.0](自身全额回收 —— 无 DVA —— 但 CVA 仍照常算)。- 所有
counterparty_marginal_pd[t] == 0.0返回[0.0, dva](视野内零违约概率交易对手)。 - 所有
own_marginal_pd[t] == 0.0返回[cva, 0.0](视野内零违约概率本行)。 - 两条 PD 剖面或两个 LGD 都为 0 返回
[0.0, 0.0]。 T == 1退化为一期双边对:[lgd_cp * pd_cp[0] * ee[0] * df[0], lgd_own * pd_own[0] * ene[0] * df[0]]。
本函数不抛异常 —— 调用方保证七个输入形状一致、所有值在声明范围内。
期望算法:单遍 O(T) —— 一次扫过平行数组、把 pd_cp[t] * ee[t] * df[t] 与 pd_own[t] * ene[t] * df[t] 累加到两个求和器、最后各乘一次 LGD、返回 [cva, dva]。没有 off-by-one、没有嵌套循环、也没有超出普通浮点乘法的数值陷阱;T <= 60 足够小,求和顺序在 1e-9 容差下无关紧要。
实现细节由 stubs/stub.py 提供。
实践背景
双边 CVA-DVA 是单边 CVA 的对称扩展。除了银行向交易对手计提 CVA 作为对手违约风险费用之外,现代会计(IFRS 13)还认列 DVA:当银行自身信用恶化时,所欠衍生品负债的现值下降,这一下降作为正的 PnL 入账。一笔衍生品的双边总公允价值调整变为 cva - dva —— CVA 美元为扣减、DVA 美元为回加。各台每日把 [cva, dva] 这一对作为衍生品负债公允价值面板的一行用于会计与资本目的。独立形式(PD 与敞口之间无错向 / 正向风险)是教科书标准起点,也是 solution(...) 的计算目标。它与单边姊妹题 coding-unilateral-cva-independence(仅 CVA、无 DVA 一侧)、与存活加权 EE 姊妹题 coding-survival-weighted-ee-profile-for-cva(产出存活加权敞口剖面而非最终 CVA 标量)、以及与终生 EL 姊妹题 coding-lifetime-el-with-survival-weighting(聚合资产终生预期损失而非衍生品双边公允价值调整)皆有区别。
约束条件
- 0 <= T == len(expected_exposure_profile) == len(expected_negative_exposure_profile) == len(counterparty_marginal_pd) == len(own_marginal_pd) == len(discount_factors) <= 60
- 0.0 <= expected_exposure_profile[t]、expected_negative_exposure_profile[t] <= 1e9(per-period EE/ENE 美元、皆非负)
- 0.0 <= counterparty_marginal_pd[t]、own_marginal_pd[t] <= 1.0(per-period **无条件边际** PD;存活到 t-1 已内嵌)
- 0.0 <= lgd_counterparty、lgd_own <= 1.0(违约损失率,跨期保持常数)
- 0.0 < discount_factors[t] <= 1.0(per-period 折现因子,例如 exp(-r*t))
- 输出为长度 2 的 list[float]——`[cva, dva]`、皆非负;按 rel_tol=1e-9、abs_tol=1e-9 比对
样例
Case 1 · statement-example: T=3 swap-like, asymmetric LGDs and PDs
输入: [[1000000,900000,800000],[600000,700000,500000],[0.02,0.018,0.016],[0.005,0.006,0.007],0.6,0.4,[0.951229424500714,0.9048374180359595,0.8607079764250578]]
期望: [26820.01005626254,3866.59333869635]
T=3 算例:cva = 0.6 * sum(pd_cp[t]*ee[t]*df[t]) ~ 26820.01;dva = 0.4 * sum(pd_own[t]*ene[t]*df[t]) ~ 3866.59;以 [cva, dva] 返回。
Case 2 · typical: T=1 collapses to single-period bilateral pair
输入: [[1000000],[400000],[0.05],[0.02],0.6,0.4,[0.951229424500714]]
期望: [28536.882735021423,3043.934158402285]
T=1:cva = 0.6*0.05*1e6*exp(-0.05);dva = 0.4*0.02*4e5*exp(-0.05);皆单期。
Case 3 · boundary: T=0 empty deal returns [0.0, 0.0]
输入: [[],[],[],[],0.6,0.4,[]]
期望: [0,0]
T=0:没有期可求和,返回 [0.0, 0.0]。
Case 4 · boundary: lgd_counterparty=0 zeroes CVA but DVA still computed
输入: [[1000000,900000],[500000,400000],[0.04,0.03],[0.02,0.015],0,0.4,[0.95,0.9]]
期望: [0,5960]
lgd_cp=0:CVA 一侧归零;dva = 0.4*(0.02*5e5*0.95 + 0.015*4e5*0.9) = 0.4*(9500+5400)=5960。
Case 5 · boundary: lgd_own=0 zeroes DVA but CVA still computed
输入: [[1000000,900000],[500000,400000],[0.04,0.03],[0.02,0.015],0.6,0,[0.95,0.9]]
期望: [37380,0]
lgd_own=0:DVA 一侧归零;cva = 0.6*(0.04*1e6*0.95 + 0.03*9e5*0.9) = 0.6*(38000+24300)=37380。
Case 6 · boundary: all counterparty PD zero -> CVA=0 only
输入: [[1000000,900000,800000],[500000,400000,300000],[0,0,0],[0.01,0.01,0.01],0.6,0.4,[0.95,0.9,0.85]]
期望: [0,4360]
对手零违约:cva=0;dva = 0.4*(0.01*5e5*0.95+0.01*4e5*0.9+0.01*3e5*0.85) = 0.4*(4750+3600+2550)=4360。
Case 7 · boundary: all own PD zero -> DVA=0 only
输入: [[1000000,900000,800000],[500000,400000,300000],[0.02,0.015,0.012],[0,0,0],0.6,0.4,[0.95,0.9,0.85]]
期望: [23586,0]
本行零违约:dva=0;cva = 0.6*(0.02*1e6*0.95+0.015*9e5*0.9+0.012*8e5*0.85)=0.6*(19000+12150+8160)=23586。
Case 8 · boundary: both LGDs zero -> [0.0, 0.0]
输入: [[1000000,900000],[500000,400000],[0.04,0.03],[0.02,0.015],0,0,[0.95,0.9]]
期望: [0,0]
两个 LGD 都为 0:[0.0, 0.0]。
Case 9 · boundary: all EE zero -> CVA=0; DVA still computed from ENE
输入: [[0,0,0],[500000,400000,300000],[0.04,0.03,0.02],[0.02,0.015,0.012],0.6,0.4,[0.95,0.9,0.85]]
期望: [0,7184]
EE 全 0:cva=0(无正向敞口);dva = 0.4*(0.02*5e5*0.95+0.015*4e5*0.9+0.012*3e5*0.85)=0.4*(9500+5400+3060)=7184。
Case 10 · boundary: all ENE zero -> DVA=0; CVA still computed from EE
输入: [[1000000,900000,800000],[0,0,0],[0.04,0.03,0.02],[0.02,0.015,0.012],0.6,0.4,[0.95,0.9,0.85]]
期望: [45540,0]
ENE 全 0:dva=0(无负向敞口);cva = 0.6*(0.04*1e6*0.95+0.03*9e5*0.9+0.02*8e5*0.85)=0.6*(38000+24300+13600)=45540。
Case 11 · boundary: PD=1 and LGD<1 single period upper-bound case
输入: [[1000000],[500000],[1],[1],0.6,0.4,[1]]
期望: [600000,200000]
PD=1.0 立即违约近似:cva=0.6*1.0*1e6*1.0=6e5;dva=0.4*1.0*5e5*1.0=2e5。
Case 12 · boundary: both LGDs=1.0 zero recovery on both sides
输入: [[1000000,900000],[500000,400000],[0.04,0.03],[0.02,0.015],1,1,[0.95,0.9]]
期望: [62300,14900]
两侧 LGD=1:cva = 0.04*1e6*0.95+0.03*9e5*0.9 = 38000+24300 = 62300;dva = 0.02*5e5*0.95+0.015*4e5*0.9 = 9500+5400 = 14900。
Case 13 · typical: DF=1.0 (no discounting) — CVA/DVA collapse to undiscounted EL
输入: [[1000000,900000,800000],[500000,400000,300000],[0.02,0.015,0.012],[0.01,0.012,0.014],0.6,0.4,[1,1,1]]
期望: [25860,5600]
DF=1:cva = 0.6*(0.02*1e6+0.015*9e5+0.012*8e5)=0.6*(20000+13500+9600)=25860;dva = 0.4*(0.01*5e5+0.012*4e5+0.014*3e5)=0.4*(5000+4800+4200)=5600。
Case 14 · typical: T=5 risky CP, prime bank — CVA dominates DVA
输入: [[2000000,1800000,1500000,1200000,1000000],[300000,400000,500000,600000,700000],[0.05,0.045,0.04,0.035,0.03],[0.001,0.0012,0.0014,0.0016,0.0018],0.65,0.35,[0.97,0.94,0.91,0.88,0.85]]
期望: [188630,1153.25]
高风险对手(PD ~ 4%)与优质银行(PD ~ 0.15%):CVA 远大于 DVA —— 典型 IFRS-13 报告情形。
Case 15 · typical: symmetric inputs -> CVA == DVA (sanity bilateral symmetry)
输入: [[1000000,1000000,1000000,1000000],[1000000,1000000,1000000,1000000],[0.02,0.02,0.02,0.02],[0.02,0.02,0.02,0.02],0.5,0.5,[0.95,0.9,0.85,0.8]]
期望: [35000,35000]
EE/ENE 相同、PD 相同、LGD 相同 -> 构造上 cva==dva。
Case 16 · typical: T=2 simple round numbers, DF=1 LGD=0.5
输入: [[1000,2000],[500,1500],[0.1,0.1],[0.05,0.05],0.5,0.5,[1,1]]
期望: [150,50]
整数验证:cva = 0.5*(100+200)=150;dva = 0.5*(25+75)=50。
Case 17 · typical: T=2 minimal multi-period bilateral
输入: [[1000000,900000],[400000,500000],[0.02,0.018],[0.005,0.006],0.6,0.4,[0.95,0.9]]
期望: [20148,1840]
T=2 最小多期:cva = 0.6*(0.02*1e6*0.95+0.018*9e5*0.9)=0.6*(19000+14580)=20148;dva = 0.4*(0.005*4e5*0.95+0.006*5e5*0.9)=0.4*(1900+2700)=1840。
最近提交
还没有提交记录。
编码区
实现 solution(...)。本地运行当前支持 Python 可见样例;服务端提交会运行可见样例和隐藏测试。
默认展示公开样例。点击「运行样例」后会在这里显示实际输出;点击「提交评测」会进入隐藏测试。
Case 1 · statement-example: T=3 swap-like, asymmetric LGDs and PDs
输入: [[1000000,900000,800000],[600000,700000,500000],[0.02,0.018,0.016],[0.005,0.006,0.007],0.6,0.4,[0.951229424500714,0.9048374180359595,0.8607079764250578]]
期望: [26820.01005626254,3866.59333869635]
T=3 算例:cva = 0.6 * sum(pd_cp[t]*ee[t]*df[t]) ~ 26820.01;dva = 0.4 * sum(pd_own[t]*ene[t]*df[t]) ~ 3866.59;以 [cva, dva] 返回。
Case 2 · typical: T=1 collapses to single-period bilateral pair
输入: [[1000000],[400000],[0.05],[0.02],0.6,0.4,[0.951229424500714]]
期望: [28536.882735021423,3043.934158402285]
T=1:cva = 0.6*0.05*1e6*exp(-0.05);dva = 0.4*0.02*4e5*exp(-0.05);皆单期。
Case 3 · boundary: T=0 empty deal returns [0.0, 0.0]
输入: [[],[],[],[],0.6,0.4,[]]
期望: [0,0]
T=0:没有期可求和,返回 [0.0, 0.0]。
Case 4 · boundary: lgd_counterparty=0 zeroes CVA but DVA still computed
输入: [[1000000,900000],[500000,400000],[0.04,0.03],[0.02,0.015],0,0.4,[0.95,0.9]]
期望: [0,5960]
lgd_cp=0:CVA 一侧归零;dva = 0.4*(0.02*5e5*0.95 + 0.015*4e5*0.9) = 0.4*(9500+5400)=5960。
Case 5 · boundary: lgd_own=0 zeroes DVA but CVA still computed
输入: [[1000000,900000],[500000,400000],[0.04,0.03],[0.02,0.015],0.6,0,[0.95,0.9]]
期望: [37380,0]
lgd_own=0:DVA 一侧归零;cva = 0.6*(0.04*1e6*0.95 + 0.03*9e5*0.9) = 0.6*(38000+24300)=37380。
Case 6 · boundary: all counterparty PD zero -> CVA=0 only
输入: [[1000000,900000,800000],[500000,400000,300000],[0,0,0],[0.01,0.01,0.01],0.6,0.4,[0.95,0.9,0.85]]
期望: [0,4360]
对手零违约:cva=0;dva = 0.4*(0.01*5e5*0.95+0.01*4e5*0.9+0.01*3e5*0.85) = 0.4*(4750+3600+2550)=4360。
Case 7 · boundary: all own PD zero -> DVA=0 only
输入: [[1000000,900000,800000],[500000,400000,300000],[0.02,0.015,0.012],[0,0,0],0.6,0.4,[0.95,0.9,0.85]]
期望: [23586,0]
本行零违约:dva=0;cva = 0.6*(0.02*1e6*0.95+0.015*9e5*0.9+0.012*8e5*0.85)=0.6*(19000+12150+8160)=23586。
Case 8 · boundary: both LGDs zero -> [0.0, 0.0]
输入: [[1000000,900000],[500000,400000],[0.04,0.03],[0.02,0.015],0,0,[0.95,0.9]]
期望: [0,0]
两个 LGD 都为 0:[0.0, 0.0]。
Case 9 · boundary: all EE zero -> CVA=0; DVA still computed from ENE
输入: [[0,0,0],[500000,400000,300000],[0.04,0.03,0.02],[0.02,0.015,0.012],0.6,0.4,[0.95,0.9,0.85]]
期望: [0,7184]
EE 全 0:cva=0(无正向敞口);dva = 0.4*(0.02*5e5*0.95+0.015*4e5*0.9+0.012*3e5*0.85)=0.4*(9500+5400+3060)=7184。
Case 10 · boundary: all ENE zero -> DVA=0; CVA still computed from EE
输入: [[1000000,900000,800000],[0,0,0],[0.04,0.03,0.02],[0.02,0.015,0.012],0.6,0.4,[0.95,0.9,0.85]]
期望: [45540,0]
ENE 全 0:dva=0(无负向敞口);cva = 0.6*(0.04*1e6*0.95+0.03*9e5*0.9+0.02*8e5*0.85)=0.6*(38000+24300+13600)=45540。
Case 11 · boundary: PD=1 and LGD<1 single period upper-bound case
输入: [[1000000],[500000],[1],[1],0.6,0.4,[1]]
期望: [600000,200000]
PD=1.0 立即违约近似:cva=0.6*1.0*1e6*1.0=6e5;dva=0.4*1.0*5e5*1.0=2e5。
Case 12 · boundary: both LGDs=1.0 zero recovery on both sides
输入: [[1000000,900000],[500000,400000],[0.04,0.03],[0.02,0.015],1,1,[0.95,0.9]]
期望: [62300,14900]
两侧 LGD=1:cva = 0.04*1e6*0.95+0.03*9e5*0.9 = 38000+24300 = 62300;dva = 0.02*5e5*0.95+0.015*4e5*0.9 = 9500+5400 = 14900。
Case 13 · typical: DF=1.0 (no discounting) — CVA/DVA collapse to undiscounted EL
输入: [[1000000,900000,800000],[500000,400000,300000],[0.02,0.015,0.012],[0.01,0.012,0.014],0.6,0.4,[1,1,1]]
期望: [25860,5600]
DF=1:cva = 0.6*(0.02*1e6+0.015*9e5+0.012*8e5)=0.6*(20000+13500+9600)=25860;dva = 0.4*(0.01*5e5+0.012*4e5+0.014*3e5)=0.4*(5000+4800+4200)=5600。
Case 14 · typical: T=5 risky CP, prime bank — CVA dominates DVA
输入: [[2000000,1800000,1500000,1200000,1000000],[300000,400000,500000,600000,700000],[0.05,0.045,0.04,0.035,0.03],[0.001,0.0012,0.0014,0.0016,0.0018],0.65,0.35,[0.97,0.94,0.91,0.88,0.85]]
期望: [188630,1153.25]
高风险对手(PD ~ 4%)与优质银行(PD ~ 0.15%):CVA 远大于 DVA —— 典型 IFRS-13 报告情形。
Case 15 · typical: symmetric inputs -> CVA == DVA (sanity bilateral symmetry)
输入: [[1000000,1000000,1000000,1000000],[1000000,1000000,1000000,1000000],[0.02,0.02,0.02,0.02],[0.02,0.02,0.02,0.02],0.5,0.5,[0.95,0.9,0.85,0.8]]
期望: [35000,35000]
EE/ENE 相同、PD 相同、LGD 相同 -> 构造上 cva==dva。
Case 16 · typical: T=2 simple round numbers, DF=1 LGD=0.5
输入: [[1000,2000],[500,1500],[0.1,0.1],[0.05,0.05],0.5,0.5,[1,1]]
期望: [150,50]
整数验证:cva = 0.5*(100+200)=150;dva = 0.5*(25+75)=50。
Case 17 · typical: T=2 minimal multi-period bilateral
输入: [[1000000,900000],[400000,500000],[0.02,0.018],[0.005,0.006],0.6,0.4,[0.95,0.9]]
期望: [20148,1840]
T=2 最小多期:cva = 0.6*(0.02*1e6*0.95+0.018*9e5*0.9)=0.6*(19000+14580)=20148;dva = 0.4*(0.005*4e5*0.95+0.006*5e5*0.9)=0.4*(1900+2700)=1840。