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:
Variet Agent
2026-03-12 00:06:23 +09:00
parent 87725b7c19
commit d1ddf06e5d
19 changed files with 1736 additions and 167 deletions

35
main.py
View File

@@ -103,18 +103,38 @@ def main():
tm_source = data_config.get("transition_source", "builtin")
tm_dir = data_config.get("transition_dir", None)
logger.info(f"전이행렬 로딩 중 (source={tm_source})...")
transition_matrices = load_transition_matrices(tm_source, data_dir=tm_dir)
transition_matrices_all = load_transition_matrices(tm_source, data_dir=tm_dir)
# 2000-2025 필터
transition_matrices_raw = {y:m for y,m in transition_matrices_all.items() if 2000 <= y <= 2025}
# PD 플로어 적용: KAP 채권 YTM 기반 시장내재 PD
from data.pd_floor import apply_pd_floor_to_matrices, build_complete_pd_floor_table
pd_floors_broad, _, pd_floors_full = build_complete_pd_floor_table()
transition_matrices = apply_pd_floor_to_matrices(transition_matrices_raw, pd_floors_broad)
ttc_matrix = compute_ttc_matrix(transition_matrices)
default_rates = get_default_rates(transition_matrices)
print(f"\n 전이행렬: {len(transition_matrices)}개 연도 ({min(transition_matrices.keys())}~{max(transition_matrices.keys())})"
f" [source={tm_source}]")
print(display_matrix(ttc_matrix, "TTC 전이행렬 (장기 평균)"))
print(f" PD 플로어 (KAP 채권 YTM 기반): AAA={pd_floors_broad['AAA']*10000:.0f}bp, AA={pd_floors_broad['AA']*10000:.0f}bp, "
f"A={pd_floors_broad['A']*10000:.0f}bp, BBB={pd_floors_broad['BBB']*10000:.0f}bp")
print(display_matrix(ttc_matrix, "TTC 전이행렬 (KAP PD Floor 적용 후 장기 평균)"))
# 거시경제변수
if args.no_api:
logger.info("Fallback 거시경제 데이터 사용")
macro_data = _fallback_macro_data()
# ECOS fallback 데이터도 병합 (37개 변수)
try:
from data.ecos_fetcher import load_macro_data as load_ecos_macro
ecos_data = load_ecos_macro()
if ecos_data is not None and not ecos_data.empty:
macro_data = pd.concat([macro_data, ecos_data], axis=1)
macro_data = macro_data.loc[:, ~macro_data.columns.duplicated()]
logger.info(f"ECOS fallback 병합 완료: {len(macro_data.columns)}개 변수")
except Exception as e:
logger.warning(f"ECOS fallback 병합 실패: {e}")
else:
macro_data = load_macro_data(args.config)
@@ -167,10 +187,19 @@ def main():
model_input = macro_data
forced_vars = config.get("model", {}).get("macro_vars", None)
macro_model = build_macro_zt_model(zt_dict, model_input, method="stepwise_aic",
macro_method = config.get("model", {}).get("macro_method", "ar1_macro")
macro_model = build_macro_zt_model(zt_dict, model_input, method=macro_method,
forced_vars=forced_vars)
print(f"\n 선택된 변수: {macro_model.selected_vars}")
if macro_model.is_ar1:
import math
phi = macro_model.ar1_phi
half_life = math.log(2) / abs(math.log(abs(phi))) if 0 < abs(phi) < 1 else float('inf')
print(f" [AR(1)+Macro] φ = {phi:.4f} (반감기 = {half_life:.1f}년)")
print(f" c = {macro_model.ar1_const:.4f}")
for var, beta in macro_model.ar1_beta.items():
print(f" β({var}) = {beta:+.6f}")
print(macro_model.summary())
diag = macro_model.diagnostics()