feat: initial project setup - Merton-KMV model, data pipeline, .agents workflows
This commit is contained in:
827
docs/technical_methodology.md
Normal file
827
docs/technical_methodology.md
Normal file
@@ -0,0 +1,827 @@
|
||||
# 주식 변동성 기반 등급별 부도율 산출 — 기술 문서
|
||||
|
||||
> **프로젝트**: KRX 상장 한국 기업 대상 Equity Volatility → Default Rate by Rating
|
||||
> **작성일**: 2026-03-11
|
||||
> **버전**: v0.1 (초안)
|
||||
|
||||
---
|
||||
|
||||
## 목차
|
||||
|
||||
1. [이론적 기초](#1-이론적-기초)
|
||||
2. [핵심 수학적 프레임워크](#2-핵심-수학적-프레임워크)
|
||||
3. [한국 시장 등급 관측 문제 및 대안](#3-한국-시장-등급-관측-문제-및-대안)
|
||||
4. [글로벌 접근 방법론 비교](#4-글로벌-접근-방법론-비교)
|
||||
5. [구현 아키텍처](#5-구현-아키텍처)
|
||||
6. [데이터 명세](#6-데이터-명세)
|
||||
7. [알고리즘 상세](#7-알고리즘-상세)
|
||||
8. [검증 방법론](#8-검증-방법론)
|
||||
9. [한국 시장 특수 고려사항](#9-한국-시장-특수-고려사항)
|
||||
10. [기술 스택 및 의존성](#10-기술-스택-및-의존성)
|
||||
11. [참고 문헌](#11-참고-문헌)
|
||||
|
||||
---
|
||||
|
||||
## 1. 이론적 기초
|
||||
|
||||
### 1.1 구조적 모형(Structural Model) 계보
|
||||
|
||||
```
|
||||
Black-Scholes (1973)
|
||||
└─ Merton (1974) ─── 기업부도를 옵션으로 해석
|
||||
├─ Black-Cox (1976) ─── First Passage Time (배리어 부도)
|
||||
├─ Geske (1977) ─── 복합옵션 (쿠폰부 부채)
|
||||
├─ Longstaff-Schwartz (1995) ─── 확률적 이자율
|
||||
└─ KMV (Kealhofer-McQuown-Vasicek)
|
||||
└─ Moody's Analytics EDF™ ─── 상용화
|
||||
```
|
||||
|
||||
### 1.2 Merton 모형 (1974)
|
||||
|
||||
**핵심 가정:**
|
||||
- 기업의 자산가치 `V(t)`는 기하 브라운 운동(GBM)을 따름
|
||||
- 부채는 만기 `T`에 원금 `D`가 일시 상환되는 제로쿠폰 채권
|
||||
- 자기자본 `E`는 자산 `V`에 대한 유럽형 콜옵션
|
||||
|
||||
**자산 역학:**
|
||||
```
|
||||
dV = μ·V·dt + σ_V·V·dW
|
||||
```
|
||||
- `μ`: 자산 기대수익률 (drift)
|
||||
- `σ_V`: 자산 변동성
|
||||
- `W`: 위너 과정
|
||||
|
||||
**부도 조건:**
|
||||
```
|
||||
Default ⟺ V(T) < D (만기 시점에 자산가치 < 부채)
|
||||
```
|
||||
|
||||
**자기자본의 옵션 해석:**
|
||||
```
|
||||
E = Call(V, D, T) = V·N(d₁) - D·e^{-rT}·N(d₂)
|
||||
```
|
||||
|
||||
### 1.3 KMV-Moody's EDF 모형
|
||||
|
||||
Merton 모형의 실무 확장:
|
||||
|
||||
| 구분 | Merton 원형 | KMV 수정 |
|
||||
|------|-------------|----------|
|
||||
| 부도점 | D (총부채) | STD + 0.5×LTD |
|
||||
| 부도 시점 | 만기 T 시점만 | 임의 시점 (First Passage) |
|
||||
| EDF 산출 | N(-DD) 이론값 | 경험적 부도 빈도 매핑 |
|
||||
| 데이터 | 단일 시점 | 시계열 반복 추정 |
|
||||
|
||||
### 1.4 축약형 모형(Reduced-Form Model)
|
||||
|
||||
**CreditRisk+ (Credit Suisse)**
|
||||
- 부도를 포아송 과정으로 모형화
|
||||
- 부도율의 변동성을 명시적 반영 (부도율 자체가 확률변수)
|
||||
- 섹터별 체계적 요인으로 부도 상관관계 간접 포착
|
||||
- 장점: 구현 용이, 대규모 포트폴리오 적합
|
||||
- 한계: 시장 데이터 반영 제한, 등급전이 미반영
|
||||
|
||||
**Jarrow-Turnbull / Duffie-Singleton**
|
||||
- 부도 강도(hazard rate)가 시장 변수에 의존
|
||||
- CDS/채권 스프레드에서 내재 부도확률 추출
|
||||
- 한국 적용 한계: CDS 시장 유동성 부족
|
||||
|
||||
### 1.5 CreditMetrics 접근법
|
||||
|
||||
- 등급전이행렬(Rating Transition Matrix) 기반
|
||||
- 잠재 변수 `Zt`를 통해 체계적 리스크 반영
|
||||
- 전이확률 × 등급별 스프레드 → 포트폴리오 가치 분포
|
||||
- 한국 시장: 신평사 발표 전이행렬과 연동 가능
|
||||
|
||||
---
|
||||
|
||||
## 2. 핵심 수학적 프레임워크
|
||||
|
||||
### 2.1 Merton 연립방정식
|
||||
|
||||
관측 가능한 `(E, σ_E)`로부터 비관측 `(V, σ_V)`를 추정:
|
||||
|
||||
**방정식 1 — 자기자본 가치:**
|
||||
```
|
||||
E = V·N(d₁) - D·e^{-rT}·N(d₂)
|
||||
```
|
||||
|
||||
**방정식 2 — 변동성 관계 (Itô's Lemma):**
|
||||
```
|
||||
σ_E = (V/E)·N(d₁)·σ_V
|
||||
```
|
||||
|
||||
**여기서:**
|
||||
```
|
||||
d₁ = [ln(V/D) + (r + σ²_V/2)·T] / (σ_V·√T)
|
||||
d₂ = d₁ - σ_V·√T
|
||||
```
|
||||
|
||||
### 2.2 Distance-to-Default (DD)
|
||||
|
||||
```
|
||||
DD = [ln(V/DP) + (μ - σ²_V/2)·T] / (σ_V·√T)
|
||||
```
|
||||
|
||||
- `DP = STD + 0.5 × LTD` (KMV 부도점)
|
||||
- `μ`: 자산 기대수익률 (실무에서는 r 또는 과거 추정값 사용)
|
||||
|
||||
**해석:** DD는 자산가치가 부도점까지 하락하는 데 필요한 표준편차 수
|
||||
|
||||
### 2.3 EDF 산출
|
||||
|
||||
**이론적 EDF (정규분포 가정):**
|
||||
```
|
||||
EDF_theoretical = N(-DD) = Φ(-DD)
|
||||
```
|
||||
|
||||
**경험적 EDF (KMV 방식):**
|
||||
```
|
||||
EDF_empirical = (DD 구간별 실제 부도 기업 수) / (DD 구간별 전체 기업 수)
|
||||
```
|
||||
|
||||
**한국 시장 보정 EDF:**
|
||||
```
|
||||
EDF_KR = EDF_theoretical × Calibration_Factor(rating_grade)
|
||||
```
|
||||
|
||||
### 2.4 주가 변동성 추정 방법
|
||||
|
||||
#### (a) 역사적 변동성 (Historical Volatility)
|
||||
```
|
||||
σ_E = √(252) × std(ln(P_t / P_{t-1}))
|
||||
```
|
||||
- 일별 로그수익률의 표준편차 × √252 (연환산)
|
||||
- 추정 윈도우: 1년 (약 250 거래일)
|
||||
|
||||
#### (b) EWMA (Exponentially Weighted Moving Average)
|
||||
```
|
||||
σ²_t = λ·σ²_{t-1} + (1-λ)·r²_{t-1}
|
||||
```
|
||||
- `λ = 0.94` (RiskMetrics 표준)
|
||||
- 최근 변동에 더 높은 가중치
|
||||
|
||||
#### (c) GARCH(1,1)
|
||||
```
|
||||
σ²_t = ω + α·ε²_{t-1} + β·σ²_{t-1}
|
||||
```
|
||||
- `ω, α, β`: 최대우도추정(MLE)으로 산출
|
||||
- `α + β < 1` (정상성 조건)
|
||||
- 변동성 클러스터링 반영 가능
|
||||
|
||||
---
|
||||
|
||||
## 3. 한국 시장 등급 관측 문제 및 대안
|
||||
|
||||
### 3.1 문제 진단
|
||||
|
||||
```
|
||||
KRX 상장사 약 2,500개
|
||||
├── 신용등급 보유: 약 500~600개 (주로 회사채/CP 발행사)
|
||||
│ ├── 관측 가능 등급: BBB ~ A 중심 (약 70%)
|
||||
│ ├── 고등급 (AAA~AA): 소수 (우량사, 등급 불필요)
|
||||
│ └── 저등급 (B 이하): 극소수 (상장 유지 자체가 어려움)
|
||||
└── 신용등급 미보유: 약 1,900개 (소형주, 미발행사)
|
||||
```
|
||||
|
||||
**등급별 관측 분포 추정:**
|
||||
|
||||
| 등급군 | KRX 상장사 중 비율 | 부도 관측 가능성 | 주요 이슈 |
|
||||
|--------|-------------------|-----------------|-----------|
|
||||
| AAA~AA | ~5% | 극히 낮음 | 부도 사례 거의 0 |
|
||||
| A | ~20% | 낮음 | 부도 희소하나 관측 가능 |
|
||||
| BBB | ~40% | 보통 | 가장 관측 풍부 |
|
||||
| BB | ~20% | 높음 | 투기등급 진입, 데이터 확보 |
|
||||
| B 이하 | ~5% | 높으나 표본 부족 | 상장폐지와 혼재 |
|
||||
| 무등급 | ~10% (등급보유 대비) | Shadow 필요 | 대부분 소형주 |
|
||||
|
||||
### 3.2 대안 전략 상세
|
||||
|
||||
#### 대안 1: Shadow Rating (내재등급) 모형
|
||||
|
||||
**목적:** DD 및 재무비율을 기반으로 무등급 기업에 내재등급 부여
|
||||
|
||||
**방법론 — Ordered Probit 모형:**
|
||||
|
||||
```
|
||||
y* = β'X + ε, ε ~ N(0, 1)
|
||||
|
||||
y = k if τ_{k-1} < y* ≤ τ_k
|
||||
|
||||
여기서:
|
||||
- y: 관측등급 (AAA=1, AA+=2, ..., D=n)
|
||||
- X: [DD, log(총자산), 부채비율, 이자보상비율, EBITDA마진, ROA, 유동비율, 산업더미]
|
||||
- τ_k: 등급 경계 절단점(cutoff)
|
||||
```
|
||||
|
||||
**학습 과정:**
|
||||
1. 등급 보유 기업의 (X, y) 쌍으로 β, τ를 MLE 추정
|
||||
2. 등급 미보유 기업에 추정된 β'X를 적용하여 각 등급 확률 계산
|
||||
3. 최대 확률 등급을 Shadow Rating으로 부여
|
||||
|
||||
**설명변수 후보:**
|
||||
|
||||
| 변수 | 정의 | 기대 부호 |
|
||||
|------|------|-----------|
|
||||
| DD | Distance-to-Default | + (높을수록 고등급) |
|
||||
| log_assets | ln(총자산) | + 규모 효과 |
|
||||
| leverage | 총부채/총자산 | - |
|
||||
| int_coverage | EBITDA/이자비용 | + |
|
||||
| ebitda_margin | EBITDA/매출 | + |
|
||||
| roa | 순이익/총자산 | + |
|
||||
| current_ratio | 유동자산/유동부채 | + |
|
||||
| cash_ratio | 현금/유동부채 | + |
|
||||
| industry | 산업 더미 | 산업별 상이 |
|
||||
|
||||
#### 대안 2: DD-Rating 직접 매핑
|
||||
|
||||
글로벌 벤치마크를 기반으로 DD 구간 → 등급 매핑:
|
||||
|
||||
| DD 범위 | Moody's 등급 | 한국 등급 (추정) | 이론적 EDF |
|
||||
|---------|-------------|-----------------|------------|
|
||||
| > 6.0 | Aaa ~ Aa1 | AAA ~ AA+ | < 0.02% |
|
||||
| 5.0 ~ 6.0 | Aa2 ~ Aa3 | AA ~ AA- | 0.02% ~ 0.05% |
|
||||
| 4.0 ~ 5.0 | A1 ~ A3 | A+ ~ A- | 0.05% ~ 0.20% |
|
||||
| 3.0 ~ 4.0 | Baa1 ~ Baa2 | BBB+ ~ BBB | 0.20% ~ 0.70% |
|
||||
| 2.5 ~ 3.0 | Baa3 | BBB- | 0.70% ~ 1.50% |
|
||||
| 2.0 ~ 2.5 | Ba1 | BB+ | 1.50% ~ 3.00% |
|
||||
| 1.5 ~ 2.0 | Ba2 ~ Ba3 | BB ~ BB- | 3.00% ~ 5.00% |
|
||||
| 1.0 ~ 1.5 | B1 ~ B2 | B+ ~ B | 5.00% ~ 10.00% |
|
||||
| 0.5 ~ 1.0 | B3 ~ Caa1 | B- ~ CCC+ | 10.00% ~ 20.00% |
|
||||
| < 0.5 | Caa2 이하 | CCC 이하 | > 20.00% |
|
||||
|
||||
> 주의: 글로벌 매핑은 한국 시장에 직접 적용 시 보정(calibration) 필수
|
||||
|
||||
#### 대안 3: 등급군 병합(Grade Pooling)
|
||||
|
||||
표본 부족 등급을 인접 등급과 통합:
|
||||
|
||||
```
|
||||
Pool 1: AAA + AA+ + AA + AA- → "최우량군" (Super-Prime)
|
||||
Pool 2: A+ + A + A- → "우량군" (Prime)
|
||||
Pool 3: BBB+ + BBB + BBB- → "투자적격군" (Investment)
|
||||
Pool 4: BB+ + BB + BB- → "투기등급군" (Speculative)
|
||||
Pool 5: B+ 이하 → "고위험군" (High-Risk)
|
||||
```
|
||||
|
||||
**병합 기준:**
|
||||
- 각 풀 내 최소 관측수: 30개 이상 (통계적 유의성)
|
||||
- Hosmer-Lemeshow 검정 등으로 풀 내 균질성 확인
|
||||
|
||||
#### 대안 4: 글로벌 데이터 블렌딩
|
||||
|
||||
한국 데이터와 글로벌 벤치마크를 표본수 기반 가중 혼합:
|
||||
|
||||
```
|
||||
DR_blended(g) = w(g) × DR_KR(g) + [1 - w(g)] × DR_Global(g)
|
||||
|
||||
w(g) = min(1, N_KR(g) / N_threshold)
|
||||
```
|
||||
|
||||
- `DR_KR(g)`: 한국 등급 g의 관측 부도율
|
||||
- `DR_Global(g)`: Moody's/S&P 등급 g의 글로벌 부도율
|
||||
- `N_KR(g)`: 한국 등급 g의 관측 표본수
|
||||
- `N_threshold`: 신뢰도 임계치 (예: 50)
|
||||
|
||||
#### 대안 5: 베이지안 보정
|
||||
|
||||
```
|
||||
사전분포(Prior): π(θ_g) ~ Beta(α_0, β_0) ← 글로벌 부도율에서 유도
|
||||
우도(Likelihood): L(data|θ_g) = θ_g^d × (1-θ_g)^{n-d}
|
||||
사후분포(Posterior): π(θ_g|data) ~ Beta(α_0 + d, β_0 + n - d)
|
||||
|
||||
여기서:
|
||||
- θ_g: 등급 g의 실제 부도율 (추정 대상)
|
||||
- d: 한국 등급 g에서 관측된 부도 건수
|
||||
- n: 한국 등급 g에서 관측된 전체 기업수
|
||||
- α_0, β_0: 글로벌 데이터에서 유도된 사전 파라미터
|
||||
```
|
||||
|
||||
**장점:** 표본 부족 등급에서 글로벌 Prior에 자연스럽게 의존, 표본 충분 등급에서는 한국 데이터 위주로 수렴
|
||||
|
||||
---
|
||||
|
||||
## 4. 글로벌 접근 방법론 비교
|
||||
|
||||
| 방법론 | 모형 유형 | 핵심 입력 | 장점 | 한계 | 한국 적용성 |
|
||||
|--------|-----------|-----------|------|------|-------------|
|
||||
| **Merton-KMV** | 구조적 | 주가, 부채 | 시장기반, 전향적 | 상장사 한정, 분포가정 | ★★★★★ |
|
||||
| **CreditMetrics** | 전이행렬 | 등급전이, 스프레드 | 포트폴리오 리스크 | 등급 의존적 | ★★★☆☆ |
|
||||
| **CreditRisk+** | 축약형 | 부도율, 변동성 | 구현 용이 | 시장 미반영 | ★★☆☆☆ |
|
||||
| **Jarrow-Turnbull** | 축약형 | CDS스프레드 | 시장가격 반영 | CDS시장 미발달 | ★★☆☆☆ |
|
||||
| **Altman Z-Score** | 판별분석 | 재무비율 | 간단, 검증됨 | 시장변동 미반영 | ★★★☆☆ |
|
||||
| **ML (XGBoost)** | 비모수 | 다양한 데이터 | 유연, 비선형 | 해석부족, 과적합 | ★★★☆☆ |
|
||||
| **Bharath-Shumway** | 구조적(간편) | 주가, 부채 | 단순 구현 | 정밀도 한계 | ★★★★☆ |
|
||||
|
||||
### Bharath-Shumway 간편 DD (Naïve DD)
|
||||
|
||||
반복 추정 없이 직접 DD 계산 (실무 빠른 적용용):
|
||||
|
||||
```
|
||||
V_naive = E + D
|
||||
σ_V_naive = (E/(E+D)) × σ_E + (D/(E+D)) × (0.05 + 0.25×σ_E)
|
||||
DD_naive = [ln(V_naive/D) + (μ - σ²_V_naive/2)×T] / (σ_V_naive × √T)
|
||||
```
|
||||
|
||||
- Bharath & Shumway (2008) 연구에서 반복추정 DD와 유사한 부도예측력 보고
|
||||
- 대규모 데이터 처리 시 1차 필터로 유용
|
||||
|
||||
---
|
||||
|
||||
## 5. 구현 아키텍처
|
||||
|
||||
### 5.1 시스템 구조
|
||||
|
||||
```
|
||||
EDF/
|
||||
├── config/
|
||||
│ ├── settings.yaml # 전역 설정 (기간, 파라미터)
|
||||
│ └── rating_mapping.yaml # DD-등급 매핑 테이블
|
||||
├── data/
|
||||
│ ├── raw/ # 원본 데이터
|
||||
│ ├── processed/ # 전처리된 데이터
|
||||
│ └── external/ # 글로벌 부도율 통계
|
||||
├── src/
|
||||
│ ├── data/
|
||||
│ │ ├── krx_fetcher.py # KRX 주가 수집
|
||||
│ │ ├── dart_fetcher.py # DART 재무제표 수집
|
||||
│ │ ├── rating_fetcher.py # 신용등급 수집
|
||||
│ │ └── preprocessor.py # 데이터 전처리
|
||||
│ ├── models/
|
||||
│ │ ├── merton.py # Merton 연립방정식 풀이
|
||||
│ │ ├── dd_calculator.py # DD/EDF 산출
|
||||
│ │ ├── shadow_rating.py # Shadow Rating 모형
|
||||
│ │ └── volatility.py # 변동성 추정 (Historical/EWMA/GARCH)
|
||||
│ ├── calibration/
|
||||
│ │ ├── global_benchmark.py # 글로벌 벤치마크 로딩
|
||||
│ │ ├── blending.py # 블렌딩/베이지안 보정
|
||||
│ │ └── grade_pooling.py # 등급군 병합
|
||||
│ ├── validation/
|
||||
│ │ ├── backtesting.py # 백테스팅
|
||||
│ │ ├── discriminatory.py # 변별력 검증 (ROC, KS, CAP)
|
||||
│ │ └── calibration_test.py # 보정력 검증 (Hosmer-Lemeshow)
|
||||
│ └── utils/
|
||||
│ ├── financial.py # 재무비율 계산
|
||||
│ └── statistics.py # 통계 유틸리티
|
||||
├── notebooks/
|
||||
│ ├── 01_data_exploration.ipynb
|
||||
│ ├── 02_merton_analysis.ipynb
|
||||
│ ├── 03_shadow_rating.ipynb
|
||||
│ └── 04_default_rate_output.ipynb
|
||||
├── outputs/
|
||||
│ ├── dd_results/ # DD/EDF 산출 결과
|
||||
│ ├── rating_results/ # 등급별 부도율 결과
|
||||
│ └── reports/ # 검증 보고서
|
||||
├── docs/
|
||||
│ └── technical_methodology.md # 이 문서
|
||||
├── requirements.txt
|
||||
└── README.md
|
||||
```
|
||||
|
||||
### 5.2 처리 파이프라인
|
||||
|
||||
```
|
||||
[Phase 1: 데이터 수집]
|
||||
KRX 주가 → 전처리 → 주가변동성 산출
|
||||
DART 재무제표 → 부채 구조(STD/LTD) 추출
|
||||
신평사 등급 → 연도별 등급 스냅샷
|
||||
|
||||
[Phase 2: Merton-KMV 모형]
|
||||
(E, σ_E, D, r, T) → 반복 추정 → (V, σ_V) → DP → DD → EDF
|
||||
|
||||
[Phase 3: Shadow Rating]
|
||||
등급 보유 기업: (DD, 재무비율) ↔ 등급 매핑 학습
|
||||
등급 미보유 기업: 학습 모형 → Shadow Rating 부여
|
||||
|
||||
[Phase 4: 등급별 부도율 집계]
|
||||
실제등급 + Shadow Rating → 등급별 연간 부도율 집계
|
||||
표본 부족 등급 → 글로벌 블렌딩 / 등급군 병합
|
||||
|
||||
[Phase 5: 검증]
|
||||
백테스팅, 변별력/보정력 검증, CRA 발표 데이터 비교
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 6. 데이터 명세
|
||||
|
||||
### 6.1 필수 데이터
|
||||
|
||||
| 데이터 항목 | 소스 | 수집 주기 | 필수/선택 |
|
||||
|-------------|------|-----------|-----------|
|
||||
| 일별 종가 | KRX / pykrx | 일별 | 필수 |
|
||||
| 시가총액 | KRX / pykrx | 일별 | 필수 |
|
||||
| 발행주식수 | KRX / DART | 분기 | 필수 |
|
||||
| 유동부채 (STD) | DART 재무제표 | 분기/연간 | 필수 |
|
||||
| 비유동부채 (LTD) | DART 재무제표 | 분기/연간 | 필수 |
|
||||
| 총자산 | DART 재무제표 | 분기/연간 | 필수 |
|
||||
| 신용등급 | 한기평/한신평/나이스 | 연간 스냅샷 | 필수 |
|
||||
| 무위험이자율 | 한국은행(ECOS) | 일별 | 필수 |
|
||||
| 부도/워크아웃 이력 | KRX 상장폐지, 뉴스 | 사건 기반 | 필수 |
|
||||
|
||||
### 6.2 보조 데이터 (Shadow Rating 강화용)
|
||||
|
||||
| 데이터 항목 | 소스 | 용도 |
|
||||
|-------------|------|------|
|
||||
| EBITDA | DART | 이자보상비율, 마진 |
|
||||
| 이자비용 | DART | 이자보상비율 |
|
||||
| 매출액 | DART | EBITDA 마진 |
|
||||
| 현금 및 현금성 자산 | DART | 유동성 비율 |
|
||||
| 산업분류코드 (KSIC) | KRX / DART | 산업 더미 변수 |
|
||||
| 거래량 | KRX | 유동성 필터링 |
|
||||
|
||||
### 6.3 글로벌 벤치마크 데이터
|
||||
|
||||
| 데이터 | 소스 | 내용 |
|
||||
|--------|------|------|
|
||||
| 등급별 연간 부도율 | Moody's Annual Default Study | Aaa~C 20년+ 평균 |
|
||||
| 등급별 누적 부도율 | S&P Global Default Study | AAA~D 1~20년 |
|
||||
| 한국 등급별 부도율 | 한기평/한신평/나이스 연간 발표 | 국내 기준 |
|
||||
|
||||
### 6.4 부도(Default) 정의
|
||||
|
||||
```
|
||||
다음 이벤트 중 하나 이상 발생 시 "부도"로 정의:
|
||||
|
||||
1. 법정관리(회생절차) 개시 결정
|
||||
2. 워크아웃(채권단 자율협약) 개시
|
||||
3. 상장폐지 (재무 사유: 자본잠식, 감사의견 거절 등)
|
||||
4. 부도어음/부도수표 발생
|
||||
5. 기업회생절차 신청
|
||||
6. 파산 선고
|
||||
|
||||
※ 제외: 합병·분할·자진 상장폐지 등 비재무적 사유
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 7. 알고리즘 상세
|
||||
|
||||
### 7.1 Merton 연립방정식 풀이
|
||||
|
||||
```python
|
||||
import numpy as np
|
||||
from scipy.optimize import fsolve
|
||||
from scipy.stats import norm
|
||||
|
||||
def solve_merton(E: float, sigma_E: float, D: float,
|
||||
r: float, T: float = 1.0) -> tuple[float, float]:
|
||||
"""
|
||||
Merton 연립방정식을 풀어 자산가치(V)와 자산변동성(σ_V)을 추정.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
E : float
|
||||
자기자본 시장가치 (시가총액, 억원)
|
||||
sigma_E : float
|
||||
주가수익률 변동성 (연환산, 예: 0.30 = 30%)
|
||||
D : float
|
||||
부도점 = STD + 0.5 × LTD (억원)
|
||||
r : float
|
||||
무위험이자율 (연, 예: 0.035 = 3.5%)
|
||||
T : float
|
||||
시간 수평선 (년, 기본 1.0)
|
||||
|
||||
Returns
|
||||
-------
|
||||
V : float
|
||||
추정 자산가치 (억원)
|
||||
sigma_V : float
|
||||
추정 자산변동성 (연환산)
|
||||
"""
|
||||
def equations(params):
|
||||
V, sigma_V = params
|
||||
d1 = (np.log(V / D) + (r + 0.5 * sigma_V**2) * T) / (sigma_V * np.sqrt(T))
|
||||
d2 = d1 - sigma_V * np.sqrt(T)
|
||||
|
||||
eq1 = V * norm.cdf(d1) - D * np.exp(-r * T) * norm.cdf(d2) - E
|
||||
eq2 = (V / E) * norm.cdf(d1) * sigma_V - sigma_E
|
||||
return [eq1, eq2]
|
||||
|
||||
# 초기값: V0 = E + D, sigma_V0 = sigma_E * E / (E + D)
|
||||
V0 = E + D
|
||||
sigma_V0 = sigma_E * E / (E + D)
|
||||
|
||||
solution = fsolve(equations, [V0, sigma_V0], full_output=True)
|
||||
V, sigma_V = solution[0]
|
||||
|
||||
return max(V, E), max(sigma_V, 0.01) # 하한 설정
|
||||
|
||||
|
||||
def calculate_dd(V: float, sigma_V: float, D: float,
|
||||
mu: float, T: float = 1.0) -> float:
|
||||
"""Distance-to-Default 산출"""
|
||||
if D <= 0 or V <= 0 or sigma_V <= 0:
|
||||
return np.nan
|
||||
DD = (np.log(V / D) + (mu - 0.5 * sigma_V**2) * T) / (sigma_V * np.sqrt(T))
|
||||
return DD
|
||||
|
||||
|
||||
def calculate_edf(DD: float) -> float:
|
||||
"""이론적 EDF 산출 (정규분포 가정)"""
|
||||
if np.isnan(DD):
|
||||
return np.nan
|
||||
return norm.cdf(-DD)
|
||||
```
|
||||
|
||||
### 7.2 변동성 추정
|
||||
|
||||
```python
|
||||
def historical_volatility(prices: np.ndarray, window: int = 252) -> float:
|
||||
"""역사적 변동성 (연환산)"""
|
||||
log_returns = np.diff(np.log(prices))
|
||||
if len(log_returns) < window:
|
||||
window = len(log_returns)
|
||||
return np.std(log_returns[-window:]) * np.sqrt(252)
|
||||
|
||||
|
||||
def ewma_volatility(prices: np.ndarray, lmbda: float = 0.94) -> float:
|
||||
"""EWMA 변동성 (연환산)"""
|
||||
log_returns = np.diff(np.log(prices))
|
||||
variance = log_returns[0]**2
|
||||
for ret in log_returns[1:]:
|
||||
variance = lmbda * variance + (1 - lmbda) * ret**2
|
||||
return np.sqrt(variance * 252)
|
||||
|
||||
|
||||
def garch_volatility(prices: np.ndarray) -> float:
|
||||
"""GARCH(1,1) 변동성 (arch 패키지 사용)"""
|
||||
from arch import arch_model
|
||||
log_returns = np.diff(np.log(prices)) * 100 # 백분율
|
||||
model = arch_model(log_returns, vol='Garch', p=1, q=1, dist='normal')
|
||||
result = model.fit(disp='off')
|
||||
# 최신 조건부 변동성을 연환산
|
||||
cond_vol = result.conditional_volatility[-1] / 100
|
||||
return cond_vol * np.sqrt(252)
|
||||
```
|
||||
|
||||
### 7.3 Shadow Rating (Ordered Probit)
|
||||
|
||||
```python
|
||||
import statsmodels.api as sm
|
||||
import pandas as pd
|
||||
|
||||
def fit_shadow_rating_model(df_rated: pd.DataFrame,
|
||||
feature_cols: list,
|
||||
rating_col: str = 'rating_numeric') -> object:
|
||||
"""
|
||||
등급 보유 기업 데이터로 Ordered Probit 모형 적합.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
df_rated : pd.DataFrame
|
||||
등급 보유 기업 데이터 (DD, 재무비율, 등급 포함)
|
||||
feature_cols : list
|
||||
설명변수 컬럼명 리스트
|
||||
rating_col : str
|
||||
등급 숫자 컬럼 (1=AAA, 2=AA+, ...)
|
||||
"""
|
||||
X = df_rated[feature_cols]
|
||||
y = df_rated[rating_col]
|
||||
|
||||
model = sm.OrderedModel(y, X, distr='probit')
|
||||
result = model.fit(method='bfgs', disp=False)
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def predict_shadow_rating(model_result, df_unrated: pd.DataFrame,
|
||||
feature_cols: list) -> pd.DataFrame:
|
||||
"""등급 미보유 기업에 Shadow Rating 부여"""
|
||||
X = df_unrated[feature_cols]
|
||||
pred_probs = model_result.predict(X)
|
||||
|
||||
# 각 기업의 최대 확률 등급
|
||||
df_unrated = df_unrated.copy()
|
||||
df_unrated['shadow_rating_numeric'] = pred_probs.values.argmax(axis=1) + 1
|
||||
|
||||
return df_unrated
|
||||
```
|
||||
|
||||
### 7.4 등급별 부도율 산출 (블렌딩)
|
||||
|
||||
```python
|
||||
def compute_blended_default_rates(df: pd.DataFrame,
|
||||
rating_col: str,
|
||||
default_col: str,
|
||||
global_dr: dict,
|
||||
threshold: int = 50) -> pd.DataFrame:
|
||||
"""
|
||||
등급별 부도율을 한국 관측 + 글로벌 벤치마크 블렌딩으로 산출.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
df : pd.DataFrame
|
||||
전체 기업 데이터 (등급 + 부도여부 포함)
|
||||
rating_col : str
|
||||
등급 컬럼명
|
||||
default_col : str
|
||||
부도 여부 컬럼명 (0/1)
|
||||
global_dr : dict
|
||||
{등급: 글로벌 부도율} 매핑
|
||||
threshold : int
|
||||
블렌딩 전환 표본수 임계치
|
||||
"""
|
||||
results = []
|
||||
for grade in sorted(df[rating_col].unique()):
|
||||
subset = df[df[rating_col] == grade]
|
||||
n = len(subset)
|
||||
d = subset[default_col].sum()
|
||||
kr_dr = d / n if n > 0 else 0
|
||||
|
||||
g_dr = global_dr.get(grade, kr_dr)
|
||||
w = min(1.0, n / threshold)
|
||||
blended = w * kr_dr + (1 - w) * g_dr
|
||||
|
||||
results.append({
|
||||
'grade': grade,
|
||||
'n_firms': n,
|
||||
'n_defaults': d,
|
||||
'korean_dr': kr_dr,
|
||||
'global_dr': g_dr,
|
||||
'weight_kr': w,
|
||||
'blended_dr': blended
|
||||
})
|
||||
|
||||
return pd.DataFrame(results)
|
||||
```
|
||||
|
||||
### 7.5 베이지안 부도율 추정
|
||||
|
||||
```python
|
||||
from scipy.stats import beta as beta_dist
|
||||
|
||||
def bayesian_default_rate(n: int, d: int,
|
||||
prior_mean: float,
|
||||
prior_strength: float = 50) -> dict:
|
||||
"""
|
||||
베이지안 방식 등급별 부도율 추정.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
n : int
|
||||
관측 기업수
|
||||
d : int
|
||||
부도 건수
|
||||
prior_mean : float
|
||||
사전 부도율 (글로벌 벤치마크)
|
||||
prior_strength : float
|
||||
사전 강도 (글로벌 표본수에 비례)
|
||||
"""
|
||||
# Beta prior 파라미터
|
||||
alpha_0 = prior_mean * prior_strength
|
||||
beta_0 = (1 - prior_mean) * prior_strength
|
||||
|
||||
# 사후 분포 (Beta-Binomial conjugacy)
|
||||
alpha_post = alpha_0 + d
|
||||
beta_post = beta_0 + (n - d)
|
||||
|
||||
# 사후 통계량
|
||||
posterior_mean = alpha_post / (alpha_post + beta_post)
|
||||
posterior_mode = (alpha_post - 1) / (alpha_post + beta_post - 2) \
|
||||
if (alpha_post > 1 and beta_post > 1) else posterior_mean
|
||||
ci_lower, ci_upper = beta_dist.ppf([0.025, 0.975], alpha_post, beta_post)
|
||||
|
||||
return {
|
||||
'posterior_mean': posterior_mean,
|
||||
'posterior_mode': posterior_mode,
|
||||
'ci_95_lower': ci_lower,
|
||||
'ci_95_upper': ci_upper,
|
||||
'prior_mean': prior_mean,
|
||||
'n_obs': n,
|
||||
'n_defaults': d
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 8. 검증 방법론
|
||||
|
||||
### 8.1 변별력(Discriminatory Power) 검증
|
||||
|
||||
| 지표 | 설명 | 기준 |
|
||||
|------|------|------|
|
||||
| **AUROC** | ROC 곡선 하 면적 | > 0.70 (수용), > 0.80 (양호) |
|
||||
| **KS 통계량** | 부도/비부도 분포 최대 이격 | > 0.30 (수용) |
|
||||
| **CAP/AR** | 정확도 비율 | > 0.50 (수용) |
|
||||
| **정보값(IV)** | 변수별 변별 기여도 | > 0.10 (유의미) |
|
||||
|
||||
### 8.2 보정력(Calibration) 검증
|
||||
|
||||
| 지표 | 설명 |
|
||||
|------|------|
|
||||
| **Hosmer-Lemeshow** | 예측 부도율 vs 실제 부도율 적합도 |
|
||||
| **Binomial Test** | 등급별 실제 부도율이 예측 구간 내 존재 여부 |
|
||||
| **Traffic Light** | Basel II 권장 — 녹색/황색/적색 신호 |
|
||||
|
||||
### 8.3 백테스팅 프로세스
|
||||
|
||||
```
|
||||
for year in [T-5, T-4, T-3, T-2, T-1]:
|
||||
1. year 말 기준 DD/EDF 산출
|
||||
2. year+1 동안의 실제 부도 여부 관측
|
||||
3. 예측 EDF vs 실현 부도율 비교
|
||||
4. 변별력/보정력 지표 산출
|
||||
```
|
||||
|
||||
### 8.4 CRA 발표 데이터와 비교
|
||||
|
||||
- 한기평·한신평·나이스 연간 발표 등급별 부도율과 본 모형 산출치 비교
|
||||
- 등급별 편차(bias) 및 상관관계 분석
|
||||
- 부도 시점 대비 DD 하락 시점의 선행성 분석
|
||||
|
||||
---
|
||||
|
||||
## 9. 한국 시장 특수 고려사항
|
||||
|
||||
### 9.1 데이터 관련
|
||||
|
||||
| 항목 | 고려사항 | 대응 |
|
||||
|------|----------|------|
|
||||
| KOSPI vs KOSDAQ | KOSDAQ 소형·고변동성 기업 다수 | 시장별 분리 분석 또는 통합+더미 |
|
||||
| 금융업 | 부채 구조 상이 (예금 = 부채) | **분석 제외** 또는 별도 모형 |
|
||||
| 등급 불일치 | 한기평·한신평·나이스 등급 차이 | 중위값 또는 최빈값 사용 |
|
||||
| 분기 vs 연간 | 재무제표 시차 | 분기 데이터 우선, 없으면 연간 보간 |
|
||||
| 상장폐지 | 부도 vs 비부도 폐지 구분 | 폐지 사유 코드로 필터링 |
|
||||
|
||||
### 9.2 구조적 특성
|
||||
|
||||
| 특성 | 영향 | 모형 반영 방법 |
|
||||
|------|------|---------------|
|
||||
| **재벌 계열** | 그룹 지원으로 개별 DD 대비 부도율 하락 | 계열사 더미 / 그룹 DD 산출 |
|
||||
| **정부 지원** | 공기업 부도율 ≈ 0 | 정부지원 등급에서 제외 또는 별도 처리 |
|
||||
| **채권단 자율협약** | 형식적 부도 회피 | 워크아웃 개시를 부도 사건에 포함 |
|
||||
| **유상증자/CB** | 부도 직전 자본 확충으로 DD 왜곡 | 이벤트 전 DD 사용 또는 플래그 |
|
||||
|
||||
### 9.3 변동성 추정 주의사항
|
||||
|
||||
| 상황 | 문제 | 대응 |
|
||||
|------|------|------|
|
||||
| 장기 거래정지 | 변동성 과소추정 | 정지 기간 제외, 30일 이상 정지 시 분석 제외 |
|
||||
| 저거래량 | 비유동성 프리미엄 혼재 | 거래량 하위 10% 제외 또는 유동성 보정 |
|
||||
| 극단 이벤트 | 일시적 급등락으로 변동성 왜곡 | Winsorization (상하 1%) 또는 트리밍 |
|
||||
| 공매도 제한 | 하락 변동성 억제 | 변동성 하향 편의 인지, 글로벌 대비 보정 |
|
||||
|
||||
---
|
||||
|
||||
## 10. 기술 스택 및 의존성
|
||||
|
||||
### 10.1 Python 패키지
|
||||
|
||||
```
|
||||
# 핵심 (requirements.txt)
|
||||
numpy>=1.24
|
||||
pandas>=2.0
|
||||
scipy>=1.10
|
||||
statsmodels>=0.14
|
||||
|
||||
# 데이터 수집
|
||||
pykrx>=1.0 # KRX 주가 데이터
|
||||
OpenDartReader>=0.3 # DART 전자공시 API
|
||||
|
||||
# 변동성 모형
|
||||
arch>=6.0 # GARCH/EWMA 모형
|
||||
|
||||
# 시각화
|
||||
matplotlib>=3.7
|
||||
plotly>=5.15
|
||||
seaborn>=0.12
|
||||
|
||||
# 머신러닝 (선택)
|
||||
scikit-learn>=1.3
|
||||
xgboost>=2.0
|
||||
|
||||
# 유틸리티
|
||||
tqdm>=4.65
|
||||
pyyaml>=6.0
|
||||
```
|
||||
|
||||
### 10.2 무위험이자율
|
||||
|
||||
- 한국은행 ECOS의 **국고채 1년물 금리** 사용
|
||||
- 또는 통화안정증권(MSB) 1년물
|
||||
|
||||
### 10.3 데이터베이스
|
||||
|
||||
- 개발 단계: SQLite (로컬 파일)
|
||||
- 운영 단계: PostgreSQL (필요시)
|
||||
|
||||
---
|
||||
|
||||
## 11. 참고 문헌
|
||||
|
||||
### 핵심 논문
|
||||
1. Merton, R.C. (1974). "On the Pricing of Corporate Debt: The Risk Structure of Interest Rates." *Journal of Finance*, 29(2), 449-470.
|
||||
2. Black, F. & Cox, J.C. (1976). "Valuing Corporate Securities: Some Effects of Bond Indenture Provisions." *Journal of Finance*, 31(2), 351-367.
|
||||
3. Bharath, S.T. & Shumway, T. (2008). "Forecasting Default with the Merton Distance to Default Model." *Review of Financial Studies*, 21(3), 1339-1369.
|
||||
4. Crosbie, P. & Bohn, J. (2003). "Modeling Default Risk." Moody's KMV Working Paper.
|
||||
|
||||
### 한국 시장 연구
|
||||
5. 한국은행. "IRB 접근법 하에서의 장기 부도확률 추정."
|
||||
6. 한국기업평가. "연간 부도율 통계" (korearatings.com)
|
||||
7. 한국신용평가. "신용등급별 부도율 및 전이행렬" (kisrating.com)
|
||||
|
||||
### 기술 참고
|
||||
8. Credit Suisse Financial Products. (1997). "CreditRisk+: A Credit Risk Management Framework."
|
||||
9. JP Morgan. (1997). "CreditMetrics — Technical Document."
|
||||
10. Basel Committee on Banking Supervision. "Studies on the Validation of Internal Rating Systems."
|
||||
Reference in New Issue
Block a user