Implementation Notes#
Status: Draft, 2026-09-03. Built from
technical-notes.md; the product those notes describe is specified in
product-spec.md, and every source tag on this page resolves in
sources.md.
This is a mechanics demonstration, not a pricing or reserving result. The contractual mechanics are sourced — the 태아가입특칙 (taea gaip teukchik, foetal enrolment special provision) verbatim [S8 제53조~제61조], the two ages a foetal contract carries [S8 제58조] [S8 제60조], the 면책기간 (myeonchaek gigan, waiting period) disapplied below 보험나이 15 and entirely on a 태아 cover [S3] [S11] R5, the 감액 removed from foetal contracts by a 2015 변경권고 R2, the statutory bar on a death benefit below 만 15세 and the 계약자적립액 (gyeyakja jeongnipaek, policyholder account) paid instead R7 REG-R17 REG-R25 REG-R50, the two premium waivers with the P코드 carve-out [S2] [S10 제22조], the 3년만기 갱신형 liability block [S2] [S5], the published 해약환급금 grid and the 무해지 cliff [S1] [S2]. Almost everything quantitative is a std standardization. Nothing on Korean child incidence was retrieved from 보험개발원, 국가암정보센터 or 통계청 in this product’s own research pass — the 장기손해보험 참조순보험요율 display that 보험개발원 does publish under 보험업법 제176조제9항, and whose age grid reaches 연령 0 and 10, was opened in the
cancerandindemnity_medicalpasses and not in this one REG-R61, so the shipped incidence rows are std as unreconciled constructions rather than for want of a public grid. The life-side 참조순보험요율 is filed and not published REG-R4; the 산출방법서 that holds each carrier’s own 적용위험률 and 예정사업비율 is an undisclosed 기초서류 REG-R2; the 제10회 경험생명표 is released only as summary statistics REG-R33 REG-R34. Exactly one 적용위험률 is published anywhere in this product’s source set — 일반상해 후유장해 발생률(3~100%), 기본계약, 5세, 상해 1급: 남자 0.0001823, 여자 0.0001163 [S1] — and it is the calibration point of the basic contract’s decrement. Replace the tables with company data and a real 산출방법서 before drawing any conclusion from the numbers.
Child_KR_S is the executable counterpart of technical-notes.md:
a monthly, by-policy projection of gross best-estimate liability cash flows for
어린이보험 (eorini boheom, children’s insurance). It states its deltas against the
cancer 정액 chassis (암보험) rather than restating the
diagnosis machinery, and it adds two things that have no counterpart in any sister
library: 태아가입, under which the projection opens on a life that does not yet exist,
and a 납입면제 (premium waiver) on the 계약자, a decrement on a life who is not the
insured.
Run it#
python products/child/run.py # the anchor cell, point_id = 1
python products/child/run.py 4 # the 무해지 (mijigeuphyeong) point
python products/child/run.py 9 # the 30세만기 short-term point
run.py prints the model point, the cash flow statement and the account, surrender and
decrement tables at the durations where the product does something, the undiscounted totals,
the equivalence premium and the thirteen check_* identities. Everything it prints is
ASCII, so the output lands on a Windows console under any code page: amounts are labelled
KRW, and the product, the two age bases and the three surrender-value forms are romanized.
Real output, elided in the middle — the statement is reproduced in full in
technical-notes.md:
Child_KR_S - eorini boheom (children's insurance), monthly grid, boheom nai
model point 1: CH-KR-0001 - sex M, taea gaip (written in utero), gyeyak nai 0, birth at policy month 5
term to boheom nai 100 (t = 0 .. 1200, 1201 rows), premium term 20 years (t = 0 .. 239), monthly
form: pyojunhyeong (standard surrender value)
premium: KRW 28,000 core + KRW 3,000 taea module to t = 16, so KRW 31,000 to t = 16 and KRW 28,000 after
napip myeonje (premium waiver) on: child + gyeyakja (M33, man nai)
...
pyojun haeyak gongjeaek (statutory surrender charge cap) = KRW 364,000.00 over 84 months
notional bohom gaipgeumaek (byeolpyo 15 no. 9) = KRW 132,306,409 from a first-year risk premium of KRW 145,537.05
acquisition cost = KRW 327,600.00 (11.70 months of premium) of which first-year commission KRW 212,940.00
[ result_cf(), result_val() and result_pols() at t = 0, 1, 4, 5, 6, 16, 17,
239, 240, 241, 600, 1140, 1200 ]
undiscounted totals per policy issued (KRW):
premiums 5458037.93 claims_death 3693345.73
claims_disability 957652.52 claims_lapse 2695713.64
claims_diagnosis 2844503.44 claims_maturity 0.00
claims_surgery 1094506.30 claims_void 306.90
claims_hospital 5033285.22 claim_expenses 79991.42
claims_event 466414.73 expenses 1009668.24
claims_liability 195939.36 commissions 365814.73
claims_neonatal 106330.72 net_cf -13085435.00
equivalence on the shipped basis, at the bojang bubun applied rate of 2.75%:
EPV of all outgo KRW 4,694,583.11 over 151.0504 monthly premium units
equivalence monthly premium KRW 31,079.59 against a shipped KRW 28,000.00
checks: all thirteen True - policy count roll forward, paying / waived split, every exit
accounted for, no cover before birth, once-only benefit ledgers, taea module inside its
terms, surrender value form floor, gyeyakja jeongnipaek bounds, surrender charge under cap,
acquisition cost under cap, published hwangeuplyul grid, equivalence premium identity, net
cash flow ledger
Three lines to the same thing:
import modelx as mx
model = mx.read_model("products/child/Child_KR_S")
model.Projection[1].result_cf() # the worked example's anchor cell
model.Projection[1].result_pols() # the decrement run, both compartments, both ages
model.Projection[1].result_val() # the account, the charge and the two surrender values
Projection takes a point_id; Projection[1] is the worked-example anchor cell — a
태아가입 contract, priced male, 계약나이 0 at the 계약일, birth at policy month 5, running
to a 100세 만기 with a 20년 납입기간. result_cf() returns a DataFrame indexed by policy
month t with one column per cash flow line, pols_if first and net_cf last; expenses
there is acquisition plus maintenance, with the claim handling expense in its own
claim_expenses column. result_pols() publishes the decrement run — the paying and waived
compartments and the two ages side by side — and result_val() the account and the surrender
values. model.Projection.doc maps the notes’ symbols to cells names and states the age
basis; model.Data.doc says what each input file is and, for the mortality table, what it is
not. The time index t is the policy month and is 0-based on the library-wide
convention: t = 0 is the first projected month, the policy year containing month t is
t // 12 + 1, proj_len() is the number of projected months, and the frame is
t = 0 … proj_len() − 1. The anchor projection is 1,201 rows, t = 0 to
t = proj_len() − 1 = 1200: the
longest in krlib, and the product rather than an artefact of it.
The horizon, and eighty years that are paid up#
proj_len() is 12 × (term_age() − issue_age()) + 1, and on a 태아 contract issue_age()
is zero because 「계약일에 있어서의 피보험자의 계약나이는 0세로 합니다」 [S8 제60조]. So the
projection runs 1,200 months to the 100세 계약해당일 — t = 0 … 1199, with the 계약해당일
itself published as the terminal row t = 1200 — and the premium runs over the first
240 of them. Eighty of the hundred years are paid-up, which is the whole shape of the
liability: net_cf(t) is positive for twenty years and negative for eighty, and the
undiscounted total on the anchor cell is −₩13,085,435.00 against premiums of
₩5,458,037.93. That is not a defect in the projection. It is what a hundred-year
contract with a twenty-year premium term looks like before discounting, and it is why
equiv_premium_mth_pp() exists.
The terminal date is fixed by the 계약일 and not by the birth, so the insured’s 만나이
at expiry is 100 less the pre-birth period — 99 years and 7 months on the anchor cell,
and age_man(1200) is 99. result_pols() prints age (보험나이) and age_man (만나이) in
adjacent columns so the five-month offset can be read off any row. Across the shipped points
the horizon runs 360 months (point 9, 30세만기) to 1,320 (point 6, 110세만기 from 태아), and
none of them is read off a mortality table: this is a term contract, not a 종신 one, so
the omega age of mort_table.csv has no part in setting it.
The pre-birth period is the part with no analogue anywhere#
Months t = 0 … 4 on the anchor cell carry premium income on all three streams, a void
decrement, and nothing else. born(t) is false, so every cover on the child’s own life is
identically zero and there is neither mortality nor morbidity on the insured: mort_rate(t)
is 0 and age_man(t) returns −1. check_cover_at_birth() asserts it over
t < birth_month(), summing the seven child-life claim kinds and requiring zero.
The decrement is pols_void, and it is not a lapse. 「태아가 유산 또는 사산에 의해
출생하지 못한 경우에는 계약을 무효로 합니다 … 이미 납입한 보험료를 돌려드립니다」
[S8 제56조] [S9]: nothing is retained, the contract is de-recognised rather than
terminated, and the cash flow is a refund of every premium paid — the 태아 module’s own
stream included, which is why claims(t, "VOID") adds prem_foetal_paid_pp(t) to
cum_prem_pp(t). It is published in its own claims_void column so that it is never
netted into claims_lapse, where it would look like a surrender value on a contract that
does not have one. On the anchor cell it totals ₩306.90, and it is non-zero on exactly
the four 태아 model points — 1, 4, 6 and 10.
The 태아 module is the one thing that pays in respect of an event before the insured legally
exists, and it pays from the date of birth [S8 제59조], so it is excluded from
check_cover_at_birth() and tested separately by check_neonatal_term(). The void rate
itself is a [std] construction and the cells says so: no Korean source retrieved gives a
foetal-loss rate. What the sources fix is the mechanic.
Processing order, and the identity it closes#
Within month t the order is void, then the waiver, then mortality, then lapse
[std order]:
l_P(t+1) = ( l_P(t) (1 - v(t)) - e(t) ) (1 - q(t)) (1 - w(t))
l_W(t+1) = ( l_W(t) (1 - v(t)) + e(t) ) (1 - q(t))
with e(t) = pols_waiver_entry(t). Summing them gives
l(t+1) = l(t) - pols_void(t) - pols_death(t) - pols_lapse(t)
exactly, which is check_pols_roll_fwd(). There are four exits, not two, and the first
of them is what makes this product different: a voided contract has not lapsed and has not
died, and netting it into either would hide a decrement and mis-state the cash flow that
goes with it. check_exit_total() is the global companion — the four decrements sum over
the projection to pols_if_init(), and on the anchor cell 0.0049757330 + 0.4688979472 +
0.5103916457 + 0.0157346742 = 1 exactly, so no mass is lost at either end.
pols_if_at(t, timing) exposes the intermediate states, "BEF_DECR" / "BEF_LAPSE" /
"AFT_DECR", on the same convention the sister libraries use.
The benefit is a bundle, and one limb of it is a percentage scale#
benefit_pp(t, kind) returns the expected outgo per policy in force; claims(t, kind)
weights it by pols_if(t). Seven morbidity kinds and four decrement kinds, published as
eleven claims_* columns that sum, with the three expense lines, to net_cf.
"DISABILITY" is not a lump sum. The 기본계약 pays 보험가입금액 × 장해지급률 on a
continuous 3~100% scale, payable more than once with the percentages accumulating
R12 [S1] [S2] [S11], and 장해 is a settled impairment — 「치유된 후 신체에 남아 있는
영구적인」 REG-R25 — so its incidence lags the accident. The model multiplies the
incidence by disab_severity = 0.12 [std]. The accident limb costs ₩555,177.98 over
the term at that severity and ₩4,626,483.18 at severity 1.0: a factor of 8.3, landing
on the largest sum insured in the contract, and the single largest modelling trap in the
product.
"DIAGNOSIS" is four 최초 1회한 ledgers. Each of 암(유사암 제외), 유사암, 뇌출혈 and
급성심근경색증 carries its own frac_open(t, cause) — the probability that a policy in
force at t has not yet claimed that benefit — recursed as
frac_open(t) = frac_open(t-1) (1 - i_m(t-1)). It is carried per policy and never
weighted by pols_if: weighting it by the in-force probability measures the block’s
consumption rather than the policyholder’s and defers exhaustion indefinitely, which on a
hundred-year term is worth a great deal. check_once_only() asserts each ledger stays in
[0, 1] and never rises. The general tier runs from 1.0000 to 0.4023261296 over the
term — paediatric cancer incidence is two orders of magnitude below the adult rate, so the
ledger is almost untouched for thirty years and then drains fast.
"HOSPITAL" is metered in days, not events. The hosp_acc and hosp_dis causes are
expected days per policy year, multiplied by hosp_daily() and by hosp_cap_factor =
0.92 [std] for what survives the 1~180일 per-stay limit. They never route through
inc_rate_mth: hosp_dis at 만나이 0 is 2.40 days a year, and 1 − (1 − 2.40)^(1/12) is
not a wrong number but a complex one. They are divided by twelve instead. No 180-day
one-hospitalization memory is implemented, no retrieved Korean child wording stating a
re-admission grouping rule. This is the largest single benefit line on the anchor cell —
₩5,033,285.22 undiscounted, 47.0% of all morbidity outgo and 92.2% of the whole premium
collected — and the infant peak is visible in the statement: claims_hospital falls from
₩7,164.01 at t = 16 to ₩3,512.46 at t = 17, which is 만나이 turning from 0 to 1.
"LIABILITY" is the only limb whose claim is a third party’s loss, and the only one a
non-life licence is needed to write R5 [S5]. It is also where the renewal mechanic has its
one cash consequence: the 누수사고 limb’s 90-day 보장개시일 resets at every renewal of the
3년만기 갱신형 block [S3] [S5], so leak_share = 0.40 [std] of the cost is off for the
first three months of each 36-month cycle. The 갱신형 chassis proper — the whole product
written of 20년/30년 renewable blocks with cover-group ceilings [S7] — is not implemented.
"NEONATAL" runs on two terms of its own. neonatal_cost_pp("birth") = ₩47,000 per
birth is the 태아보장기간 limbs — 출생위험 on its three tiers and 조산 진단 — paid at
t = birth_month(); neonatal_cost_pp("block") = ₩63,450 is the 1년만기 신생아 block,
spread evenly over its twelve months. Two of the limbs are day-capped rather than
amount-capped, and the table holds expected paid days after the contractual deduction and
inside the cap:
incubator benefit = 50,000 x max(0, min(days_used, 60) - 2) [S1]
perinatal cash = 10,000 x max(0, min(stay_days, 120) - 3), [S1] [S8]
payable only where stay_days >= 4
The module’s cost is therefore a length-of-stay question rather than an amount question, which is why the supervisor’s own worked claim — ₩16,836,420 on a birth at 32 weeks and 1.84 kg, of which ₩4,200,000 was neonatal day benefits R3 — is the useful datum. On the anchor cell the module costs ₩106,330.72 undiscounted against a module premium of ₩3,000 × 17 = ₩51,000, and every won of it falls inside the first thirteen months of a hundred-year contract. It does not pay for itself on the shipped basis, and that is reported rather than tuned away.
The 면책기간 is tested at the 계약일, once, and never again#
암보장개시일 =
the day the first premium is received if 보험나이 < 15 at the 계약일
the 91st day counting 계약일 as day 1 if 보험나이 >= 15 at the 계약일
the day the first premium is received if the cover is a 태아가입용 form
waiting_mths() is a model point input and cover_open(t, cover) applies it to the two
cancer limbs alone. A model that re-tests the rule at each anniversary is wrong: the
wording is 「계약일 현재 보험나이 15세 미만 피보험자의 경우」 [S11] and 「최초계약과
부활계약의 면책기간은 보험나이 15세 이상인 경우에만 적용」 [S3], so a contract issued at
계약나이 0 has no cancer waiting period at any point in its hundred-year life, including the
eighty-five years during which the insured is an adult. Model point 7, issued at 보험나이 15,
is the cell on which the switch is on.
reduction_mths() returns zero whatever the model point says on a 태아 contract, because
the 2015 변경권고 inserted 「단, 피보험자가 보험가입 당시 태아(胎兒)인 경우에는 보험금의
100%를 지급합니다」 across 17 carriers and 56 products R2. The disapplication lives in the
cells rather than in the data, so that it cannot be switched off by editing a CSV.
Death pays the account, because a death benefit would be void#
claims(t, "DEATH") is (av_pp(t) + unearned_prem_pp(t)) × pols_death(t) and it is not a
death benefit. 상법 제732조 makes a contract on the death of a person under 15 무효
R7 REG-R50, 표준약관 제19조제2호 restates it and 제19조제3호 refuses to extend the
age-correction saving to it REG-R25; what is paid instead is the 계약자적립액 at the date
of death plus the 미경과보험료, which is what 감독규정 제7-63조제1항제1호 requires of a
제3보험 contract on a death it does not cover REG-R17 and what 상법 제736조 floors
REG-R50.
On the anchor cell that is ₩3,693,345.73 undiscounted — the second largest outgo line
after hospital cash — because the 표준형’s account crosses premiums paid at about t = 353
and keeps rising, and most deaths on a hundred-year contract are late ones. On the 미지급형
switch (model point 4) the same line is close to nil for the whole payment period, and a
family whose child dies in year 10 receives almost nothing. That is a real and uncomfortable
property of the suppressed form, and the model reproduces it rather than smoothing it.
The account is recovered from a published grid, and the first two years are std#
av_table.csv carries the 표준형 환급률 grid a current 상품요약서 publishes on a named
specimen contract [S2] as a build curve indexed by duration in years, and a taper curve
indexed by the fraction of the term run off. refund_ratio(t) is their product,
cv_std_pp(t) = refund_ratio(t) × cum_prem_pp(t), and check_refund_grid() asserts that
the model returns the published figure at every node it reaches — 0.0% at 1 year, 45.6% at
3, 62.5% at 5, 73.7% at 10, 78.3% at 15, 82.6% at 20, 101.2% at 30, 122.5% at 40, 144.1% at
50 and 158.9% at 60. It is the one check in the model that ties a computed quantity to a
number a reader can look up.
Splitting the progression in two is what lets one shipped grid serve a 30세만기, a 100세만기 and a 110세만기 point; the taper node at 0.95 is calibrated so that a 100세만기 contract reproduces the published 16.0% at 95 years and pays nothing at 만기.
Recovering the 계약자적립액 from that grid is where a std enters. What the 상품요약서
publishes is 「순보험료식 계약자적립액에서 해약공제액을 공제한 금액」 [S2] — already net of
the charge and floored at zero — so the account can be recovered by adding the unamortised
charge back only where the floor is not binding. Where it is, the identity gives no more than
0 ≤ AV ≤ 해약공제액, and av_pp(t) is capped instead at the cumulative net premium,
the most a 순보험료식 reserve can have accumulated before interest or mortality:
min(cv_std_pp + surr_chg_pp, max(cv_std_pp, net_prem_ratio × cum_prem_pp)). It therefore
starts at nil as it must, rather than at the surrender charge — a model adding the charge
back unconditionally holds ₩364,000 on a contract that has collected nothing.
check_av_bounds() asserts the three inequalities the derivation allows.
The surrender charge is computed from the regulation, and both its readings are carried#
surr_chg_cap_pp() is the 표준해약공제액 of 감독규정 [별표 14] REG-R20:
5% x 연납순보험료 x 해약공제계수 + 보장성보험의 보험가입금액 x 10/1000
surr_chg_prem_rate is the schedule’s 5% and surr_chg_sa_rate its 10/1000 — one per
cent, 0.01, not one per mille; both are read off the schedule and neither is a
standardization.
The 해약공제계수 is the policy term capped at 20 — 「보험기간(최대 20년)」 — and binds at 20 on every model point here. The second term is the harder half, and it is the one place where this product’s lack of a death benefit changes the arithmetic: [별표 15] 제3호 does not apply and 제9호 does, 「보험가입금액 = (위험보험료 / 정기보험의 위험보험료) × 정기보험의 보험가입금액」 REG-R21. A term policy’s risk premium per unit of face is its mortality rate, so the notional amount is the first policy year’s risk premium divided by that rate at the 기준연령 요건, 남자 만 40세 REG-R9 제1-2조제2호. On the anchor cell:
Quantity |
Value |
|---|---|
first-year risk premium |
₩145,537.05 |
notional 보험가입금액 |
₩132,306,409 |
연납순보험료 |
₩252,000.00 |
[별표 14] formula limb, at 10/1000 = 1% |
₩1,575,064.09 = 56.25 months of premium |
13 x monthly premium, |
₩364,000.00 |
표준해약공제액 |
₩364,000.00 |
계약체결비용 |
₩327,600.00 |
the same, in months of premium |
11.70 |
The two readings of one ceiling are 4.33 times apart on this product, and the formula limb
does not bind. [별표 14] and the FSC’s 2019 expense reform describe the same cap, the
reform stating it as 보장성보험 13배 of the monthly premium REG-R29; here the formula
gives 56.25 months against thirteen, because 제9호 divides this contract’s whole first-year
risk premium by a 40-year-old’s mortality rate and a bundled child stack has a large risk
premium and a very small death rate. surr_chg_cap_pp() therefore takes the lesser of the
two — the treatment Cancer_KR_S states for the same mechanic, and the reason
surr_chg_cap_months is a Reference here — and the thirteen-month limb binds on all ten
shipped model points, the formula limb running ₩245,582 to ₩1,654,269 across them.
acq_cost_months() publishes the ratio actually reached, 11.70, rather than asserting the
two readings equal. check_acq_cost_cap() tests the bound; check_surr_chg_cap() tests that
the deducted charge never exceeds it, over a 해약공제기간 capped at seven years
REG-R19 제7-66조제1항제2호. Evaluating [별표 15] 제9호 at the insured’s own age instead of
at 남자 만 40세 is a second trap: at 만나이 5 the mortality rate is 0.00012 and the formula
limb comes out at ₩12,380,087.45 — 442.1 months of premium.
The three surrender-value forms#
cv_pp(t) = cv_std_pp(t) [pyojunhyeong]
= 0 t < m [mijigeuphyeong]
= k x cv_std_pp(t) t >= m
= 0 t < m [mijigeuphyeong III]
= min(0.05 (1 + (t-m)//24), k) x cv_std_pp(t) t >= m
check_cv_floor() asserts all three, including that the suppressed value is exactly nil
through the whole 납입기간: the cliff is a contractual fact and not an approximation, and the
「60원」 and 「550원」 entries in the published grid are rounding on a nominally zero quantity
[S2]. The graded ladder is the published ten-step one — 5% from the day after the end of year
M to the day before the M+2 계약해당일, then 10, 15, 20, 25, 30, 35, 40, 45 and finally 50%
from M+18 [S1].
Child_KR_S ships the 표준형 as its base, which is the opposite of Cancer_KR_S. The
market is in the suppressed forms — 63.8% of 보장성 초회보험료 by 2024 H1 R11 REG-R27 —
and the cancer chassis ships one. This product ships the standard form because the 적립부분
credited at the 공시이율 exists only there, the suppressed forms being 순수보장성 and showing
「-」 for it on the board [S2] [S11]; and because the 표준형’s value exceeds premiums paid
from about t = 353, a shape only a hundred-year term produces. Shipping the two forms on
two products lets a reader compare them without either model carrying both.
Columns that are deliberately zero#
claims_maturity is identically zero on every one of the ten shipped model points and is
published rather than dropped. There is no 만기환급금 on the protection part [S1] [S2] and the
shipped taper reaches zero at 만기, so the 1.57% of anchor-cell policies reaching the 100세
계약해당일 receive nothing. The column stays because the residual 적립부분 is a real quantity
on a contract whose term ends earlier, and because pols_maturity is a real decrement whose
absence from the roll-forward would lose 1.57% of the block with no cause. A model that pays
av_pp at maturity without the taper pays ₩10,678,080 to those policies.
claims_void is zero on the six non-태아 points and non-zero only before birth on the other
four: a column and not a netting, because a void is not a surrender. And unlike the
cancer chassis, whose 미지급형 base makes claims_lapse identically zero
for the whole 납입기간 before it steps up at 납입완료, this product’s 표준형 base pays a
surrender value on a lapse from about year 3 — the 환급률 grid is 0.0% through the first policy
year, so claims_lapse is the 미경과보험료 alone there and a real amount thereafter.
Discounting, and the one place the model does discount#
The projection publishes undiscounted gross liability cash flows, as every model in this library does; discounting, the 책임준비금, the IFRS 17 CSM and the K-ICS 요구자본 belong to a layer that consumes them.
The exception is a set of pricing diagnostics that are not in result_cf(). pv_factor(t)
discounts at the 보장부분 적용이율 of 2.75% — the modal value of the comparison board’s
column, whose observed range is 2.50%–3.00% [S11], and the pricing rate under another name,
the 감독규정 speaking only of the 계약자적립액 적용이율 REG-R9 REG-R48. Then
equiv_premium_mth_pp() = epv_outgo_pp() / epv_prem_unit_pp()
On the anchor cell that is ₩31,079.59 against a shipped ₩28,000, from an EPV of outgo of
₩4,694,583.11 over 151.0504 discounted monthly premium units. It is a first-order
equivalence — the expense basis is held at the level the shipped premium produces rather than
re-scaled with the answer — and check_equiv_premium() verifies that the two 1,201-term
summations reproduce each other. epv_prem_unit_pp() is the model’s whole behaviour in one
number: out of 240 scheduled instalments the projection expects to collect the discounted
equivalent of 151.05, or 62.9%.
Where the equivalence premium and the shipped premium differ, the computed figure governs. Nothing in the model depends on the model point’s premium being a market rate: no carrier publishes a rate table by age and duration, and the board’s own specimen premiums vary by a factor of seven on a nominally standardised basis — ₩21,502 to ₩148,250 for a male 5-year-old — because carriers include different compulsory sets in the quoted 보장보험료 [S11]. That the shipped basis lands 11.00% short of its own equivalence premium is the calibration finding, and it is the honest one.
Modules that are off in the base run, and modules that are not modelled#
Off but switchable, on a model point: the 해약환급금 미지급형 and 미지급형Ⅲ (points 4
and 5), the 감액기간 (reduction_mths, observed 0 and 12; point 7), the 면책기간
(waiting_mths, observed 0 and 3; points 7 and 8), the broad 뇌혈관질환 / 허혈성심장질환
definitions (broad_def, at broad_def_factor = 4.0 [std]; point 8), the 2026 저출산
premium discount (1%–5% for twelve months R6; point 10 at 5%), 110세만기 (point 6),
the two waiver modules, the 태아 module, and the three lapse bases. Each is asserted
in both positions of its switch.
Not modelled, and deliberately: the full 갱신형 chassis [S7]; the 임신·출산질환 module
written on the mother and the 부양자 benefit stack written on the parent [S2] [S5] [S11],
the second of which the composite replaces with the waiver — because a benefit and a decrement
are not the same cash flow, and their expected values differ by more than an order of
magnitude; 다태아 plans R4 R5; the named-cancer riders and the 후유장해 생활지원금
annuity forms [S1] [S11]; 일반상해사망 from 만 15세 [S1] [S4]; 부활; the 공시이율
reset, which the model carries by reference to WholeLife_KR_S; and 실손의료비 riders of
any kind, which have not been attachable to a child policy since April 2018 and are a
statutory impossibility rather than a design choice R9 R10 REG-R17. No exclusion
decrement is modelled: the general 보험금을 지급하지 않는 사유 articles were not read in full
for this product line, and that gap is stated rather than filled.
Inputs are external files#
Seven CSVs live beside run.py in products/child/, not inside the model folder. The model
folder holds __init__.py and _system.json and its two Space folders and nothing else — no
_data/, no IOSpec, no embedded values — so a diff of the model shows logic changes only.
This is the annuallife.TradLife_A layout; contrast basiclife.BasicTerm_S, which keeps its
inputs inside the model. The consequence worth knowing: the model is not portable on its
own. Copying Child_KR_S without its parent’s CSVs produces a model that reads and then
fails on first evaluation.
File |
Reference |
Reader |
Contents |
|---|---|---|---|
|
|
|
ten model points, indexed by |
|
|
|
annual |
|
|
|
eleven causes x two sexes x fourteen pivot ages |
|
|
|
thirteen scalar std parameters that turn an incidence into a cost |
|
|
|
the 태아 module’s nine limbs, with timing, frequency, amount and units |
|
|
|
three lapse bases, three parameters each |
|
|
|
the published 환급률 |
Read once, in Data#
Projection is parameterized by point_id, so every Projection[N] is a separate ItemSpace
with its own cells cache; readers placed there would re-read every file for every policy. They
live in the unparameterized Data Space instead, and
test_inputs_are_read_once_not_once_per_model_point asserts the property against the file set
registered in kr_registry.INPUT_FILES — the set, not merely whatever happened to be read,
so a file that stops being read fails rather than dropping quietly out of the count.
input_dir() returns _model.path.parent, resolved at run time and never hard-coded.
Every assumption CSV carries a provenance column and every cell in it begins with a
citation tag. model_point_table.csv is the only exemption, a model point being a
configuration rather than an assumption. To swap in a company basis, replace the files with
same-schema ones or point the filename References at different names, then clear the cache.
No formula changes.
mort_table.csv — one construction, two lives#
The industry table is the 경험생명표 (gyeongheom saengmyeongpyo), prepared by
보험개발원; the current edition is the 제10회, applied from April 2024. It is not
published — what is released is the summary, 평균수명 and 65세 기대여명, and not the rates
REG-R33 REG-R34. mort_table.csv is therefore a std construction, log-linear
between fourteen anchor 만나이 shaped on the 통계청 완전생명표 age pattern REG-R38
REG-R39, and every row’s provenance says so. It must never be called the 경험생명표.
What it must have, and what a table graduated from age 20 upwards would not, are the three
features a child policy is exposed to: the infant peak (male q(0) = 0.0025, about
twenty times q(5)), the childhood trough at about age 10 and the adolescent turn.
The infant peak falls on the anchor cell in exactly the twelve months when the 태아 module is
also paying, which is why it is in the table rather than smoothed out of it.
The same file is read for two lives: the insured at age_man(t) and the 계약자 at
payer_age + t // 12, whose rate at issue, q(33) = 0.00067713, drives the whole waiver
decrement for the first policy year. mort_be_factor is 1.0, and that identity is a
decision: the shipped table is a population all-cause construction with no prudential margin
to unwind, so scaling it would invent one. Model point 10 runs at 1.10. On a child policy
mortality releases the liability, so understating it overstates the liability.
incidence_table.csv — one published rate, and ten shapes around it#
Eleven causes by sex at pivot 만나이 0, 1, 5, 10, 15, 20, 30, 40, 50, 60, 70, 80, 90 and 100, graduated log-linearly between adjacent pivots and returned exactly at a pivot. The logarithm is not decoration: these rates span two or more orders of magnitude across the age range — general-tier cancer incidence rises about two-hundredfold from 만나이 10 to 80 — and a linear interpolation between decade pivots is wrong by a factor of two mid-span.
Exactly one rate in the file is published anywhere: disability at 만나이 5, 「일반상해
후유장해 발생률(3~100%), 기본계약, 5세, 상해 1급 — 남자 0.0001823, 여자 0.0001163」 [S1]. It
is a 적용위험률, already a priced rate rather than a best estimate, and it is the point the
basic contract’s whole decrement is calibrated on; it reproduces to its printed digits only
because the interpolator short-circuits at a pivot. Everything else is a shape drawn around it,
and each row’s provenance names the authority its shape rests on — 국가암등록통계 연령별
발생률 REG-R40, the 「기타피부암 및 갑상선암 이외의 암 발생률」 and 질병입원율 grids of the
참조순보험요율 display REG-R61, the 국민건강보험 진료비 실태조사 REG-R41 — rather than a
source for its level. The sex direction is male-heavier, following that one published pair
(a ratio of 1.57) against a market with no fixed sign: four carriers on the board price the
female above the male and seven below, the spread running 62% to 114% [S11].
The two hosp_* causes are expected days, not probabilities, so the file’s rate column
carries two different units. hosp_dis at 만나이 0 is 2.40 days a year. That is the single
most important dimensional fact in the input set, and why benefit_pp(t, "HOSPITAL") divides
by twelve rather than calling inc_rate_mth.
basis_table.csv — thirteen scalars that turn an incidence into a cost#
Every one is a standardization with no published anchor, tagged in its own provenance cell
and listed with its rationale in Standardizations used below. It is a file rather than a
set of References in Projection for one reason: these are the parameters a user replacing
the model’s basis changes first, and a CSV is the thing to hand them.
neonatal_table.csv — nine limbs, two timings, two of them day-capped#
Each limb carries a frequency per birth, an amount (fixed, or a ratio to the module’s own
₩10,000,000 가입금액), an expected number of units and a timing — birth for the four
태아보장기간 limbs paid at t = birth_month(), block for the five limbs of the 1년만기
신생아 block, spread evenly over its twelve months. The two day-capped limbs are implemented
as written, so their units are expected paid days after the contractual deduction and
inside the cap. The neonatal_haem frequency carries a caveat in its provenance cell: it
is regime-dependent rather than stationary, because the 2013-09 supervisory decision
requiring neonatal claims to be paid on the diagnosis name rather than the KCD code ended
refusals of 뇌출혈 coded P52 and raised frequency sharply R5.
lapse_table.csv — three bases, and the vector is the argument#
lapse_rate(t) is the annual rate and lapse_rate_mth(t) the monthly one, per the house
convention.
loglinear— the 2024-11-07 계리가정 guideline’s 원칙모형: a log-linear decay from the first-year rate to 0.1% at 납입완료 and 0.8% thereafter R11 REG-R27. The guideline’s functional form was never converted from HWP and is unverified at instrument level; the two endpoints are verified from the 보도자료. The 5.0% start is the top band of the only 적용해지율 any Korean child product publishes [S1], so unlike every other lapse assumption in this library it has an observed anchor.disclosed— the step function one carrier discloses for its suppressed forms, 5.0% for ten years, 3.0% to fifteen, 1.0% thereafter in payment and 0.5% after 납입완료 [S1]: the comparison the guideline obliges an insurer departing from the 원칙모형 to disclose. The two produce visibly different contracts — model point 5 runs ondisclosedand totals −₩8,061,541.17 against the anchor’s −₩13,085,435.00.flat— a level vector, the nearest a projection can come to the synthetic 표준형 the 환급률 comparison is made against, priced with no lapse assumption at all [S1] [S3].
Lapse is absorbing. 부활 is available within three years even where there is no surrender value [S8] REG-R25 제27조, every waiting period re-runs from the 부활일 [S3], and below 보험나이 15 there is no cancer waiting period to re-run — so a reinstated child policy is, uniquely in this library, very nearly the policy that lapsed. The model does not carry it; the simplification is conservative on a protection product and is recorded as one.
av_table.csv and model_point_table.csv#
av_table.csv holds thirteen build rows and five taper rows. Eleven of the build rows
are the published 환급률 progression on a named specimen contract — 표준형, 남자 5세, 상해 1급,
100세만기 20년납 월납 at 월납 50,000원, 공시이율 1.7% at 2026-07 [S2] — and the remaining two,
at 70 and 100 years, are [std] shaping between the published 60-year and 95-year figures; the
whole taper curve is [std] calibration. check_refund_grid() asserts the ten published
durations the grid reaches while the taper is still 1 (1, 3, 5, 10, 15, 20, 30, 40, 50 and 60
years), and the taper is calibrated so that 1.589 × 0.1007 reproduces the published 16.0% at
95 years.
model_point_table.csv covers both sexes; 태아가입 on four points and issue 보험나이 0, 5,
15 and 30 on the rest; 30세, 100세 and 110세 만기; 20년납 and 30년납; all three
surrender-value forms; both waiver modules in both positions; the 면책기간 and 감액기간
switches; the broad adult-disease definitions; the 2026 저출산 discount; and all three lapse
bases. Its ten premiums are std inputs, not computed quantities — see Discounting.
No input file is keyed by the frame’s t#
Recorded here because the 0-based time-index convention turns on it: not one of the seven CSVs is keyed by the projection’s time index, so none of them carries a column that moves with the frame.
File |
Time-like column |
Decision |
|---|---|---|
|
|
unchanged — an elapsed duration in years (0, 1, 3, …, 60, 70, 100), read through |
|
|
unchanged — a runoff fraction on |
|
|
unchanged — an attained 만나이, read at |
|
|
unchanged — an attained 만나이 pivot, read at |
|
|
unchanged — a point on the frame’s own time axis (the policy month of birth, 5 on the anchor cell), and the frame’s rows do not move, so the values stand |
|
|
unchanged — elapsed counts and ages, 0-based by nature and compared with |
|
none |
no time-like column at all |
Sign convention#
net_cf is income positive — premiums less benefits, claim handling expense, acquisition
and maintenance expense and commission. That is the library-wide sign and it is the notes’
own, so unlike the payout-annuity models there is no outgo-positive liability_cf companion
to publish: one stream, one sign, one name.
The shape to expect is a deep month-0 strain — ₩327,600 of acquisition cost and initial
commission against one month’s ₩31,000 premium, giving net_cf(0) = −₩298,646.21 — then
one negative month at birth as the 태아 module pays, then a positive stretch of nearly twenty
years averaging about ₩14,000 a month, and then eighty years of pure outgo with not a single
positive month in it.
The identity check_net_cf() closes#
net_cf(t) = premiums − claims_disability − claims_diagnosis − claims_surgery −
claims_hospital − claims_event − claims_liability − claims_neonatal − claims_death −
claims_lapse − claims_maturity − claims_void − claim_expenses − expenses −
commissions — the fifteen cash-flow columns of result_cf(), read back out of the frame
row by row so that a reader adding up the printed statement gets the printed total.
Reading it back out of the frame rather than recomputing it is the point: it is the check that
catches a benefit kind that exists in claims(t, kind) but was never given a column, which
would leave the statement silently short of outgo the model is charging. It is also why
result_cf() publishes the eleven claims_* split columns and no aggregate claims
column — an aggregate beside the splits would double-count the whole benefit outgo, which is
the ruling RETIRED_COLUMNS carries across all six libraries. check_net_cf_resid(t) gives
the signed per-month residual; the tolerance is val_tol scaled by the largest sum insured,
so it is far below one won on amounts of order 1e8.
Naming#
House vocabulary throughout: model_point, proj_len, age, pols_if, mort_rate,
claims, expenses, net_cf, result_cf; pols_death, pols_lapse, pols_maturity,
pols_if_init, pols_if_at, premium_mth_pp, mort_rate_mth, lapse_rate /
lapse_rate_mth, av_pp, cv_pp, surr_chg_pp, cv_floor_ratio, refund_ratio,
mort_be_factor, check_pols_roll_fwd, check_net_cf, roll_fwd_tol, val_tol.
The notes’ symbols, and where they live#
The full map is in the Projection Space docstring, which is where a reader holding the notes
beside the model will look for it. Six cases needed care:
Notes |
Cells |
Why |
|---|---|---|
|
|
Two compartments of one block, not two blocks. |
|
|
The notes’ rate is monthly and says so in the suffix, beside |
|
|
Annual and monthly, on the house convention; the two limbs are |
|
|
The second age. |
(no symbol) |
|
The birth gate. A boolean cells rather than a comparison inlined at each call site, so that |
(no symbol) |
|
A 최초 1회한 ledger, named for what it holds — the fraction of policies for which that benefit is still open — rather than for a letter. Per policy, never per block |
Product-specific names are kept English and descriptive — neonatal_cost_pp for the 태아
module, cover_open for the 면책기간 gate, reduction_factor for the 감액,
prem_foetal_paid_pp for the second premium stream, sa_notional_pp for the notional
보험가입금액 of [별표 15] 제9호, equiv_premium_mth_pp for the pricing diagnostic — and no
romanized Korean appears in a cells identifier.
What this product argued in the cross-model naming review#
This is the model with the most Korean-specific machinery in the library, so it is where the temptation to romanize was strongest and where three of the register’s rulings were settled:
decl_rate, notgongsi_rate, andprem_int_rate, notyejeong_rate. 공시이율 is the declared crediting rate under the definitiondelibsettled for the laufende Verzinsung, and 예정이율 is the pricing rate, a different quantity. This product carries both at once, exactly the case that would have made two romanized names look natural.cv_floor_ratio, notcv_ratio. This model carries two ratios on the same chassis, the suppressed fractionkand the 환급률, and a barecv_ratiosaid nothing about which;refund_ratiois the other, named for the published quantity a supervisor regulates.surr_chg_ppwithsurr_chg_cap_ppbeside it, againstsurr_charge_pp. The savings chassis owns the first name; the Korean addition is the cap, from the 표준해약공제액, a different cells with a different formula and its own check.
Two more the register already carried and this product would otherwise have broken:
pols_maturity rather than pols_expiry — 1.57% of the block here, against a
claims_maturity of zero — and check_net_cf rather than check_cf_ledger.
Standardizations used#
Every row is std. The sourced contractual and pricing parameters are in
product-spec.md and technical-notes.md and are not
repeated here. “Observed range” is what the retrieved documents actually bound, and for this
product most of them bound nothing at all — which is said rather than papered over.
Parameter |
Value |
Rationale |
Observed range |
|---|---|---|---|
every rate in |
eleven causes x two sexes x fourteen pivots |
nothing on Korean child incidence was retrieved from 보험개발원, 국가암정보센터 or 통계청; each row’s provenance names the authority its shape rests on REG-R40 REG-R41 REG-R61 |
one observation only: 일반상해 후유장해 발생률(3~100%) at 5세, 상해 1급 — 남 0.0001823 / 여 0.0001163 [S1], which the file reproduces exactly |
incidence graduation |
log-linear between pivots |
the rates span two or more orders of magnitude; a linear interpolation is wrong by a factor of two mid-span, and only a log-linear one returns the published pivot exactly |
none published |
|
log-linear between fourteen anchors on the 완전생명표 age pattern |
the 제10회 경험생명표 is published only as 평균수명 and 기대여명 REG-R33 REG-R34; the 참조순보험요율 for mortality is filed and never published REG-R4 |
none; the shape check is the infant peak, male |
|
1.0 |
the shipped table is a population all-cause construction with no prudential margin to unwind; scaling it would invent one |
none published; model point 10 runs 1.10 |
|
0.12, 0.15 |
the 기본계약 pays |
none; the sensitivity is a factor of 8.3 on the accident limb, ₩555,177.98 at 0.12 against ₩4,626,483.18 at 1.0 |
|
0.85, 0.50, 0.70 |
the 수술비 limb pays per qualifying operation R12; no Korean operation-given-diagnosis rate was retrieved |
none published |
|
₩600,000 |
mean paid on a 가족일상생활배상책임 claim |
the ₩100,000,000 limit and the ₩200,000 / ₩500,000 대물 deductibles are sourced [S5]; the severity is not |
|
0.92 |
the share of expected 입원 days surviving the 1~180일 per-stay cap |
the cap is sourced R12 [S2]; no Korean child wording states a re-admission grouping rule, so no 180-day memory is modelled — a real difference from the Japanese third-sector chassis |
|
0.08, 0.25 |
the 50% 이상 threshold that fires the waiver [S2], and the 계약자’s 50% 장해 incidence as a ratio to mortality [S10 제22조] |
no Korean disability incidence table is public |
waiver independence |
|
nothing in the sources relates the two lives, and nothing the model can see does |
none |
계약자 age and sex |
만 33, male, fixed for the projection |
mid-point of the band the mother-side riders state |
20~47세 [S2]; a change of 계약자 mid-term is unverified |
P코드 carve-out scope |
child limb off over |
the carve-out itself is sourced [S2]; its exact scope over the 1년만기 block is the standardization |
none published |
|
0.40 |
the 누수사고 share of the liability cost, being the limb whose 90-day 보장개시일 resets at each renewal |
the reset is sourced [S3] [S5]; the share is not |
|
0.012 |
the most exposed number in the file. No Korean source retrieved gives a foetal-loss rate; what is sourced is the mechanic — 무효, whole premium returned [S8 제56조] [S9] |
none at all; worth ₩306.90 on the anchor cell, so small in cash and large in principle |
|
4.0 |
broad 뇌혈관질환 / 허혈성심장질환 ranges against the narrow 뇌출혈 / 급성심근경색증 the comparison basis prices |
both definitions are sourced [S2] [S11] R12; the ratio is not |
|
0.75 |
순보험료 as a share of 영업보험료, used only in the 표준해약공제액 formula of [별표 14] REG-R20 |
no Korean 예정사업비율 is published: the 산출방법서 is an undisclosed 기초서류 REG-R2 |
|
0.9 of the cap, 0.65, 0.03 |
no Korean carrier publishes any expense or commission figure for this product; the statutory ceiling is all there is |
the cap is ₩364,000.00 = 13.00 months of premium on the anchor and the 90% of it deducted is 11.70 months; the [별표 14] formula limb is ₩1,575,064.09 = 56.25 months and does not bind, so the FSC’s 13-month reading of the same cap governs REG-R29; commission is capped at the first year’s expected premium, instalments at 60% of the 표준해약공제액 a year REG-R22 제4-32조제5항·제8항 |
which limb of the cap binds |
the lesser of [별표 14] and 13 x monthly premium |
REG-R20 and REG-R29 are two readings of one ceiling and disagree by 4.33x here; taking the lesser is the treatment |
neither reading is std — |
|
₩400/month, 5% of premium, ₩30,000/claim |
both 상품요약서 define 계약체결비용 and 계약관리비용 and then give no number |
none published; 보험가격지수 dispersion on the board is the only indirect handle [S11] REG-R22 제7-45조제7항 |
|
2.0% p.a. |
the Bank of Korea’s own target; not a detail on this product — it compounds to x7.24 over a hundred years and the ₩400 charge is ₩2,898 a month at |
none published |
lapse shape |
log-linear between the two prescribed endpoints |
the guideline’s functional form was never converted from HWP and is unverified at instrument level |
the endpoints are prescribed, 0.1% at 납입완료 and 0.8% after R11 REG-R27; the 5.0% start is the top band of the only published 적용해지율 [S1], whose full disclosed vector ships beside it as |
lapse absorbing |
no 부활 inflow |
reinstatement within three years is sourced [S8] REG-R25 제27조 and no take-up rate is published; below 보험나이 15 there is no waiting period to re-run [S3], so the simplification is larger here than on the chassis |
none published; direction stated — it understates persistency |
decrement order |
void, waiver, mortality, lapse |
fixed by the contract’s own sequence: a void de-recognises the contract, a waiver changes who pays, and only a paying policy can lapse |
not a disclosure question |
해약공제액 release |
linear over the 해약공제기간 |
the regulation caps the amount and not the shape REG-R19 REG-R20 |
the seven-year cap is sourced REG-R19 제7-66조제1항제2호 |
|
capped at |
the published grid is 「순보험료식 계약자적립액에서 해약공제액을 공제한 금액」, already net and floored at zero [S2], so the identity gives only |
none; the constraint is that |
|
node 0.95 set so 1.589 x 0.1007 = 16.0% |
one shipped grid must serve a 30세, a 100세 and a 110세 만기 |
the published nodes it reproduces [S2] |
|
2.75%, 1.70%, 0.30%, 2.50% |
the modal value of each published column is the standardization; the columns themselves are sourced. Only |
2.50–3.00%, 1.60–2.20%, 0.20–0.50% [S2] [S11] |
the ten office premiums |
₩3,026 to ₩71,000 |
model point inputs, not computed quantities; no carrier publishes a rate table by age and duration REG-R2 REG-R4 |
the board’s specimen premiums for a male 5-year-old run ₩21,502 to ₩148,250, a factor of seven, because carriers quote different compulsory sets [S11] |
|
1e-10, 1e-7 |
one closes an identity between cells evaluated in one expression; the other re-reads won amounts of order 1e8 back out of a |
both far below one won |
Tests#
tests/test_child_kr.py is this model’s own suite. It asserts the notes’ worked example
hard-coded as a module-level table rather than pickled, so a reviewer can check it against
the notes by eye:
The pre-birth months
t = 0 … 4line by line — premium on all three streams, the void refund of ₩122.13 att = 4, and every child-life claim column exactly zero, asserted as zeros rather than left implied.The month of birth and the month after,
t = 5andt = 16 / 17, where the 태아 module pays,age_manturns from 0 to 1 andclaims_hospitalfalls from ₩7,164.01 to ₩3,512.46.The policy-year-1 aggregate and the undiscounted totals over all 1,201 rows, line by line on unrounded values — ₩5,458,037.93 of premium against ₩17,087,999 of benefit and ₩1,455,474 of expense and commission, for −₩13,085,435.00 — and the four exits summing to one: 0.0049757330 + 0.4688979472 + 0.5103916457 + 0.0157346742.
The pricing diagnostics
epv_outgo_pp()= 4,694,583.10870084,epv_prem_unit_pp()= 151.0503621937853 andequiv_premium_mth_pp()= 31,079.588559199034; the published 환급률 grid at all ten checkable nodes and the 16.0% at 95 years; and the [별표 14] chain ₩145,537.05 → ₩132,306,409 → a formula limb of ₩1,575,064.09 that does not bind → the 13-month cap ₩364,000.00 → ₩327,600.00 → 11.70 months.
Each of the notes’ Known modeling pitfalls earns a test named after it, and each fails if
its pitfall is committed: cover attaching at the 계약일 rather than at birth, the void netted
into lapse, the projection run on one age, the monthly conversion applied to a day count, the
면책기간 re-tested at the claim date, a 감액 applied to a foetal contract, the child’s waiver
limb running over the 신생아 block, the parent modelled as a benefit rather than a decrement,
the waiver running after 납입완료, the waived compartment exposed to lapse, the 기본계약
treated as a lump sum, frac_open ledgers weighted by pols_if, renewal commission from
t = 1 or after 납입완료, a 만기환급금 paid, the account started at the surrender charge, the
notional 보험가입금액 computed at the insured’s own age, an exit dropped from the roll-forward,
the incidence grid interpolated linearly, the female rate assumed below the male, and monthly
rounding assumed to re-add. The optional modules are asserted in both switch positions.
tests/test_model_conventions_kr.py adds the house style, parametrized over
kr_registry.MODELS rather than restated here: the two-Space layout with no orphan CSV beside
the model, the provenance column with a citation tag on every assumption row, the docstrings
and their required phrases, the age basis declared in the Projection docstring and matching
the registry’s BOHEOM metadata, the retired-name register, the result_cf() contract —
indexed by t, first column pols_if, a net_cf column, all names lower_snake_case, no
NaN, contiguous, starting at a non-negative index and ending at proj_len() − 1 — the
read-once property against
kr_registry.INPUT_FILES, and the read → write → re-read round trip.
Thirteen check_* cells carry this product’s own identities. Each takes no argument and
returns a real bool over all t, with the signed per-t residual at check_*_resid(t), and
all thirteen return True on all ten shipped model points.
Check |
What it closes |
|---|---|
|
|
|
|
|
the four exits sum over the projection to |
|
every cover on the child’s own life is identically zero for |
|
each |
|
the 태아 module pays inside |
|
the suppressed forms pay exactly nil through the 납입기간, and the graded ladder never exceeds |
|
the account is never negative, never below the amount payable on surrender, and never above that amount grossed up by the whole unamortised 해약공제액 |
|
the deducted charge never exceeds the 표준해약공제액, over a 해약공제기간 capped at seven years |
|
the acquisition cost is inside the [별표 14] bound |
|
the model returns the published 환급률 at every node it reaches |
|
the two 1,201-term summations behind |
|
the printed statement adds to |
python -m pytest tests -q