The Projection Space#
The by-policy projection of the Term_KR_S model.
The Space is parameterized by point_id, so Projection[1] is an ItemSpace
projecting model point 1:
>>> Projection[1].result_cf() # the worked example's anchor cell
>>> Projection.point_id = 3 # or switch the default
t counts policy months and is 0-based: t = 0 is the first policy month,
period t runs from time t to time t + 1, the attained 보험나이 is
age_at_entry() + t // 12, the contractual policy year is the derived 1-based label
t // 12 + 1 and is never indexed by, and proj_len() is the number of projected
periods, so the frame is t = 0, 1, ..., proj_len() - 1 — lifelib’s own
for t in range(proj_len()). A 20년만기 contract projects 240 rows.
On the representative 순수보장형 there is nothing after it —
no 만기보험금, no 해약환급금 at any duration, no run-off and no tail state of any kind
[S1] [S2 제33조제2항] [S12]. On the 만기환급형 variant the last year pays 100% of the
premiums paid and the contract ends there [S1] [S12].
The age basis
Every age in this model is 보험나이 (boheom nai, insurance age): 만나이 with fractions of six months or more rounded up, incrementing on the policy anniversary and not on the birthday [S2 제22조] [REG-R25 제21조]. It is the contractual age, the index of every Korean rate card, and the basis the 경험생명표 is graduated on, so the model point ages, the premium table and the mortality table are all on one basis and no shift is applied. The one place Korean practice uses 만나이 instead is the 상법 제732조 voidness test for a life under 만 15 [S2 제22조제1항 단서], which is an issue rule and not a projection quantity. Reading a 만나이 model point against this table would understate the rate by about half a year of ageing on every row.
Where the horizon ends
This is a product question rather than a convention, and on a Korean term policy it is the contract-boundary question in disguise.
A 비갱신형 (bi-gaengsinhyeong, non-renewable) contract has one 보험기간, one premium
and no repricing [S1] [S12], so proj_len() = policy_term().
A 갱신형 (gaengsinhyeong, renewable) contract renews automatically and negative-
option — unless the policyholder objects 15 days before expiry — with no 고지, no
underwriting and no health condition, at attained 보험나이 on the whole 기초율 then in
force, on a new product code, until it reaches the renewal ceiling of 보험나이 80
[S6] [S9] [S15]. So the 보험기간 of the contract in force is one cycle and the horizon of
the cash flows the contract generates is the ceiling: proj_len() = renew_ceiling() -
age_at_entry(), and a ten-year cycle issued at 40 is projected for forty years across
four priced cycles. contract_boundary = current_term truncates instead at the end of
the cycle in force, which is the short reading of the boundary. Model points 3 and 4 are
the same cell on the two readings.
Input data
Inputs are external files: plain CSVs living in the model folder’s parent directory,
products/term_life/, read at run time rather than stored inside the model. The model
folder therefore holds nothing but formulas — no _data/, no IOSpec, no embedded
values — so a diff of the model shows logic changes only, and an input can be edited or
swapped without rewriting the model. This follows annuallife.TradLife_A; contrast
basiclife.BasicTerm_S, which keeps its inputs inside the model.
The consequence worth knowing: the model is not portable on its own. Copying the
Term_KR_S folder without its parent’s CSVs produces a model that reads and then fails
on first evaluation.
Each table has a filename Reference and a reader Cells, both on
Data, reached here through the data Reference:
Reference |
Cells |
File |
|---|---|---|
model_point_file |
data.model_point_table() |
model_point_table.csv |
mort_table_file |
data.mort_table() |
mort_table.csv |
rate_class_file |
data.rate_class_table() |
rate_class_table.csv |
prem_rate_file |
data.prem_rate_table() |
prem_rate_table.csv |
lapse_table_file |
data.lapse_table() |
lapse_table.csv |
Naming
Cells names follow lifelib’s basiclife.BasicTerm_S wherever that model has an
analogue — pols_* for policy counts, plural nouns for cash flows, *_rate for
rates, *_pp for per-policy amounts, claims(t, kind) with an uppercase kind
string, pols_if_at(t, timing) for the within-year in-force reads. The technical notes
use compact actuarial symbols instead. The mapping is:
Notes symbol |
Cells |
Meaning |
|---|---|---|
(row label) |
model_point() |
The selected model point row |
t |
(the index of result_cf) |
Policy month index, 0-based |
y(t) |
policy_year(t) |
Policy year label, t // 12 + 1 |
x |
age_at_entry() |
가입나이, 보험나이 |
x + floor(t/12) |
age(t) |
Attained 보험나이 at time t |
(none) |
sex() |
Rating factor, M or F |
(none) |
renewal_type() |
gaengsin or bi_gaengsin |
(none) |
rate_class() |
표준체 / 비흡연자 / 건강체 … |
(none) |
maturity_form() |
pure or rop (만기환급형) |
n |
policy_term() |
보험기간, in years |
n_p |
pay_term() |
납입기간, in years |
w_r |
renew_ceiling() |
보험나이 renewal stops |
(horizon) |
horizon_ceiling() |
Years from entry to w_r |
N_y |
proj_years() |
Horizon in policy years |
N |
proj_len() |
Projected months, 12 N_y; the frame is t = 0..N-1 |
(none) |
contract_boundary() |
ceiling or current_term |
k |
term_index(t) |
Renewal index, 1 in the first |
x_k |
term_start_age(k) |
보험나이 at cycle k start |
m_k |
term_len(k) |
Length of cycle k, truncated |
m_k^p |
term_pay_years(k) |
Paying years inside cycle k |
SA |
sum_assured() |
보험가입금액, level |
i_p |
prem_int_rate |
적용이율, 2.50% |
g |
pay_factor(k) |
Shortened-pay uplift |
r(sex, x, m) |
prem_rate_mth(t) |
Rate per 100,000,000 of cover |
qbar(x, m) |
mort_table_mean(x, m) |
Mean table rate over m years |
P_m(k) |
premium_mth_pp(t) |
Monthly office premium, the month’s actual premium income |
P_a(k) |
prem_pp(t) |
Annualized premium, 12 P_m |
(none) |
prem_payable(t) |
1 inside the 납입기간, else 0 |
(none) |
cum_prem_pp(t) |
Premiums paid to date, per pol |
(table) |
mort_rate_at_age(x) |
표준체 table rate at an age |
(table) |
acc_mort_rate_at_age(x) |
예정 재해사망률 at an age |
(class) |
class_mort_ratio() |
Rate-class mortality ratio |
(class) |
class_prem_ratio() |
Rate-class premium ratio |
(basis) |
mort_rate_base(t) |
Class table rate in period t |
(margin removal) |
mort_be_factor |
Best-estimate factor, 0.85 |
q(t) |
mort_rate(t) |
Annual death rate at age(t) |
q^m(t) |
mort_rate_mth(t) |
Monthly death decrement |
a_q(t) |
acc_mort_share(t) |
Accidental share of q(t) |
w(t) |
lapse_rate(t) |
Annual ordinary lapse rate |
w^m(t) |
lapse_rate_mth(t) |
Monthly lapse decrement |
d(t) |
renewal_decline_rate(t) |
Renewal-decline rate |
d_0 |
renewal_decline_base |
Flat decline rate, 20% |
beta, d_max |
renewal_decline_beta, _max |
Decline elasticity module |
l(t) |
pols_if(t) |
In force at time t, l(0) = 1 |
(within-year) |
pols_if_at(t, timing) |
BEF_DECR / BEF_LAPSE / … |
D(t) |
pols_death(t) |
Expected death claims |
(none) |
pols_lapse(t) |
Ordinary lapses |
(none) |
pols_decline(t) |
Renewal declines |
(none) |
pols_maturity(t) |
Cover ending at the horizon |
lap(t) |
pols_lapse_pool(t) |
Reinstatable population |
rho |
reinstate_rate |
Reinstatement rate |
(window) |
reinstate_window |
36 months [S2 제28조] |
(none) |
pols_reinstate(t) |
부활 into l(t+1) |
(none) |
pols_lapse_expire(t) |
Pool leavers, window expired |
u(t) |
wop_waived_frac(t) |
Fraction premium-waived |
(none) |
pols_waived(t) |
Policies with premiums waived |
(none) |
pols_payer(t) |
Policies paying premium |
A |
accel_amount() |
선지급 accelerated amount |
i_s |
accel_disc_rate |
평균공시이율, 2.50% |
a(t) |
accel_share(t) |
Acceleration take-up |
(payout formula) |
accel_payout_pp(t) |
Discounted acceleration |
P_a x l |
premiums(t) |
Premium income |
SA x D(t) |
claims(t, kind) |
Benefit outgo by kind |
ec |
expense_claim |
Claim expense per claim |
ec x D(t) |
claim_expenses(t) |
Claim expense outgo |
E0 |
expense_acq |
Acquisition expense |
e(t) |
expenses(t) |
Acquisition + maintenance |
c0 |
comm_init_pp() |
Initial commission per policy |
c_r |
comm_renewal_rate |
Renewal commission rate |
(none) |
comm_new_term(t) |
Commission at a 갱신 |
(none) |
commissions(t) |
Commission outgo |
CF(t) |
net_cf(t) |
Net cash flow, income positive |
Four names needed care.
d(t) is spelled renewal_decline_rate() and never any variant of lapse, and
never renew_rate, which reads as its complement. It is a different event at a
different time from a different population.
q(t) is the decrement and qbar(x, m) is a mean of table rates used by the
premium scale. Those are different quantities on different bases — one is best-estimate
and one is not — so mort_rate() is the decrement and mort_table_mean()
averages mort_rate_at_age(), which reads the table unadjusted. Feeding the
best-estimate rate into the premium extension would move a premium scale by an assumption
that has nothing to do with pricing.
P_m(k) is indexed by the renewal cycle in the notes and by the period index here.
premium_mth_pp() takes t and resolves the cycle through term_index(),
which keeps every cash flow line indexed the same way. The premium is nonetheless level
within a 보험기간, and check_prem_level() asserts it. On a monthly grid it is also
the cash flow itself: 월납 is the base frequency and the only one on seven of the
retrieved products [S1] [S6] [S8] [S9] [S12] [S17] [S18], so the month’s premium income is
the month’s premium and no annualization convention stands between the rate card and the
statement. P_a = 12 P_m survives as a reporting quantity and as the base of the
commission scale, not as a cash flow.
lap(t) is spelled pols_lapse_pool() because it is a stock, the lapsed lives
still inside the three-year 부활 window, whereas pols_lapse() is the year’s flow
into it.
갱신 reprices, and it also resets things a 更新 does not
At a renewal boundary the premium is recomputed at attained 보험나이 on the whole 기초율 then in force — 적용이율, 계약체결비용, 계약관리비용 and 위험률, each named in the carriers’ own words [S9] [S15] — and the renewal is issued on a new product code [S9] [S15]. What carries and what does not is the crux of the boundary question, and the Korean answer is mixed:
pols_ifis continuous across the boundary. There is no reset to 1: a renewal reprices the contract, it does not re-issue it to a new life.A premium waiver already running does not survive the renewal. 흥국생명, verbatim: 「다만, 새로이 갱신되는 계약에서는 갱신 전 보험료 납입면제 사유로 인한 보험료 납입면제를 적용하지 않고, 보험료를 계속 납입하여야 합니다」 [S6]. A disabled life resumes paying. This is a material cash-flow rule with no
jplibcounterpart, and it is the sharpest single piece of evidence that a Korean renewal really is a fresh contract.wop_waived_frac()therefore resets to zero in the first period of every renewed cycle, andcheck_waiver_reset()asserts it.The suicide and contestability clocks do not restart. They run from the original 보장개시일 and restart only on 부활 [S2 제6조·제28조]. Neither is monetized in the base run; both are stated here because a model that treated each renewed cycle as a fresh policy would get persistency, the strain pattern and both clocks wrong at once.
No acquisition expense and, in the base run, no commission is paid at a renewal (
comm_new_term_rateis 0). That is a choice, not a fact — a Korean renewal is a new product code, which is an argument the other way — and switching it on changes the sign of the cash flow in the earlier repriced years, where the commission on the new premium is larger than the year’s whole margin.
Truncation at the ceiling shortens the cycle, not the horizon: 「갱신일부터 최종
갱신계약의 보험기간 종료일까지가 10년미만일 경우에는 갱신일부터 갱신계약의 보험기간
종료일까지 이 계약의 보험기간으로 합니다」 [S6]. That is term_len().
Renewal decline is not lapse
renewal_decline_rate() is non-zero only in the last month of a cycle, and the
exits it produces are taken after mortality and after ordinary lapse. The ordering
is not cosmetic: reversing it applies the decline to lives that died or lapsed during that
month and understates the exposure of the renewed cohort. On a monthly grid the decline is
also visibly the discrete event it is — one row of 240 carries it, where an annual grid put
it in the same period as a year of continuous lapse.
The rate is [std] 20% and is published nowhere in Korea for any product — the
disclosure requires the price path and not the persistency path [S7] [S16]. It is argued
from three directions. The option is negative and the notice is 15 days, so inertia
dominates and the rate must sit well below a positive-election rate. The step is large
and disclosed in advance — 2.33x at the first renewal on the published path [S7] — so an
insurer expecting no reaction would not need to print the projection. And the nearest
Korean supervisory calibration of a behavioural jump at a discrete contractual event is
the FSS’s floor of at least 30% additional lapse where a 단기납 종신보험’s refund
ratio peaks [REG-R27]; a renewal offers the policyholder no cash and no maturing option,
only a higher price, so 20% sits deliberately below that floor. An arguable range is
roughly 5% to 40%, and renewal_decline_max is set at the top of it.
Zero in the final projected month, where cover ends at the ceiling rather than renewing, and zero on a 비갱신형 point.
One decrement, one benefit — and the disability benefit Korea does not have
A Korean term policy pays the 보험가입금액 on death within the 보험기간 and nothing else,
and payment terminates the contract immediately and automatically [S2 제4조·제23조].
There is no Korean analogue of the Japanese 高度障害保険金, so unlike Term_JP_S
this model carries no competing benefit on one sum assured. What the 장해 (janghae,
disability) state does instead is switch the premium off — the 보험료 납입면제 on a
장해지급률 of 50% or more from any cause, in the 주계약 at no separate premium [S1]
[S2 제5조] [S6] [S8] [S9] [S10] [S11] [S12] — so the state space is: in force paying, in
force premium-waived, dead, lapsed, and on a 갱신형 declined at renewal.
The waiver is cause-neutral: sickness qualifies equally with accident, so the waiver
incidence is a general disability incidence and must not be scaled off
mort_rate(). No Korean document publishes a 50%-plus 장해 incidence and the
참조순보험요율 behind it is not public [REG-R4] [R19], so wop_inc_rate is an
arbitrary placeholder and the module is off on eight of the ten shipped model points.
Lapse pays nothing, and there is no policy loan
On the representative 전기납 무해지 contract the 약관 pays nothing at any duration:
「보험료 납입기간이 보험기간과 동일한 계약 … 의 경우에는 보험기간 중 계약이 해지될 경우
해약환급금을 지급하지 않습니다」 [S2 제33조제2항]. 한화생명’s published 해약환급금 예시
for the same shape shows 환급률 0.0% at all eleven durations printed, for both sexes [S1].
So an ordinary lapse is a pure decrement: it moves pols_if() and pays nothing.
claims(t, "LAPSE") exists and returns zero, and result_cf() carries the zero
column, because the 표준형 comparator does have a value and a reader must not infer one
from the product class.
On a shortened-pay 무해지 contract a value does arise after 납입완료 — 50% of the
표준형’s [S1] [S2 제33조제2항] [S12] — and this model does not compute it. The 표준형
해약환급금 is the 순보험료식 계약자적립액 less the 해약공제액, which is the savings
chassis’s quantity and belongs to WholeLife_KR_S; projecting it here would duplicate
that machinery in the one product that exists to demonstrate the decrement recursion
without it. What the shortened-pay model point does exercise is the lapse-rate step
at 납입완료 — the 적용해지율 falls to 0.1% and then steps to the 0.8% ultimate
[REG-R27] — and the premium ceasing. Model point 5 is that point, and the omitted
surrender value is recorded here rather than left to be discovered.
There is likewise no 보험계약대출 and no 자동대출납입 in fact. Both are granted by the 약관 [S2 제26조·제34조] and both are inoperative, there being no surrender value to lend against — a point the supervisor made in terms of the 무해지 form generally [REG-R28]. 납입최고 (14 days), then 실효, then 부활-or-not is the whole persistency machinery here, which is part of why this is the right chassis to specify first.
The premium chassis, and where it stops being sourced
Korean rate cards are published and the anchor cell is published twice, so the level is
sourced where jplib’s and uklib’s are not:
P_m(k) = r(form, sex, x_k, m_k) * c_p(class, sex) * g(k) * SA / 100,000,000
x_k = x + (k - 1) * n
m_k = min(n, w_r - x_k)
P_a(k) = 12 * P_m(k)
rounded to the nearest 10 won before annualization, which is the granularity the anchor
carrier quotes [S12]. No flat policy element can be separated out: unlike jplib’s
オリックス生命 grid, every Korean grid retrieved fixes the sum assured and varies age, sex,
rate class or product form instead [S1] [S8] [S11] [S12] [S14], so the office premium is
treated as proportional in the sum assured and the approximation is recorded rather than
hidden. One consequence is visible in the data: female premiums run at 52-56% of male
across the six direct writers on the same cell and from 47% to 90% across the eleven
face-to-face and simplified-issue rows [S4] – consistent with a flat per-policy loading
on a small risk premium, but not proof of one, the two bands overlapping at the bottom.
g(k) is the [std] shortened-pay uplift, a-due(m_k) / a-due(m_k^p) at the
적용이율 of 2.50% [S1] [S12]. No Korean document retrieved publishes a shortened-pay
premium for a term contract at all, so an equivalence had to be chosen; a certain annuity
rather than a life annuity is a simplification that overstates the uplift slightly, by
the mortality that would have been shed between the two periods.
P_a = 12 P_m is a reporting quantity on this grid and no longer a cash flow
convention: the monthly step collects P_m in the month it falls due, so the half-year
of interest an annual grid used to gain – 1.136% of a year’s premium at the 적용이율,
the mean deferral of the twelve payments being 5.5/12 of a year – is not gained here.
P_a survives because the rate card is quoted monthly and read annually, and because
the commission scale is written on an annualized premium.
Modules that are off in the base run
Five optional constructions are implemented and switched off on the anchor cell, so that the base run reproduces the worked example while the machinery stays visible and testable. All five are model point columns:
보험료 납입면제 (
waiver), the premium waiver on a 50%-plus 장해지급률 from any cause. On for model points 3 and 4, which are 갱신형, so that the waiver not surviving the renewal is exercised and not merely asserted [S6].선지급서비스특약 (
accel), the accelerated death benefit on a 12-month prognosis, discounted at the 평균공시이율, capped at 50% of the sum assured aggregated to 50,000,000 won, with up to 10,000,000 won payable in full [S2 제3조·제4조]. On for model points 7 and 9 — one where the cap does not bind and one where it does. At the anchor’s 100,000,000 won the cap is exactly reached and reduces nothing, whichaccel_cap_binds()reports with a strict inequality.부활 (
reinstatement), the lapsed-but-reinstatable population and its three-year window [S2 제28조]. On for model point 8. The window is sourced and expressly covers a policy with no surrender value — 「해약환급금이 없는 경우를 포함합니다」 — so a 무해지 policy is always eligible; the rate beside it is an arbitrary placeholder.재해사망 uplift (
acc_death), the product 형 paying 2x the sum assured on 재해사망 and 1x otherwise [S6] [S10]. On for model point 10. It is modelled as a split of the existing decrement using the published 예정 재해사망률, never as a second decrement.Contract boundary (
contract_boundary),current_termtruncating at the end of the cycle in force.ceilingon model point 3,current_termon model point 4.
Two further switches are References rather than columns: the renewal-decline
elasticity d = min(d_max, d_0 (P_a(k+1)/P_a(k))^beta) with beta = 0 giving the
flat 20%, and commission at a 갱신 with comm_new_term_rate = 0.
Sign convention and the timing of the monthly step
net_cf() is income positive — premiums less claims, claim expense, expenses and
commission — which is the library-wide sign, so there is no outgo-positive
liability_cf companion to publish: one stream, one sign, one name.
Premiums are monthly in advance, claims fall at the end of the month of death, and the decrements act inside the month they belong to. The annual grid this model was first written on carried a matched pair of offsetting distortions — a whole year’s premium collected from lives that died or lapsed in the year, against a death benefit paid a year late — and the monthly step removes both rather than netting them: the residual timing error is now half a month either way instead of half a year.
What is not modelled, and why
감액 (a reduction in the sum assured) changes SA and P_a together and pays
nothing on this form, so it is a model point re-parameterization rather than a decrement
[std scope] [S2] [S12]. 증액 is not available at all; a new contract with fresh
underwriting is required [S1] [S12]. 청약철회 is out of scope: the projection begins
with cover in force and the 15-day statutory population already out [S2 제18조]
[REG-R51]. The 위법계약의 해지 — which returns the whole 계약자적립액 with no
surrender charge [S2 제30조의2] [REG-R25 제29조의2], and so is worth the entire value on
a form whose ordinary surrender pays nothing — is not modelled, no incidence of
mis-selling findings being published; it is stated because a Korean model treating the
surrender value as uniformly nil would be wrong about a real if small cash flow. The
rate class is a state and not a parameter: a Korean class rider tracks smoking status
for the life of the contract and moves in both directions, with a 정산차액 recovered
or the 보험가입금액 reduced in the ratio of the two premiums [S2 건강체서비스특약Ⅱ
제4조] [S11] [S12]. This model does not carry the transition, and a model that later needs
it will need a transition and not a relabelling. And the claim timetable — 3영업일,
10영업일 where investigation is needed, 30영업일 outside — is contractual and real, but no
Korean document publishes the mix of claims falling into the three bands, so the
composite pays at the projection step in which the claim arises and says so [S2 제9조].
Cells Descriptions#
- age_at_entry()[source]#
x: the 가입나이 (issue age) in 보험나이 [S2 제22조] [REG-R25 제21조].
만나이 with fractions of six months or more rounded up, incrementing on the policy anniversary and not on the birthday, so the whole model is on one age basis and no shift is applied anywhere. The composite’s envelope is 만19세 to 보험나이 65 [S1] [S6] [S9] [S11] [S12]; the mixed basis in that sentence is the documents’ own, a minimum written 만19세 being 만나이 and a maximum written 65세 being 보험나이.
- renewal_type()[source]#
gaengsinfor a 갱신형 contract,bi_gaengsinfor a 비갱신형 one.The single most consequential model point attribute. A 갱신형 contract renews automatically at attained 보험나이 to the ceiling with no 고지 and no underwriting [S6] [S9] [S15]; a 비갱신형 contract has one 보험기간, one premium and no repricing [S1] [S12], and applying the renewal machinery to it invents cover it does not have. 비갱신형 is the base because it is the market: only three of the 45 disclosed products renew and only two carriers sell a renewable term at all [S4].
- rate_class()[source]#
The underwriting class: 표준체 / 비흡연자 / 건강체 / 슈퍼건강체.
Spelled
standard/nonsmoker/preferred/super_preferredso thatrun.pystays ASCII. Observed class counts run from one to four [S15] [S11] [S12]; the base run is 표준체 because a class structure multiplies the premium basis without changing a contractual mechanic. It is parameterized rather than dropped because Korea publishes the mortality behind it — two carriers print a full 예정 경험사망률 table per class [S11] [S12] — which no other library here can do.The class is a state and not a parameter in the contract: the rider tracks smoking status for the life of the policy and moves in both directions [S2 건강체서비스특약Ⅱ 제4조]. This model does not carry the transition.
- maturity_form()[source]#
purefor the 순수보장형,ropfor the 만기환급형 [S1] [S8] [S12].The 순수보장형 has no 만기보험금 at all and passes the 보장성보험 test by construction [REG-R9]. The 만기환급형 returns exactly 100% of 「이미 납입한 주계약 보험료」 at maturity, computed as if any waived premiums had been paid [S1] [S12], and passes the same test by design; 감독규정 제7-60조제9호 is part of why it returns exactly 100% and not less [REG-R16]. It costs 9.42x the 순수보장형 at male 40 and 10.90x at female 40 [S12], which is what a savings contract with a small amount of insurance stapled to it looks like.
- policy_term()[source]#
n: the 보험기간 in years — the priced term, not the projection horizon.
Read from
term_yon a 년만기 point and implied byexpiry_ageon a 세만기 one; every carrier offering a menu offers both shapes and the 세만기 ceiling has crept from 80세 to 90세 and 100세 [S1] [S9] [S12] [S17]. On a 갱신형 contract this is the length of one cycle and the horizon ishorizon_ceiling(), which is longer.
- pay_term()[source]#
n_p: the 납입기간, in years from issue, over which premium is payable.
0in the model point table means 전기납 (jeongi-nap, whole-term pay), which is the disclosure’s basis [S5] and available at every carrier, and which on this chassis means paying for the whole projection — so the payment period never ends before the cover does and the post-완납 machinery never fires [S2 제33조제2항]. Shortened pay is carried because it is the only way the 무해지 form’s post-완납 step-up can arise at all, and with it the 0.8% ultimate lapse rate [REG-R27].
- renew_ceiling()[source]#
w_r: the 보험나이 at which renewal stops, 80 on the composite [S6].
Observed ceilings are 80세 [S6], five years’ total cover [S15] and the main contract’s expiry [S9]; the composite takes 흥국생명’s, which is the only one that supports a multi-cycle projection. Inert on a 비갱신형 point.
- sum_assured()[source]#
SA: the 보험가입금액, level for the whole term and unchanged through a 갱신.
Paid on death within the 보험기간 and on nothing else; payment terminates the contract [S2 제4조·제23조]. The composite’s envelope is 30,000,000 to 500,000,000 won in 10,000,000 won units [S6] [S9] [S11] [S12] [S14]; 체증형 (escalating) is corporate-only and 체감형 (decreasing) is a disclosure category with no retail product in it [S4] [S18].
The 납입주기 — 월납 (monthly) in the base run [S1] [S6] [S8] [S9] [S12].
Monthly is available at every carrier retrieved, is the only frequency on seven of the retrieved products, is the disclosure’s basis [S5] and is half of the 감독규정 기준연령 요건 [REG-R9]. It is the projection’s own step, so the mode is no longer a convention the grid has to absorb: the month’s premium income is
premium_mth_pp, collected in the month it falls due. A non-월납 mode would need its ownprem_mode_monthsschedule and is not shipped, every retrieved rate card being quoted monthly.
- contract_boundary()[source]#
ceilingorcurrent_term: how far the liability is projected.A Korean 갱신형 reprices the entire 기초율 at renewal, 위험률 included, and the carriers say so in terms [S9] [S15]; the renewal is issued on a new product code [S9] [S15]; and a waiver already running is extinguished [S6]. Against that, the renewal is guaranteed-issue — no 고지, no underwriting, no health condition [S6] [S9] [S15] — so the repricing is at portfolio level and cannot reflect the risks of the particular policyholder, which is the test that keeps a renewal inside the boundary. Nothing retrieved settles it [REG-R60], so the model does not rule: it projects to the ceiling in the base run [std] and carries the truncation as a switch. Naming the convention is part of reporting the number.
- acc_death()[source]#
Whether the 재해사망 uplift module is on; false in the base run [S6] [S10].
Two of nine carriers sell it, and both sell it as a product 형 rather than a rider, paying twice the 보험가입금액 on 재해사망 and once otherwise. It is cheap: on the shipped table the 예정 재해사망률 [S6] is about a third of the all-cause rate [S12] at male 20 and about a tenth of it at male 60, so a doubled benefit costs a fraction of the base risk premium — which is why it is bundled into the base price rather than priced separately. One structural asymmetry is worth recording: 흥국생명 does not sell its 기본형 to women at all, so a female life there must buy the 보장추가형 and the disclosure prints 0 won in the 기본형 female column [S4] [S6].
- waiver()[source]#
Whether the 보험료 납입면제 module is on; false in the base run.
The trigger is identical at eight carriers in identical words: a 장해지급률 summing to 50% or more from 「동일한 재해 또는 재해이외의 동일한 원인」, waiving 「차회 이후의 보험료 납입」 with no refund of past premiums, the contract continuing in force [S1] [S2 제5조제1항] [S6] [S8] [S9] [S10] [S11] [S12]. It is cause-neutral, so the incidence is a general disability incidence and not a scaled accident rate, and the 장해지급률 is a percentage scale rather than a binary trigger [REG-R25 부표 3]. On for model points 3 and 4, which are 갱신형, so that the waiver not surviving a renewal is exercised [S6].
- accel()[source]#
Whether the 선지급서비스특약 module is on; false in the base run [S2] [S12].
A 제도성특약 attached as standard at every carrier whose full document set was retrieved, carrying no separate premium in any of them — that it is genuinely free is [unverified], no document stating a nil 특약보험료, but the discount in the payment formula supplies the economic reason it can be. Against Japan’s リビング・ニーズ特約 the Korean trigger is 12 months rather than six, the cap is half the sum assured to 50,000,000 won rather than the whole benefit, and there is no bar on payment near expiry at all.
- reinstatement()[source]#
Whether the 부활 module is on; false in the base run [S2 제28조].
부활 is available for three years from the termination date provided the surrender value was not drawn — expressly 「해약환급금이 없는 경우를 포함합니다」, so a 무해지 policy is always eligible — with arrears at 「평균공시이율+1% 범위 내」. Reinstatement re-runs the 계약 전 알릴 의무 and restarts the two-year suicide window, where a 갱신 does not [S2 제6조·제28조]. Off by default because
reinstate_rateis an arbitrary placeholder with a material persistency effect: no Korean document publishes a reinstatement rate. What is published, and is therefore not [std], is the window.
- horizon_ceiling()[source]#
The number of policy years from entry to the renewal ceiling.
renew_ceiling() - age_at_entry()on a 갱신형 point, because the contract renews until it gets there [S6]; the term itself on a 비갱신형 point, which never renews [S1] [S12].
- proj_years()[source]#
N_y: the number of projected policy years —
horizon_ceiling(), or the cycle.The horizon in the unit the contract states it in.
contract_boundary = current_termtruncates at the end of the 보험기간 in force, which for a policy projected from issue ispolicy_term(). On a 비갱신형 point the two coincide. A model that can project to the ceiling can always be truncated to one cycle; the reverse is not true, which is why the long reading is the base.Kept separate from
proj_len()because the contract is written in years — 보험기간, 납입기간 and the 보험나이 80 ceiling are all annual quantities — while the projection steps in months. Everything that reads a contractual term in years reads this; everything that indexes the grid readsproj_len().
- proj_len()[source]#
N: the number of projected policy months,
12 x proj_years().The exclusive end of the frame: the projection covers
t = 0, 1, ..., proj_len() - 1andresult_cf()hasproj_len()rows. 240 on the anchor cell — a 20년만기 contract projected month by month.There is no terminal row beyond the months of cover. The 순수보장형 pays nothing at the horizon and the 만기환급형’s 만기보험금 falls in the last month of cover along with
pols_maturity(), so nothing is left over to need an instant of its own.
- age(t)[source]#
x + floor(t / 12): the attained 보험나이 in policy month t.
보험나이 increments on the policy anniversary and not on the birthday [S2 제22조], and a monthly grid anchored at issue steps its anniversaries exactly twelve months apart, so
t // 12is the number of anniversaries passed and the alignment is exact rather than approximate.tis 0-based, soage(0)is the 가입나이 itself and the attained age advances att = 12, 24, ....
- policy_year(t)[source]#
y(t): the contractual policy year containing month t,
t // 12 + 1.The 1-based contractual label, derived from the 0-based month index and never the index itself. Month
t = 0falls in policy year 1. It is what the 납입기간, the 보험기간 and the disclosed 적용해지율 vector are written in, solapse_rate()andprem_payable()read it rather than counting months by hand.
- term_index(t)[source]#
k: the renewal index — 1 in the original 보험기간, 2 after the first 갱신.
1 + floor(t / n)on a 갱신형 point; always 1 on a 비갱신형 one, which never renews [S1] [S12]. The premium is a function of k and not of t, which is the state variable a Korean protection model needs: a model that indexes the premium by policy year cannot represent a 갱신형, and one that carries a single level premium across a renewal boundary silently converts a 갱신형 into a 비갱신형 at the wrong price.
- term_start_age(k)[source]#
x_k: the attained 보험나이 at which cycle k starts,
x + (k - 1) n.kis the contractual 1-based cycle label, not the 0-based time index: cycle 1 is the original 보험기간 and starts att = 0, cyclekstarts att = (k - 1) n.
- term_len(k)[source]#
m_k: the length of cycle k in years,
min(n, w_r - x_k).The ceiling truncates rather than refuses: 「갱신일부터 최종 갱신계약의 보험기간 종료일까지가 10년미만일 경우에는 갱신일부터 갱신계약의 보험기간 종료일까지 이 계약의 보험기간으로 합니다」 [S6]. The truncated cycle is priced over its own shorter length, which is why this feeds
prem_rate_mth().
- term_pay_years(k)[source]#
m_k^p: the years of premium payment falling inside cycle k.
Equal to
term_len()on a 전기납 contract and on every cycle of a 갱신형 one, and shorter on a 비갱신형 contract bought with a shortened 납입기간. Zero once the 납입기간 has run out, which cannot happen on the shipped points but is defined so the premium formula stays total.
- class_mort_ratio()[source]#
The rate class’s mortality relativity to 표준체, from rate_class_table.csv.
1.000 / 0.828 / 0.723 / 0.583 at male 40 and 1.000 / 0.956 / 0.907 / 0.856 at female 40, computed from the anchor carrier’s own class-by-class 예정 경험사망률 [S12]. A second carrier’s full table gives 0.597 and 0.861 at the same two cells [S11], so the relativity is a market feature rather than one carrier’s design. Held flat across ages [std]: the disclosures are at ages 20, 40 and 60 and the ratios move little between them.
- class_prem_ratio()[source]#
The rate class’s premium relativity to 표준체, from rate_class_table.csv.
1.000 / 0.865 / 0.763 / 0.586 at male 40 and 1.000 / 0.964 / 0.890 / 0.846 at female 40, from the published premium grid [S12]. It sits above the mortality ratio in the three male classes and in the female 비흡연자, which is what a loading that does not scale with the risk does, and marginally below it at female 건강체 (0.890 against 0.907) and female 슈퍼건강체 (0.846 against 0.856). Nothing retrieved explains the reversal, so the two ratios are carried as separate columns and neither is derived from the other.
- mort_rate_at_age(x)[source]#
The 표준체 table mortality rate at attained 보험나이 x, unadjusted.
A [std] construction of the 예정 경험사망률 basis: a Makeham law fitted exactly to the anchor carrier’s three disclosed rates [S12] and tilted above age 60 so that the shipped table reproduces the 제10회 경험생명표’s published 65세 기대여명 exactly [REG-R33]; see
Data. This is a pricing rate with its margin still in it, and it is read directly by the premium scale and only throughmort_rate_base()by the decrement.
- acc_mort_rate_at_age(x)[source]#
The 예정 재해사망률 (accidental-death rate) at attained 보험나이 x [S6].
Published by two carriers, who agree to three significant figures at age 20 and to within 10% everywhere [S6] [S10] — strong evidence that both take the 보험개발원 참조 재해사망률 almost unadjusted, where the all-cause rates are heavily adjusted and differ by a factor of 1.77 at male 40. Used only to split the death decrement for the 재해사망 uplift variant, never as a decrement of its own.
- mort_table_mean(x, m)[source]#
qbar(x, m): the mean 표준체 table rate over ages x .. x + m - 1.
The shape parameter of the [std] premium extension. Deliberately built on the table rate rather than on
mort_rate(): a premium scale is not a best-estimate quantity, and feeding the best-estimate factor in would move a published rate card by an assumption that has nothing to do with pricing.
- mort_rate_base(t)[source]#
The class-adjusted table rate at the attained age of period t.
mort_rate_at_age(age(t)) * class_mort_ratio(). Still a pricing rate; the best-estimate factor is applied bymort_rate(). No age-basis shift is applied anywhere in this model, both the model point and the table being on 보험나이 [S2 제22조].
- mort_rate(t)[source]#
q(t): the annual best-estimate death rate at the attained age of month t.
mort_be_factortimes the class-adjusted table rate, capped at 1. One decrement carrying one benefit: a Korean term policy pays the 보험가입금액 on death and nothing else, and payment terminates the contract [S2 제4조·제23조]. There is no Korean analogue of the Japanese 高度障害保険金, so unlikeTerm_JP_Sthere is no competing benefit to double-count; what the 장해 state does instead is switch the premium off, which iswop_waived_frac().mort_be_factor = 0.85[std] is this model’s largest single lever and its least evidenced number. The shipped table is a carrier’s 예정 경험사망률, which is a pricing rate carrying a margin over experience that no public Korean document sizes — the 산출방법서 in which it would be justified is a 기초서류 filed with the FSC and never published [REG-R2]. What can be bracketed is the scale and not the margin: seven carriers’ disclosures at male 40 run from 0.000480 to 0.000850, a factor of 1.77 around the anchor’s 0.000650 [S1] [S6] [S8] [S10] [S11] [S12] [S17], so the cheapest carrier prices at 0.74x the anchor before any margin is removed. A round 0.85 sits between that and unity and the technical notes carry the sensitivity.
- mort_rate_mth(t)[source]#
q^m(t): the monthly death decrement,
1 - (1 - q(t))^(1/12)[std].The uniform-force conversion of the annual best-estimate rate of the policy year month
tfalls in, which is the conversion every monthly model in this library uses. The annual rate is the quantity the sources publish — every Korean 예정 경험사망률 disclosure is annual [S12] [S11] [S6] — so the annual rate is the one the model reads and the monthly rate is derived from it, never the other way round.It is the decrement
pols_death()andpols_if_at()actually apply. The twelve monthly rates inside a policy year are equal, the annual table rate stepping only at each 계약해당일: 보험나이 increments on the anniversary [S2 제22조], so a within-year interpolation of the table would be modelling an age the contract does not recognize.
a_q(t): the accidental share of period t’s death decrement [S6] [S10].
acc_mort_rate_at_age / mort_rate_at_ageon the 표준체 table basis, so that the ratio is not disturbed by the class relativity or the best-estimate factor — neither of which has anything to say about the cause of death. Capped at 1. It runs around 0.35 at age 20 and 0.10 at age 60 on the shipped table, which is the right order for a doubled-benefit variant to be cheap enough to bundle into the base price rather than price separately. Reported on every model point; it enters the cash flows only whereacc_death()is on.
- lapse_rate(t)[source]#
w(t): the ordinary lapse rate applied at the end of period t.
The shape is supervisory and not chosen: the 2024 IFRS17 계리가정 가이드라인 makes a 로그-선형 model converging to 0.1% the 원칙모형 for 무·저해지 business, permits only 선형-로그 and 로그-로그 as exceptions and on onerous disclosure conditions, and sets a post-완납 ultimate of 0.8% [REG-R27]. The endpoints are disclosed: 「납입기간 이내에 대하여 경과기간별로 연 0.1%~4.6%, 납입기간 이후에 대하여 경과기간별로 연 0.7%~1.6%」 at the anchor carrier [S12] and 「연 0.1%~8.4%, 납입기간 이후 연 0.8%」 at another [S1]. So:
w(t) = 0.046 * (0.001 / 0.046) ** (t / (n_p - 1)) for t < n_p w(t) = 0.008 for t >= n_p
times
lapse_be_factor, read at the 0-based policy yeary = policy_year(t) - 1rather than at the month index: the vector is published by 경과기간 in years, so the 4.6% upper endpoint covers the whole of the first projected year and the 0.1% convergence point the whole of the last paying one.lapse_rate_mth()is the decrement actually applied. Two [std] steps remain and both are recorded rather than absorbed. Both disclosed ranges are on a 10년납 basis and the composite is 전기납 over twenty years, so the same endpoints are stretched over the representative’s own 납입기간 — which flattens the curve and is why model point 5, at 10년납, is the one that reproduces the disclosed shape at its disclosed length. And the 적용해지율 is a pricing rate for the 무해지 form, deliberately low by regulatory design [REG-R19 제7-66조제4항], and is not a best-estimate. Nothing retrieved discloses a best-estimate term lapse rate; the only Korean experience datum available is a whole-life one, a 저해지 단기납 종신보험 running a 37회차 유지율 of 50.2% against an assumed 71.5% [R18]. The direction of that error is the reasonlapse_be_factorexists as a switch and is 1.0 [std] in the base run, with the sensitivity carried in the technical notes rather than a point estimate dressed as a fact.A lapse pays nothing on this form: there is no 해약환급금 at any duration [S1] [S2 제33조제2항] [S12].
- lapse_rate_mth(t)[source]#
w^m(t): the monthly lapse rate,
1 - (1 - w(t))^(1/12)[std].The 적용해지율 the supervisor’s 원칙모형 prescribes is an annual rate by duration — 「경과기간별로 연 0.1%~4.6%」 [S12] [REG-R27] — so the annual vector is what the model reads and the monthly rate is its uniform-force conversion, level inside a policy year and stepping at each 계약해당일. This is the rate
pols_lapse()andpols_if_at()apply.A lapse still pays nothing on this form [S1] [S2 제33조제2항] [S12]; what the monthly grid changes is when the exposure leaves, not what leaves with it. Twelve monthly exits compound to the year’s annual rate exactly, so the year-end in-force is unchanged and the mid-year exposure carrying premium and mortality is not — which is the whole reason to step monthly.
- renewal_decline_rate(t)[source]#
d(t): the renewal-decline rate — non-zero only in a boundary period [std].
A boundary period is the last month of a cycle that is not the last of the projection: with
t0-based that is(t + 1) % 12n == 0andt < proj_len() - 1, so a ten-year cycle declines att = 119, 239, 359and the repriced premium takes effect att = 120, 240, 360.At each 갱신 date a fraction of the surviving in-force leaves rather than accept the repriced contract. It is not ordinary lapse: ordinary lapse is continuous, spread through the year and driven by affordability and by competing products, whereas this is discrete, concentrated on a single date, and driven by the size of the repricing step — a step the policyholder was warned about in the 상품요약서 and which, on the published path, is 2.33x at the first renewal and 3.6x at the third [S7]. Folding it into
lapse_rate()makes the boundary invisible.renewal_decline_base = 0.20is published nowhere in Korea for any product, and that is a real gap rather than a research failure: the 예상 갱신보험료 예시 the disclosure requires shows the price path and not the persistency path [S7] [S16]. See the Space docstring for the three-way argument behind the 20% and the 5%-to-40% arguable range.Zero on a 비갱신형 point, which never renews [S1] [S12], and zero in the final projected year, where cover ends at the ceiling rather than renewing. The optional elasticity
d = min(d_max, d_0 (P_a(k+1)/P_a(k))^beta)responds to the premium jump;renewal_decline_beta = 0in the base run gives the flat rate.
- pay_factor(k)[source]#
g(k): the [std] shortened-pay uplift on the premium of cycle k.
a-due(m_k) / a-due(m_k^p)at the 적용이율, the ratio of an annuity-certain-due over the cover period to one over the paying period — the level premium that pays for the same cover over fewer years. 1.0 on a 전기납 contract, and 1.78 on a 20-year term bought 10년납.[std] because no Korean document retrieved publishes a shortened-pay premium for a term contract at all: every published grid is 전기납 or fixes the 납입기간 equal to the 보험기간 [S1] [S8] [S11] [S12]. A certain annuity rather than a life annuity is a simplification that overstates the uplift slightly, by the mortality that would have been shed between the two periods; at the ages this composite issues at, that is a fraction of a percent.
- prem_rate_mth(t)[source]#
r(form, sex, x_k, m_k): the monthly 표준체 rate per 100,000,000 won of cover.
The published cell where one exists — the anchor carrier’s 20-year grid at ages 30, 40 and 50 for both sexes and both maturity forms [S12], and the 갱신형 ladder at ages 40, 50, 60 and 70 on a ten-year cycle [S6] [S7] — and otherwise the [std] extension off the
is_anchorrow of the matching form and sex:r(form, sex, x, m) = r_anchor * qbar(x, m) / qbar(x_a, m_a)
The anchor is the age-40 20-year cell, which for the 순수보장형 is simultaneously the 감독규정 기준연령 요건 [REG-R9] and the disclosure’s 대표계약 [S5], and whose 15,080 won appears independently in the carrier’s own grid and in the cross-carrier disclosure, agreeing to the won [S12] [S4].
The 10-year rows and the 20-year rows are different carriers, and the model never mixes them: the shipped 갱신형 points reach published cells only. That the two are at the same level is checkable — the 흥국생명 비갱신형 20-year premium on the disclosure basis is 15,000 won against the anchor’s 15,080 [S4].
P_m: the monthly 영업보험료 (office premium) per policy in period t.
r * c_p * g * SA / 100,000,000, rounded half up to the nearest 10 won, which is the granularity the anchor carrier quotes [S12]. Level within the 보험기간 and recomputed at each 갱신 at attained 보험나이 on the whole 기초율 then in force [S9] [S15] — it is not guaranteed beyond the current cycle, which is what makescontract_boundary()a question rather than a detail.No flat policy element is separated out. Every Korean rate card retrieved fixes the sum assured and varies age, sex, rate class or product form instead [S1] [S8] [S11] [S12] [S14], so the per-mille rate and any per-policy fee cannot be decomposed and the premium is treated as proportional in the sum assured. On the anchor cell this reproduces the published 15,080 won exactly [S12] [S4].
No 단체취급 discount (1.5%-5% for an affinity group of five or more), 고액할인, 걷기할인형 or 선납 discount is applied: all four are documented and none has a published rate that could be applied without inventing the number that matters [S1] [S8] [S9] [S10] [S12].
- prem_pp(t)[source]#
P_a: the annualized 영업보험료 per policy in period t,
12 P_m.The annualization is [std]: 월납 is the base frequency and the only one on seven of the retrieved products, from five carriers [S1] [S6] [S8] [S9] [S12] [S17] [S18], and no carrier publishes a mode discount, so no allowance is made for the timing difference. The simplification is conservative in the insurer’s favour by half a year’s interest on the whole premium – 1.136% of a year’s premium at the 적용이율, the mean deferral of the twelve payments being 5.5/12 of a year. On the anchor cell
P_a = 12 x 15,080 = 180,960.
- prem_payable(t)[source]#
1 while period t falls inside the 납입기간, 0 after 납입완료.
With
t0-based the 납입기간 ofn_pyears ist < n_p, the last paying period beingt = n_p - 1. On a 전기납 contract this is 1 for the whole projection, which is why the representative form has no post-완납 period at all and hence no surrender-value step-up [S2 제33조제2항].
- cum_prem_pp(t)[source]#
Scheduled premiums paid per policy to the end of month t,
t + 1months’ worth.The 만기환급형’s maturity benefit is 100% of 「이미 납입한 주계약 보험료」 computed as if any waived premiums had been paid [S1] [S12], so this is the scheduled premium and not the collected one, and
wop_waived_frac()does not enter it. That is exactly why the waived state is a real state and not a cash-flow adjustment.
- pols_if_init()[source]#
l(0) = 1: the model point is one policy, projected on an expected basis.
Survivorship multiplies the per-policy cash flows; no aggregation logic is specified in the technical notes and none is implemented.
- pols_if(t)[source]#
l(t): the in-force probability at time t, the start of period t.
pols_if_init()att = 0, then the roll-forwardl(t+1) = l(t)(1 - q)(1 - w)(1 - d) + reinstatements - maturities. This is the weight on every cash flow of the sameresult_cf()row.It is continuous across a renewal boundary: a 갱신 reprices the contract, it does not re-issue it [S6] [S9] [S15], so there is no reset to 1 and no new cohort — even though the renewal is issued on a new product code, which is one of the facts that pulls the other way on the contract-boundary question. Defined one step beyond the frame and zero at
proj_len(), the time at which the horizon is reached: everything still in force there leaves throughpols_maturity(), whether or not anything is paid for it.
- pols_if_at(t, timing)[source]#
The number of policies in force at a point inside period t.
The processing order is death, then ordinary lapse, then the renewal decline, and each timing reads the population the next decrement is taken from:
"BEF_DECR"l(t), the start of the period, before any decrement; the same number as
pols_if()and the weight on that period’s cash flows."BEF_LAPSE"after deaths, before ordinary lapse.
"BEF_DECLINE"after ordinary lapse, before the renewal decline. Equal to
"AFT_DECR"in every period that is not a renewal boundary."AFT_DECR"after all three decrements — the end-of-period state, before any 부활 reinstatement is added back and before the horizon’s
pols_maturity()removes the remainder.
The order is load-bearing and the specification is explicit about it: applying the renewal decline before mortality and ordinary lapse would apply it to lives that died or lapsed during the boundary month and overstate the exposure of the renewed cohort.
Zero outside
0 .. proj_len() - 1: the cover has not started or has ended.
- pols_death(t)[source]#
D(t) = l(t) q(t): expected death claims in period t.
One decrement carrying one benefit. A court 실종선고 and a 관공서 disaster notification count as death and are inside this rate [S2 제5조제2항]; a withdrawal of life-sustaining treatment expressly does not affect the cause of death or the payment [S2 제5조제3항]. The three 면책 limbs — suicide within two years of the 보장개시일, and intentional killing by the 보험수익자 or the 계약자 — are not monetized: no Korean document publishes their incidence, and gross negligence is not an exclusion, 상법 제732조의2 preserving the benefit [REG-R50] [R4].
- pols_lapse(t)[source]#
Ordinary lapses at the end of period t, from the survivors of mortality.
Pays nothing on this form [S1] [S2 제33조제2항] [S12], so this moves
pols_if()and nothing else. With the 부활 module on, these lives flow intopols_lapse_pool()rather than leaving for good. The machinery behind the rate is short and is the whole of it: 납입최고(독촉)기간 of 14일 from a written, recorded-telephone or electronic demand, termination the day after it ends, and a claim arising before termination still paid [S2 제27조] [REG-R25 제26조].
- pols_decline(t)[source]#
Renewal declines at the end of a boundary period, after ordinary lapse.
Zero in every period that is not a 갱신 boundary and zero on a 비갱신형 point. Nothing is paid: the policyholder who declines simply lets the cover end, and on the 갱신형 the reserve has already unwound to zero within the cycle — 흥국생명’s ten-year renewable shows 환급률 0.0% at 10년 [S6].
- pols_maturity(t)[source]#
Policies whose cover ends at the horizon, in the last period
proj_len() - 1only.The count whose cover ends at the scheduled end of the contract, whether or not anything is paid for it — nothing on the 순수보장형, which expires with no maturity value and a surrender value that has already run to zero [S1] [S8] [S12], and 100% of the premiums paid on the 만기환급형 [S1] [S12]. Reinstatements arriving in the final period are inside it, so that a contract revived under 부활 and then reaching maturity is treated consistently.
- reinstate_rate_eff()[source]#
rho: the 부활 reinstatement rate actually applied — zero unless the module is on.
Keeping the effective rate in one cells is what lets
pols_lapse_pool()andcheck_lapse_pool()carry the same ledger in both positions of the switch: with the module off the pool still tracks the lapsed-but-reinstatable population, and nothing is reinstated out of it.
- pols_lapse_pool(t)[source]#
lap(t): lapsed lives still inside the three-year 부활 window at time t.
A stock, where
pols_lapse()is the flow into it. Tracked by vintage rather than as one blanket balance, because the window runs from each life’s own 해지 and a single indicator would drop a whole cohort months early or late:lap(t) = sum over s in [t - W, t - 1] of pols_lapse(s) (1 - rho)^(t - 1 - s)
with
W = reinstate_window = 36months — the three years the 약관 gives [S2 제28조], counted on the projection’s own step so that the window closes on the month it actually closes on rather than at the next anniversary. Renewal declines never enter it: a declined 갱신 is an expiry and not a 해지, and there is nothing to reinstate.
- pols_reinstate(t)[source]#
Reinstatements out of the pool into
pols_if(t + 1):lap(t) rho.부활 is available for three years from the termination date and expressly covers a policy with no surrender value — 「해약환급금이 없는 경우를 포함합니다」 — so a 무해지 policy is always eligible [S2 제28조]. The arrears, which bear interest at 「평균공시이율+1% 범위 내에서 회사가 정하는 이율」, are not monetized: they settle premiums for years in which this projection collected none, so recognizing them would need a missed-premium ledger [std scope]. Reinstatement re-runs the 계약 전 알릴 의무 and restarts the two-year suicide window, where a 갱신 does not [S2 제6조·제28조]. Zero in the base run.
- pols_lapse_expire(t)[source]#
Lives leaving the pool in period t because their three-year window has run out.
The vintage that lapsed in period
t - W, net of the reinstatements taken out of it along the way. They are gone for good: after the window there is no 부활 [S2 제28조].
- wop_waived_frac(t)[source]#
u(t): the fraction of in-force policies with premiums waived at time t.
A two-state incidence chain [std],
u(t+1) = u(t)(1 - rec) + (1 - u(t)) inc, starting fromu(0) = 0. Two Korean rules shape it and both are sourced.It resets at every 갱신, so it is zero again at
t = (k - 1) n, the first period of cycle k. 흥국생명, verbatim: 「다만, 새로이 갱신되는 계약에서는 갱신 전 보험료 납입면제 사유로 인한 보험료 납입면제를 적용하지 않고, 보험료를 계속 납입하여야 합니다」 [S6]. A disabled life must resume paying at the renewal date.check_waiver_reset()asserts it, and model points 3 and 4 exercise it.It is zero after 납입완료, there being no premium left to waive [S2 제5조제1항].
wop_inc_rate = 0.0008is an arbitrary placeholder. The trigger is a 장해지급률 summing to 50% or more from any cause, additive across body parts, determined at 180 days with a two-year look-back [S2 제5조]; it is cause-neutral, so it is a general disability incidence and must not be scaled offmort_rate(), which would be a false derivation dressed as one. No Korean document publishes a 50%-plus 장해 incidence and the 참조순보험요율 behind it is not public [REG-R4] [R19], so the module is off on eight of the ten shipped points and no conclusion should be drawn from its level.Entering the waived state also forfeits the 무해지 post-완납 step-up [S2 제33조제2항 단서] [S12] — a value effect this model does not carry, the 표준형 계약자적립액 belonging to
WholeLife_KR_S.
- wop_inc_rate_mth()[source]#
The monthly 납입면제 incidence,
1 - (1 - wop_inc_rate)^(1/12)[std].wop_inc_rateis stated as an annual incidence, because that is the unit a 장해 incidence would be published in if Korea published one; the monthly grid needs the monthly equivalent and derives it here rather than restating the placeholder in a unit no source would ever use. The level itself is arbitrary and the module is off on eight of the ten shipped points — seewop_waived_frac().
- wop_rec_rate_mth()[source]#
The monthly recovery rate out of the waived state, from
wop_rec_rate[std].Zero in the base run: the 약해지급률 trigger is assessed at 180 days with a two-year look-back and the 약관 provides no re-assessment that puts a waived life back on premium [S2 제5조], so recovery is carried as a switch at zero rather than as a modelled transition.
- pols_waived(t)[source]#
In-force policies whose premiums are waived in period t; zero in the base run.
Mortality and lapse are assumed independent of the waiver state [std], which is what lets the waived population be carried as a fraction of the in-force rather than as its own decrement. That assumption is more comfortable here than it would be on a disability product: the waiver is a premium mechanic on a contract whose only benefit is death, so the waived lives are still the same lives on the same cover.
- pols_payer(t)[source]#
In-force policies actually paying premium in period t.
l(t)inside the 납입기간, less the waived fraction; zero after 납입완료. Equal topols_if()while premiums are payable unless the 납입면제 module is on.
- accel_cap_binds()[source]#
Whether the 선지급 cap would reduce a single-contract acceleration.
0.5 SA > 50,000,000, a strict inequality. The 약관 is 「주계약 사망보험금액의 50% 이내에서 피보험자별로 통산하여 최고 5,000만원까지 … 다만, 1,000만원까지는 주계약 사망보험금액의 100% 이내」 [S2 제4조]. At the anchor’s 100,000,000 won of cover the 50% limb gives exactly 50,000,000 and the aggregate cap is exactly reached and reduces nothing, so the cap is visible at the anchor rather than only at large model points and a model reporting it as binding there has a strict-versus-weak inequality error. Model point 9, at 200,000,000 won, is where it genuinely binds.
- accel_amount()[source]#
A: the accelerated amount under 선지급서비스특약; zero unless the module is on.
SAwhere the sum assured is within the 10,000,000 won full-payment window, andmin(0.5 SA, 50,000,000)above it [S2 제4조]. Against Japan’s リビング・ニーズ特約 the Korean cap is tighter — half the sum assured to 50,000,000 won rather than the whole benefit — while the trigger is looser, 12 months rather than six, and there is no bar near expiry at all.
- accel_available(t)[source]#
Whether an acceleration can be claimed in period t.
True in every projected period where the module is on. Unlike Japan’s rider, which is barred within a year of a non-renewable expiry, the Korean 선지급서비스특약 has no bar near expiry in any retrieved 약관 [S2 제3조·제4조] [S10] [S12] [S17]. The one observed narrowing is a carrier that shortens the prognosis to six months specifically for 정기보험 [S17].
a(t): the share of period t’s decrement arriving as an acceleration [std].
Modelled as a split of the existing death decrement rather than as an additional incidence: an acceleration is a re-timing and re-pricing of the death benefit, not a second claim, and a separate incidence on top would double-count it. Payment reduces the 보험가입금액 from the payment date, no surrender value arises on the reduction, and there is one payment per contract [S2 제4조].
accel_take_up = 0.10is an arbitrary placeholder, and the honest defence of it is not a rationale but the switch: no retrieved document gives an acceleration take-up for any Korean carrier and nothing in the sources bounds it. A round tenth was chosen because it is visibly round — a number no reader can mistake for an estimate.
- accel_payout_pp(t)[source]#
The 선지급 payment per accelerated claim in period t.
The accelerated amount discounted over the remaining life expectancy at the 평균공시이율, less the similarly discounted premiums that would have fallen due on it and less any outstanding 보험계약대출, which is nil on this form [S2 제4조제6항] [S2 제34조]:
payout = A v^(m/12) - m P_m (A / SA) v^(m/24)
with
m = accel_prognosis_months = 12[S2 제3조] andvataccel_disc_rate. The discount is the economic reason the rider can be offered without a separate premium, and it is the sharpest contrast with a UK terminal-illness benefit, which is undiscounted.accel_disc_rate = 0.025is the 2026 평균공시이율 [S12], which the 약관 uses for instalment settlement and for this discount [S2 제10조]. That it equals the composite’s 적용이율 is a coincidence of level and not an identity of concept: there is no 공시이율 and no 최저보증이율 on a Korean protection product, and the disclosure’s guarantee columns are empty for every 정기보험 row [S4].
Premium income at the start of period t (at time t), an inflow.
P_a(k(t))on the policies actually paying —pols_payer(), which ispols_if()inside the 납입기간 unless the 납입면제 module is on, and zero after 납입완료. Monthly in advance: the month’s income is one month’s office premium on the lives in force when the month opens, which is what the contract collects and what the rate card quotes. The annual grid’s matched pair of offsetting errors — a year’s premium taken from lives that exited during the year, against a death benefit paid a year late — is gone rather than netted, and no half-year adjustment belongs on top of this one.
- claims(t, kind=None)[source]#
Benefit outgo in period t, by kind; the total when kind is omitted.
"DEATH"the 보험가입금액 on the period’s death claims, net of the share arriving as an acceleration:
SA (1 - a(t)) D(t)[S2 제4조]."ACC_DEATH"the second sum assured on the accidental subset, on the 재해사망 uplift variant only:
SA a_q(t) (1 - a(t)) D(t)[S6] [S10]. Zero elsewhere. It is a split of the existing decrement, never a second decrement: 재해 is defined by 별표3 재해분류표 as 「한국표준질병·사인분류상의 (S00~Y84)에 해당하는 우발적인 외래의 사고」 plus a 제1급감염병, with a closed carve-out list [S2 별표3]."ACCEL"the discounted 선지급서비스특약 acceleration on the share
a(t)of the same decrement. Zero in the base run."MATURITY"the 만기보험금 of the 만기환급형 variant: 100% of the premiums paid, computed as if any waived premiums had been paid, on the policies reaching the horizon [S1] [S12]. Zero on the 순수보장형, which has no maturity value at all [S1] [S8] [S12].
"LAPSE"zero, always. On a 전기납 무해지 contract the 약관 pays nothing at any duration [S1] [S2 제33조제2항] [S12], and 한화생명’s published 해약환급금 예시 shows 환급률 0.0% at all eleven durations printed for both sexes [S1]. The kind exists so that the zero is stated rather than inferred: the 표준형 comparator does have a value, reaching 46% of premiums paid by duration six [S10], and a shortened-pay 무해지 contract pays 50% of it after 납입완료 [S1] [S12] — a value this chassis deliberately does not compute, the 계약자적립액 belonging to
WholeLife_KR_S.
- claim_expenses(t)[source]#
ec D(t): the claim handling expense on period t’s death claims [std].
300,000 won per claim, uninflated, on the whole death decrement whether the benefit is paid as a death claim or accelerated. No Korean document publishes a claim handling cost; the level is a standardization and the notes carry it as such. A maturity payment carries no claim expense here, being a scheduled settlement rather than an investigated claim — the 약관’s 3영업일 / 10영업일 / 30영업일 timetable applies to 보험금 지급사유 [S2 제9조]. Kept out of
expenses()because the notes’ worked example prints the two as separate columns.
- inflation_factor(t)[source]#
The expense inflation factor in month t:
(1 + pi)^floor(t/12)[std].1.0 through the whole of the first policy year, then stepping at each 계약해당일: an expense basis is reset annually and inflating it monthly would claim a precision the assumption does not have.
inflation_rate = 0.02. No Korean insurer publishes an expense inflation assumption; 2% is a round central choice and the notes carry it as a standardization.
- expenses(t)[source]#
E0 and e(t): acquisition and inflating maintenance expense in period t [std].
120,000 won per policy at issue — that is, in the first projected period
t = 0— then 2,000 won per policy per month — the same 24,000 a year — inflating at 2.0% a year, stepping at each 계약해당일 rather than monthly, both at the start of the period. No Korean carrier publishes either level: every 상품요약서 defines 계약체결비용 and 계약관리비용 in the same words — 「보험회사가 보험계약의 체결, 유지 및 관리 등에 필요한 경비로 사용하기 위하여 보험료 중 일정비율을 책정한 것」 — and not one publishes a rate [S1] [S6] [S8] [S10] [S11] [S12].Two public handles bound the standardization. The 보험가격지수 is the product’s total premium as a percentage of a 참조순보험료 총액 plus an industry-average 평균사업비 총액, and it is 88.1 male / 85.5 female at the anchor [S4] [S1]; its dispersion across the 45 disclosed products, 51.6% to 239.1%, bounds what an expense assumption may plausibly be. And the 표준해약공제액 of 별표 14 caps the recoverable acquisition cost by formula [REG-R20]; at the anchor its sum-assured limb alone is 100,000,000 x 10/1000 = 1,000,000 won, which is 5.5 years’ gross premium, so the statutory cap is very far from binding on this product and is not computed here. The constraint that actually shapes a Korean term surrender value is 제7-66조제1항제2호’s 해약공제기간, capped at seven years [REG-R19] — and this contract has no surrender value for it to shape.
No acquisition expense is charged at a 갱신. That is a choice rather than a fact: a Korean renewal is issued on a new product code [S9] [S15], which is an argument the other way, and
comm_new_term_rateis the switch that carries it.
- comm_init_pp()[source]#
c0: initial commission per policy issued [std], 60% of
P_aatt = 0.Paid upfront at issue, in the first projected month
t = 0, and computed on the annualized premium because that is the unit a commission scale is written in. With the acquisition expense this is 228,576 won of first-month outgo against 15,080 won of first-month premium on the anchor cell, which is the deep new business strain the protection shape starts from — and which a monthly grid shows as the single-row cliff it is rather than spread against a year of premium. No Korean document in the source set discloses a commission scale — the 모집수수료 reforms bound the first-year share of premium rather than publishing a level [REG-R29] — so both this andcomm_renewal_rateare levels chosen for the reference implementation.
- comm_new_term(t)[source]#
Commission paid at a 갱신 [std]; zero in the base run.
The base run pays no acquisition commission on a renewed cycle. That is a choice and not a fact, and the Korean evidence cuts both ways: a 갱신 takes no 고지 and no underwriting [S6] [S9] [S15], which is an argument that it is not new business, while the renewal is issued on a new product code — 푸본현대생명 prints 주계약 최초계약
LO01011and 갱신계약LO01012separately [S15], and 삼성생명 states 「갱신형특약은 매 갱신시마다 갱신시점의 상품코드를 적용합니다」 [S9] — which is an argument that it is. Setcomm_new_term_rateto switch it on; it then falls in the first month of each cycle after the first —t = 12 (k - 1) nfor cyclek > 1— and on the shipped 갱신형 anchor at a first-year rate it turns the opening months of each repriced cycle sharply negative.
- commissions(t)[source]#
Commission outgo in period t [std].
The initial commission in the first month
t = 0, then 3% of premium income from the start of policy year 2 —t = 12— while premiums are payable, plus any commission at a 갱신 (off in the base run). The renewal commission rides onpremiums(), so it stops when the 납입면제 stops the premium and when the 납입기간 ends. No clawback on early lapse is modelled: no Korean clawback rule appears in the retrieved set, so a clawback would be an invention rather than a standardization of something observed.
- net_cf(t)[source]#
CF(t): the net cash flow of period t, income positive.
Premiums less claims, claim expense, maintenance and acquisition expense and commission. This is the library-wide sign, so there is no outgo-positive
liability_cfcompanion to publish.Lapse and the renewal decline contribute no term: they act only through
pols_if(), there being no surrender value to pay [S2 제33조제2항]. The shape to expect on the anchor cell is a deep strain att = 0, then thin positive margins that decay as the level premium falls behind the rising mortality cost, and on a 갱신형 point a saw-tooth: a negative period immediately before each renewal and a jump back into surplus the period after, as the premium resets to attained age.
- check_pols_roll_fwd_resid(t)[source]#
The in-force roll-forward residual in period t; zero everywhere.
l(t) - l(t+1) - D(t) - lapses - declines - maturities + reinstatements, with the 부활 inflow and the horizon’s maturity outflow carried as their own terms so that the same residual closes in both positions of every switch. Non-zero would mean the decrements and the roll-forward have drifted apart — most easily by applying the renewal decline to the wrong population, since it is taken after mortality and after ordinary lapse.
- check_pols_roll_fwd()[source]#
True when the in-force roll-forward closes in every projected period.
The library-wide form of a roll-forward check: no argument, one bool over
t = 0 .. proj_len() - 1, so one test can call it across every model.check_pols_roll_fwd_resid()gives the signed residual of the period that failed.
- check_lapse_pool_resid(t)[source]#
The 부활 pool roll-forward residual in period t; zero everywhere.
lap(t) - lap(t+1) - reinstatements - window expiries + lapses. The pool is a stock with one inflow (pols_lapse()) and two outflows (pols_reinstate()andpols_lapse_expire()), and the vintage bookkeeping of the three-year window is exactly where an implementation drops or double-counts a cohort. Closes with the module off as well as on, since the pool is tracked either way.
- check_pols_payer_resid(t)[source]#
The premium-paying population residual in period t; zero everywhere.
l(t) x prem_payable(t) - payers - waived. The 납입면제 module carries the waived lives as a fraction of the in-force rather than as a separate decrement, which is only legitimate while payers and waived lives partition the population that owes a premium at all. Theprem_payablefactor is what makes the identity survive 납입완료 on a shortened-pay point, where nobody owes a premium and both parts are zero.
- check_prem_level_resid(t)[source]#
The premium-level residual in period t; zero everywhere.
P_a(t) - P_a(t-1)inside a 보험기간, and zero by definition in the first period of a cycle. The premium is level within the 보험기간 and changes only at a 갱신 [S1] [S9] [S12] [S15]; there is no premium review within a term and no insurer discretion over the level. A residual here means the premium is drifting with the policy year, which is what happens if the rate lookup is keyed on attained age rather than on the cycle’s entry age — the single most likely way to convert a 갱신형 into something that is neither form.
- check_decline_timing()[source]#
True when the renewal decline falls on renewal boundaries and nowhere else.
The decline rate must be non-zero in exactly those months that end a 갱신 cycle short of the horizon —
(t + 1) % 12n == 0witht < proj_len() - 1on the 0-based index — and zero in every other month, including the last onet = proj_len() - 1, where cover ends at the ceiling rather than renewing, and every period of a 비갱신형 point, which never renews [S1] [S12]. This is the check that catches the decline being modelled as a lapse loading: a rate that is non-zero in a non-boundary period has stopped being a renewal decline whatever it is called.
- check_waiver_reset()[source]#
True when no premium waiver survives a 갱신 into the next cycle.
「다만, 새로이 갱신되는 계약에서는 갱신 전 보험료 납입면제 사유로 인한 보험료 납입면제를 적용하지 않고, 보험료를 계속 납입하여야 합니다」 [S6]. The waived fraction must therefore be zero in the first month of every cycle, not merely at
t = 0. On a 비갱신형 point the check reduces tou(0) = 0and on a point with the module off it is vacuous; model points 3 and 4 are where it bites, and where a model that carried the waiver across the boundary would be caught collecting no premium from a population the contract says must resume paying.
- check_net_cf_resid(t)[source]#
The published cash flow statement’s ledger residual in period t; zero.
net_cf()less the sum of the columns ofresult_cf(), so a reader adding up the printed statement gets the printed total. It is the check that catches a benefit kind that exists inclaims()but was never given a column — which would leave the statement silently short of outgo it is charging.
- check_net_cf()[source]#
True when the published cash flow statement adds up in every projected period.
Tested against
cash_tol, not theroll_fwd_tolthe decrement checks use. The wider tolerance is a property of what is compared: the other checks close an identity between cells evaluated in one expression, where the residual is a unit or two in the last place of a count near 1.0, while this one re-reads won amounts of order 1e7 back out of theresult_cf()DataFrame, so the round trip through column construction leaves float64 rounding in absolute won.cash_tol = 1e-6is well above that noise and far below one won, which is the smallest error a reader adding up the printed statement could observe.
- result_cf()[source]#
Result table of cashflows, indexed by the 0-based period index t.
t = 0is the first policy month and the frame runs toproj_len() - 1, so the table hasproj_len()rows and the contractual policy year of rowtispolicy_year(t) = t // 12 + 1.pols_ifis the start-of-period count, which is the weight applied to every cash flow on the same row.net_cfis income positive.claims_lapseis a column of zeros by product design — there is no 해약환급금 at any duration on the representative form — and is published rather than dropped; seeclaims().
- result_pols()[source]#
Result table of policy counts, decrement rates and the premium, indexed by t.
Same 0-based monthly frame as
result_cf():t = 0 .. proj_len() - 1. Both the annual rates and the monthly decrements derived from them are printed, because the annual rate is the sourced quantity and the monthly one is what the projection applies; a reader checking a disclosure checks the first and a reader checking the roll-forward checks the second. The renewal machinery is only legible next to the decrements it drives, soterm_indexandprem_ppare printed here withrenewal_decline_rate: a boundary month is the row where the decline rate is non-zero and the premium changes on the next row.