Technical Notes#
Status: Draft, 2026-09-03 (all cited sources accessed 2026-09-03).
Scope note. These notes derive the standardized composite Korean deferred variable
annuity — 변액연금보험 (byeonaek yeongeum boheom) — specified in product-spec.md in
this directory into the arithmetic of the reference model VA_KR_S. Where the two
disagree the specification governs and this document is wrong. The composite describes no
single insurer’s contract; it is built on one carrier’s 상품요약서 for the expense stack,
the surrender-charge scale and the fund charges [S2] and on a second carrier’s 상품안내장
for the guarantee design and both guarantee charges [S1], and the reason those two may be
joined and others may not is argued once in product-spec.md and not repeated here.
[S#] tags refer to primary product documents — 약관 (yakgwan, policy conditions),
상품요약서 (sangpum yoyakseo, the statutory product summary), 상품안내장 and 상품설명서 —
and [R#] to product-specific regulatory and actuarial references; both resolve in
sources.md in this directory, whose numbering is carried verbatim from
_research/variable-annuity.md and is never renumbered. [REG-R#] resolves against the
cross-product reference library references/regulatory-and-actuarial-references.md, whose
own R1–R62 numbering is distinct from this product’s. std marks a standardization
introduced for the reference implementation; every one of them is also tagged in
product-spec.md and carries a rationale in the provenance column of the CSV it lives
in. unverified marks a claim the research pass could not confirm against a retrieved
document. Every parameter value below is the value in product-spec.md and the value
in the shipped CSVs.
VA_KR_S runs on a monthly grid with every age in 보험나이 (boheom nai,
insurance age). It is the library’s only 특별계정 (teukbyeol gyejeong, separate account)
product and the only one whose cash flows cross an account boundary, so every flow below
is labelled with the account it falls in, and the identity that the two account ledgers
add back to the whole-contract cash flow is asserted by the model rather than argued in
prose. Amounts are in Korean won; because Korean documents quote in 만원 (10,000) and 억원
(100,000,000), both forms are given where a Korean reader would expect one —
₩36,000,000 (3,600만원).
Model scope and conventions#
Purpose. Project gross liability cash flows for one contract: 영업보험료 received, 사망보험금 (death benefit), 해약환급금 (haeyak hwanreupgeum, surrender value), 연금 (annuity instalments), 중도인출금 (jungdo inchulgeum, partial withdrawals), the third-party costs borne by separate-account assets, and the insurer’s own expenses and commission. The 책임준비금, the 보증준비금 (bojeung junbigeum, guarantee reserve), the 해약환급금준비금, the IFRS 17 CSM and the K-ICS 요구자본 are not computed; see Valuation and reserve pointers.
Two periods, one projection. 연금개시 전 보험기간 (the deferral) runs 「계약일부터 연금개시나이 계약해당일의 전일까지」 and the 연금개시 후 보험기간 (the payout) from there for life [S1] [S7 제2조].
t_ann()is the boundary month. The 특별계정 exists strictly fort < t_ann()and is empty afterwards, the whole 계약자적립액 (gyeyakja jeongnibaek, account value) having moved to the 일반계정 (general account) 「연금개시시점부터 계약자적립액 모두에 대하여 특별계정에서 일반계정으로 자동전환하여 공시이율로 운용합니다」 [S6].Projection frequency: monthly, 0-based.
t = 0is the month containing the 계약일 and the first 기본보험료; rowtofresult_cf()carries montht.proj_len()is the number of projected months and not the last row index: the frame ist = 0 … proj_len() − 1, so the anchor cell hasproj_len()= 960 rows, 0 … 959. Policy year is the contractual 1-based label derived fromt:policy_year(t)= ⌊t/12⌋ + 1, so the first policy year ist = 0 … 11.The monthly grid is itself a std standardization, and a consequential one. The 계약자적립액 is contractually a daily 좌수 (jwasu, unit count) × 기준가격 (gijun gagyeok, unit price) ledger quoted per 1,000좌 [S7 제43조], valued every business day [S7 제37조] [S7 제42조]. Collapsing it onto months also collapses the two-business-day pricing lag that applies to every 펀드변경, 중도인출 and 해지 [S5] [S7 제39조] [S7 제50조제2항]. 감독규정 제7-65조제2항 expressly permits an annualized-premium basis for the 계약자적립액 instead REG-R18; the model does not use that permission and states the discretization it does use.
The account recursion itself is std. Its exact form sits in the 산출방법서 (sanchul bangbeopseo), a filed 기초서류 that is not public REG-R18 제7-64조. The recursion in
av_ppis consistent with, and not derived from, the retrieved documents, and the same limit applies to the surrender value and to the annuity conversion. It is the hard boundary on how far a public-source reconstruction of a Korean variable annuity can go, and it is stated here rather than buried in a footnote.Age basis: 보험나이 throughout. 만나이 (age last birthday) at the 계약일 with a remainder of six months or more rounded up and less than six months discarded, incrementing on the policy anniversary and not on the birthday REG-R25 제21조. The research file records no 보험나이 article read from the retrieved 약관, so no [S#] pinpoint is claimed for it. It is the contractual age, the index of every Korean rate card, and the basis both shipped mortality tables are graduated on, so no shift is applied anywhere. The one place Korean practice uses 만나이 instead is the 가입나이 envelope, 만15세–70세 [S1] [S2], which is an issue rule and not a projection quantity.
Model points and rounding. Single-contract model points on an expected (probability-weighted) basis with
pols_if_init = 1.0, so every*_ppcells is per contract and everyresult_cf()column is that quantity weighted by the in-force count on the same row. No intermediate rounding anywhere; displayed figures are rounded independently for display.Sign convention:
net_cfis income-positive, income less outgo, and it is natively so — there is noliability_cfcompanion on this product and the worked example prints the stream the way the model produces it.net_cf(0)is negative on the anchor cell, because the insurer’s own acquisition expense and the first year’s commission together exceed the first month’s premium.Investment return is not a liability cash flow. The gross separate-account return and the 특별계정 운용보수 (unyong bosu, management fee) drive the account value and are published as
inv_income_ppandmgmt_fee_pp, but neither is a column ofresult_cf(). This library projects gross liability cash flows and leaves the asset side, discounting and every reserve to a layer that consumes them.What the model computes and what it does not. It computes the 계약자적립액 and the 해약환급금, both contractual quantities REG-R18 REG-R19 REG-R20; it computes the intrinsic value of both guarantees on one path and publishes it as such. It is a mechanics demonstration, not a pricing or reserving result, and on this product that sentence carries more weight than anywhere else in
krlib, because the two things it is asked to value are options.
Model point attributes#
Every column of model_point_table.csv, with the cells that reads it. The anchor cell is
model point 1, the illustration point three independent carriers publish
[S1] [S2] [S6].
Column |
Cells |
Type |
Anchor value |
Note |
|---|---|---|---|---|
|
|
str |
|
label only |
|
|
enum {M, F} |
M |
selects the mortality column |
|
|
int, 보험나이 |
40 |
가입나이 envelope 만15–70 [S1] [S2] |
|
|
KRW/month |
300,000 |
기본보험료, level, in advance |
|
|
years |
10 |
납입기간; |
|
|
int, 보험나이 |
60 |
연금개시나이, band 45–80 [S1] [S2] |
|
|
0/1 |
1 |
1 보증형, 0 미보증형 [S4] [S5] |
|
|
key of |
|
채권형 50% / 주식형 50% |
|
|
key of |
|
투자수익률 2.50% |
|
|
key of |
|
payout-phase rate ladder |
|
|
ratio of 기본보험료 |
0.0 |
추가납입 module, off |
|
|
ratio of 해약환급금 |
0.0 |
중도인출 module, off |
|
|
completed policy years |
0 |
계약해당일 of the first 중도인출 |
|
|
count |
1.0 |
contracts at issue |
Derived on the anchor: prem_ann_pp() = ₩3,600,000, prem_total_pp() = ₩36,000,000
(3,600만원), t_ann() = 240, defer_years() = 20, bond_floor() = 0.50 (the
12년 rung),
proj_len()= 960 months, so the last row ist= 959 (attained 보험나이 119, terminal ageomega_age= 120 std).
The ten shipped model points#
# |
sex |
가입 |
기본보험료 |
납입 |
연금개시 |
GMAB |
fund_set |
scenario |
crediting |
module |
what it exercises |
|---|---|---|---|---|---|---|---|---|---|---|---|
1 |
M |
40 |
300,000 |
10 |
60 |
on |
bond50_eq50 |
base |
decl_2026 |
— |
anchor; the three-carrier illustration cell |
2 |
F |
40 |
300,000 |
10 |
60 |
on |
bond50_eq50 |
base |
decl_2026 |
— |
sex: the annuity factor, not the account |
3 |
M |
40 |
300,000 |
10 |
60 |
off |
bond50_eq50 |
base |
decl_2026 |
— |
미보증형: guarantee and both charges removed |
4 |
M |
40 |
300,000 |
10 |
60 |
on |
bond50_eq50 |
low |
decl_2026 |
— |
GMAB in the money at −1.00% |
5 |
M |
40 |
300,000 |
10 |
60 |
on |
bond50_eq50 |
high |
decl_2026 |
— |
the 3.75% mandated illustration return |
6 |
M |
55 |
500,000 |
5 |
65 |
on |
bond80_eq20 |
base |
decl_2026 |
— |
<12년 ladder rung; 표준해약공제액 cap binds |
7 |
F |
48 |
200,000 |
5 |
60 |
on |
bond70_eq30 |
base |
decl_2026 |
— |
=12년 ladder rung; cap binds |
8 |
M |
35 |
300,000 |
10 |
60 |
on |
bond50_eq50 |
base |
decl_2026 |
추가납입 100% |
strike ₩72,000,000; the charge/strike asymmetry |
9 |
F |
45 |
400,000 |
10 |
62 |
on |
bond50_eq50 |
base |
decl_2026 |
중도인출 10%/yr from the 11th anniversary |
proportional re-basing of both guarantees |
10 |
F |
70 |
1,000,000 |
5 |
80 |
on |
bond80_eq20 |
base |
min_guar |
— |
issue-envelope corners; 최저보증이율 ladder |
Every point satisfies the issue envelope of product-spec.md: 가입나이 ≤ 70,
연금개시나이 45–80, 기본보험료 ≤ ₩1,000,000 per 구좌 [S1] [S2] [S9], and the minimum
거치기간 after 납입완료.
State variables#
Every one is a cells of Projection and every one is per contract except pols_*. The
account-value cells are stated at the end of the month; the in-force count is stated
at the start, so a row of result_cf() reads as the exposure the month opens with and
the flows that month produces.
Symbol |
Cells |
Description |
Updated |
|---|---|---|---|
F_j(t) |
|
Balance of fund j at the end of month t |
monthly |
— |
|
The same inside the month, at one of four timings |
within month |
AV(t) |
|
계약자적립액 at the end of month t = Σ_j F_j(t) |
monthly |
— |
|
The same inside the month |
within month |
— |
|
채권형 share of the account at the end of month t |
monthly |
K_d(t) |
|
이미 납입한 보험료 — the strike of both guarantees |
premium; 중도인출 |
DB(t) |
|
사망보험금 = Max[AV(t), K_d(t)], 연금개시 전 only |
monthly |
— |
|
GMDB top-up = max(0, K_d(t) − AV(t)) |
monthly |
C(t) |
|
해약공제액 applying to a surrender at the end of month t |
annually |
CV(t) |
|
해약환급금 = max(0, AV(t) − C(t)) |
monthly |
— |
|
Cumulative 중도인출금 to the end of month t |
on withdrawal |
— |
|
Premiums actually paid, before any withdrawal reduction |
monthly |
B(t) |
|
보험료총액, the base of the premium-based GMAB charge |
monthly |
l(t) |
|
Contracts in force at the start of month t |
monthly |
— |
|
The same inside the month: |
within month |
d(t) |
|
Expected deaths in month t |
monthly |
s(t) |
|
Expected 해지 in month t, on the survivors of the deaths |
monthly |
— |
|
Survivors carried out at the horizon |
horizon month only |
l(T) |
|
Count reaching the 연금개시 계약해당일 |
once |
— |
|
Count an instalment is owed to in month t |
annually |
Four one-off scalars are struck once, at t_ann(), and never move again:
av_ann_pp() = AV(T−1), gmab_base_pp() = K(T), annuity_fund_pp() = 연금재원 and
annuity_net_pp() = the instalment actually paid. The contract permits the insurer to
move the annuity with the 공시이율 as it is re-declared [S5] and to re-strike the
연금생명표 in the policyholder’s favour [S1] [S2] [S5]; the model holds both level
std and says so.
pols_if(t) is a genuine contract count on both sides of annuitisation — deferred
contracts before t_ann(), living annuitants after it. It is not the count an annuity
instalment is owed to: inside the 10-year 보증기간 that is pols_annuity_oblig(t) =
pols_annuitised(), every contract that reached annuitisation whether the annuitant lives
or not, 「사망하더라도 남은 보증기간의 연금은 지급됩니다」 [S2] [S5]. The step down at the
end of the 보증기간 is real and is visible in the worked example.
Assumption inputs#
Three classes, following the house arrangement, because they behave differently under governance. (a) is what the contract promises and the insurer cannot change; (b) is what the insurer declares and may re-declare; (c) is the modeller’s own view. On this product (c) is unusually thin and unusually consequential, and it says so.
(a) Contractual / guaranteed elements (cited)#
Input |
Value |
Cells / CSV |
Basis |
|---|---|---|---|
계약체결비용 |
5.17% of 기본보험료 = ₩15,510/month, ten years from the 계약일 |
|
[S2] |
계약관리비용, 납입기간 이내 |
3.50% of 기본보험료 = ₩10,500/month |
|
[S2] |
계약관리비용, 납입기간 이후 |
1.33% of 기본보험료 = ₩3,990/month (the document prints ₩4,000) |
|
[S2] [S7 제2조] |
위험보험료 band |
0.004%–0.011% of 기본보험료 = ₩12–₩32/month |
|
[S2] [S4] |
최저사망보험금 보증비용 |
연 0.07% of 계약자적립액, monthly at rate/12 |
|
[S1] |
최저연금적립금 보증비용, asset |
연 0.25% of 계약자적립액, monthly at rate/12 |
|
[S1] |
최저연금적립금 보증비용, premium |
연 0.30% of 보험료총액, monthly, for at most 7 years |
|
[S1] |
특별계정 운용보수 |
채권형 연 0.40%, 주식형 연 0.60%, daily at rate/365 |
|
[S2] |
해약공제액 |
₩830,000 × (n − k) ÷ n in completed years k, nil from k = n, with n = min(납입기간, 7) = 7 on the anchor |
|
[S2], fitted to its published scale; the fit std |
해약공제기간 cap |
7 years where the 납입기간 is 7 years or more |
|
|
표준해약공제액 |
5% × 연납순보험료 × min(납입기간, 12) = ₩1,643,940 on the anchor |
|
|
해약환급금 zero floor |
「… 음(陰)의 값인 경우에는 이를 영(零)으로 처리한다」 |
|
|
사망보험금 |
Max[계약자적립액, 이미 납입한 보험료], no 기본사망보험금 |
|
[S1] [S4] [S10] R2 |
GMDB is compulsory |
감독규정 제7-60조제7호 requires a 최저사망보험금 on 변액보험 |
— |
|
최저연금적립금 strike |
이미 납입한 보험료 at 100%, at the single date T |
|
[S1] R2 |
GMAB void on early exit |
not payable on 해지, on death before T, or on 조기연금개시 |
|
[S1] [S6] [S7 제50조제3항] |
Mandatory 채권형 ladder |
거치기간 <12년 ≥80%, =12년 ≥70%, >12년 ≥50% |
|
[S1] R1 |
Pre-annuitisation de-risking |
채권형 topped to 80% at the three 계약해당일 inside 「개시일 − 3년」 |
|
[S1] |
추가납입 cap |
200% of basic premium paid and payable, cumulative, no loading |
|
[S1] |
중도인출 limits |
≤50% of 해약환급금 [S1] [S2] [S5]; residual 계약자적립액 ≥ ₩5,000,000 per 구좌 [S1] [S5] ([S2] publishes ₩3,000,000); cumulative ≤ premiums paid inside 10 years [S1] [S2] [S5] |
|
[S1] [S2] [S5] REG-R58 |
중도인출 re-basing |
이미 납입한 보험료 × (AV − W) ÷ AV, proportional |
|
[S2] [S7 제51조제8항] |
최저보증이율, payout |
경과 5년 미만 1.00% / 5–10년 0.75% / 10년 이상 0.50% |
|
[S1] |
보증지급기간 |
10 years, 종신연금형 정액형, annual instalments in advance |
|
[S1] [S2] [S5] |
연금수령기간 중 계약관리비용 |
연금 연액의 0.5%, netted off each payment |
|
[S4] |
중도인출 수수료 |
None |
— |
[S1] [S2] [S9] |
추가납입 수수료 |
None — but the fee-stack carrier [S2] charges 1.5%, so this line is not its |
— |
[S1]; conflict recorded in |
GMDB extinguishes at 연금개시 |
「일반적으로 연금개시 후 보장은 소멸됨」 |
|
|
Account boundary |
the movements 감독규정 제5-7조 permits between the two accounts |
|
|
예정이율 |
none exists — a variable contract’s accumulation is the fund |
— |
|
무·저해지환급형 |
barred on 변액보험 by 제7-66조제4항제1호 |
— |
(b) Insurer-discretionary current elements#
Two lines only, and they are the two the product’s economics turn on after the fee stack. Both are re-set by the insurer and neither is guaranteed at the level shown.
Input |
Value |
Cells |
Basis |
|---|---|---|---|
공시이율, payout phase |
2.50% at every duration |
|
|
Credited rate actually used |
Max[공시이율, 최저보증이율] = 2.50% at every duration |
|
derived; the floor never binds |
특별계정 fund menu and allocation |
채권형 50% / 주식형 50%, no rebalancing |
|
allocation std; fees [S2] |
기타비용 |
0.00% |
|
|
증권거래비용, 기초펀드 보수 |
0.00%; observed 0.00–0.79% and 0.01–0.45% |
|
std; both ex-post estimates [S2] [S4] |
모집수수료 scale, years 1–5 |
1.34% / 0.41% / 0.28% / 0.25% / 0.11% of 보험료총액 |
|
R1 <표 Ⅴ-3>, 2017 census mean |
The 공시이율 is re-declared monthly off a published 공시기준이율, majority-weighted to
the insurer’s own 운용자산이익률 under a formula each carrier parameterizes for itself
REG-R18 REG-R24. Holding it level is a std simplification that is exact only
where the rate is level, and on this basis it is. It matters in exactly one place — the
annuity factor at t_ann() — because the model strikes the annuity once and holds it.
The 모집수수료 scale is a channel assumption before it is a level assumption. R1’s 2017 census puts the observed year-one range at 0.63%–2.38% and the five-year total at 1.10%–3.13%; bancassurance and online 계약체결비용 were capped at 50% of the tied-agent level from 2016, and the one 변액연금 R1 found buyable directly online carried no acquisition commission at all. The composite is a 전속설계사 (tied agent) contract std and the direction of that choice is stated rather than absorbed.
(c) Behavioral / experience assumptions (modeler’s view — all std)#
Every row here is std. That is not a formatting accident: it is the finding. The 제10회 경험생명표 is not published in full REG-R33 REG-R34, the 참조순보험요율 display does not reach the life side REG-R61, no Korean carrier publishes a unit expense cost R2 [S12], and no retrieved document publishes a 변액연금 lapse table or a single dynamic-lapse parameter R1.
Input |
Value |
Cells / CSV |
Rationale |
|---|---|---|---|
보험사망률 q(x) |
Makeham |
|
std 25% heavier in force than the annuitant basis |
연금사망률 q_a(x) |
Makeham |
|
|
— A |
0.0002 |
— |
|
— c |
1.10 |
— |
|
— B, male |
0.007040013548 |
— |
solved so complete e(65) rounds to 23.7 REG-R33 |
— B, female |
0.004803209921 |
— |
solved so complete e(65) rounds to 27.1 REG-R33 |
Annual q from mu |
|
|
std closed form |
Monthly split |
|
|
std uniform force |
해지율, annual by policy year |
0.28 / 0.22 / 0.17 / 0.14 / 0.12 / 0.10 / 0.09 / 0.08 ultimate |
|
|
해지율 after 연금개시 |
0.00 |
|
std: no retrieved document permits surrender of a 종신연금형 |
Monthly split |
|
|
|
Decrement order |
death first, then 해지 |
|
|
Insurer acquisition expense |
₩300,000 per contract at issue |
|
std; a per-contract amount, not a rate |
Insurer maintenance expense |
₩3,000 per contract per month, level, no inflation |
|
|
Gross asset return, |
3.00% p.a. on both funds → blended 투자수익률 2.50% |
|
|
Gross asset return, |
−0.50% → blended −1.00% |
|
|
Gross asset return, |
+4.25% → blended +3.75% |
|
|
Volatility, correlation, time series |
none |
— |
|
위험보험료 age scale |
15 → 0.000040, 30 → 0.000055, 40 → 0.000080, 50 → 0.000095, 60 → 0.000110 |
|
level [S2] [S4]; scale std |
Terminal age omega |
120 |
|
The mortality construction, and how thin its anchor is. Both columns of
mort_table.csv come from one Makeham law fitted to two published numbers: the 제10회
경험생명표 65세 기대여명 of 23.7 years for men and 27.1 for women REG-R33. The implied
complete expectation at 보험나이 40 on the annuitant basis is 46.425 (M) and 50.292
(F) — curtate plus a half-year, computed off the shipped table — against the population
완전생명표 figures of 41.9 and 47.4 REG-R38, gaps of 4.5 and 2.9 years beside the 4.2 and
3.4 the two published 65세 figures themselves imply, so the extrapolation is at least
internally consistent. It is not the 경험생명표, it is not
published, and the whole of it is std; substituting a filed basis is a CSV
replacement and no formula changes.
The 고도재해장해급여금 of ₩10,000,000 per 구좌 is charged for and never paid. The 위험보험료 buys it [S1] [S2], the model collects the 위험보험료 in the 월공제액, and the benefit is absent because no 장해 incidence rate on this contract’s basis was retrieved: the 참조순보험요율 display is a 장기손해보험 display and does not reach the life side, and although it does carry 상해 후유장해 grids, their values were not extracted and a non-life 상해 rate is not a life 고도재해장해 rate REG-R34 REG-R61. The bias is small — ₩24 a month at issue — and it runs one way, in the insurer’s favour. It is stated rather than hidden.
Cash flow components and recursions#
Notation#
Symbol |
Cells |
Meaning |
|---|---|---|
t |
(index of |
projection month, 0-based; row t carries month t |
N |
|
number of projected months; rows run 0 … N − 1 |
x |
|
가입나이, 보험나이 |
x + ⌊t/12⌋ |
|
attained 보험나이 in month t |
y |
|
policy year containing month t, = ⌊t/12⌋ + 1 |
k |
|
completed whole policy years at the end of month t, = ⌊(t+1)/12⌋ |
n_p, 12 n_p |
|
납입기간 in years and in months |
y_a, T |
|
연금개시나이 and the month of its 계약해당일 |
m |
|
연금개시 전 보험기간 in whole years |
j |
|
fund index; 1 = 채권형, 2 = 주식형 |
w_j, f_j, i_j |
|
allocation, 운용보수, gross asset return of fund j |
g_j |
|
one month’s growth factor |
P |
|
기본보험료, per month |
P(t), A(t) |
|
기본보험료 and 추가납입보험료 payable in month t |
alpha, beta_1, beta_2, gamma |
|
the four expense lines |
L |
|
부가보험료율 = alpha + beta_1 + gamma rates = 0.0867 |
P_sa(t) |
|
특별계정 투입보험료 reaching the fund in month t |
R(t) |
|
위험보험료 |
c_d(t), c_a(t), c_p(t) |
|
the three guarantee-charge components |
B(t) |
|
보험료총액, the base of c_p |
D(t) |
|
월공제액 = R + beta_2 + c_d + c_a + c_p |
W(t) |
|
중도인출금 |
F_j(t), AV(t) |
|
fund balance and 계약자적립액 at the end of month t |
I(t), M(t) |
|
gross separate-account return and 운용보수 taken |
K_d(t) |
|
이미 납입한 보험료 — the strike of both guarantees |
DB(t), C(t), CV(t) |
|
사망보험금, 해약공제액, 해약환급금 |
K(T) |
|
최저연금적립금 strike |
i_c |
|
credited rate the annuity is struck at |
ä |
|
종신연금형 10년 보증기간부 annuity-due factor |
Y, Y_net |
|
연금 연액, gross and net of the payout charge |
q(x), q_a(x) |
|
보험사망률 and 연금사망률 |
l(t), d(t), s(t) |
|
in force at the start of month t; deaths; 해지 |
CF(t) |
|
whole-contract external cash flow, income positive |
CF_g, CF_s |
|
the 일반계정 and 특별계정 ledgers |
Dimensional check: P, P_sa, D, W, F_j, AV, I, M, K_d, DB, C, CV, K(T), Y and every flow
are currency; alpha, beta, gamma, L, w_j, f_j, i_j, q, l and every ratio are dimensionless;
ä has dimensions of years, and annuity_fund_pp / ä is currency per year. c_p is a rate
per annum on a currency that is not the fund, which is the single most important
dimensional statement in this document.
The two deduction points, and why they are not one#
Confusing them is the commonest way to get a Korean variable model wrong, and the policy conditions are explicit [S7 제2조]:
「월공제액이라 함은 해당월의 위험보험료, 계약관리비용(납입기간 종료 후 유지관련비용), 최저사망적립금 보증비용 및 … 보증비용의 합계액을 말합니다. … 다만, 계약체결비용, 계약관리비용(납입기간 중 유지관련비용), 계약관리비용(기타비용)은 보험료를 납입할 때 공제하며 …」
So there are three places a charge is taken and they are not interchangeable:
Out of the premium, in the 일반계정 — 계약체결비용, 납입 중 계약관리비용, 기타비용. This money never enters the 특별계정. It is
prem_charge_pp(t).Out of the 계약자적립액, by cancelling units on the 월계약해당일 — the 월공제액: 위험보험료, 납입 후 계약관리비용, and both guarantee charges. It is
mth_deduct_pp(t), and it moves 특별계정 → 일반계정.Inside the 기준가격 — the 특별계정 운용보수, deducted out of net assets before the unit price is struck [S7 제43조제2호]. The policyholder never sees a deduction; the unit price is simply lower. It is
mgmt_fee_pp(t)and it is written as a factor on the growth, not as a unit cancellation.
The identity R2 states is
특별계정 투입보험료 = 납입보험료 − (계약체결비용 + 납입 중 계약유지비용 + 기타비용)
= 순보험료 + 납입 후 계약유지비용
and the second line is the one that matters: the 계약관리비용 for the period after 납입완료 is collected during the premium-paying period and carried inside the account value, then drawn back out month by month once premiums stop. That is why the monthly deduction steps up at 납입완료 with no premium arriving to offset it, and why [S2]’s own illustration shows its cumulative separate-account contribution falling from ₩32,877,360 at ten years to ₩32,393,520 at twenty.
The 월공제액 (특별계정 → 일반계정)#
R(t) = r(age(t)) P r from risk_prem_table
beta_2 = 0.0133 P for 12 n_p <= t < T, else 0 [S2]
c_d(t) = (0.0007 / 12) x av_pp_at(t, "BEF_DEDUCT") [S1]
c_a(t) = (0.0025 / 12) x av_pp_at(t, "BEF_DEDUCT") if gmab_flag() = 1 [S1]
c_p(t) = (0.0030 / 12) x B(t) for t < min(12 n_p, 84 months, T) [S1]
B(t) = 보험료총액 = 12 n_p P + (추가납입 paid before month t) [S1]
D(t) = min[ R(t) + beta_2(t) + c_d(t) + c_a(t) + c_p(t) ,
max(0, av_pp_at(t, "BEF_DEDUCT")) ] [std] cap
The two asset-based guarantee charges are struck on the account value after the
premium has gone in, at the BEF_DEDUCT timing — that is a modelling choice and it is
tagged where it is made. The premium-based component c_p is not on the fund at all:
its base is 「이미 납입한 보험료(특약보험료 제외) 및 추후 납입할 기본보험료 합계」, the
whole premium the policyholder has undertaken to pay, past and future [S1]. On the anchor
cell that is a flat ₩9,000 a month against a first-year account value of ₩3,216,621
— over 3% a year of the fund at outset, falling below 0.5% a year by the seventh
year, after which it stops entirely. A model that treats guarantee charges as basis points
on the account value misstates this contract’s early-duration cash flow by an order of
magnitude, which is why the asset and premium components are separate cells with separate
bases and separate stopping rules.
The cap at the available account value is std. The contract’s own remedy for an unpayable deduction is to end the premium holiday or to lapse the contract [S1]; neither is represented, and on the shipped points the cap never binds.
중도인출 and the guarantee re-basing#
W(t) = 0 unless the module is on, t is a 계약해당일 (t mod 12 = 0 and t > 0; t = 0 is the
계약일 itself, not an anniversary), t >= 12 x wd_start_year
= min[ wd_ratio x CV, 0.50 x CV, AV_after_deduct − 5,000,000,
(premiums paid − withdrawals to date) if t < 120 months ] [S1] [S2] [S5]
K_d(t) = [ K_d(t−1) + P(t) + A(t) ] x (AV_bef − W(t)) / AV_bef [S2] [S7 제51조제8항]
where AV_bef is the account after the 월공제액 and before the withdrawal. Without the
proportional re-basing a policyholder could withdraw the fund and keep the strike, and
R1 is explicit that the reduction is a guarantee-risk mitigant and not a convenience:
「중도인출금은 최저보증한도에서 차감된다」. The ten-year cumulative limit is a tax rule
showing through into the policy conditions — it is what keeps the 소득세법 시행령 제25조
ten-year exemption open REG-R58. The model takes one withdrawal a year on the
계약해당일 std, against a contract permitting twelve [S1].
The mandatory pre-annuitisation de-risking#
derisk_amount_pp(t) = max(0, 0.80 x AV_aft_deduct(t) − bond_aft_deduct(t))
at t = T − 36, T − 24, T − 12 only [S1]
「「연금지급개시일 − 3년」시점부터 매년 연계약해당일에 … 채권형 … 계약자적립액의 합계가
펀드 전체 계약자적립액의 80% 미만인 경우 … 자동 조정됩니다」 [S1]. It conserves the
total: money moves between funds and never out of the account, which is why it does not
appear in check_av_roll_fwd_resid. It is applied after the 월공제액 and before
the month’s growth std. Unlike 펀드자동재배분 and 펀드자동전환옵션 — which the base
run leaves off, a single deterministic path being unable to distinguish them from a
different fixed allocation — this one is not optional and is on.
The account recursion#
Fund by fund, in the order the month applies them:
F_j(t, BEF_PREM) = 0 for t = 0, else F_j(t−1) (no account before the first premium)
F_j(t, BEF_DEDUCT) = F_j(t, BEF_PREM) + P_sa(t) w_j
F_j(t, AFT_DEDUCT) = F_j(t, BEF_DEDUCT)
− [D(t) + W(t)] x F_j(t, BEF_DEDUCT) / AV(t, BEF_DEDUCT)
F_j(t, AFT_DERISK) = F_j(t, AFT_DEDUCT) +/- the de-risking transfer
F_j(t) = F_j(t, AFT_DERISK) x g_j, g_j = (1 + i_j)^(1/12) (1 − f_j/12)
AV(t) = SUM_j F_j(t)
so that, summed over funds,
AV(t) = [ AV(t−1) + P_sa(t) − D(t) − W(t) ] grown at the fund-weighted g
= AV(t−1) + P_sa(t) − D(t) − W(t) + I(t) − M(t)
which is exactly the residual check_av_roll_fwd_resid(t) drives to zero, with the
연금재원 transfer subtracted in the month t = T. The opening balance AV(t−1) is nil
in t = 0, so the identity closes on the first row too — the row that carries the single
premium, the 계약체결비용 and the whole first month’s charge stack. The 월공제액 and the
중도인출 are taken pro rata across funds on the BEF_DEDUCT weights std.
Two quantities fall out of the growth step and are published separately, because they land in different places:
I(t) = SUM_j F_j(t, AFT_DERISK) [ (1 + i_j)^(1/12) − 1 ] gross return, to the fund
M(t) = SUM_j F_j(t, AFT_DERISK) (1 + i_j)^(1/12) f_j / 12 운용보수, to the 일반계정
check_charge_split() asserts I(t) − M(t) = AV(t) − AV(t, AFT_DERISK) at every month.
That identity is the guard against the charge-base confusion this product is most often
modelled wrong at: four different bases in one stack — the fund (운용보수, both
asset-based guarantee charges), the premium (계약체결비용, 계약관리비용, 위험보험료), the
보험료총액 (the premium-based guarantee charge) and the 연금 연액 (the payout charge).
The 운용보수 is taken monthly at rate/12 against a contractual rate/365 daily std, the monthly grid having no daily step. Note that the disclosed 투자수익률 is already net of it: [S6]’s illustration shows a gross-to-net gap of 0.01 percentage points on a product with no guarantee charge — far too small to contain a management fee — while [S1]’s gap of 0.32pp is exactly its two account-based guarantee charges.
Benefits before 연금개시#
DB(t) = Max[ AV(t), K_d(t) ] [S1] [S4] [S10]
gmdb_claim_pp(t) = max(0, K_d(t) − AV(t)) the 일반계정 보증준비금 part [R2]
n = min(n_p, 7) the 해약공제기간; 7 on the anchor, 5 on points 6, 7, 10
C(t) = min(0.2305555556 x 12 P, surr_chg_cap_pp()) x (n − k) / n, nil from k = n
CV(t) = max(0, AV(t) − C(t)) [REG-R19]
check_gmdb_floor() asserts DB(t) = AV(t) + gmdb_claim_pp(t) at every month — the death
benefit splits exactly into the part released from the 특별계정 and the part met from
the 일반계정 보증준비금, and that split is what makes the two account ledgers add back to
net_cf.
The 해약공제액 runs off linearly in the amount, not in the ratio. All three retrieved
scales fit C × (n − k) ÷ n exactly [S2] [S4] [S5]; the published ratio falls far faster
only because its denominator is growing. Expressing C as 23.05556% of the annualized
기본보험료 so that [S2]’s ₩830,000 scales to other cells is std. The charge is
the unamortised 계약체결비용 R2, which is why the composite takes its acquisition cost
and its surrender charge from one carrier: pairing [S2]’s 5.17% with [S5]’s ₩1,077,000
would recover more on surrender than was ever loaded.
The 표준해약공제액 cap is 0.05 × 12P × (1 − L) × min(n_p, 12) REG-R19 REG-R20. Note
6 to 별표 14 further requires the acquisition cost loaded onto the premium to be discounted
at the 평균공시이율 and netted off the cap; no retrieved document works that netting,
so the exact residual cap is unverified REG-R21 and the model applies the gross
cap. It binds on three shipped points, all 5년납. check_surr_chg_cap() asserts
compliance.
Annuitisation, at the single month T#
AV(T) = av_ann_pp() = av_pp(T − 1)
K(T) = gmab_base_pp() = prem_paid_pp(T − 1) [S1] [R2]
GMAB = gmab_claim_pp() = max(0, K(T) − AV(T)) if gmab_flag() = 1
연금재원 = annuity_fund_pp() = AV(T) + GMAB [S6]
i_c = Max[공시이율, 최저보증이율] at duration 0
ä = SUM_{k=0..9} v^k + SUM_{k=10..omega−y_a−1} v^k (k p_{y_a}), v = 1/(1 + i_c)
Y = 연금재원 / ä
Y_net = Y (1 − 0.005) [S4]
Three things about this block are load-bearing.
The GMAB is a European option struck on one date. It is not payable on 해지, not
payable on death before T, and forfeited on 조기연금개시 — 「만기 전에 사망 또는 해약이
발생하는 경우 이 보증은 성립하지 않으며」 [S1] [S6] [S7 제50조제3항] [S8] [S10] R1 — so
its payoff is weighted by pols_annuitised(), which carries every decrement that
occurred before T. A model treating it as a floor on the account at every duration would
overstate its cost by the whole of the pre-annuitisation exit probability, which on a
seven-year persistency below 30% R1 is most of it.
The account-value part and the guarantee part move differently. av_transfer(t) moves
AV(T) from the 특별계정 to the 일반계정 and appears in both ledgers with opposite
signs; the GMAB top-up moves inside the 일반계정, from the 보증준비금 to the 연금재원,
and so appears in neither. Its only cash-flow consequence is a larger annuity for the
rest of the projection, and that is where a reader should look for it.
The first ten instalments are certain and the rest are life-contingent. Inside the
보증기간 the weight is one whatever the annuitant does, which is the arithmetic statement
of 「사망하더라도 남은 보증기간의 연금은 지급됩니다」 [S2] [S5]. The sum is truncated at
omega_age for consistency with the projection horizon.
Decrements#
q(t) = 보험사망률(age(t)) for t < T, 연금사망률(age(t)) for t >= T
q_mth(t) = 1 − (1 − q(t))^(1/12)
w(t) = 해지율 by policy year for t < T, 0 for t >= T
w_mth(t) = 1 − (1 − w(t))^(1/12)
d(t) = l(t) q_mth(t) death first [std]
s(t) = [ l(t) − d(t) ] w_mth(t) then 해지 [std]
l(t+1) = l(t) − d(t) − s(t) − pols_maturity(t)
The two periods are priced on different mortality tables in Korea and the model does not
pretend otherwise: 보험사망률 through the deferral, 연금사망률 from t_ann(). The switch
is visible in the worked example — mort_rate(239) = 0.0054591503 on the insurance basis
and mort_rate(240) = 0.0047847455 on the annuitant basis, a 12.35% drop across one
month that is a change of table and not a change of risk.
pols_maturity(t) is nil except in the horizon month, where it carries out the survivors
so that the roll-forward closes. A 종신연금형 pays nothing at the horizon, so
claims_maturity is structurally zero at every t; the column exists so that the truncation
at omega_age is visible rather than absorbed into the last row’s decrements.
Processing order (month t = 0 … N − 1)#
The order is not presentational: five of the flows depend on it, and two of the check_*
identities exist only because it is fixed.
Premium, received into the 일반계정:
prem_pp(t)= 기본보험료 + 추가납입보험료.Front-end deduction, retained in the 일반계정:
prem_charge_pp(t). This money never enters the 특별계정 and never comes back out of one.Transfer to the 특별계정:
prem_to_av_pp(t), allocated across funds at the fixedfund_alloc(j). TimingBEF_DEDUCT.월공제액, cancelled out of the 계약자적립액 pro rata across funds. The two asset-based guarantee charges are struck on
av_pp_at(t, "BEF_DEDUCT")— after the premium has gone in. Capped at the available account value std.중도인출, taken with the 월공제액, pro rata across funds. Timing
AFT_DEDUCT.Guarantee-base re-basing:
prem_paid_pp(t)grows by the month’s premiums and is then scaled by (AV − W) ÷ AV.Mandatory de-risking at
t = T − 36, −24, −12. TimingAFT_DERISK. Conserves the total.Growth, fund by fund: gross asset return first, then the 운용보수, which is inside the 기준가격 [S7 제43조제2호].
Decrements on
pols_if(t): death first, then 해지 std;pols_maturityonly in the horizon month.Benefits on the end-of-month account: 사망보험금 Max[AV(t), K_d(t)], 해약환급금 max(0, AV(t) − C(t)).
At t = T:
annuity_fund_pp()= AV(T) + GMAB; the account-value part transfers 특별계정 → 일반계정, the GMAB top-up moves inside the 일반계정. The 특별계정 is empty from here.Payout phase: an annual instalment at
t = T, T+12, T+24, …, level, owed topols_annuitised()while the 보증기간 runs and topols_if(t)afterwards. Death decrement on the 연금사망률; no lapse; no surrender; no death benefit.
Two consequences worth stating because they are easy to get backwards. The benefit is
struck on the end-of-month account, so a death in month t is paid on AV(t), after that
month’s deduction and growth. And the guarantee charges are struck before the growth,
on BEF_DEDUCT, so a rising month raises next month’s charge and not this month’s.
Net cash flow#
net_cf(t) = premiums(t)
− claims_death(t) − claims_lapse(t) − claims_annuity(t) − claims_maturity(t)
− withdrawals(t) − fund_expenses(t) − expenses(t) − commissions(t)
income-positive, and every internal transfer is absent by construction, which is what
makes the columns of result_cf() sum to this line. There is no claims column beside the
four claims_* columns: a cash flow statement must not publish its own subtotal beside its
parts. The claims(t, kind) cells stays and takes DEATH, LAPSE, ANNUITY,
MATURITY.
The two account ledgers decompose it:
CF_s(t) = prem_to_av(t) − av_charges(t) − surr_charges(t) − claims_from_av(t, DEATH)
− claims(t, LAPSE) − withdrawals(t) − av_transfer(t) − fund_expenses(t)
CF_g(t) = premiums(t) + av_charges(t) + surr_charges(t) + av_transfer(t)
− prem_to_av(t) − gmdb_claims(t) − claims(t, ANNUITY) − claims(t, MATURITY)
− expenses(t) − commissions(t)
Every transfer that appears in these two lines is one of the movements 감독규정 제5-7조
permits between the two accounts REG-R15: premium receipt and benefit payment, transfer
to the general account of the amounts needed for risk cover and for acquisition,
maintenance and administration, the management fee, and the 연금재원 moved at 연금개시.
Each appears in both with opposite signs, so their sum is the whole-contract external cash
flow and nothing else. check_net_cf() asserts exactly that at every month, and it is
the identity a 변액연금보험 has to cross the 특별계정 / 일반계정 boundary to state. A
model that cannot state it has not represented the boundary.
Eight check_*() cells are published, each taking no argument and returning a bool,
with the signed per-month residual under <name>_resid(t):
Check |
What it asserts |
|---|---|
|
|
|
|
|
the 계약자적립액 recursion, including the 연금재원 transfer at T |
|
|
|
|
|
the 채권형 weight meets the mandatory ladder at every month |
|
the 해약공제액 stays inside the 표준해약공제액 |
|
the premium allocation matches the published fee stack |
All eight are True on all ten shipped model points.
Optional modules (all off in the base run)#
Module |
Control |
State on the anchor |
Exercised by |
|---|---|---|---|
추가납입보험료 |
|
off |
point 8, at 100% of the 기본보험료 |
중도인출 |
|
off |
point 9, 10% a year from the 11th anniversary |
The GMAB itself |
|
on |
point 3 turns it off (미보증형) |
The return path |
|
|
points 4 (−1.00%) and 5 (3.75%) |
The 최저보증이율 ladder |
|
inert — 2.50% exceeds every step |
point 10 ( |
The 채권형 ladder rung |
|
>12년, floor 50% |
points 6 (<12년) and 7 (=12년) |
증권거래비용, 기초펀드 보수 |
|
0.00 |
not exercised; a CSV change |
Documented in product-spec.md and deliberately not implemented: 펀드자동재배분,
펀드자동전환옵션, 조기연금개시, 일반계정 전환, 보험계약대출, 감액, 보험료 납입
일시중지/중지/종료, 성과·장기유지 보너스, the roll-up / step-up / ratchet GMAB bases, the
CPPI-funded monthly-ratchet guarantee that carries no guarantee charge [S6], the
elective switchable GMAB [S9], and the 실적배당 종신연금 (GLWB) in which the money stays in
the separate account through the payout phase [S2] [S7] [S8] [S10]. Every one of them is a
first-order lever on guarantee cost and none of them can be exercised meaningfully on one
deterministic path.
One implementation limitation of the 추가납입 module, stated rather than discovered
later. gmab_prem_base_pp(t) counts 추가납입 paid before month t using a closed form
that assumes the cumulative 200% cap has not yet bitten. On the shipped points it never
does — point 8 accumulates ₩36,000,000 of additional premium against a cap of ₩72,000,000 —
but a user who raises addl_prem_ratio past the point where the cap binds will find the
charge base and the actual premium diverge.
Policyholder behavior modeling#
Lapse is static and exogenous here, and it is neither in reality. That sentence is the whole of this section’s content and everything else is its justification.
The scale is annual by policy year — 0.28 / 0.22 / 0.17 / 0.14 / 0.12 / 0.10 / 0.09 /
0.08 ultimate — converted to a monthly rate by 1 − (1 − w)^(1/12) std and applied
to the survivors of the month’s deaths. Its level is calibrated to the only published
Korean figure for this product: 「변액보험의 7년 평균 유지율은 30% 미만으로 알려져 있다」,
itself second-hand inside R1 and reported from a 2016 금융감독원 release that was not
retrieved. The scale produces a lapse-only seven-year persistency of 0.28891508 and,
with mortality, an in-force count at month 84 of 0.28606298. Its shape by duration
is std: a monotone run-down from the first-year rate to the ultimate, with the
ultimate starting in the eighth policy year, the duration at which the 해약공제 has run off
and R1’s seven-to-ten-year break-even window opens. No Korean carrier publishes a
변액연금 적용해지율 [S12].
The market and reserving convention is dynamic, and the model does not use it. R1 states the convention plainly:
「동적해지율이란 최저보증 발생률(In-the-moneyness)에 따라 해지율을 달리 적용하는 방법으로, 최저보증 발생률이 높을수록 해지율을 감소시키고, 최저보증 발생률이 낮을수록 해지율을 증가시켜야 한다」
but no retrieved document publishes a functional form or a single parameter. Any
dynamic-lapse formula written here would be a std construction dressed as a cited one, so
the base run does not attempt one. The consequence is stated where it bites: on a path
where the guarantee goes deeply in the money, a static lapse rate lets contracts leave that
a real policyholder would keep, and the guarantee cost is understated in exactly the
scenarios that drive the reserve. Substituting a dynamic form is a change to
lapse_rate(t) alone and touches nothing else in the model.
The other behaviours the contract permits are switches, not hazards. 추가납입 and 중도인출 are modelled as deterministic per-model-point rules — 100% of the basic premium every month, 10% of the surrender value once a year — because there is no Korean utilisation study to calibrate an intensity against. The point of the two modules is not to predict take-up; it is to show what take-up does to the guarantee bases, and the two work in opposite directions:
추가납입 grows the strike without a loading. Point 8’s GMAB strike is ₩72,000,000 against the anchor’s ₩36,000,000, and its 보험료총액 charge base grows with the premiums actually paid. The asymmetry is the interesting part:
c_pstops at seven years while the strike keeps growing for the remaining three years of the premium term, so late additional premium buys guarantee for nothing [S1].중도인출 shrinks the strike proportionally. Point 9’s strike falls from a contractual ₩48,000,000 to ₩25,509,168, and every won of the reduction is the re-basing rule doing what R1 says it is for.
Every option the policyholder holds points the same way, and none of them can be exercised on one path. 조기연금개시 is available only where the guarantee is out of the money [S1] [S9] [S10]; 일반계정 전환 is offered at or above 130% of premiums paid, irreversibly R1; and the automatic transfer at a CPPI barrier is the same trade made by the insurer instead [S6]. A deterministic run has no mechanism to represent a decision that depends on a distribution, and the model does not pretend to.
Annuitisation is certain in this model. Every contract reaching t_ann() annuitises,
on the 종신연금형 10년 보증기간부 정액형 form std, which is the modal election, the
only one exercising both longevity and a guarantee period, and the form the 소득세법
종신형 연금보험 route is written around — that route requiring the guarantee period to sit
within the published 기대여명 REG-R58. The market menu is uniform across carriers —
보증기간 of 10 / 15 / 20 years, to age 100, or 기대여명보증, in 정액형 or 체증형
[S1] [S2] [S5] — and choosing among them is a policyholder decision this model does not
model.
Worked example#
Everything in this section was read off VA_KR_S and can be reproduced by running it.
tests/test_variable_annuity_kr.py asserts these figures against the model cell by cell
to the precision shown, so a discrepancy between this document and the model is a failure
of the library and not a rounding matter.
cd /home/user/lifelib-products
python lifelib/libraries/krlib/products/variable_annuity/run.py
One arithmetic caveat governs every trace below. The model computes in IEEE-754 double
precision with no intermediate rounding. 0.2305555556 × 3,600,000 is
830,000.0001599999, not ₩830,000 exactly, and the residue propagates through the whole
surrender-charge scale; 0.000080 × 300,000 is 24.000000000000004. Traces therefore
use the model’s own values rather than the round contractual ones, and every figure quoted
as a result is the model’s own. Where an intermediate is printed rounded, a figure
recomputed by hand from it can differ in its last digit or two.
The anchor cell and every assumption it uses#
Model point 1, policy_id VA-000001: 남자, 보험나이 40, 기본보험료 ₩300,000
월납, 10년납, 연금개시나이 60, 보증형, 채권형 50% / 주식형 50%, the base
return path, the decl_2026 crediting basis, no 추가납입 and no 중도인출,
pols_if_init 1.0. This is the illustration cell three independent carriers publish
[S1] [S2] [S6] and the only cell at which the composite’s parameters can be checked
against published surrender-value tables.
Derived, at the precision the model produces:
pay_months() 120
t_ann() 240
defer_years() 20
proj_len() 960 rows 0 ... 959; (120 − 40) x 12
prem_ann_pp() 3,600,000.00
prem_total_pp() 36,000,000.00 (3,600만원)
loading_rate() 0.0867
bond_floor() 0.50 the >12년 rung
surr_chg_cap_pp() 1,643,940.00 표준해약공제액, 별표 14
Every assumption value the cell uses, in full, with tags:
Quantity |
Cells |
Value |
Tag |
|---|---|---|---|
계약체결비용 rate |
|
0.0517 |
[S2] |
계약관리비용 납입 중 rate |
|
0.0350 |
[S2] |
기타비용 rate |
|
0.0000 |
|
계약관리비용 납입 후 rate |
|
0.0133 |
[S2] |
위험보험료 rate at 보험나이 40 |
|
0.000080 |
level [S2] [S4]; scale std |
— at 보험나이 50 |
|
0.000095 |
|
GMDB 보증비용 rate |
|
0.0007 p.a. |
[S1] |
GMAB 보증비용, asset |
|
0.0025 p.a. |
[S1] |
GMAB 보증비용, premium |
|
0.0030 p.a. |
[S1] |
특별계정 운용보수, 채권형 |
|
0.0040 p.a. |
[S2] |
특별계정 운용보수, 주식형 |
|
0.0060 p.a. |
[S2] |
증권거래비용·기초펀드 보수 |
|
0.0000 |
|
해약공제 level rate |
|
0.2305555556 |
[S2], expressed as a ratio std |
표준해약공제액 rate |
|
0.0500 |
|
연금수령기간 중 계약관리비용 |
|
0.0050 |
[S4]; adoption std |
모집수수료, years 1–5 |
|
0.0134 / 0.0041 / 0.0028 / 0.0025 / 0.0011 |
|
Insurer acquisition expense |
|
300,000.0 per contract |
|
Insurer maintenance expense |
|
3,000.0 per contract per month |
|
Fund allocation |
|
0.5, 0.5 |
|
Gross asset return, both funds |
|
0.0300 |
|
Monthly growth factor, 채권형 |
|
1.0021321143490463 |
derived |
Monthly growth factor, 주식형 |
|
1.0019650366374175 |
derived |
보험사망률, 보험나이 40 M |
|
0.0011138523 |
std Makeham |
— monthly |
|
9.286844533373806e-05 |
|
— 보험나이 41 |
|
0.0011989710 |
|
— 보험나이 50 |
|
0.0024695609 |
|
— 보험나이 59 (last deferral month) |
|
0.0054591503 |
|
연금사망률, 보험나이 60 M |
|
0.0047847455 |
|
해지율, policy year 1 |
|
0.28 |
|
— monthly |
|
0.027004030272665847 |
|
— policy year 2 |
|
0.22 |
|
— policy year 8+ |
|
0.08 |
|
공시이율, payout |
|
0.025 |
The charge stack in month 0, per contract#
Five lines, three deduction points, four bases. This is the table the rest of the worked example is arithmetic on.
Line |
Cells |
Amount, KRW |
Base |
Account |
|---|---|---|---|---|
계약체결비용 |
|
15,510.00 |
기본보험료 |
일반계정, out of the premium |
계약관리비용, 납입 중 |
|
10,500.00 |
기본보험료 |
일반계정, out of the premium |
기타비용 |
|
0.00 |
기본보험료 |
일반계정, out of the premium |
= 특별계정 투입보험료 |
|
273,990.00 |
— |
일반계정 → 특별계정 |
위험보험료 |
|
24.000000000000004 |
기본보험료 |
특별계정 → 일반계정 |
계약관리비용, 납입 후 |
|
0.00 (₩3,990.00 from t = 120) |
기본보험료 |
특별계정 → 일반계정 |
GMDB 보증비용 |
|
15.98275 |
계약자적립액 |
특별계정 → 일반계정 |
GMAB 보증비용, asset |
|
57.081250000000004 |
계약자적립액 |
특별계정 → 일반계정 |
GMAB 보증비용, premium |
|
9,000.00 |
보험료총액 ₩36,000,000 |
특별계정 → 일반계정 |
= 월공제액 |
|
9,097.063999999998 |
— |
특별계정 → 일반계정 |
특별계정 운용보수 |
|
110.64426393373063 |
특별계정 순자산 |
inside the 기준가격 |
증권거래비용·기초펀드 보수 |
|
0.00 |
특별계정 자산 |
특별계정 → third parties |
해약공제액 if surrendered now |
|
830,000.0001599999 |
annualized 기본보험료 |
특별계정 → 일반계정 |
prem_alloc_ratio(0) = 0.9133 exactly, the ratio three carriers publish at 91.3%,
91.3% and 91.4% on this cell [S1] [S2] [S6].
Read the first-year totals off that table. 계약체결비용 ₩186,120 + 계약관리비용 ₩126,000 + 위험보험료 ₩288 + GMAB premium component ₩108,000, plus the two account-based guarantee charges of ₩5,576.29 — ₩425,984.29 on ₩3,600,000 of premium, 11.83% — against R1’s industry band of 「선취상품은 납입보험료의 5~15%를 … 차감한 후 85~95%만 투자」. Over a quarter of the first year’s charge is the premium-based guarantee component alone, and it is not on the fund: the two charges struck on the account are ₩1,219.81 and ₩4,356.47 in a year in which the account is still being built.
The surrender-charge scale, to the won#
surr_chg_pp(12k) for k = 0 … 8, being the specification’s published table:
k = 0 830,000.0001599999
k = 1 711,428.5715657143
k = 2 592,857.1429714285
k = 3 474,285.7143771428
k = 4 355,714.2857828572
k = 5 237,142.8571885714
k = 6 118,571.4285942857
k = 7 0.0
k = 8 0.0
against the 표준해약공제액 cap of ₩1,643,940.00, which the level charge is 50.5% of and so does not bind on this cell. It binds on points 6, 7 and 10, all 5년납.
First periods of the base run#
Per contract-equivalent, income-positive, to two decimal places — the form run.py prints.
claims_annuity, claims_maturity, withdrawals and fund_expenses are 0.00 at every
row shown here and are omitted; they are columns of result_cf() all the same.
t |
|
|
|
|
|
|
|
|---|---|---|---|---|---|---|---|
0 |
1.0000000000 |
300,000.00 |
27.86 |
0.00 |
303,000.00 |
40,200.00 |
−43,227.86 |
1 |
0.9729056091 |
291,871.68 |
54.21 |
0.00 |
2,918.72 |
39,110.81 |
249,787.95 |
2 |
0.9465453242 |
283,963.60 |
79.11 |
0.00 |
2,839.64 |
38,051.12 |
242,993.73 |
3 |
0.9208992552 |
276,269.78 |
102.63 |
5,833.06 |
2,762.70 |
37,020.15 |
230,551.24 |
4 |
0.8959480508 |
268,784.42 |
124.81 |
12,142.30 |
2,687.84 |
36,017.11 |
217,812.35 |
5 |
0.8716728841 |
261,501.87 |
145.71 |
18,116.58 |
2,615.02 |
35,041.25 |
205,583.30 |
6 |
0.8480554382 |
254,416.63 |
165.39 |
23,769.13 |
2,544.17 |
34,091.83 |
193,846.11 |
7 |
0.8250778927 |
247,523.37 |
183.90 |
29,112.73 |
2,475.23 |
33,168.13 |
182,583.38 |
8 |
0.8027229098 |
240,816.87 |
201.28 |
34,159.69 |
2,408.17 |
32,269.46 |
171,778.28 |
9 |
0.7809736215 |
234,292.09 |
217.58 |
38,921.90 |
2,342.92 |
31,395.14 |
161,414.54 |
10 |
0.7598136169 |
227,944.09 |
232.86 |
43,410.83 |
2,279.44 |
30,544.51 |
151,476.44 |
11 |
0.7392269297 |
221,768.08 |
247.14 |
50,004.27 |
2,217.68 |
29,716.92 |
139,582.06 |
12 |
0.7191980263 |
215,759.41 |
280.40 |
40,913.80 |
2,157.59 |
8,846.14 |
163,561.47 |
13 |
0.7043896277 |
211,316.89 |
295.75 |
43,992.11 |
2,113.17 |
8,663.99 |
156,251.87 |
14 |
0.6898861362 |
206,965.84 |
310.35 |
46,933.14 |
2,069.66 |
8,485.60 |
149,167.09 |
15 |
0.6756812739 |
202,704.38 |
324.23 |
49,741.13 |
2,027.04 |
8,310.88 |
142,301.11 |
The account behind those rows, per contract:
t |
|
|
|
|
|
|
|
|---|---|---|---|---|---|---|---|
0 |
265,435.59 |
9,097.06 |
830,000.00 |
0.00 |
300,000.00 |
300,000.00 |
34,564.41 |
1 |
531,344.02 |
9,167.85 |
830,000.00 |
0.00 |
600,000.00 |
600,000.00 |
68,655.98 |
2 |
797,726.13 |
9,238.76 |
830,000.00 |
0.00 |
900,000.00 |
900,000.00 |
102,273.87 |
3 |
1,064,582.77 |
9,309.79 |
830,000.00 |
234,582.77 |
1,200,000.00 |
1,200,000.00 |
135,417.23 |
4 |
1,331,914.78 |
9,380.95 |
830,000.00 |
501,914.78 |
1,500,000.00 |
1,500,000.00 |
168,085.22 |
11 |
3,216,620.89 |
9,882.65 |
711,428.57 |
2,505,192.32 |
3,600,000.00 |
3,600,000.00 |
383,379.11 |
12 |
3,487,786.59 |
9,954.83 |
711,428.57 |
2,776,358.02 |
3,900,000.00 |
3,900,000.00 |
412,213.41 |
Three features of these sixteen rows are the product, and each is traced or explained below.
claims_lapse is nil at t = 0, 1, 2 and ₩5,833.06 at t = 3. The 해약공제액 of
₩830,000 exceeds the 계약자적립액 for the first three months, and the statutory zero floor
REG-R19 제7-66조제1항제1호 turns the difference into nothing rather than a debt.
[S6]’s own illustration shows exactly this: a surrender value of zero at three months on an
account of ₩821,751. It is not a modelling artefact; it is the product, and it is the
single most consumer-visible fact about a Korean front-loaded variable annuity.
commissions falls by a factor of 3.36 at t = 12, from ₩29,716.92 to ₩8,846.14: the
first-year 1.34% of 보험료총액 giving way to the second-year 0.41% R1 <표 Ⅴ-3>. The
in-force count falls only 2.7% across the same month, so essentially the whole of the step
is the commission scale.
net_cf is negative in month 0 and only in month 0 across the whole premium-paying
period. The ₩300,000 of premium is met by ₩303,000 of the insurer’s own expense and
₩40,200 of commission, so the contract opens −₩43,227.86. From month 1 the acquisition
expense is gone and the row is strongly positive; the first twelve months sum to
+₩2,104,181.53.
Hand trace, month 0 — the two deduction points and the first growth#
Premium, 일반계정
P(0) = 300,000.0000000000
alpha(0) = 0.0517 x 300,000 = 15,510.0000000000
beta_1(0) = 0.0350 x 300,000 = 10,500.0000000000
gamma(0) = 0.0000 x 300,000 = 0.0000000000
prem_charge_pp(0) = 26,010.0000000000
P_sa(0) = 300,000 − 26,010 = 273,990.0000000000
prem_alloc_ratio(0) = 273,990 / 300,000 = 0.9133
Into the funds at the fixed allocation (BEF_DEDUCT)
F_1(0, BEF_DEDUCT) = 0 + 273,990 x 0.50 = 136,995.0000000000
F_2(0, BEF_DEDUCT) = 0 + 273,990 x 0.50 = 136,995.0000000000
AV(0, BEF_DEDUCT) = 273,990.0000000000
월공제액, struck on AV(0, BEF_DEDUCT)
R(0) = 0.000080 x 300,000 = 24.0000000000
beta_2 = 0 (t < pay_months()) = 0.0000000000
c_d(0) = (0.0007 / 12) x 273,990 = 15.9827500000
c_a(0) = (0.0025 / 12) x 273,990 = 57.0812500000
c_p(0) = (0.0030 / 12) x 36,000,000 = 9,000.0000000000
D(0) = 9,097.0640000000
AV(0, AFT_DEDUCT) = 273,990 − 9,097.064 = 264,892.9360000000
pro rata, both funds equal: 264,892.936 / 2 = 132,446.4680000000
no de-risking at t = 0, so AFT_DERISK = AFT_DEDUCT
Growth, fund by fund
(1.03)^(1/12) = 1.0024662697723037
g_1 = (1.03)^(1/12) x (1 − 0.0040/12) = 1.0021321143490463
g_2 = (1.03)^(1/12) x (1 − 0.0060/12) = 1.0019650366374175
F_1(0) = 132,446.468 x g_1 = 132,728.8590149033
F_2(0) = 132,446.468 x g_2 = 132,706.7301621166
AV(0) = 265,435.5891770198
I(0) = 264,892.936 x [(1.03)^(1/12) − 1] = 653.2974409536
M(0) = 264,892.936 x (1.03)^(1/12) x 0.0050/12 = 110.6442639337
check: 264,892.936 + 653.297441 − 110.644264 = 265,435.5891770198 OK
Decrements and benefits
q(0) = 0.0011138523; q_mth(0) = 1 − (1 − q)^(1/12) = 0.0000928684
d(0) = 1.0 x 0.00009286844533 = 0.0000928684
w(0) = 0.28; w_mth(0) = 1 − (0.72)^(1/12) = 0.0270040303
s(0) = (1 − 0.00009286845) x 0.02700403027 = 0.0270015225
l(1) = 1 − 0.0000928684 − 0.0270015225 = 0.9729056091
K_d(0) = 300,000; DB(0) = Max(265,435.59, 300,000) = 300,000.0000000000
C(0) = min(830,000.00016, 1,643,940) x (7 − 0)/7 = 830,000.0001599999
CV(0) = max(0, 265,435.589 − 830,000.000) = 0.0000000000 <- floor
Cash flow row
premiums(0) = 300,000 x 1.0 = 300,000.0000000000
claims_death(0) = 300,000 x 0.00009286844533 = 27.8605336001
claims_lapse(0) = 0.00 x 0.0270015225 = 0.0000000000
expenses(0) = (300,000 + 3,000) x 1.0 = 303,000.0000000000
commissions(0) = (0.0134/12) x 36,000,000 x 1.0 = 40,200.0000000000
net_cf(0) = 300,000 − 27.8605336 − 0 − 303,000 − 40,200 = −43,227.8605336001
Read the account boundary off that row. net_cf_gen(0) = −300,818.3366588763 and
net_cf_sep(0) = +257,590.4761252762; they sum to −43,227.86053360 to within
8.7e−11, which is check_net_cf_resid(0). Both ledgers reconcile line by line, and the
two lines a reader is most likely to put on the wrong side are the 해약공제액 and the
death claim:
net_cf_gen(0) = + premiums(0) 300,000.0000000000
+ av_charges(0) = D(0) + M(0) 9,207.7082639337
+ surr_charges(0) = min(C(0), AV(0)) x s(0) 7,167.1650202870
− prem_to_av(0) 273,990.0000000000
− gmdb_claims(0) = gmdb_claim_pp(0) x d(0) 3.2099430970
− expenses(0) 303,000.0000000000
− commissions(0) 40,200.0000000000
= −300,818.3366588763
net_cf_sep(0) = + prem_to_av(0) 273,990.0000000000
− av_charges(0) 9,207.7082639337
− surr_charges(0) 7,167.1650202870
− claims_from_av(0, DEATH) = AV(0) x d(0) 24.6505905031
= +257,590.4761252762
So the 일반계정 received ₩300,000, kept ₩26,010 of front-end charges and sent ₩273,990 across; took back the ₩9,097.06 월공제액 and the ₩110.64 운용보수, and took the ₩7,167.17 of 해약공제액 retained on the month’s surrenders — the whole account value of the surrendering contracts, the charge exceeding it — and paid ₩303,000 of its own expenses, ₩40,200 of commission and only the ₩3.21 GMDB top-up of the ₩27.86 death claim, the other ₩24.65 being the 계약자적립액 released by the 특별계정. The 특별계정 received ₩273,990 and gave up ₩16,399.52 in the same month, of which ₩9,097.06 was the 월공제액 cancelled before the growth: the ₩264,892.94 that then grew is the account after that cancellation and before the ₩110.64 운용보수, which is taken inside the 기준가격.
Hand trace, month 3 — where the surrender value clears the floor#
The first month in which a surrendering policyholder receives anything, and therefore the
first month with a claims_lapse line.
Opening
AV(2) = F_1(2) + F_2(2) = 797,726.1281495993
F_1(2) = 398,929.0515490024, F_2(2) = 398,797.0766005968
Premium and transfer
P_sa(3) = 300,000 − 26,010 = 273,990.0000000000
F_1(3, BEF_DEDUCT) = 398,929.0515490024 + 136,995 = 535,924.0515490024
F_2(3, BEF_DEDUCT) = 398,797.0766005968 + 136,995 = 535,792.0766005968
AV(3, BEF_DEDUCT) = 1,071,716.1281495993
월공제액
R(3) = 24.000000000000004
c_d(3) = (0.0007/12) x 1,071,716.1281495993 = 62.5167741421
c_a(3) = (0.0025/12) x 1,071,716.1281495993 = 223.2741933645
c_p(3) = (0.0030/12) x 36,000,000 = 9,000.0000000000
D(3) = 9,309.7909675066
AV(3, AFT_DEDUCT) = 1,071,716.1281496 − 9,309.7909675 = 1,062,406.3371820927
F_1 share = 535,924.0515490024 / 1,071,716.1281495993 = 0.5000615718
F_1(3, AFT_DEDUCT) = 531,268.5828448085
F_2(3, AFT_DEDUCT) = 531,137.7543372842
Growth
F_1(3) = 531,268.5828448085 x 1.0021321143490463 = 532,401.3082134894
F_2(3) = 531,137.7543372842 x 1.0019650366374175 = 532,181.4594840726
AV(3) = 1,064,582.7676975620
Surrender value — the floor releases
C(3): yrs_completed(3) = (3 + 1) // 12 = 0, so k = 0 = 830,000.0001599999
CV(3) = max(0, 1,064,582.7676975620 − 830,000.0001600) = 234,582.7675375621 <- first
compare CV(2) = max(0, 797,726.128 − 830,000.000) = 0.00
Decrements
l(3) = 0.9208992552115434
d(3) = 0.9208992552115434 x 0.00009286844533373806 = 0.0000855225
s(3) = (0.9208992552115434 − 0.0000855225) x 0.02700403 = 0.0248656819
Cash flow row
premiums(3) = 300,000 x 0.9208992552115434 = 276,269.7765634630
claims_death(3) = 1,200,000 x 0.00008552248214049331 = 102.6269785686
claims_lapse(3) = 234,582.7675375621 x 0.0248656819141 = 5,833.0604801209
expenses(3) = 3,000 x 0.9208992552115434 = 2,762.6977656346
commissions(3) = 40,200 x 0.9208992552115434 = 37,020.1500595040
net_cf(3) = 276,269.7765635 − 102.6269786 − 5,833.0604801
− 2,762.6977656 − 37,020.1500595 = 230,551.2412796349
The death benefit is ₩1,200,000 and the account is ₩1,064,583, so the GMDB is in the
money by ₩135,417.23 — and it is in the money at every month up to t = 122 — the
whole premium-paying period and three months beyond it, gmdb_claim_pp(123) being the
first zero — because premium at a 91.33% allocation cannot outrun premiums-paid until
compound return has had a decade to work. That is the structural point about a
return-of-premium GMDB on a front-loaded contract: it is in the money by construction
at short durations, and its cost is a decreasing function of duration rather than a
random one.
Hand trace, month 120 — 납입완료, and the deduction that steps up#
The premium stops and the monthly deduction rises by 42%, because the 계약관리비용 for the period after 납입완료 was collected inside the premium and is now drawn back out of the fund.
Opening
AV(119) = 35,813,337.7735828300
F_1(119) = 17,998,819.2913504020, F_2(119) = 17,814,518.4822324300
Premium — none
P(120) = 0 (t = 120 = pay_months()); P_sa(120) = 0.0000000000
AV(120, BEF_DEDUCT) = AV(119) = 35,813,337.7735828300
월공제액 — three of the five lines have changed since month 0
R(120) = risk_prem_rate(50) x 300,000 = 0.000095 x 3e5 = 28.5000000000
beta_2 = 0.0133 x 300,000 <- steps IN at t = 120 = 3,990.0000000000
c_d(120) = (0.0007/12) x 35,813,337.7735828 = 2,089.1113701257
c_a(120) = (0.0025/12) x 35,813,337.7735828 = 7,461.1120361631
c_p(120) = 0 <- stopped at t = 84 (7 years) = 0.0000000000
D(120) = 13,568.7234062888
compare D(119) = 24 + 0 + 2,085.3970430603 + 7,447.8465823581
= 9,557.2436254184
the step is +4,011.48: beta_2 3,990.00, the age band 4.50, and 16.98 of
growth in c_d (+3.71) and c_a (+13.27) on a larger account
AV(120, AFT_DEDUCT) = 35,799,769.0501765460
F_1(120, AFT_DEDUCT) = 17,992,000.0163041000
F_2(120, AFT_DEDUCT) = 17,807,769.0338724400
Growth
F_1(120) = 17,992,000.0163041 x 1.0021321143490463 = 18,030,361.0177069050
F_2(120) = 17,807,769.0338724 x 1.0019650366374175 = 17,842,761.9524546680
AV(120) = 35,873,122.9701615730
Benefits and decrements
K_d(120) = 36,000,000 (all 120 premiums paid)
DB(120) = Max(35,873,122.97, 36,000,000) = 36,000,000.0000000000
gmdb_claim_pp(120) = 36,000,000 − 35,873,122.97 = 126,877.0298384279
C(120) = 0 (k = 10 >= 7); CV(120) = AV(120) = 35,873,122.9701615730
l(120) = 0.2213584991; d(120) = 0.0000456065; s(120) = 0.0015324551
Cash flow row
premiums(120) = 0.0000000000
claims_death(120) = 36,000,000 x 0.00004560650207599255 = 1,641.8340747357
claims_lapse(120) = 35,873,122.9701616 x 0.0015324551487 = 54,973.9519946892
expenses(120) = 3,000 x 0.2213584991 = 664.0754971924
commissions(120) = 0 (year 11 > 5) = 0.0000000000
net_cf(120) = −1,641.8340747 − 54,973.9519947 − 664.0754972 = −57,279.8615666174
The statement flips sign here and never comes back. Month 119 is +₩9,418.79 and month
120 is −₩57,279.86: the premium that carried the row is gone and the surrender stream is
not. Every subsequent month of the deferral is negative, and the account boundary confirms
where the money is — net_cf_gen(120) = +5,640.336569994052 (the 일반계정 still
collects the 월공제액 and the 운용보수 and the retained 해약공제액) and net_cf_sep(120) =
−62,920.198136611405 (the 특별계정 pays out the surrendering and dying accounts and has
no premium coming in).
Month 204 — the mandatory de-risking bites#
At t = T − 36 = 204, the first of the three annual 계약해당일 inside the 「연금개시일 −
3년」 window, the 채권형 weight at the AFT_DEDUCT timing is 0.5060742578243943 — the
value bond_weight(203) also carries, above the 50% ladder floor for a 20-year deferral but
below the 80% the de-risking rule targets [S1]. bond_weight(204) is the post-transfer
0.8000266764480309.
AV(204, AFT_DEDUCT) = 41,211,386.0778102300
bond = F_1(204, AFT_DEDUCT) = 20,856,021.6232423860
target = 0.80 x 41,211,386.0778102 = 32,969,108.8622481820
derisk_amount_pp(204) = 32,969,108.8622482 − 20,856,021.6232424
= 12,113,087.2390057970
F_1(204, AFT_DERISK) = 20,856,021.6232424 + 12,113,087.2390058
= 32,969,108.8622481820
F_2(204, AFT_DERISK) = 20,355,364.4545678 − 12,113,087.2390058
= 8,242,277.2155620450
total unchanged = 41,211,386.0778102270
Two consequences are visible in the output and neither is decoration. The 운용보수 falls
from ₩17,143.34 to ₩15,148.11 in one month — an 11.6% drop with no change in the account
— because 29.4% of the account, three fifths of the 주식형 balance, has moved from a 0.60%
fund to a 0.40% one. And bond_weight(t) stays above 0.80 from here to annuitisation
without any further transfer
(derisk_amount_pp(216) and derisk_amount_pp(228) are both 0.00), because the
채권형 carries the lower 운용보수 on the same gross asset return and so drifts upwards
on its own. On a path with different returns by fund it would not, and the two later
windows would fire.
The rows where the product does something#
Every event row of the anchor cell’s statement, to two decimal places.
t |
event |
|
|
|
|
|
|
|
|
|---|---|---|---|---|---|---|---|---|---|
0 |
issue; acquisition expense |
1.0000000000 |
300,000.00 |
27.86 |
0.00 |
0.00 |
303,000.00 |
40,200.00 |
−43,227.86 |
3 |
해약환급금 clears the zero floor |
0.9208992552 |
276,269.78 |
102.63 |
5,833.06 |
0.00 |
2,762.70 |
37,020.15 |
230,551.24 |
12 |
commission steps to year 2 |
0.7191980263 |
215,759.41 |
280.40 |
40,913.80 |
0.00 |
2,157.59 |
8,846.14 |
163,561.47 |
83 |
last month of the GMAB premium charge |
0.2883626523 |
86,508.80 |
1,072.96 |
54,234.14 |
0.00 |
865.09 |
0.00 |
30,336.61 |
84 |
GMAB premium charge stops (7 years) |
0.2860629838 |
85,818.90 |
1,168.83 |
48,216.27 |
0.00 |
858.19 |
0.00 |
35,575.60 |
119 |
last premium |
0.2229441583 |
66,883.25 |
1,519.23 |
55,276.40 |
0.00 |
668.83 |
0.00 |
9,418.79 |
120 |
납입완료; deduction steps up |
0.2213584991 |
0.00 |
1,641.83 |
54,973.95 |
0.00 |
664.08 |
0.00 |
−57,279.86 |
121 |
first full post-premium month |
0.2197804374 |
0.00 |
1,630.13 |
54,673.17 |
0.00 |
659.34 |
0.00 |
−56,962.64 |
203 |
before de-risking |
0.1215837337 |
0.00 |
1,744.87 |
34,696.10 |
0.00 |
364.75 |
0.00 |
−36,805.73 |
204 |
de-risking to 80% 채권형 |
0.1206998103 |
0.00 |
1,897.78 |
34,502.45 |
0.00 |
362.10 |
0.00 |
−36,762.34 |
239 |
last deferral month |
0.0932722265 |
0.00 |
1,866.77 |
28,329.63 |
0.00 |
279.82 |
0.00 |
−30,476.22 |
240 |
연금개시; first instalment |
0.0925841296 |
0.00 |
0.00 |
0.00 |
200,728.58 |
277.75 |
0.00 |
−201,006.33 |
241 |
a payout month with no instalment |
0.0925471325 |
0.00 |
0.00 |
0.00 |
0.00 |
277.64 |
0.00 |
−277.64 |
252 |
second instalment, still guaranteed |
0.0921411381 |
0.00 |
0.00 |
0.00 |
200,728.58 |
276.42 |
0.00 |
−201,005.00 |
348 |
last guaranteed instalment |
0.0868296734 |
0.00 |
0.00 |
0.00 |
200,728.58 |
260.49 |
0.00 |
−200,989.07 |
360 |
first life-contingent instalment |
0.0858776937 |
0.00 |
0.00 |
0.00 |
186,188.58 |
257.63 |
0.00 |
−186,446.21 |
959 |
horizon; |
0.0000000917 |
0.00 |
0.00 |
0.00 |
0.00 |
0.00 |
0.00 |
−0.00 |
Four of those rows carry the product’s structure.
t = 84, the GMAB premium charge stops. The 월공제액 falls from ₩15,422.57 to
₩6,504.62, a 57.8% drop in one month, because c_p is levied 「납입기간(최대 7년)
동안」 [S1] and the seventh year has ended. Nothing else changes: c_d and c_a rise
smoothly with the account, and the premium keeps arriving for three more years. This is the
single largest discontinuity in the charge stack and it is invisible in any model that
puts guarantee charges on the account value.
t = 240, annuitisation. claims_death and claims_lapse go to zero permanently — the
death cover extinguishes at 연금개시 R2 and no retrieved document permits surrender of a
종신연금형 — and claims_annuity appears. The 특별계정 is emptied: net_cf_sep(240) =
−4,062,956.72108272, exactly the av_transfer, and net_cf_gen(240) =
+3,861,950.3910125117, the same amount less the instalment and the month’s expense.
t = 241 and every non-anniversary month afterwards carry nothing but the insurer’s own ₩3,000-per-contract maintenance expense, weighted by a slowly falling annuitant count. The statement is eleven-twelfths empty for sixty years — t = 240 to t = 959.
t = 360, the 보증기간 ends. The instalment falls from ₩200,728.58 to
₩186,188.58, a 7.24% step, not because the annuity changed — annuity_net_pp() is
the same ₩2,168,066.80 — but because the weight changed from pols_annuitised() =
0.09258412964405735, every contract that reached annuitisation, to pols_if(360) =
0.08587769374658065, the ones whose annuitant is still alive. Ten years of annuitant
mortality at 보험나이 60–70 is 7.24% of the cohort.
The two guarantees at t_ann() = 240#
Quantity |
Cells |
Value |
|---|---|---|
계약자적립액 at T |
|
43,883,943.57329801 |
최저연금적립금 strike K(T) |
|
36,000,000.0 |
GMAB payoff max(0, K − AV) |
|
0.0 |
연금재원 |
|
43,883,943.57329801 |
Credited rate at annuitisation |
|
0.025 |
Annuity factor, 10년 보증 종신 |
|
20.139842488678187 |
연금 연액, gross |
|
2,178,961.6079652957 |
연금수령기간 중 계약관리비용 |
|
10,894.80803982648 |
연금 연액 actually paid |
|
2,168,066.7999254693 |
Contracts reaching T |
|
0.09258412964405735 |
Y = 43,883,943.57329801 / 20.139842488678187 = 2,178,961.6079652957
Y_net = 2,178,961.6079652957 x (1 − 0.005) = 2,168,066.7999254693
claims_annuity(240) = 2,168,066.7999254693 x 0.09258412964405735
= 200,728.5776812762
Only 9.26% of contracts reach annuitisation. That number is the point R1 makes and it is the single most important number in this document: against a seven-year persistency below 30% and 8% ultimate lapse thereafter, a model treating the GMAB as a floor at every duration would overstate its cost roughly tenfold. The guarantee is a European option struck on one date, void on every earlier exit [S1] [S6] [S7 제50조제3항], and the exit probability is 90.7%.
The GMAB finishes out of the money on this path, so its intrinsic cost is exactly
zero while the full ₩657,417.59 of charge is collected. That is an artefact of the
path, not a finding about the guarantee, and the gap is a single-path residual and not
a profit. run.py labels it so and so does this document. Model point 4, on the mandated
−1.00% return, is the counter-example: there the strike bites at ₩10,041,179.61 per
annuitising contract, ₩929,653.88 of expected cost against ₩603,909.13 of charge — the
charge does not cover the guarantee on the low path. The statutory 보증준비금 is a
CTE(70) over a thousand scenarios or a standard factor, whichever is greater
REG-R10 REG-R26 R1, and this model publishes neither.
Undiscounted totals#
Over t = 0 … 959, income-positive:
pols_if (a sum of counts, not money) 99.6122423885
premiums 15,215,257.48
claims_death 310,883.37
claims_lapse 11,077,101.66
claims_annuity 5,759,786.33
claims_maturity 0.00
withdrawals 0.00
fund_expenses 0.00
expenses 598,836.73
commissions 617,364.10
net_cf −3,148,714.71
Guarantee memo lines, undiscounted, from the same run:
gmdb_charges collected 79,244.38
gmdb_claims incurred 4,945.39
gmab_charges collected 657,417.59
gmab_claims incurred 0.00
Four of those numbers repay a second look.
premiums totals ₩15,215,257.48 against a contractual ₩36,000,000 — 42.26%. The
whole of the difference is lapse: a contract that pays all 120 premiums pays ₩36,000,000,
and the expected contract pays 42% of that because 78% of the cohort has gone by the last
premium. That single ratio is the economics of a Korean front-loaded variable annuity:
the acquisition cost is levied on a premium stream that mostly does not arrive, which is
why the 해약공제 exists and why 감독규정 제7-66조 caps it.
claims_lapse at ₩11,077,101.66 is 72.8% of premiums. Surrender, not death and not
annuity, is what this product mostly pays. The 사망보험금 total of ₩310,883.37 is 2.0% of
premiums and the annuity total of ₩5,759,786.33 is 37.9%, but the annuity is paid to the
9.26% who stay.
commissions totals ₩617,364.10 against 2.39% × ₩36,000,000 = ₩860,400 unweighted —
71.8%, the in-force weighting of the five-year scale. The 2.39% is the sum of R1’s five
per-year means; the same table reports a mean total of 2.11%, and the two differ
because a mean of contract totals is not the sum of per-year means. The model runs the
per-year scale, so the unweighted figure to compare against is 2.39%. expenses totals
₩598,836.73, of which ₩300,000 is the day-one acquisition amount, so more than half of
the insurer’s own lifetime expense on this contract falls in month 0.
net_cf sums to −₩3,148,714.71 and must be negative: undiscounted, the insurer
receives ₩15.2m and pays ₩17.1m of benefits plus ₩1.2m of its own costs over eighty years.
The sign becomes meaningful only when the stream is discounted, which this library does not
do. Σ pols_if = 99.61 is the expected number of contract-months of exposure — 8.3
contract-years — against a 960-month projection: another statement of the same persistency
fact.
Reading the shape of the result#
The statement has four regions and each says something about the product.
Months 0–119, the premium-paying deferral. Strongly positive after month 0 and falling
on trend, from +₩249,787.95 at t = 1 to +₩9,418.79 at t = 119, because the premium is
weighted by an in-force count that falls from 0.9729 to 0.2229 while the surrender stream
per surviving contract grows with the account. The fall is not monotone: the row steps
up at t = 12, 24, 36, 48, 60, 72 and 84, the seven policy-year boundaries at which the
annual 해지율 drops a rung and the month’s claims_lapse falls with it. The insurer’s
positive cash flow is a melting block of ice, and the melting is lapse.
Months 120–239, the paid-up deferral. Uniformly negative, between −₩57,279.86 and
−₩30,476.22, because nothing comes in and the surrender stream is at its largest per
contract. This is where the 계약관리비용 collected in the premium period is spent, and
the model shows both halves of that transaction — the money went into the account at
t < 120 and comes back out as mth_deduct_pp at t ≥ 120.
Month 240, the hinge. ₩4,062,956.72 of 계약자적립액 crosses from the 특별계정 to the 일반계정 in one movement, the death and surrender streams stop dead, and the annuity starts. The 특별계정 is empty from here and the remaining 719 months are a general- account liability.
Months 240–959, the payout. Ten annual instalments of ₩200,728.58 — t = 240, 252, …,
348, the whole 10-year 보증기간 — guaranteed regardless of survival, then a
life-contingent stream falling from ₩186,188.58 with the
annuitant count, and ₩277-and-falling of maintenance expense in every intervening month for
sixty years. The tail is thin and long: pols_if(959) is 9.17e−08.
What the four regions say together is that this is not one product but two bolted at month 240 — a front-loaded separate-account savings contract with a 90.7% exit probability, and a general-account life annuity on the 9.3% who survive it. The guarantees straddle the join: the GMDB is a monthly strip of puts on the first, worth ₩4,945.39 in expected cost against ₩79,244.38 of charge on this path, and the GMAB is a single European put at the join itself, worth zero here and ₩929,653.88 on the low path. Neither number is a valuation, and the 별표 24 CTE(70) that would be is not computed.
Contrasts across model points#
The same anchor cell on four variations, showing which lever moves what:
Point |
Variation |
|
|
|
Σ |
|---|---|---|---|---|---|
1 |
anchor, 투자수익률 2.50% |
43,883,943.5733 |
0.0 |
2,168,066.7999 |
−3,148,714.7117 |
2 |
female |
43,883,943.5733 |
0.0 |
2,006,441.2426 |
— |
3 |
미보증형 (GMAB off) |
46,722,879.2288 |
— |
2,308,323.1589 |
−4,033,326.0 |
4 |
투자수익률 −1.00% |
25,958,820.3874 |
10,041,179.6126 |
1,778,564.0588 |
−192,370.8500 |
5 |
투자수익률 3.75% |
52,811,343.3686 |
0.0 |
2,609,121.0337 |
−5,173,103.5565 |
Point 2 has the same account value as point 1 to the last digit. The 계약자적립액 is a
per-contract quantity and mortality enters only through the counts and through the
annuity factor: annuity_factor() is 20.139842488678187 for the male and
21.762174205458386 for the female, so the same ₩43,883,943.57 buys 7.45% less annual
income. That is the whole of the sex effect on this product, and it lands entirely at
t_ann().
Point 3 quantifies the guarantee’s price to the policyholder. Removing the GMAB and both its charges raises the terminal account by ₩2,838,935.66 — 6.47% — and the annuity by the same 6.47%. Over twenty years, 0.25% a year of the fund plus 0.30% a year of ₩36,000,000 for seven years costs the policyholder about one and a third years’ annuity income.
Valuation and reserve pointers#
This library projects gross liability cash flows. Every valuation layer consumes them and is cited, not implemented. On this product one of those layers is not merely uncomputed but uncomputable from this run, and that is stated first.
보증준비금 (guarantee reserve) — the one this model cannot produce. 감독규정 제6-11조의5 requires a reserve inside retained earnings for expected losses on benefit guarantees REG-R10, and the calculation delegated to 시행세칙 별표 24 is 「사망률, 해지율, 자산이익률(1,000개)을 이용하여 만기까지 장래 예상되는 순손실액을 현가로 환산한 상위 30% 평균 금액」 — a CTE(70) over a thousand scenarios — or a standard factor table, whichever is greater R1 REG-R26. The standard factor exists precisely because a deterministic number is meaningless. This model runs one path and publishes an intrinsic value; it publishes neither the CTE(70) nor a factor result, and the factor tables reproduced in
product-spec.mdare at second hand from R1 and are unverified against the rule itself REG-R26. Note the incentive the factor table creates and the model surfaces: it is indexed to 주식비중한도, 「기초서류상 최대 주식투자 비중을 적용함」, so a lower equity cap is a lower reserve floor — which is whycheck_bond_floor()is a compliance check and not a housekeeping one.책임준비금, and the 해약환급금준비금 beside it. 보험업법 제120조 requires the reserve and delegates its computation to the FSS Governor REG-R3; 감독규정 제6-11조 sets it as a current-estimate quantity REG-R10. On top of it Korea appropriates a 해약환급금준비금 inside retained earnings, to stop a balance sheet distributing earnings the contractual surrender-value floor would later demand REG-R11 — it has no counterpart anywhere else in this repository. Here it is not inert: the 해약공제액 is ₩830,000 running off over seven years and the surrender value is nil for the first three months, so the gap between account value and surrender value is real at short durations.
계약자적립액 and 해약환급금 are the two quantities this model does compute, both contractual: 감독규정 제7-65조제1항 makes the 계약자적립액 whatever the 산출방법서 says it is — and permits an annualized-premium basis at 제7-65조제2항, which this model does not use — and 제7-66조제1항 makes the surrender value the 계약자적립액 less the 해약공제액 floored at zero, with 별표 14’s 표준해약공제액 as the cap REG-R18 REG-R19 REG-R20. The 산출방법서 is not public, so the recursion is std and says so.
The 특별계정 itself is a statutory construct. 보험업법 제108조 requires a separate account for 변액보험 and 감독규정 제5-6조 and 제5-7조 govern its establishment and the movements permitted between it and the 일반계정 REG-R6 REG-R15.
net_cf_genandnet_cf_separe written against that article andcheck_net_cf()asserts they close.K-IFRS 제1117호 and K-ICS have both been in force since 2023-01-01 REG-R60 REG-R13, so Korea runs an economic-value solvency measure and a CSM-based earnings measure together and live. The fulfilment cash flows are this vector with a risk adjustment and a CSM layered on. On a variable annuity the CSM question is sharper than elsewhere, because the fee stack is a stream of charges on a fund and the guarantee is an embedded derivative; nothing product-specific to 변액연금 on that treatment was retrieved. The 계리가정 guideline’s functional form is unverified at instrument level REG-R27, and 별표 22, the K-ICS shock schedule including the 대량해지 shock, was not retrieved REG-R26 unverified.
The 공시이율 is not a discount rate. It appears in this model in exactly one place — the annuity factor at
t_ann()— and it is the contract’s own basis, not a statement about value. Nothing inresult_cf()is discounted.Professional and supervisory frame. The work sits under a 선임계리사’s verification duties at 보험업법 제181조 and 제184조 REG-R5; the 기초서류 are filed under 제5조제3호 with 제128조의2 requiring compliance REG-R2; and the 수수료 안내표 this document’s charge stack reproduces is itself a disclosure obligation REG-R22 R2.
Policyholder taxation does not enter the insurer’s liability cash flows and is specified in
product-spec.md. Two rules nonetheless show through into the modelled mechanics and are cited where they do: the ten-year cumulative withdrawal limit inwd_pp, which is what keeps the 소득세법 시행령 제25조 exemption open, and the requirement that a tax-exempt 종신형’s guarantee period lie inside the published 기대여명 REG-R58.
Key sensitivities and model risks#
Dominant assumptions, in order of how far they move the answer.
The return path, and not merely its mean. It moves the terminal account by a factor of two across the three mandated illustration returns — ₩25,958,820 at −1.00%, ₩43,883,944 at 2.50%, ₩52,811,343 at 3.75% — and it is the only thing that decides whether the GMAB pays at all. Volatility is worth more than drift here and the model has none:
return_scenario.csvcarries a constant per fund, no volatility, no correlation and no time series, because none was retrieved R10 [S11]. This is the largest single gap in the model and it is structural: a guarantee’s cost is a distributional quantity and this run is a point.Lapse, because it decides who is there to be paid. Only 9.26% of contracts reach annuitisation, so the GMAB’s expected cost is nine-tenths a lapse assumption and one-tenth an option-pricing problem. The scale’s level is calibrated to a single second-hand sentence R1 and its shape is std. And the convention is dynamic and the model is static — R1 states the in-the-moneyness form and publishes no parameter — so on precisely the paths where the guarantee matters, the model lets contracts leave that would stay. The bias runs one way: guarantee cost understated.
The premium-based guarantee charge, because nothing else in the stack behaves like it. ₩9,000 a month on a first-year fund of ₩3.22m is over 3% a year; the same ₩9,000 in year seven is under 0.5%; in year eight it is zero. Its base is the 보험료총액 and not the fund, its term is the shorter of the 납입기간 and seven years, and it grows with 추가납입 while the strike it pays for grows further and for longer. Getting any of those four facts wrong changes the early-duration cash flow by an order of magnitude.
The mortality basis, which is entirely std and rests on two published numbers. The 제10회 경험생명표 is not published REG-R33 REG-R34; both columns of
mort_table.csvare a Makeham law fitted to the 65세 기대여명 of 23.7 and 27.1 years, with the insurance basis a std 25% loading on the force. It drives the GMDB cost through the deferral and the entire payout liability afterwards — the annuity factor is 20.14 for a male and 21.76 for a female on the same fund, a 7.45% swing in income from the table alone. Substituting a filed basis is a CSV replacement.The 해약공제 level, which is a channel choice as much as a number. Three retrieved scales differ by 42% — ₩830,000 [S2], ₩1,077,000 [S5], ₩1,180,000 [S4] — all on the same cell and all the same function. The composite takes the lowest, because the surrender charge is the unamortised 계약체결비용 R2 and must come from the same carrier as the 5.17%. The composite is therefore a cheap tied-channel contract at both ends and its surrender recoveries are correspondingly low; the 2017 market-mean first-year 해지공제율 of 25.6% of premiums paid R1 <표 Ⅴ-2> is
C = ₩1,075,200on the same function, and on it thesurr_chargestotal of ₩430,510.48 becomes ₩545,164.49 — 26.6% higher, less than the 29.5% rise inCbecause the charge is capped at the account value at short durations.The insurer’s own expense, which is unsourced in its entirety. ₩300,000 at issue and ₩3,000 a month are std with no inflation, and no Korean carrier publishes a unit cost — the 사업비 disclosure is of charges, not of costs R2 [S12]. They total ₩598,836.73 undiscounted, 3.9% of premiums received, and they are the only line in the statement with no document behind it at all.
Discretization, in three places at once. The account is a daily unit ledger modelled monthly [S7 제43조]; the 운용보수 is contractually rate/365 daily and is taken at rate/12; and the two-business-day pricing lag on every switch, withdrawal and surrender [S5] [S7 제39조] is absent. Each is small and they compound in one direction on a rising path. Changing any one changes the answer, so all three are documented.
Omissions with a stated sign. 증권거래비용 and 기초펀드 보수 are zero against observed ranges of 0.00–0.79% and 0.01–0.45% [S2] [S4], so the modelled drag is understated by up to about half a percentage point a year. The 고도재해장해급여금 is charged for and never paid. Both run in the insurer’s favour, both are stated, and neither is large.
Known modeling pitfalls#
These are the specific ways an implementation of this product looks right and is wrong.
Each is checkable against the shipped model, and most are already asserted by one of the
eight check_*() cells.
Putting the guarantee charges on the account value. The GMAB charge has two components on two different bases: 0.25% a year of the 계약자적립액 and 0.30% a year of the 보험료총액 [S1]. On the anchor cell at t = 0 they are ₩57.08 and ₩9,000.00 — a factor of 158. Collapsing them onto the fund understates month-0 charge income by ₩8,942.92 per contract and misstates the whole first-year cash flow. Test:
gmab_charge_asset_pp(0) == 57.081250000000004andgmab_charge_prem_pp(0) == 9000.0on point 1.Running the premium-based guarantee charge for the whole premium term. It is levied 「납입기간(최대 7년) 동안」 [S1] — the shorter of the two. On a 10년납 contract it stops at t = 84, three years before the premiums do, and the 월공제액 falls 57.8% in that one month, from ₩15,422.57 to ₩6,504.62. Running it to t = 120 adds ₩324,000 of undiscounted charge per persisting contract that the contract does not permit. Test:
gmab_charge_prem_pp(83) == 9000.0andgmab_charge_prem_pp(84) == 0.0.Expecting the monthly deduction to fall at 납입완료. It rises: from ₩9,557.24 at t = 119 to ₩13,568.72 at t = 120, because the 계약관리비용 for the period after 납입완료 was collected inside the premium and is now drawn out of the fund [S2] [S7 제2조]. A model that stops all charges when premiums stop overstates the account by roughly ₩4,000 a month for the remaining ten years. Test:
mth_deduct_pp(120) > mth_deduct_pp(119)andmaint_charge_after_pp(119) == 0.0,maint_charge_after_pp(120) == 3990.0.Letting the front-end charges reach the 특별계정. 계약체결비용, 납입 중 계약관리비용 and 기타비용 are deducted from the premium in the 일반계정 and never enter the fund [S7 제2조]; only the 월공제액 and the 운용보수 come out of the account. Conflating the two deduction points either double-charges the fund or gives it ₩26,010 a month it never receives. The observable is the allocation ratio: 0.9133, against 91.3%, 91.3% and 91.4% published on this cell [S1] [S2] [S6]. Test:
check_prem_alloc(), andprem_alloc_ratio(0) == 0.9133.Treating the 운용보수 as a unit cancellation. It is deducted inside the 기준가격, out of net assets before the unit price is struck [S7 제43조제2호], so it is a factor on the growth and not a deduction from the account. Modelled as a cancellation it would change the base every other charge is struck on. The identity that separates them is
I(t) − M(t) = AV(t) − AV(t, AFT_DERISK). Test:check_charge_split()on every model point, andmgmt_fee_pp(0) == 110.64426393373063.Treating the GMAB as a floor on the account at every duration. It is a European option struck on one date, void on 해지, on death before T and on 조기연금개시 [S1] [S6] [S7 제50조제3항] R1. Weighting it by
pols_if(t)at every t rather than bypols_annuitised()at T alone overstates its cost by the whole 90.74% pre-annuitisation exit probability — roughly tenfold on this cell. Test:pols_annuitised() == 0.09258412964405735andgmab_claims(t) == 0.0for everyt != t_ann().Reading the GMAB residual as profit. ₩657,417.59 of charge is collected against ₩0.00 of intrinsic cost on the base path. That is a single-path residual: the option was written, the path finished out of the money, and by Jensen’s inequality the intrinsic value is a lower bound on the expected cost. Model point 4 is the counter-example — ₩929,653.88 of cost against ₩603,909.13 of charge on the mandated −1.00% return. Test: on point 1,
gmab_claim_pp() == 0.0; on point 4,gmab_claim_pp() == 10041179.61262558.Netting the GMDB and paying only the excess. The death benefit is Max[계약자적립액, 이미 납입한 보험료] and it splits exactly into the account value released from the 특별계정 and the top-up met from the 일반계정 보증준비금 R2. Projecting only the top-up as the claim understates gross benefit outgo by the whole account value; projecting both double-counts. Test:
check_gmdb_floor(), andclaims_death(0) == 27.860533600121418againstgmdb_claims(0) = gmdb_claim_pp(0) x pols_death(0).Forgetting the statutory zero floor on the surrender value.
cv_ppis max(0, AV − C) REG-R19 제7-66조제1항제1호. Without the floor the first three months produce a negative surrender value — −₩564,564.41 at t = 0 — which a naive model would book as income.claims_lapseis 0.00 at t = 0, 1 and 2 and ₩5,833.06 at t = 3, and [S6] publishes exactly this shape. Test:cv_pp(2) == 0.0,cv_pp(3) == 234582.76753756206.Running the 해약공제 off linearly in the ratio instead of the amount. All three retrieved scales are
C × (7 − k) ÷ 7in the amount [S2] [S4] [S5]; the published ratio falls far faster only because its denominator is growing. A ratio-linear run-off over-recovers at every duration but the first. Test: the nine values ofsurr_chg_pp(12k)above, to the won.Ignoring the 표준해약공제액 cap because it does not bind on the anchor. It is ₩1,643,940 against a level charge of ₩830,000, so it is invisible on point 1 — and it binds exactly on points 6, 7 and 10, all 5년납, where the scaled charge would otherwise exceed it (point 6: ₩1,369,950 charge against a ₩1,369,950 cap). Test:
check_surr_chg_cap()on all ten points, andsurr_chg_pp(0) == surr_chg_cap_pp()on points 6, 7 and 10.Using
pols_if(t)as the annuity payment weight inside the 보증기간. The instalment is owed to every contract that annuitised, alive or not, for ten years [S2] [S5].pols_annuity_oblig(348) = 0.09258412964405735whilepols_if(348) = 0.08682967335056192— a 6.6% difference on the last guaranteed instalment, and the step at t = 360 from ₩200,728.58 to ₩186,188.58 is the whole of the guarantee’s value showing up at once. Test:pols_annuity_oblig(348) == pols_annuitised()andpols_annuity_oblig(360) == pols_if(360).Keeping the death benefit or the surrender value alive after 연금개시. Both stop: the cover extinguishes at 연금개시 R2 and no retrieved document permits surrender of a 종신연금형.
claims_death(t)andclaims_lapse(t)are 0.00 for every t ≥ 240. Test:claims(240, "DEATH") == 0.0andlapse_rate(240) == 0.0.Using one mortality table across the join. Korea prices the deferral on the 보험사망률 and the payout on a separate, lighter 연금사망률, and neither is public REG-R34.
mort_rate(239) = 0.0054591503andmort_rate(240) = 0.0047847455— a 12.35% fall across one month that is a change of table, not of risk. Using the annuitant basis through the deferral understates the GMDB cost; using the insurance basis in the payout understates the annuity. Test: both values on point 1, andmort_rate_at_age(60) != ann_mort_rate_at_age(60).Reading
proj_len()as the last row index. It is the number of projected months, the frame’s exclusive end: the frame isrange(proj_len())and the last row isproj_len() − 1. The anchor has 960 rows, 0 … 959, and(120 − 40) × 12 = 960. An off-by-one either drops the horizon month, in whichpols_maturitycarries out the survivors and the in-force roll-forward closes, or adds a phantom row past it. Test:len(result_cf()) == proj_len()andresult_cf().index[-1] == proj_len() − 1on every model point, andcheck_pols_roll_fwd().Reversing the decrement order, or applying both rates to the opening count. Death is taken first and 해지 on the survivors std:
s(0) = (1 − d_rate) × w_mth, notl(0) × w_mth. The difference is second-order in a month and first-order over 240 of them. Test:pols_lapse(0) == 0.02700152245035668againstpols_if(0) * lapse_rate_mth(0) == 0.027004030272665847.Striking the asset-based guarantee charges before the premium goes in. They are struck on
av_pp_at(t, "BEF_DEDUCT"), after the transfer. At t = 0 that is the difference between charging on ₩273,990 and charging on zero —gmdb_charge_pp(0)would be 0.00 instead of ₩15.98, and the month-0 account would be wrong by the difference. Test:gmdb_charge_pp(0) == 15.98275andav_pp_at(0, "BEF_PREM") == 0.0.Forgetting the mandatory 채권형 ladder, or applying the wrong rung. It is by 연금개시 전 보험기간, not by fund choice: <12년 ≥80%, =12년 ≥70%, >12년 ≥50% [S1] R1. The anchor’s 20-year deferral takes the 50% rung; points 6 and 7 take 80% and 70%. It binds both the premium allocation and the account mix and survives every later 펀드변경, and the insurer’s own reserve floor is indexed to the equity cap R1 REG-R26. Test:
check_bond_floor()on all ten points, andbond_floor()= 0.50 / 0.80 / 0.70 on points 1, 6 and 7.Skipping the pre-annuitisation de-risking, or applying it at the wrong times. It fires at the three annual 계약해당일 inside 「개시일 − 3년」 — t = 204, 216, 228 on the anchor — tops the 채권형 to 80%, and conserves the total [S1]. On the anchor it moves ₩12,113,087.24 at t = 204 and nothing afterwards, because the bond fund’s lower 운용보수 keeps the weight above 80% on its own. Test:
derisk_amount_pp(204) == 12113087.239005797,derisk_amount_pp(216) == 0.0, andcheck_av_roll_fwd()— which would break if the transfer did not conserve.Failing to re-base the guarantee strikes on a 중도인출. 이미 납입한 보험료 is reduced proportionally, by (AV − W) ÷ AV [S2] [S7 제51조제8항], and it is the strike of both guarantees. Without it a policyholder withdraws the fund and keeps the strike. On point 9 the strike falls from a contractual ₩48,000,000 to ₩25,509,168. Test:
gmab_base_pp() == 25509167.99999999on point 9.Publishing a
claimscolumn beside theclaims_*columns. The house rule is that the columns ofresult_cf()sum tonet_cf; a subtotal beside its parts breaks that and silently double-counts in any downstream aggregation. Theclaims(t, kind)cells stays. Test:"claims" not in result_cf().columnsand the column sum identity.Reading
net_cfas including investment return. It does not: this library projects gross liability cash flows and the separate-account return is an asset-side quantity.inv_income_ppandmgmt_fee_ppexist and are not columns. A reader who adds them gets a number that is neither a liability cash flow nor a profit. Test:"inv_income" not in result_cf().columns;check_net_cf().Treating
charge_income(t)as revenue. Most of it is an internal transfer between the two accounts, and adding it topremiumscounts the same money twice. It is a memo cells and the docstring says so; the external cash flow isnet_cf. Test:check_net_cf(), which would fail if any transfer reachednet_cf.Running the model on 만나이. Every table, every model point age and the whole rate card are 보험나이 REG-R25 제21조; the 완전생명표 and every Korean population statistic are 만나이 REG-R38 REG-R39. The six-month rule makes the two differ for half of all issue dates, so the error is worth about half a year of ageing on every row and raises nothing. Test: the registry metadata records the basis per model and the conventions suite reads it.
Presenting
mort_table.csvas the 경험생명표. It is a std Makeham construction on two published life expectancies, and the 제10회 경험생명표 is not published REG-R33 REG-R34. Every row of the CSV carries aprovenancecell that says so. Test: theprovenancecolumn is non-empty on every row of every CSV, and the conventions suite asserts it.