10.1 동적해지율 엔진설계#
이 챕터는 설계 노트입니다 — 아직 구현되지 않았습니다
아래 API · 필드 · 코드 스케치는 현재 엔진에 없습니다. 실행되는 레시피가 아니라, 동적해지율 (dynamic lapse) 을 fastcashflow 에 어떻게 넣을지의 설계 방향을 기록한 로드맵입니다. 지금 동적해지가 필요하면 이 챕터의 코드를 그대로 쓸 수 없습니다 — 단계함수 해지율 등 정적 표현으로 근사해야 합니다 (3.2 paid-up 의 변형 절 참조).
배경 — 해지율의 네 단계#
같은 위험률이라도 해지율은 여러 축으로 달라집니다. 그 의존성을 표현하는 정교함은 네 단계로 나뉘고, 현 엔진은 처음 셋까지 표현합니다:
종류 |
무엇에 의존 |
현 엔진 |
|---|---|---|
평탄 (flat) |
상수 |
됨 |
duration 의존 |
가입경과 (policy duration) — 납입후 하락이 여기 |
됨 ( |
상태 의존 |
상태 모델의 상태 (active / paidup 등) |
됨 ( |
동적 (dynamic) |
금리 경로 · 해약환급금 moneyness · 계좌가치 등 시나리오 변수 |
안 됨 — 이 챕터의 주제 |
여기서 moneyness (해약환급금이 계약을 계속 유지하는 것 대비 얼마나 유리한지) 란, 예를 들어 시장금리가 적용금리보다 높아 해약 후 재투자가 유리해지면 해지가 늘고, 반대면 줄어드는 행동을 가리킵니다.
처음 세 종류의 공통점은 해지율이 exogenous (투영을 시작하기 전에
(sex, issue_age, duration, ...) 만으로 미리 정해지는, 외생적) 이라는 점입니다.
그래서 엔진이 투영 전에 (성별, 연령, 연도) 격자에 해지율을 미리 깔아두고,
이를 전이확률 (edge probability — 한 상태에서 다음 상태로 넘어가는 월별 확률)
에 합쳐 둘 수 있습니다.
왜 단순 추가가 아니라 구조 변경인가#
동적해지율은 endogenous (투영 내부에서 매월 굴러가며 정해지는, 내생적) 입니다. 그 달의 moneyness 나 금리 스프레드를 보고 해지율이 정해지는데, 그 변수 자체가 시간 루프 안에서 비로소 알려집니다. 따라서:
해지율을 투영 전에 격자로 미리 깔 수 없습니다.
시간 루프 안에서 매월 재평가 해야 합니다.
즉 엔진의 “격자를 미리 깔고 → 루프를 돌린다” 아키텍처에서, 해지 한 항목만 ‘루프 안에서 평가’로 옮기는 것 이 설계의 본질입니다. 나머지 (사망 · 납입면제) 는 그대로 미리 깔아도 됩니다.
핵심 설계 결정 세 가지#
① 어디서 평가하나 — 속도가 지배한다#
fastcashflow 의 시간 루프는 numba @njit 커널 (파이썬 코드를 기계어로 미리
컴파일해 빠르게 도는 핵심 루프) 안에서 돕니다. 평가 위치 선택은 이 제약에
지배됩니다.
방안 |
내용 |
판정 |
|---|---|---|
(A) Python 콜백 주입 |
매월 임의의 파이썬 함수를 커널에서 호출 |
✗ |
(B) 계수표 + 루프 내 룩업 |
base 해지 격자 + moneyness 를 이산화한 배수표 (multiplier table) 를 미리 만들고, 루프 안에서 그 달 moneyness 로 배수를 룩업해 곱함 |
✓ numba 호환 (배열 인덱싱 / 보간만). 권장 |
(C) 닫힌형 공식 하드코딩 |
arctan / 구간선형 공식을 스칼라 파라미터로 커널 안에 직접 |
✓ 빠름. 단 함수형이 고정 — (B) 보다 덜 유연 |
→ (B) 가 정답입니다. 동적해지를 코드 가 아니라 데이터 (배수표) 로 표현하면 numba 커널이 그대로 돌립니다.
② 순환을 피하는 driver 선택#
해지율이 “계속 유지 가치 vs 해지 가치” 같은 완전한 경제가치 에 반응하면, 값과 해지율이 서로를 참조합니다 — 값을 알아야 해지율이 정해지고, 해지율을 알아야 값이 정해지는 순환입니다. 이를 풀려면 fixed-point iteration (고정점 반복 — 값과 해지율이 수렴할 때까지 번갈아 다시 계산) 이 필요하고, 이는 scope 밖입니다.
driver (해지율을 움직이는 변수) 를 계좌가치 (VFA) 나 시장금리 - 적용금리
스프레드 처럼 루프에서 forward 로 (앞쪽으로 한 번에) 이미 계산되는 양으로
잡으면 순환이 없습니다. 둘 다 BEL을 몰라도 매월 구해집니다. fastcashflow 에는
이미 surrender_cf (해약환급금) 가 있으므로, moneyness driver 가 그것을 바로
재사용합니다.
③ 시나리오 차원#
진짜 동적해지는 확률적 금리 분포 아래에서 의미가 큽니다. 그런데 fastcashflow 는 결정론 커널입니다. 따라서 여기서의 동적해지는 단일 결정론 시나리오 (포워드 커브 / 스트레스 경로) 에 반응하는 해지 를 한 번 굴리는 것이고, 여러 시나리오는 커널을 시나리오마다 돌려 밖에서 집계 합니다 (scenario-conditioned projection — 시나리오별로 결정론 투영을 돌리고 결과를 합치는 구조).
VFA의 return_scenarios (펀드 수익률 경로를 받아 보증의 시간가치 TVOG를
계산) 가 이미 이 구조라, 동적해지가 같은 자리에 꽂힙니다. nested stochastic
(시나리오 안에서 다시 시나리오를 도는 중첩 확률투영) 은 영원히 scope 밖 입니다.
fastcashflow 구체 제안 (VFA 먼저, 최소 · 속도보존)#
1. 새 옵션 필드 — 콜백이 아니라 spec 개체#
# 설계 스케치 -- 아직 구현 안 됨
@dataclass(frozen=True, slots=True)
class DynamicLapse:
driver: str # {"account_value_moneyness", "rate_spread"}
breakpoints: FloatArray # moneyness 구간 경계 (오름차순)
multipliers: FloatArray # 각 구간의 base lapse 배수
# → 구간선형 / 계단형. 코드가 아닌 '데이터' 라 numba 가 룩업으로 처리
Basis.dynamic_lapse: DynamicLapse | None = None 로 추가합니다. None
이면 기존 정적 해지 그대로 — back-compat (기존 입력이 손대지 않아도 동작) 가
설계 제약입니다.
2. 커널 변경 — VFA 경로부터#
VFA 커널에는 이미 계좌가치 av[t] 와 시나리오가 흐릅니다. 매월:
moneyness = f(av[t], 보증가치) # 또는 rate_spread = market[t] - credited
mult = lookup(moneyness, breakpoints, multipliers) # 배수표 룩업
eff_lapse = base_lapse[year] * mult
eff_lapse = clamp(eff_lapse, 0.0, 1.0) # [0, 1] 범위로 자름
# → 정적 격자값 대신 eff_lapse 를 그 달의 해지 decrement 로 투입
GMM 경로보다 VFA가 먼저인 이유는, AV 궤적과 시나리오 plumbing (데이터를 커널까지 전달하는 배관) 이 이미 깔려 있기 때문입니다.
3. edge 합성만 부분 변경#
해지 edge 하나만 루프 안에서 합성하고 (base 격자 + 배수표), 나머지 edge (사망 · 납입면제) 는 기존대로 루프 전에 합성합니다. 전면 재작성이 아니라 전이확률 합성 단계의 한 자리만 손봅니다.
4. GMM 경로는 더 큰 작업#
rate_spread 기반 동적해지는 금리 경로 (n_time,) 를 커널 인자로 받아야
합니다 → 시나리오 경로 배관 추가가 VFA보다 큽니다. 인자가 없으면 정적
해지로 fallback 합니다.
5. 검증#
moneyness 가 breakpoint 를 넘는 2~3개월짜리 손계산 케이스를 만들어, 배수가 점프하는 달의 in-force 궤적이 손계산과 일치하는지 assert 합니다 — 쿡북의 다른 챕터와 같은 손계산 검증 원칙입니다.
비용 · 순서#
단계 |
분량 |
|---|---|
VFA 동적해지 (계좌가치 moneyness) — AV · 시나리오 배관이 이미 있어 가장 쌈 |
중간 |
GMM 동적해지 (금리 스프레드) — 시나리오 경로 배관 추가 |
큼 |
N 시나리오 집계 (동적해지의 TVOG) — 커널 밖 집계, scenario-conditioned 재사용 |
별도 |
한 줄 요약: 동적해지율은 “정적 격자 → 루프 내 배수표 룩업” 으로 해지 한 항목만 내생화하는 작업이고, VFA 경로 (계좌가치 moneyness) 부터 붙이는 것이 가장 자연스럽고 싸다.
인접 레시피#
3.2 paid-up 분리 — 정적 해지의 끝 (duration 의존 · 상태 의존). 동적해지가 시작되는 출발점.
변액보험 최저보증 (GMDB / GMAB) — VFA 측정. 동적해지가 먼저 붙을 경로이고, 보증 moneyness 와 직접 상호작용.
검증 패턴 — 손계산 검증 원칙.