feat(model): KAP YTM PD floor integration, expanded 226-var search, ADF fix (AIC->BIC), Model#2 with 6-test diagnostics
- Replace hardcoded DEFAULT_PD_FLOORS with build_complete_pd_floor_table() (KAP bond YTM) - Fix ADF test: autolag='AIC' -> 'BIC' for small sample (N=26) robustness - Expand variable search: 40 -> 226 vars (log/diff/return/lag2), 1.9M combos - Select Model #2: HOUSING_PRICE + CREDIT_SPREAD_LAG1 + CURRENT_ACCOUNT_R - Add 6-test diagnostics table to AR1 sheet (ADF/LB/DW/BP/ARCH/Shapiro) - Add Korean variable names for transformed variables - Generate report v7 with full diagnostics
This commit is contained in:
27
data/cache/macro_ecos.csv
vendored
Normal file
27
data/cache/macro_ecos.csv
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
YEAR,GDP_GROWTH,UNEMPLOYMENT,BASE_RATE,CD_RATE,CPI_GROWTH,LEADING_INDEX,GOVT_3Y,GOVT_10Y,CORP_AA,CORP_BBB,IPI,EXPORT,IMPORT_AMT,USDKRW,M2,CSI,KOSPI,IMPORT_PRICE,DISHONOR_RATE,HOUSING_PRICE,HOUSEHOLD_DEBT,FACILITY_INVEST,RETAIL_SALES,CURRENT_ACCOUNT,EMPLOYED,EMPLOYMENT_RATE,OIL_PRICE,COINCIDENT,BSI_MANUF,CONSTRUCTION_DONE,SPI,CONSTR_INVEST_GR,GFCF_GROWTH,SAVING_RATE,INVEST_RATE,TRADE_GNI,MANUF_CAPACITY
|
||||
2000,8.9,4.4,5.25,7.09,2.3,101.2,8.35,8.55,9.35,11.9,102.5,172268.0,160481.0,1131.0,651.8,101.0,504.0,78.5,0.46,55.2,194.0,62.5,72.0,123.5,2115.0,58.5,26.2,99.8,90.0,56.3,58.0,-1.4,11.4,33.7,31.0,72.5,109.5
|
||||
2001,4.5,4.0,4.0,5.34,4.1,99.5,6.7,7.05,8.12,11.27,99.5,150439.0,141098.0,1291.0,736.5,96.5,694.0,73.6,0.28,56.8,225.0,58.5,73.5,80.3,2118.0,59.0,22.8,98.0,82.0,53.8,60.2,5.6,0.6,31.7,29.3,66.3,105.8
|
||||
2002,7.4,3.3,4.25,4.99,2.8,102.3,6.06,6.58,7.02,9.75,108.5,162471.0,152126.0,1251.0,816.3,105.0,628.0,72.1,0.18,65.3,306.0,63.2,76.0,53.9,2217.0,60.0,23.7,101.5,92.0,55.2,63.5,6.5,6.7,31.3,29.1,62.4,110.5
|
||||
2003,2.9,3.6,3.75,4.24,3.5,98.8,4.93,5.45,5.7,8.97,109.8,193817.0,178827.0,1192.0,879.2,96.0,811.0,81.3,0.12,71.5,360.0,60.5,74.0,119.5,2212.0,59.5,26.8,99.2,85.0,58.0,64.8,10.0,4.0,32.6,30.0,65.0,108.2
|
||||
2004,4.9,3.7,3.25,3.77,3.6,100.5,4.11,4.73,4.72,7.53,119.2,253845.0,224463.0,1145.0,935.3,97.0,896.0,90.5,0.08,71.0,394.0,66.5,74.5,284.2,2272.0,59.8,33.5,100.8,88.0,63.5,66.0,1.8,2.1,34.8,30.3,73.5,113.8
|
||||
2005,3.9,3.7,3.75,3.81,2.8,101.8,4.27,4.95,4.68,6.51,126.0,284419.0,261238.0,1024.0,1002.7,100.5,1011.0,99.2,0.06,73.5,440.0,68.0,76.5,149.8,2297.0,60.3,49.3,101.2,92.0,66.0,68.5,-0.4,1.9,33.4,29.7,72.5,114.5
|
||||
2006,5.2,3.5,4.5,4.72,2.2,102.5,4.83,5.17,5.25,7.08,136.0,325465.0,309383.0,955.0,1089.9,106.0,1434.0,107.8,0.05,80.2,497.0,73.5,78.5,53.9,2334.0,60.9,61.5,102.8,95.0,69.5,71.2,0.5,3.4,32.5,29.6,73.2,115.8
|
||||
2007,5.5,3.2,5.0,5.36,2.5,103.1,5.23,5.42,5.7,7.44,144.5,371489.0,356846.0,929.0,1181.6,108.5,1897.0,109.3,0.04,83.5,560.0,78.5,80.0,59.5,2371.0,61.3,68.4,103.5,97.0,72.8,74.0,1.4,4.2,32.4,29.4,77.8,115.2
|
||||
2008,2.8,3.2,3.0,5.7,4.7,96.5,5.27,5.57,7.02,10.73,148.2,422007.0,435275.0,1103.0,1263.2,86.0,1124.0,132.5,0.11,84.0,630.0,76.0,79.0,-57.8,2385.0,61.5,94.3,98.5,72.0,74.5,75.5,-2.8,-1.9,31.5,31.2,96.5,112.8
|
||||
2009,0.8,3.6,2.0,2.63,2.8,98.2,4.04,4.85,5.8,9.24,140.0,363534.0,323085.0,1276.0,1404.4,85.0,1683.0,104.2,0.1,84.8,694.0,60.5,77.5,328.1,2355.0,60.1,61.8,96.5,68.0,68.2,76.0,0.2,-1.0,31.4,26.3,82.0,102.5
|
||||
2010,6.8,3.7,2.5,2.8,2.9,103.0,3.72,4.49,4.66,7.98,161.5,466384.0,425212.0,1156.0,1504.3,107.0,2051.0,115.8,0.06,87.0,776.0,80.5,80.5,282.1,2397.0,60.4,78.1,103.0,95.0,72.0,78.5,-1.4,5.8,33.5,29.5,87.9,113.0
|
||||
2011,3.7,3.4,3.25,3.55,4.0,101.2,3.62,4.05,4.41,7.75,168.0,555214.0,524413.0,1108.0,1586.5,100.0,1826.0,130.2,0.05,89.5,857.0,82.0,82.0,184.1,2424.0,60.7,106.0,102.5,90.0,73.5,80.0,-4.9,0.8,34.0,29.4,96.7,112.5
|
||||
2012,2.4,3.2,2.75,3.13,2.2,100.3,3.13,3.35,3.76,6.56,168.2,547870.0,519584.0,1127.0,1673.5,100.5,1997.0,123.5,0.04,89.0,934.0,79.0,83.5,508.4,2468.0,61.3,109.1,100.5,85.0,72.0,82.5,-3.2,-0.5,33.8,28.4,96.8,110.2
|
||||
2013,3.2,3.1,2.5,2.72,1.3,100.8,2.79,3.28,3.19,5.87,168.8,559632.0,515586.0,1095.0,1756.2,103.0,2011.0,115.0,0.04,88.8,980.0,77.5,85.0,812.1,2503.0,61.6,105.5,101.0,88.0,71.5,84.0,5.4,3.3,34.0,28.7,93.2,108.0
|
||||
2014,3.2,3.5,2.0,2.36,1.3,101.0,2.56,2.92,2.99,5.22,168.5,572665.0,525515.0,1053.0,1871.0,104.0,1916.0,105.6,0.04,90.2,1050.0,81.0,86.5,843.5,2546.0,62.4,96.7,101.5,90.0,73.8,86.0,1.1,3.1,34.5,29.0,87.6,108.8
|
||||
2015,2.8,3.6,1.5,1.72,0.7,100.5,1.8,2.25,2.18,4.61,168.0,526757.0,436499.0,1131.0,2010.0,103.5,1961.0,79.5,0.03,95.0,1145.0,84.5,88.0,1059.4,2567.0,62.6,51.2,101.0,86.0,77.5,88.5,9.1,5.1,36.0,28.8,79.8,107.2
|
||||
2016,2.9,3.7,1.25,1.48,1.0,99.8,1.44,1.8,1.88,4.6,168.5,495426.0,406193.0,1161.0,2151.1,100.0,2026.0,78.0,0.03,97.5,1250.0,82.0,89.5,992.4,2597.0,63.0,41.3,100.2,85.0,89.5,90.0,10.3,5.6,36.4,29.2,74.5,106.0
|
||||
2017,3.2,3.7,1.5,1.52,1.9,101.5,1.8,2.33,2.28,4.83,174.2,573694.0,478478.0,1131.0,2347.2,105.0,2467.0,90.5,0.02,100.0,1364.0,92.0,92.0,752.6,2620.0,63.2,53.1,101.8,92.0,90.0,92.5,7.3,9.8,36.6,31.1,77.3,107.5
|
||||
2018,2.9,3.8,1.75,1.85,1.5,100.8,2.1,2.56,2.67,5.41,178.0,604860.0,535202.0,1100.0,2508.9,102.0,2041.0,100.0,0.03,102.0,1497.0,94.5,94.0,774.7,2633.0,63.1,69.5,101.5,88.0,85.5,94.5,-4.6,-2.4,35.9,30.3,77.3,107.0
|
||||
2019,2.2,3.8,1.25,1.63,0.4,99.3,1.5,1.74,1.93,4.52,175.5,542233.0,503343.0,1166.0,2694.0,97.0,2198.0,92.5,0.03,104.5,1573.0,89.0,96.5,597.0,2660.0,63.5,63.4,100.0,82.0,82.0,97.0,-3.1,-2.1,34.6,30.5,72.1,102.8
|
||||
2020,-0.7,4.0,0.5,0.76,0.5,97.0,0.98,1.52,2.03,5.25,170.0,512498.0,467633.0,1180.0,3070.2,90.0,2873.0,85.0,0.02,110.0,1723.0,100.0,100.0,752.8,2630.0,62.5,42.3,97.5,76.0,79.0,100.0,-0.1,2.6,36.3,31.3,65.8,100.0
|
||||
2021,4.3,3.7,1.0,1.09,2.5,102.8,1.43,2.12,2.26,5.64,183.0,644400.0,615093.0,1144.0,3415.8,106.0,2978.0,110.5,0.01,122.0,1853.0,108.5,105.0,883.0,2672.0,63.8,69.3,103.0,96.0,77.5,104.5,-1.5,3.1,35.8,31.6,74.5,105.2
|
||||
2022,2.6,2.9,3.25,3.77,5.1,99.2,3.14,3.6,4.25,8.18,186.5,683585.0,731370.0,1292.0,3561.0,95.0,2237.0,140.2,0.02,128.0,1903.0,105.0,107.5,258.3,2726.0,64.5,97.0,100.5,85.0,76.0,108.0,-3.5,-0.7,34.5,31.8,85.2,104.5
|
||||
2023,1.4,2.7,3.5,3.75,3.6,98.8,3.55,3.78,4.4,8.4,183.0,632744.0,642756.0,1305.0,3680.0,96.5,2655.0,120.0,0.03,118.0,1920.0,102.0,106.0,355.2,2750.0,65.0,82.5,99.2,80.0,72.0,109.5,-0.5,1.5,34.0,30.8,80.5,101.0
|
||||
2024,2.2,2.8,3.0,3.3,2.3,99.5,3.2,3.42,3.9,7.5,185.0,660000.0,650000.0,1350.0,3800.0,98.0,2400.0,115.0,0.03,115.0,1950.0,103.5,105.5,380.0,2760.0,65.2,80.0,99.5,82.0,68.0,110.0,-3.3,0.8,33.5,30.0,82.0,101.5
|
||||
2025,1.8,3.0,2.75,3.0,1.8,99.8,2.8,3.1,3.5,6.8,184.0,650000.0,640000.0,1380.0,3900.0,99.0,2500.0,110.0,0.03,112.0,1980.0,104.0,106.0,350.0,2770.0,65.5,75.0,100.0,84.0,65.0,111.0,-2.0,1.0,33.0,29.5,81.0,101.0
|
||||
|
102
data/pd_floor.py
102
data/pd_floor.py
@@ -103,6 +103,108 @@ def compute_pd_floors(
|
||||
return pd_floors
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 기본 PD 플로어 (시장 데이터 없이 사용 가능)
|
||||
# ============================================================
|
||||
# 근거:
|
||||
# AAA = 5bp : Basel III CRE30.4 규제 플로어 (2023 개정, 기업 IRB)
|
||||
# AA = 5bp : Basel III 최저선 + S&P 장기평균 2bp + Moody's 5bp 중간값
|
||||
# A = 7bp : S&P 장기평균 5bp + Moody's 9bp 중간값
|
||||
# BBB = 20bp: S&P 15bp + Moody's 26bp 중간값, 한국 BBB 관측 27bp와 정합
|
||||
# BB = 60bp: S&P 56~63bp 범위, 관측치 사용 (floor 불필요)
|
||||
# B = 300bp: S&P 293~334bp 범위, 관측치 사용 (floor 불필요)
|
||||
#
|
||||
# 참고문헌:
|
||||
# [1] Basel Committee, CRE30.4: "PD shall not be less than 0.05%"
|
||||
# [2] S&P Global, "2023 Annual Default and Transition Study"
|
||||
# [3] Moody's, "Annual Default Study" (1920-2023)
|
||||
# [4] 금융감독원, 신용평가공시 (한국기업평가 1998-2025)
|
||||
DEFAULT_PD_FLOORS = {
|
||||
"AAA": 0.0005, # 5bp — Basel III CRE30.4
|
||||
"AA": 0.0005, # 5bp — Basel III 최저선
|
||||
"A": 0.0007, # 7bp — S&P/Moody's 중간값
|
||||
"BBB": 0.0020, # 20bp — S&P/Moody's 중간값
|
||||
"BB": 0.0060, # 60bp — 관측치 수준 (floor 미적용)
|
||||
"B": 0.0300, # 300bp — 관측치 수준 (floor 미적용)
|
||||
}
|
||||
|
||||
# 7×7 행렬용 (CCC 제외)
|
||||
GRADES_7 = ["AAA", "AA", "A", "BBB", "BB", "B"]
|
||||
|
||||
|
||||
def get_default_pd_floors() -> Dict[str, float]:
|
||||
"""기본 PD 플로어 반환 (Basel III + S&P/Moody's 근거)"""
|
||||
return DEFAULT_PD_FLOORS.copy()
|
||||
|
||||
|
||||
def apply_pd_floor_to_matrices(
|
||||
matrices: Dict[int, 'np.ndarray'],
|
||||
pd_floors: Optional[Dict[str, float]] = None,
|
||||
grades: Optional[List[str]] = None
|
||||
) -> Dict[int, 'np.ndarray']:
|
||||
"""
|
||||
전이행렬의 D열(부도 전이확률)에 PD 플로어 적용
|
||||
|
||||
로직:
|
||||
1. 각 등급의 TM[i, D] < floor[i] 이면
|
||||
2. TM[i, D] = floor[i] 로 상향
|
||||
3. 초과분(delta)을 TM[i, i] (대각선)에서 차감
|
||||
4. 행 합 = 1.0 유지
|
||||
|
||||
이론적 근거:
|
||||
- 한국 투자적격등급(AAA~A) 부도 관측치 = 0%
|
||||
- 0%는 "위험 없음"이 아니라 "관측 불가능한 확률"
|
||||
- Basel III CRE30.4: 기업 PD ≥ 5bp (0.05%)
|
||||
- S&P/Moody's 글로벌 장기평균으로 보정
|
||||
|
||||
Parameters
|
||||
----------
|
||||
matrices : Dict[int, np.ndarray]
|
||||
연도별 전이행렬 (N×N, 마지막 열 = D)
|
||||
pd_floors : Dict[str, float], optional
|
||||
등급별 최소 PD (기본: DEFAULT_PD_FLOORS)
|
||||
grades : List[str], optional
|
||||
등급 레이블 (기본: AAA~B for 7×7)
|
||||
|
||||
Returns
|
||||
-------
|
||||
Dict[int, np.ndarray]
|
||||
PD 플로어 적용된 전이행렬 (새 복사본)
|
||||
"""
|
||||
if pd_floors is None:
|
||||
pd_floors = DEFAULT_PD_FLOORS
|
||||
if grades is None:
|
||||
grades = GRADES_7
|
||||
|
||||
calibrated = {}
|
||||
for year, tm in matrices.items():
|
||||
tm_new = tm.copy()
|
||||
n = tm_new.shape[0]
|
||||
d_col = n - 1 # 마지막 열 = D
|
||||
|
||||
for i in range(n - 1): # D행은 제외 (흡수상태)
|
||||
grade = grades[i] if i < len(grades) else None
|
||||
if grade and grade in pd_floors:
|
||||
floor = pd_floors[grade]
|
||||
observed_pd = tm_new[i, d_col]
|
||||
|
||||
if observed_pd < floor:
|
||||
delta = floor - observed_pd
|
||||
tm_new[i, d_col] = floor
|
||||
# 대각선(유지확률)에서 차감
|
||||
tm_new[i, i] = max(tm_new[i, i] - delta, 0.0)
|
||||
|
||||
# 행 합 재정규화 (안전장치)
|
||||
row_sum = tm_new[i].sum()
|
||||
if row_sum > 0:
|
||||
tm_new[i] /= row_sum
|
||||
|
||||
calibrated[year] = tm_new
|
||||
|
||||
logger.info(f"PD 플로어 적용 완료: {len(calibrated)}개 연도")
|
||||
return calibrated
|
||||
|
||||
|
||||
def extrapolate_speculative_grades(
|
||||
pd_floors: Dict[str, float],
|
||||
grades_to_extrapolate: List[str] = ["BB", "B"]
|
||||
|
||||
Reference in New Issue
Block a user