fix(critical): complete Zt sign alignment across all modules
Fixed ALL instances of (d - sqrt_rho*z) -> (d + sqrt_rho*z): - models/vasicek.py: conditional_transition_matrix() (used by lifetime PD) - data/transition_matrices.py: _generate_model_consistent_matrix() - models/credit_cycle.py: already fixed in previous commit Added sign convention docs: - vasicek.py conditional_pd() uses Basel convention (Z↑=loss↑) - conditional_transition_matrix() uses Belkin convention (Z↑=호황) - Both conventions documented in module docstrings Pipeline 8/8 validation pass after fix
This commit is contained in:
@@ -128,18 +128,18 @@ def _generate_model_consistent_matrix(
|
|||||||
cum_prob_clipped = np.clip(cum_prob, 1e-10, 1.0 - 1e-10)
|
cum_prob_clipped = np.clip(cum_prob, 1e-10, 1.0 - 1e-10)
|
||||||
thresholds[i, j] = norm.ppf(cum_prob_clipped)
|
thresholds[i, j] = norm.ppf(cum_prob_clipped)
|
||||||
|
|
||||||
# 2. Z-조건부 전이확률 계산
|
# 2. Z-조건부 전이확률 계산 (Belkin convention: Z>0 = 호황)
|
||||||
cond_tm = np.zeros((n, n))
|
cond_tm = np.zeros((n, n))
|
||||||
for i in range(n - 1):
|
for i in range(n - 1):
|
||||||
for j in range(n):
|
for j in range(n):
|
||||||
d_upper = thresholds[i, j]
|
d_upper = thresholds[i, j]
|
||||||
upper = norm.cdf((d_upper - sqrt_rho * z) / sqrt_1_rho)
|
upper = norm.cdf((d_upper + sqrt_rho * z) / sqrt_1_rho)
|
||||||
|
|
||||||
if j == 0:
|
if j == 0:
|
||||||
lower = 0.0
|
lower = 0.0
|
||||||
else:
|
else:
|
||||||
d_lower = thresholds[i, j - 1]
|
d_lower = thresholds[i, j - 1]
|
||||||
lower = norm.cdf((d_lower - sqrt_rho * z) / sqrt_1_rho)
|
lower = norm.cdf((d_lower + sqrt_rho * z) / sqrt_1_rho)
|
||||||
|
|
||||||
cond_tm[i, j] = max(upper - lower, 0.0)
|
cond_tm[i, j] = max(upper - lower, 0.0)
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,12 @@
|
|||||||
"""
|
"""
|
||||||
Vasicek 단일팩터 모델 기반 조건부 PD 및 전이행렬 모듈
|
Vasicek 단일팩터 모델 기반 조건부 PD 및 전이행렬 모듈
|
||||||
|
|
||||||
핵심 공식:
|
핵심 공식 (Basel/Vasicek convention: Z↑ = loss↑ = 불황):
|
||||||
PD_PIT(Z) = Φ( (Φ⁻¹(PD_TTC) - √ρ · Z) / √(1-ρ) )
|
PD_PIT(Z) = Φ( (Φ⁻¹(PD_TTC) - √ρ · Z) / √(1-ρ) )
|
||||||
|
|
||||||
|
주의: Belkin & Suchower에서는 Z↑ = 호황 (반대 부호).
|
||||||
|
조건부 전이행렬은 Belkin convention 사용 (d + √ρ·Z).
|
||||||
|
|
||||||
이 모듈은 Belkin & Suchower의 임계값 방식 대신,
|
이 모듈은 Belkin & Suchower의 임계값 방식 대신,
|
||||||
Vasicek 공식을 직접 적용하는 간편 버전도 제공합니다.
|
Vasicek 공식을 직접 적용하는 간편 버전도 제공합니다.
|
||||||
|
|
||||||
@@ -27,6 +30,9 @@ def conditional_pd(pd_ttc: float, z: float, rho: float) -> float:
|
|||||||
|
|
||||||
PD_PIT(Z) = Φ( (Φ⁻¹(PD_TTC) - √ρ · Z) / √(1-ρ) )
|
PD_PIT(Z) = Φ( (Φ⁻¹(PD_TTC) - √ρ · Z) / √(1-ρ) )
|
||||||
|
|
||||||
|
주의: 이 함수의 Z는 Basel/Vasicek convention (Z↑ = 불황).
|
||||||
|
Belkin Z(양수=호황)를 사용하려면 -Z를 넣어야 합니다.
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
pd_ttc : float - TTC (Through-the-Cycle) 부도확률
|
pd_ttc : float - TTC (Through-the-Cycle) 부도확률
|
||||||
@@ -110,18 +116,19 @@ def conditional_transition_matrix(
|
|||||||
thresholds[i, j] = norm.ppf(cum_prob_clipped)
|
thresholds[i, j] = norm.ppf(cum_prob_clipped)
|
||||||
|
|
||||||
# 조건부 전이행렬 계산
|
# 조건부 전이행렬 계산
|
||||||
|
# Belkin convention: Z>0 = 호황, 누적확률 오름차순 → (d + √ρ·Z)
|
||||||
cond_tm = np.zeros((n, n))
|
cond_tm = np.zeros((n, n))
|
||||||
|
|
||||||
for i in range(n - 1):
|
for i in range(n - 1):
|
||||||
for j in range(n):
|
for j in range(n):
|
||||||
d_upper = thresholds[i, j]
|
d_upper = thresholds[i, j]
|
||||||
upper = norm.cdf((d_upper - sqrt_rho * z) / sqrt_1_rho)
|
upper = norm.cdf((d_upper + sqrt_rho * z) / sqrt_1_rho)
|
||||||
|
|
||||||
if j == 0:
|
if j == 0:
|
||||||
lower = 0.0
|
lower = 0.0
|
||||||
else:
|
else:
|
||||||
d_lower = thresholds[i, j - 1]
|
d_lower = thresholds[i, j - 1]
|
||||||
lower = norm.cdf((d_lower - sqrt_rho * z) / sqrt_1_rho)
|
lower = norm.cdf((d_lower + sqrt_rho * z) / sqrt_1_rho)
|
||||||
|
|
||||||
cond_tm[i, j] = max(upper - lower, 0.0)
|
cond_tm[i, j] = max(upper - lower, 0.0)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user