The Projection Space#
The by-policy projection of the FXWholeLife_JP_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, 0-based: t = 0 is the month beginning at issue and
t = proj_len() - 1 the last projected month. The step is the 月単位の契約応当日, not the
calendar month end. There is no maturity date and no 満期保険金: the horizon is the
terminal age of the mortality table, proj_len() = 12 (omega - x + 1) months, and at
t = proj_len() - 1 the table’s rate is 1, so the projection ends with nobody left
and no tail states.
Input data
Inputs are external files: plain CSVs living in the model folder’s parent
directory, products/fx_whole_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 through modelx’s IOSpec machinery.
The consequence worth knowing: the model is not portable on its own. Copying the
FXWholeLife_JP_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 |
lapse_table_file |
data.lapse_table() |
lapse_table.csv |
charge_table_file |
data.charge_table() |
charge_table.csv |
fx_path_file |
data.fx_path_table() |
fx_path_table.csv |
Naming
Cells names follow lifelib’s basiclife.BasicTerm_S and savings.CashValue_SE
wherever those models have an analogue — pols_* for policy counts, plural nouns for
cash flows, *_rate for annual rates with *_rate_mth for their monthly
equivalents, *_pp for per-policy amounts, claims(t, kind) with an uppercase
kind string, av_pp_at(t, timing) and pols_if_at(t, timing) for the
within-month reads. The technical notes use compact actuarial symbols instead. The
mapping is:
Notes symbol |
Cells |
Meaning |
|---|---|---|
(model point row) |
model_point() |
The selected model point |
(shape) |
shape() |
LEVEL or SINGLE |
x |
issue_age() |
契約年齢, 満年齢 at 契約日 |
x + floor(t/12) |
age(t) |
Attained age in month t |
(none) |
sex() |
M or F |
omega |
omega_age() |
Terminal age of the table |
T = 12(omega - x + 1) |
proj_len() |
Projected months |
n |
prem_months_eff() |
保険料払込期間 in months |
SA |
sum_assured() |
基本保険金額 |
P |
prem_due_pp(t) |
Premium due at the start of t |
(single premium) |
single_premium() |
一時払保険料 |
i0 |
guar_floor() |
最低保証積立利率 / 予定利率 |
ic |
credit_rate() |
Declared 積立利率 |
j |
credit_rate_mth() |
(1 + ic)^(1/12) - 1 |
(none) |
guar_floor_mth() |
(1 + i0)^(1/12) - 1 |
q(t) |
mort_rate(t) |
Annual decrement, incl. 高度障害 |
q_m(t) |
mort_rate_mth(t) |
Monthly decrement |
(charge basis) |
coi_rate(t) |
Unadjusted table rate |
(charge basis) |
coi_rate_mth(t) |
Monthly charge rate |
w(t) |
lapse_rate(t) |
Annual surrender rate |
w_m(t) |
lapse_rate_mth(t) |
Monthly surrender rate |
(dynamic module) |
lapse_dyn_factor(t) |
FX-driven surrender multiplier |
l(t) |
pols_if(t) |
In force at the start of t |
l(t)(1-q), l(t+1) |
pols_if_at(t, timing) |
BEF_DECR / BEF_LAPSE / AFT_DECR |
(none) |
pols_payer(t) |
In force and paying premium |
(APL cohort) |
pols_if_apl(t) |
Carried by the 自動振替貸付 |
(APL balance) |
loan_pp(t) |
Average advance per APL policy |
D(t) |
pols_death(t) |
Expected death / 高度障害 claims |
S(t) |
pols_lapse(t) |
Expected surrenders |
(target hit) |
pols_target(t) |
Policies reaching the 目標値 |
phi(t) |
prem_charge_rate(t) |
契約初期費用 rate on the premium |
mu |
maint_rate() |
維持費率 p.a. of the 積立金 |
C_init(t) |
charge_init(t) |
契約初期費用 taken in month t |
C_maint(t) |
charge_maint(t) |
維持費 taken in month t |
C_coi(t) |
charge_coi(t) |
保障部分 charge on the 危険保険金額 |
P - C_init |
prem_to_av_pp(t) |
Premium credited to the 積立金 |
AV(t) |
av_pp(t) |
積立金 at the start of month t |
AVg(t) and after |
av_pp_at(t, timing) |
AFT_PREM / AFT_CHARGE / AFT_INT |
AV0(t) |
av0_pp(t) |
The same fund at i0 |
(prospective AV0) |
av0_pro_pp(t) |
The 予定利率 prospective fund |
特別積立金 |
special_reserve_pp(t) |
Ten- and twenty-year top-up |
IDB(t) |
idb_pp(t) |
増加死亡保険金額 |
DB(t) |
benefit_pp(t) |
Death benefit per policy |
sc(t) |
surr_charge_rate(t) |
解約控除率 |
rem(t) |
mva_rem(t) |
Years left in 積立利率適用期間 |
Delta(t) |
mva_delta(t) |
Rate move since the rate was set |
mva(t) |
mva_rate(t) |
市場価格調整率, can be negative |
kl(t) |
low_cv_rate(t) |
低解約返戻金割合 |
CV(t) |
cv_pp(t) |
解約返戻金 |
e(t) |
fx_rate(t) |
Reference TTM, yen per US$1 |
s |
fx_spread() |
為替手数料 spread, each way |
g |
target_g() |
目標値, a multiple of yen paid |
(target test) |
target_hit(t) |
Yen-converted CV has reached it |
(target test) |
target_month() |
The month it is first reached |
P l_p(t) |
premiums(t) |
Premium income |
DB D, CV S |
claims(t, kind) |
DEATH and LAPSE outgo |
(conversion) |
conversions(t) |
Value leaving on a target hit |
ec D(t) |
claim_expenses(t) |
Claim expense, its own column |
E0, e_m(t) |
expenses(t) |
Acquisition + maintenance |
c0, c_r |
commissions(t) |
Commission outgo |
CF(t) |
net_cf(t) |
Net cash flow, income positive |
CF_JPY(t) |
net_cf_jpy(t) |
The three-rate yen translation |
s (premiums + benefits) |
fx_spread_jpy(t) |
Spread income, published apart |
The policy currency is the model currency
Every state variable, every assumption and every cash-flow column above is in US
dollars. Yen enters only through fx_rate() and fx_spread(), and the
exchange rate is a model point column, never a literal in a formula: an exchange rate
buried in a recursion is an economic assumption disguised as a product feature and
cannot be varied by the point that owns it.
The yen ledger is three translations, not one. Premiums cross at e + s under the
円入金特約, benefits at e - s under the 円支払特約, and expenses and commission at the
plain e, because they are the insurer’s own costs and never cross the policyholder
boundary. So
net_cf_jpy(t) != net_cf(t) x fx_rate(t)
identically, and the difference is the insurer’s spread income. fx_spread_jpy()
publishes it as its own column rather than letting it hide inside a translated net
figure: on the anchor cell it is ¥125.17 in month 0 and ¥39,266 over the whole run.
check_fx_ledger() asserts the identity
net_cf_jpy = net_cf x fx_rate + fx_spread_jpy in every month.
The account-value charges are not cash flows
charge_init(), charge_maint() and charge_coi() are internal transfers
from the 積立金 to the insurer. They move av_pp() and appear nowhere in
net_cf(); the insurer’s outgo is the expense and commission stream instead.
Booking a charge as revenue alongside the premium that funded it double-counts the
premium. check_net_cf() rebuilds net_cf() from the published columns alone
and would catch it.
The order inside the month is fixed, because it changes the answer at the third decimal
and the published surrender-value run is reproduced to the dollar: premium in, then
charge_init(), then charge_maint(), then charge_coi() on the net
amount at risk measured after the maintenance charge, then interest at
(1 + ic)^(1/12) — the geometric twelfth root [std], not ic/12.
Two mechanics that vanish at the guaranteed floor
The base run credits at ic = i0, the contract’s own 予定利率, which is the guaranteed
column of the only published surrender-value run and the only crediting figure for this
shape that is a contract term. Under the [std] definition of av0_pp() — the
account value the same recursion produces with ic replaced by i0 and the
benchmark benefit held at SA — the fund and its benchmark coincide identically, so
idb_pp() is zero for every t and special_reserve_pp() with it. The
published guaranteed column shows 特別積立金 of (0) at both 10 and 20 years, so that is
what a correct implementation must produce: a non-zero uplift or top-up on the
guaranteed run is a bug, not a refinement.
The alternative reading of AV0 — the prospective fund at i0 needed to carry
SA with no future premiums on the same charge basis — is implemented as
av0_pro_pp() and selected by idb_basis = "prospective" on the model point. It
does not give an identically zero uplift: on the anchor cell it gives AV - AV0 of
-US$22,044.31 at ten years, +US$36.52 at 払込満了, +US$296.03 at fifty years and
+US$30,762.05 at the terminal month. The near-zero crossing at 払込満了 is a strong
independent check on the back-solved charge stack — actuarial equivalence predicts a
contract that is almost exactly self-funding at the floor — but a definition that
manufactures a positive uplift on the guaranteed run contradicts the one document that
shows the guaranteed run, so it is the switch and not the base.
The surrender layer, and what is not a charge
CV = AV (1 - mva - sc) kl, and all three factors can be active at once on the
SINGLE shape. Paying a surrender on av_pp() instead of cv_pp() overstates
every early exit by up to 7% plus the adjustment.
surr_charge_rate() is a charge: one-sided, never adding value, 7.0% in policy
year 1 falling 0.7 points per completed policy year to zero at ten, constant within the
year, and applied to the 積立金. Three different bases are in use across the market —
the account value, the 責任準備金 and the 基本保険金額 — and a rate quoted against one means
nothing against another.
mva_rate() is not a charge. It is symmetric, it can be negative, and a fall in
rates increases the surrender value; implementing it floored at zero models a
different product. It is zero on the whole LEVEL shape, zero on an 積立利率計算基準日 and zero
inside a one-year 積立利率適用期間 — a discontinuity a monthly model has to place on the
right month. The reconstruction
mva(t) = 1 - (1 + (Delta(t) + A) / (1 + r0)) ^ (-d rem(t))
is a [std] fit to the published 15-year rate table. Two structural facts drop out of
the fit rather than being imposed: the zero column sits at Delta = -0.1%, which is
what A is, so a contract surrendered with no rate move at all still carries a small
positive adjustment; and the effective duration is d rem, 0.70 of the remaining
term rather than the remaining term itself.
low_cv_rate() is a cliff: 0.70 while four or more premium-paying years remain,
stepping to 0.775, 0.85 and 0.925 at three, two and one, and to 1.00 at 払込満了, on whole
remaining years rounded up. Interpolating across the boundary is wrong.
mort_be_factor moves the decrement and never the charge
mort_be_factor is an experience assumption and multiplies mort_rate() only.
coi_rate() reads the same table unadjusted, because the cost-of-insurance
basis is a pricing element the insurer sets in its 算出方法書. Wiring one lever to both is
the easiest way to make this model self-consistent and wrong: raising
mort_be_factor would then raise claims and raise the charge that funds them, and
the account value would
absorb the sensitivity instead of the cash flow showing it. Model point 7 runs
mort_be_factor = 1.20 and the two rates part company there.
Modules that are off in the base run
Seven of the notes’ 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:
The prospective uplift basis,
idb_basis = "prospective", described above; the base is"fund". Model point 7.The uplift ratchet,
idb_ratchet, which holdsidb_pp()at its running maximum. It is on in the base run and makes no difference there, because the uplift is identically zero; it is sourced to the ご契約のしおり and not to the extracted 約款 text, so it is carried as a switch and turned off on model point 7.The 低解約返戻金特則,
low_cv, the four-step suppression ramp with its cliff at 払込満了. Model points 2 and 6.The 自動振替貸付,
apl_on. A policy does not lapse while its surrender value can advance the premium, soapl_nonpay_shareof the surrender decrement is redirected intopols_if_apl()rather than lost while the fund can carry it; the advance accumulates atapl_int_rateinloan_pp()and is repaid out of whatever the policy is eventually paid. Applying a lapse rate to unpaid premiums without first running that test models a decrement the contract does not have. The split of the surrender decrement into voluntary and non-payment parts is [std] — no source separates them — and the cohort’s loan is carried as an average rather than as a full triangle, which is exact in aggregate. The module is structurally absent on the SINGLE shape: there is no premium to advance, so the two shapes have different decrement sets, not merely different rates. Model point 6.Dynamic surrender on the FX rate,
dyn_lapse. The economically natural driver on this product is the currency rather than the crediting rate: a policyholder in yen profit surrenders, one in yen loss holds on. SINGLE only. Model point 4.An FX path,
fx_path, readingfx_path_table.csvby policy year instead of holding the model point’sfx_ttmflat. Model point 7.The target-value rider,
target_onwithtarget_action, which converts or surrenders the contract attarget_month().target_actionhas no default where the rider is elected, and the rubric below says why a deterministic run cannot choose one. Model points 3 (convert) and 4 (surrender).
The target-value rider is priced at intrinsic only
target_month() is the first month at or after the contractual one-year dead zone
at which the yen-converted surrender value reaches the 目標額. Two things about that
test are easy to get wrong and both are contractual. It runs on cv_pp(), after FX
and after the MVA, not on av_pp(): on the base SINGLE cell testing the account
value converts at month 39 against month 52, thirteen months early, and the error grows
with any rate move. And the one-year dead zone is real — a target reached inside the
first year does not trigger, and a model that converts at month 6 has invented a
contract term.
target_action has no default, because the contract and the evidence disagree and
neither is the modeller’s to assume silently. The 約款 converts the contract to a yen
whole life; the observed population surrenders on the hit and buys the same product
again, paying the front-loaded commission twice. Under "surrender" the value leaves
through claims() (t, "LAPSE"); under "convert" it leaves through
conversions(), and the yen contract it becomes is out of scope — this model’s
ledger is denominated in dollars and the converted liability is not. That scope boundary
is [std] and is why the two elections differ in where the money is booked rather
than in how much of it there is.
What a deterministic run cannot do is value the option. On one path the rider either converts at one determinate month or never converts, so its time value is zero by construction. A scenario set is the only instrument that can price it and this library does not ship one.
Sign convention
The notes’ CF(t) is already income positive — premiums less claims, surrender
benefits, expenses and commission — which is the library-wide sign of net_cf(), so
there is no outgo-positive liability_cf companion to publish: one stream, one sign,
one name.
Cells Descriptions#
- shape()[source]#
The contract shape:
LEVEL(平準払 積立利率変動型) orSINGLE(一時払 積立利率更改型).The two shapes share the whole account-value recursion and differ in the premium stream, the rate-reset cycle, the presence of the 市場価格調整 and the relation of the death benefit to the fund. A third market shape, a level yen premium converted to US dollars each month, is a different cash-flow object and is out of scope; a model point naming it is rejected here.
- issue_age()[source]#
x: the 契約年齢 at 契約日, 満年齢 with the fractional year discarded.
The age increments on the 年単位の契約応当日, so the attained age in month
tisx + floor(t/12)exactly. 生保標準生命表2018(死亡保険用)is built on a 保険年齢 (nearest-birthday) basis and is read here at the 満年齢 attained age with no adjustment [std], as the savings chassis does.
- currency()[source]#
The operating currency; USD on every shipped model point.
Only USD and AUD are inside the 標準責任準備金 regime and the published run-off tables the composite is built on are USD tables, so the reference implementation writes USD and rejects anything else by name rather than silently pricing it.
- sum_assured()[source]#
SA: the 基本保険金額 in US dollars.
On the SINGLE shape it equals the 一時払保険料 at issue and never binds, because that shape’s death benefit is
max(積立金, 解約返戻金)with no sum assured above the fund.
P: the level monthly premium in US dollars on the LEVEL shape.
Guaranteed for the whole of 保険料払込期間 with no unilateral repricing right, which is what puts every future premium inside the contract boundary. US$239.60 on the anchor cell is sourced, not constructed: it is the published premium for exactly that cell, and the same booklet publishes 225.00 for the 低解約返戻金特則 form. Zero on the SINGLE shape.
The 一時払保険料 in US dollars on the SINGLE shape; zero on the LEVEL shape.
- prem_months()[source]#
The 保険料払込期間 in months as the model point states it.
0denotes 終身払, for which no 払込満了 exists;prem_months_eff()resolves it against the projection horizon.240on the anchor cell is 60歳払込満了.
- credit_rate()[source]#
ic: the declared 積立利率, annual effective.
Held flat over the projection [std]. On the LEVEL shape the base run holds it at the guaranteed floor, which is the guaranteed column of the published illustration and the only crediting figure for that shape that is a contract term; the declared-rate history is not machine-fetchable. On the SINGLE shape it is a rate actually declared in the market and fixed for the whole 積立利率適用期間.
- guar_floor()[source]#
i0: the 最低保証積立利率, fixed at issue, which the declared rate can never breach.
3.00% on the LEVEL shape, where it equals the contract’s own 予定利率 and therefore also defines the 増加死亡保険金額 benchmark; 0.01% on the SINGLE shape, which is a floor in name only because that shape resets its rate every 積立利率適用期間.
- rate_period_y()[source]#
The 積立利率適用期間 in whole years; zero on the LEVEL shape, 15 on the SINGLE shape.
Fifteen years is taken because it is the only period for which a complete 市場価格調整 rate table is published, and the reconstruction in
mva_rate()is anchored on that table.
- mva_delta(t)[source]#
Delta(t): the move in the applicable 基準利率 since the contract’s rate was set.
A deterministic model point input, held flat, because this library projects contractual cash flows and not a rate view. It is not a neutral zero: the published table’s zero column sits at
Delta = -0.1%, so a flat path still charges a small positive adjustment. Model point 4 runs it at -1.0%, where the adjustment turns negative and raises the surrender value.
- low_cv()[source]#
Whether the 低解約返戻金特則 is elected; off on the anchor cell.
The suppression is a cliff released at 払込満了, so it is meaningless on a 終身払 contract, which has no 払込満了 — a model point combining the two is rejected here rather than given an arbitrary release date.
- idb_ratchet()[source]#
Whether the 増加死亡保険金額 is held at its running maximum.
The ratchet appears in the ご契約のしおり but not in the extracted 約款第46条 text, so it is [unverified] and carried as a switch. It is on in the base run and makes no difference there, because the uplift is identically zero at the floor.
- idb_basis()[source]#
Which definition of the uplift benchmark
AV0applies."fund"[std]the account value the same recursion produces with
icreplaced byi0and the benchmark benefit held atSA:av0_pp(). Under it the uplift is identically zero on the guaranteed run, which is what the published guaranteed column requires."prospective"the fund needed at
tto carrySAto the end of the table with no future premiums, on the same charge basis:av0_pro_pp(). See the Space docstring for why this is the switch and not the base.
- target_on()[source]#
Whether the target-value conversion rider is elected; SINGLE shape only.
The rider converts the contract to a yen whole life when the yen-converted surrender value reaches the 目標額. It exists only on the single-premium shape in the retrieved set, so a LEVEL model point electing it is rejected by name.
The rider has no settled name: the two carriers whose documents were retrieved call theirs 円建終身移行特約 and 目標値到達時終身保険移行特約, and the name 目標到達時円建終身保険移行特約 that the wider market uses is [unverified] — the carrier whose documents carry it could not be fetched at all. The mechanic is verified; only the name is not.
- target_g()[source]#
g: the 目標値, a multiple of the yen the policyholder actually paid.
110% [std], the only value inside all three published menus and a target a two-and-a-half-year average holding period can actually reach. The target is measured against the yen-converted premium, so a weaker yen alone can trigger it.
- target_action()[source]#
What happens on a target hit:
"convert","surrender"or"none".There is no default. The 約款 converts the contract to a yen whole life; at every focus-monitored distributor most ターゲット型 policies are instead surrendered on the hit and the same product immediately re-sold to the same customer. The contract and the evidence disagree and the choice is the user’s.
- dyn_lapse()[source]#
Whether the FX-driven dynamic surrender module is on; off in the base run.
SINGLE shape only, because the yen profit it keys on is measured against a single premium actually paid at a known rate.
- apl_on()[source]#
Whether the 自動振替貸付 module is on; off in the base run.
Structurally absent on the SINGLE shape: there is no premium to advance, so that shape’s decrement set is smaller, not merely differently rated. A SINGLE model point carrying a premium-default decrement is modelling a contract that does not exist, and is rejected here.
- fx_ttm()[source]#
The reference TTM in yen per US$1, held flat unless
fx_pathis set.¥159.43 is the published reference level and the base run holds it flat [std]: this library models contractual cash flows, not an FX view, and a projected currency path would be an economic assumption dressed as a product feature.
- fx_spread()[source]#
s: the 為替手数料 spread in yen per US$1, charged on each crossing.
¥0.50 each way, the modal and the widest published value. At the reference TTM that is 0.3136% one leg and 0.6292% on a round trip — which is why every carrier warns that a loss can arise with no exchange-rate movement at all. Zero where neither yen rider is attached.
- mort_be_factor()[source]#
The experience adjustment to the mortality decrement; 1.00 in the base run.
The shipped table is a valuation table with an explicit margin, so any best-estimate basis is a [std] adjustment of it. This lever moves
mort_rate()and must never movecoi_rate(); see the Space docstring.
- omega_age()[source]#
The terminal age of the shipped table for this life: the first age at which q = 1.
109 male and 113 female on 生保標準生命表2018(死亡保険用). It is read off the table rather than hard-coded, so replacing the table moves the horizon with it.
- proj_len()[source]#
T: the projection length in months,
12 (omega - x + 1).840 on the anchor cell.
truns0 ... proj_len() - 1; there is no maturity date and no 満期保険金, so the horizon is the table’s terminal age and nothing else. Truncating at 払込満了, or at age 100, is a direct understatement: 85% of expected death claims on the anchor cell arrive after 払込満了.
- prem_months_eff()[source]#
n: the 保険料払込期間 in months as the projection uses it.
One month on the SINGLE shape; the whole horizon where
prem_monthsis 0, which denotes 終身払; otherwise the model point’s own value.
- coi_rate(t)[source]#
The table mortality rate at the attained age, unadjusted.
This is the cost-of-insurance basis: 生保標準生命表2018(死亡保険用)with no further loading, on the ground that it is already a valuation table carrying an explicit margin. It is a pricing element the insurer sets in its 算出方法書, so
mort_be_factordoes not touch it. Includes 高度障害, which the published death rate already carries.
- mort_rate(t)[source]#
q(t): the annual mortality decrement in month t, including 高度障害.
The table rate times
mort_be_factor, capped at 1. One decrement covering both benefits: 高度障害 pays the same amount and extinguishes the contract, and the published table’s death rate already includes it, so adding a second decrement would double-count the benefit.
- mort_rate_mth(t)[source]#
q_m(t): the monthly decrement,
1 - (1 - q)^(1/12).0.0000983866at the anchor cell’s first attained age, whereq40 = 0.00118.
- lapse_rate_base(t)[source]#
The table annual surrender rate for this shape in month t, before any module.
Two curves. The SINGLE curve, 28 / 23 / 18 / 14 / 8%, is calibrated so the cumulative four-year exit is 60.90%, against a published reading that about 60% of 外貨建一時払保険 are surrendered within four years; the LEVEL curve, 8 / 7 / 6 / 5 / 5 / 4 / 3%, rests on no public evidence at all and is a [std] judgement. Policy years beyond the table take its last row.
- lapse_dyn_factor(t)[source]#
The FX-driven dynamic surrender multiplier [std]; 1 unless
dyn_lapse.min(2.5, max(0.5, 1 + beta (CV(t)(e(t) - s) / P_jpy0 - 1)))withbeta = 2.0. A policyholder in yen profit surrenders and one in yen loss holds on, which is the economically natural driver on this product — the currency, not the crediting rate. Under the base run’s flat FX path the multiplier moves only with the account value, which is precisely the limitation the notes name.
- lapse_rate(t)[source]#
w(t): the annual surrender rate applied in month t, capped at 1.
The table rate times the dynamic multiplier. A surrender pays
cv_pp(), neverav_pp().
- lapse_rate_mth(t)[source]#
w_m(t): the monthly surrender rate,
1 - (1 - w)^(1/12).0.0069243826in the anchor cell’s first policy year, wherew = 8%.
- credit_rate_mth()[source]#
j: the monthly crediting factor,
(1 + ic)^(1/12) - 1.The geometric twelfth root [std], not
ic/12. The convention has to be stated because the published surrender-value run is reproduced to the dollar and a nominal-over-12 implementation misses the fit.1 + j = 1.0024662698at 3.00%.
- charge_param(item)[source]#
One row of charge_table.csv for this shape, by item name.
The whole shape-dependent parameter set lives in the CSV with a
provenancecolumn on every row: the back-solved 契約初期費用 and 維持費率, the 解約控除 scale, the 低解約返戻金割合 ramp, the three constants of the 市場価格調整 reconstruction and the two 特別積立金 rates.
- prem_charge_rate(t)[source]#
phi(t): the 契約初期費用 rate deducted from the premium received in month t.
Two rates on the LEVEL shape — 38% over policy months 0 to 23 and 12% thereafter — back-solved from the published guaranteed surrender-value run, because every carrier in the source set refuses to quantify the charge and the rates live in an unpublished 基礎書類. One front-end rate on the SINGLE shape, 4.50% of the single premium at issue, which is published.
- maint_rate()[source]#
mu: the 維持費率 per annum of the 積立金, deducted monthly.
0.50% p.a. on the LEVEL shape, back-solved with the two premium charges. Zero on the SINGLE shape: that shape’s in-force costs sit inside the declared 積立利率, and reproducing its published surrender values requires the fund to grow at the declared rate exactly.
- coi_charged()[source]#
Whether a 保障部分 charge is deducted from the fund; true on the LEVEL shape only.
On the SINGLE shape the death benefit never exceeds the fund by design and the 保障 cost is taken inside the crediting-rate calculation, so nothing is deducted from the 積立金 — which is why a negative 市場価格調整 can raise the death benefit above the account value without creating a charge.
- prem_due_pp(t)[source]#
P(t): the premium due per policy at the start of month t, in US dollars.
Level and guaranteed over months
0 ... n - 1on the LEVEL shape; a single collection att = 0on the SINGLE shape.
- charge_init(t)[source]#
C_init(t): the 契約初期費用 taken out of month t’s premium.
phi(t) P(t). Not a cash flow — an internal transfer from the premium to the insurer, taken before anything reaches the 積立金.
- prem_to_av_pp(t)[source]#
The part of month t’s premium that reaches the 積立金:
P(t) - C_init(t).US$148.5520 in every month of the anchor cell’s first two policy years.
- charge_maint(t)[source]#
C_maint(t): the 維持費 taken in month t,
(mu / 12) x AVg(t).Charged on the fund after the premium and the 契約初期費用 and before the cost of insurance, which is what fixes the order of the recursion. Not a cash flow.
- charge_coi(t)[source]#
C_coi(t): the 保障部分 charge in month t, on the 危険保険金額.
q_m(t) x max(0, DB(t) - (AVg(t) - C_maint(t)))— the monthly table rate applied to the net amount at risk measured after the maintenance charge. The floor at zero is structural, not cosmetic: on the anchor cell the account value overtakes the sum assured at month 709 and the charge stops, and the death benefit must not be silently floored at the fund in exchange. Not a cash flow.The charge is also capped at what the fund actually holds, so the 積立金 can never run negative: it is an account, not a debt. Where the cap binds — as it does on the 低解約返戻金特則 model point at the far end of the projection, whose lower premium the back-solved charge stack does not make self-funding — the contract’s guaranteed 終身 cover at a guaranteed level premium is being carried by the insurer rather than by the fund, and the surrender value is nil. Without the cap the shortfall compounds into the net amount at risk and the projection diverges.
- av_pp_at(t, timing)[source]#
The 積立金 per policy at a point inside month t, in US dollars.
"BEF_PREM"AV(t), the start of the month before that month’s premium; the same number asav_pp()."AFT_PREM"AVg(t) = AV(t) + P(t) - C_init(t), after the premium and the 契約初期費用."AFT_CHARGE_MAINT"after the 維持費 as well; this is the fund the net amount at risk is measured against.
"AFT_CHARGE"after all three charges, the fund interest is credited to.
"AFT_INT"AV(t+1), the end-of-month state including any 特別積立金.
- av_pp_bef_sr(t)[source]#
AV(t) before any 特別積立金 top-up is added; zero at issue.
Split out from
av_pp()so that the top-up has a base to be computed against without the recursion feeding on itself.
- special_reserve_pp(t)[source]#
特別積立金: the top-up added to the 積立金 after 10 and after 20 years in force.
Computed from ten-year investment performance and never paid to a contract terminating earlier. The [std] reconstruction is a share of the fund’s excess over its 予定利率 benchmark,
0.24at ten years and0.16at twenty, fitted to the four published amounts — 147 and 527 on the 3.50% column, 302 and 1,120 on the 4.00% column — with a worst deviation of 3.0%.On the guaranteed run it is identically zero, because the fund and its benchmark coincide there, and the published 3.00% column shows (0) at both durations. A non-zero top-up on the base run is a bug.
- av_pp(t)[source]#
AV(t): the 積立金 at the start of month t, before that month’s premium.
The one-line recursion, in the order the notes fix:
AVg(t) = AV(t) + P(t) - C_init(t) AV(t+1) = (AVg(t) - C_maint(t) - C_coi(t)) x (1 + j)
plus the 特別積立金 at ten and twenty years.
AV(1) = 139.0080451on the anchor cell. This is a per-policy quantity: it carries no survivorship, and the weight on the cash flows it drives ispols_if().
- av0_pp(t)[source]#
AV0(t): the same fund on the 予定利率 basis — the uplift’s [std] benchmark.
The 約款 does not define
AV0numerically, because it rests on the insurer’s unpublished 予定死亡率 and 予定事業費率. The definition taken here is the account value the same recursion produces withicreplaced byi0and the benchmark benefit held atSAwith no uplift of its own. It follows that wheneveric = i0the two funds coincide exactly andidb_pp()is identically zero — which is what the published guaranteed column requires.
- av0_pro_pp(t)[source]#
The prospective 予定利率 fund: what is needed at t to carry SA with no premiums.
The same charge mechanic run backwards with the premium switched off, terminating at
AV0(T) = SAbecause death is certain in the last month:AV0(t) = (AV0(t+1) / (1 + j0) + q_m(t) SA) / ((1 - mu/12)(1 + q_m(t)))
Selected by
idb_basis = "prospective". It givesAV - AV0of -22,044.31 at ten years, +36.52 at 払込満了, +296.03 at fifty years and +30,762.05 at the terminal month on the anchor cell. The near-zero crossing at 払込満了 is a strong independent check on the back-solved charge stack.
- idb_pp(t)[source]#
IDB(t): the 増加死亡保険金額, the ratcheting death-benefit uplift.
max(IDB(t-1), AV(t) - AV0(t))floored at zero, recomputed at each 月単位の契約応当日, with themaxagainst the previous month being the ratchet. It exists only on the main contract of the LEVEL shape: the SINGLE shape has no sum assured above the fund for an uplift to sit on top of.Identically zero on the guaranteed run, by construction of
av0_pp().
- benefit_pp(t)[source]#
DB(t): the death and 高度障害 benefit per policy in month t, in US dollars.
SA + IDB(t)on the LEVEL shape.max(AV(t), CV(t))on the SINGLE shape, where there is no sum assured above the fund at all — and themaxbinds: where the 市場価格調整 is strongly negative the surrender value exceeds the account value and the death benefit follows the higher.
- surr_charge_rate(t)[source]#
sc(t): the 解約控除率 applying to a surrender at month t.
7.0% in policy year 1 falling 0.7 percentage points per completed policy year to zero at ten years, constant within the year, applied to the 積立金. It is a charge: one-sided and never adding value.
- mva_rem(t)[source]#
rem(t): the years remaining in the current 積立利率適用期間; zero on the LEVEL shape.
Each period restarts at its 積立利率計算基準日 [std], so
remsaws from the full period down to zero and back.rem(36) = 12on the worked example’s cell.
- mva_rate(t)[source]#
mva(t): the 市場価格調整率 at month t; not a charge, and it can be negative.
1 - (1 + (Delta(t) + A) / (1 + r0)) ^ (-d rem(t)), the [std] reconstruction of the published 15-year rate table. Zero on the whole LEVEL shape, zero on an 積立利率計算基準日 and zero inside a one-year 積立利率適用期間 — a discontinuity a monthly model must place on the right month.A rise in market rates since the contract’s own rate was set reduces the surrender value and a fall increases it. Implementing this as a deduction floored at zero models a different product.
- low_cv_rate(t)[source]#
kl(t): the 低解約返戻金割合 at month t; 1.00 unless the 特則 is in force.
0.70 while four or more premium-paying years remain, stepping to 0.775, 0.85 and 0.925 at three, two and one, and to 1.00 from 払込満了 — with the remaining count rounded up to whole years. The step is a cliff and interpolating across it is wrong: on the published run the 特則 form pays US$27,706 at duration 15 against US$53,029 at duration 20.
- cv_pp(t)[source]#
CV(t): the payable 解約返戻金 per policy at month t, in US dollars.
AV(t) (1 - mva(t) - sc(t)) kl(t). All three factors can be active at once on the SINGLE shape.CV(1) = 129.2774820on the anchor cell, where the 積立金 is 139.0080451 and the 解約控除率 7.0%. Paying a surrender onav_pp()instead overstates every early exit by up to 7% plus the adjustment.
- fx_rate(t)[source]#
e(t): the reference TTM in month t, yen per US$1.
The model point’s own
fx_ttm, held flat, unlessfx_pathis set — in which case the path table is read by policy year, its last row carried forward. The rate is never a literal inside a formula.
P_jpy0: the yen the policyholder actually paid for the contract.
The single premium converted at the 入金用為替レート on day one,
e(0) + s: ¥15,993,000 on the worked example’s SINGLE cell. It is the base of both the 目標額 and the dynamic-surrender multiplier, which is why a weaker yen alone can trigger a conversion.
- target_amount_jpy()[source]#
The 目標額 in yen:
gtimes the yen premium paid.¥17,592,300 on the worked example’s cell, from a 目標値 of 110%.
- target_hit(t)[source]#
Whether the yen-converted 解約返戻金 has reached the 目標額 at month t.
The test is on
cv_pp(), after FX and after the 市場価格調整 — not on the account value — and it does not apply inside the contractual one-year dead zone.
- target_month()[source]#
The first month at which the 目標値 is reached, or
proj_len() + 1if never.Month 52 on the worked example’s cell — four years four months — where the 積立金 is 116,626.82, the 市場価格調整率 0.007219, the 解約控除率 4.2% and the 解約返戻金 110,886.51, worth ¥17,623,193 against a 目標額 of ¥17,592,300.
- apl_intercept(t)[source]#
Whether the 自動振替貸付 can carry the premium falling due in month t.
True while the module is on, a premium is due, and the policy’s net surrender value — the 解約返戻金 less the advance already outstanding — covers it. While it is true the non-payment share of the surrender decrement does not lapse: it is redirected into
pols_if_apl(). A policy does not lapse while the account value can carry the premium, and applying a lapse rate to unpaid premiums without running this test models a decrement the contract does not have.
- pols_apl_new(t)[source]#
The policies whose premium the 自動振替貸付 advances at the end of month t.
The non-payment share of the surrenders the paying cohort would otherwise have made. The split of the surrender decrement into a voluntary part and a premium-non-payment part is [std]: no retrieved source separates them.
- pols_payer(t)[source]#
The policies in force at the start of month t that are paying their own premium.
pols_if_init()att = 0, then(1 - q_m)(1 - w_m)— the same recursion the whole cohort follows, with the intercepted non-payers moving out of it intopols_if_apl()rather than lapsing. Zero fromtarget_month()on, where the contract has left the dollar ledger.
- pols_if_apl(t)[source]#
The policies in force at the start of month t carried by the 自動振替貸付.
Zero everywhere unless
apl_on. The cohort accumulates the intercepted non-payers, is decremented by mortality and by the voluntary part of the surrender rate only, and runs off through the ordinary decrement once the fund can no longer carry the premium.
- loan_total(t)[source]#
The aggregate 自動振替貸付 advance outstanding at the start of month t.
Advanced premiums accumulated at
apl_int_rateand decremented with the cohort that owes them; policies entering the cohort bring no balance with them. Carried in aggregate rather than as a full entry-year triangle, which is exact for the total and makesloan_pp()the cohort average [std].apl_int_rateis 2.75% p.a., the savings chassis’s own [std] level, taken unchanged because this product changes nothing about the 自動振替貸付 except whether the shape has one at all. The contractual ceiling the chassis cites is 年8%.
- loan_pp(t)[source]#
The average 自動振替貸付 advance per policy in the APL cohort at month t.
Repaid out of whatever the policy is eventually paid: a death benefit or a surrender value net of it, floored at zero. Zero everywhere unless
apl_on.
- pols_if(t)[source]#
l(t): the policies in force at the start of policy month t.
pols_payer(t) + pols_if_apl(t), and the weight on every cash flow of the sameresult_cf()row.pols_if(0) = 1on a single-policy model point;pols_if(proj_len()) = 0, because the table’s terminal rate is 1 and every policy leaves by death, by surrender or through the target conversion.
- pols_if_at(t, timing)[source]#
The policies in force at a point inside month t.
"BEF_DECR"l(t), the start of the month before any decrement; the same number as
pols_if()and the weight on that month’s cash flows."BEF_LAPSE"after deaths, before surrenders — the processing order is death before surrender [std order], so this is the population surrenders are taken from.
"AFT_DECR"l(t+1), the end-of-month state.
- pols_lapse(t)[source]#
S(t): expected surrenders at the end of month t, on the survivors of mortality.
The paying cohort surrenders at the full monthly rate, less whatever the 自動振替貸付 intercepts; the APL cohort surrenders at the voluntary part only. Does not include the policies leaving through a target conversion, which are
pols_target().
- pols_target(t)[source]#
The policies leaving the dollar ledger at the end of month t on a target hit.
Non-zero in exactly one month,
target_month() - 1, where every survivor of that month’s decrements either converts to a yen whole life or surrenders — the election the model point makes. Zero everywhere on every model point without the rider.
Premium income at the start of month t, an inflow, in US dollars.
Carried on
pols_payer(), not onpols_if(): a policy whose premium the 自動振替貸付 is advancing pays the insurer nothing, though the premium still reaches the 積立金.239.60in month 0 and237.9175077in month 1 on the anchor cell.
- claims(t, kind=None)[source]#
Benefit outgo at the end of month t, by kind; the total when kind is omitted.
"DEATH"DB(t) D(t), the death and 高度障害 benefit. The APL cohort’s payment is net of the advance outstanding, floored at zero."LAPSE"CV(t+1) S(t), the surrender benefit — valued on the surrender value after that month’s interest, and net of any APL advance. Where the target election is"surrender"the policies leaving on the hit are paid here as well.
- conversions(t)[source]#
The 解約返戻金 leaving the dollar ledger on a 目標値 conversion at the end of month t.
Zero unless the target election is
"convert". The contract becomes a yen whole life whose death benefit and surrender value are fixed in yen and on which neither the exchange rate nor the 市場価格調整 acts again; that contract is out of scope, so the dollar model books its value out at the conversion date and stops. The scope boundary is [std] and is why the two target elections differ in where the money is booked rather than in how much of it there is.
- inflation_factor(t)[source]#
The expense inflation factor in month t:
(1 + pi)^floor(t/12)[std].1.0 through the first twelve months, then 1% a year on the anniversary.
- claim_expenses(t)[source]#
ec D(t): the claim handling expense on the month’s death claims [std].
US$150 per claim, uninflated. Kept out of
expenses(), deducted on its own line innet_cf()and published as its ownresult_cf()column: it is driven by the death decrement, not by the in-force count, so folding it into the acquisition-and-maintenance column hides which lever moves it.
- expenses(t)[source]#
Acquisition and maintenance expense in month t [std], in US dollars.
Acquisition expense of US$300 per policy at issue, then US$60 a year per policy inflating at 1%, accrued monthly and payable for life — this is a whole-life contract with no maturity date, so the maintenance stream runs to the terminal age. The claim expense is not in here: it is
claim_expenses(), its own column.305.0000000in month 0 on the anchor cell.No carrier publishes an expense basis, so every level here is a standardization. Expenses are the insurer’s own costs, incurred in yen, held in dollars at the model’s convenience and translated at the plain TTM: they do not cross the policyholder boundary and so never meet the 為替手数料 spread.
- commissions(t)[source]#
Commission outgo in month t [std], in US dollars.
LEVEL: 90% of the annualized premium at issue, then 3% of premium income from month 12 to 払込満了. SINGLE: 5.5% of the single premium at issue and a 継続手数料 of 0.75% p.a. of the account value for seven years — the shape the published schedules and the FSA’s L-shaped 5.5% / 0.1% reading of the sector both describe. Only the upfront pattern is evidenced; the levels are standardizations.
- net_cf(t)[source]#
CF(t): the net cash flow of policy month t, income positive, in US dollars.
Premiums less death and 高度障害 claims, surrender benefits, any target conversion, claim expense, acquisition and maintenance expense and commission. The notes’ own sign, which is also the library-wide one, so there is no outgo-positive
liability_cfcompanion to publish.The three account-value charges are not in it: they are internal transfers from the 積立金, and booking one as revenue alongside the premium that funded it double-counts the premium.
The shape to expect is a deep new business strain in month 0 — upfront commission and acquisition expense against a single monthly premium — then thin positive margins that thin further as the surrender benefit grows, and a long negative tail after 払込満了 where claims and maintenance run on with no premium behind them.
- benefits_usd(t)[source]#
The total policyholder payment in month t: claims plus any target conversion.
The quantity that crosses the currency boundary outbound, at
e - s.
Premium income in month t translated at the 入金用為替レート,
e(t) + s.¥38,319.23 in month 0 on the anchor cell. Where the 円入金特約 is not attached the policyholder pays in US dollars and the plain TTM applies.
- benefits_jpy(t)[source]#
Benefit outgo in month t translated at the 支払用為替レート,
e(t) - s.¥1,705.91 in month 0 on the anchor cell.
- expenses_jpy(t)[source]#
Expense and commission outgo in month t translated at the plain TTM.
All three lines — the claim expense, the acquisition and maintenance expense and the commission. The insurer’s own costs never cross the policyholder boundary, so they never meet the spread.
- net_cf_jpy(t)[source]#
The yen ledger of month t: three translations, not one.
premiums_jpy - benefits_jpy - expenses_jpy. ¥-424,569.01 in month 0 on the anchor cell, againstnet_cf(0) x 159.43 = ¥-424,694.18— the two figures are both correct and mean different things, and a model that publishes only the second has silently given the spread away.
- fx_spread_jpy(t)[source]#
The insurer’s 為替手数料 spread income in month t, published as its own column.
s x (premiums + benefits)over the legs that actually convert. ¥125.17 in month 0 on the anchor cell and ¥39,266 over the whole run — exactly the gap betweennet_cf_jpy()andnet_cf(t) e(t), month by month and so in total. Summingnet_cffirst and translating once ate(0)reproduces that gap only where the rate is flat; wherefx_pathis on it does not.
- check_pols_roll_fwd_resid(t)[source]#
The in-force roll-forward residual in month t; zero everywhere.
l(t) - l(t+1) - D(t) - S(t) - target(t). The table terminates, so every policy leaves by one of the decrements and the residual has nowhere to hide.
- check_pols_roll_fwd()[source]#
True when every policy leaves by a named decrement and none is lost.
The per-month roll-forward closes,
pols_if(proj_len())is zero, and the whole-run decrements sum to the cohort: on the anchor cellsum D = 0.211608544andsum S = 0.788391456, which is 1.000000000 exactly. Surrenders take 78.8% of the cohort out against mortality’s 21.2%, so this is a lapse-driven liability wearing a mortality product’s clothes.
- check_av_roll_fwd_resid(t)[source]#
The account-value roll-forward residual in month t; zero everywhere.
AV(t+1) - [(AV(t) + P - C_init - C_maint - C_coi)(1 + j) + 特別積立金(t+1)], rebuilt from the charge cells rather than from the recursion that produced it.
- check_av_roll_fwd()[source]#
True when the 積立金 recursion closes in every projected month.
The identity the whole product hangs on: premium in, three charges out, interest credited, in that order.
check_av_roll_fwd_resid()gives the signed residual of the month that failed.
- check_cv_ledger_resid(t)[source]#
The surrender-benefit ledger residual in month t; zero everywhere.
claims()(t, "LAPSE")less an independent rebuild of it fromCV(t+1), the decrement split and the APL advance — with no reference to the cells that produced the claim. A model paying surrenders onav_pp(), or valuing them before that month’s interest, or forgetting the 低解約返戻金 suppression, would show up here.
- check_cv_ledger()[source]#
True when the surrender benefit equals
CV(t+1)times the exits in every month.The surrender value is read after that month’s interest and after the 市場価格調整, the 解約控除 and the 低解約返戻金 suppression, which is what
CV(t+1)means; the rebuild is independent of the cells that produce the claim.
- check_net_cf_resid(t)[source]#
The cash-flow ledger residual in month t; zero everywhere.
net_cf()less the sum of the columnsresult_cf()publishes. It is what would catch an account-value charge leaking into the cash flow:C_init,C_maintandC_coiare internal transfers and appear in no column, so booking one as revenue alongside the premium that funded it would break this identity.
- check_fx_ledger_resid(t)[source]#
The yen-ledger residual in month t; zero everywhere.
net_cf_jpy(t) - [net_cf(t) e(t) + fx_spread_jpy(t)]. The identity states the whole currency layer: premiums translate ate + s, benefits ate - sand the insurer’s own costs ate, so the yen net is the translated dollar net plus the spread income. A model that translates the net figure at one rate fails here.
- check_fx_ledger()[source]#
True when the three-rate yen translation closes in every projected month.
- result_cf()[source]#
Result table of cash flows, indexed by policy month t.
pols_ifis the start-of-month count, which is the weight applied to every cash flow on the same row.net_cfcarries the notes’ own income-positive sign.net_cf_jpyandfx_spread_jpyare the translation block: the yen net is not the dollar net times anything, and the spread income is published rather than hidden inside it.av_ppandcv_ppare the state columns and are stated at the end of the month,AV(t+1)andCV(t+1), which is where the surrender benefit on the same row is valued.conversionsis a column of zeros on every model point without the target rider.