The Projection Space#
The by-contract projection of FIA_US_S.
The Space is parameterized by point_id, so Projection[1] is an ItemSpace
projecting model point 1:
>>> Projection[1].result_cf() # the worked-example anchor cell, by month
>>> Projection[1].result_cf_annual() # the same, summed into contract years
>>> Projection.point_id = 2 # or switch the default
Input data
Inputs are external files: plain CSVs living in the model folder’s parent directory,
products/fixed_indexed_annuity/, 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
FIA_US_S folder without its parent’s CSVs produces a model that reads
and then fails on first evaluation.
The readers and the filename References live on the sibling
Data Space, reached here through the data Reference, so
each file is read once per model rather than once per model point:
Reference (on Data) |
Cells |
File |
|---|---|---|
model_point_file |
data.model_point_table() |
model_point_table.csv |
mort_table_file |
data.mort_table() |
mort_table.csv |
surr_charge_file |
data.surr_charge_table() |
surr_charge_table.csv |
rollup_file |
data.rollup_table() |
rollup_table.csv |
payout_rate_file |
data.payout_rate_table() |
payout_rate_table.csv |
rate_scenario_file |
data.rate_scenario() |
rate_scenario.csv |
withdrawal_file |
data.withdrawal_table() |
withdrawal_table.csv |
Projection basis
t is the month index and it is 0-based: t = 0 is the first month of a model
point projected from issue, duration(t) = t // 12 is the completed contract years at
the start of month t, and the contractual label is policy_year(t) = duration(t) + 1.
The frame is t = entry_mth() … proj_len() - 1, and proj_len() is 12 *
policy_term(). The grid matches MYGA_US_S, Term_US_S and the rest of the
library, and it is what the product assignment table records for this product.
The monthly grid does not make the product monthly. The technical notes make the
anniversary the single event date — “All transactions occur at the anniversary and are
processed as the last events of the contract year ending there” [std] — and that is
still true here: every contractual event is an annual event landing in the anniversary
month, is_anniv(t), the last month of each contract year. What the finer grid buys is
everything that is not a contractual event: mortality and surrender now fall in the month
they happen rather than all at the anniversary, the Model #805 floor and the fixed account
accrue month by month so a mid-year death or surrender is valued on the balance it actually
has, and maintenance expense accrues where it is incurred. Because the monthly decrement
rates compound to the annual ones and every contractual step still happens once a year,
every state value at an anniversary is identical to the annual grid’s — account value,
benefit base, rollup base, lifetime withdrawal, Model #805 floor, phase and pols_if at
t = 12k. What changes is the timing and the weighting of the cash, which is the point.
Three vocabulary cells carry the split, and the whole model is written in terms of them:
duration() for anything keyed by contract year, is_anniv() for anything that
happens once a year, and year_open_mth() for the month whose closing value opens the
contract year — because on a monthly grid the previous month is no longer the previous
year, and reaching for t - 1 where a year is meant is the mistake this conversion
exists to prevent.
age(t) = age_at_entry() + duration(t) is the attained age opening the contract year
of month t, so mortality over that year reads age(t) itself — the library
convention of Term_US_S and MYGA_US_S. Age changes on the anniversary, not
on the birthday and not monthly. The transactions at the closing anniversary are one year
older, and that age is exercise_age(), covered_age(t) + 1: it is what reads the
lifetime-withdrawal percentage table and what clears the contractual minimum exercise age.
There is no issue-instant row. The single premium, the premium bonus and the
acquisition expense are beginning-of-month flows of month 0 on a new-issue model point,
whose first projected month is t = 0. A model point may instead enter in force after
entry_year() completed contract years, on balances stated in model_point_table.csv
— which is what the worked example does, its anniversary-7 balances being explicitly
“illustrative … broadly consistent with a seven-year deferral” [std] rather than
derived. entry_year() is an elapsed count of whole years, so entry_mth() = 12 *
entry_year() is the index of the model point’s first projected month and the frame always
opens on an anniversary. Every recursion opens there on the *_init cells, read through
the opening timing (av_pp_at(t, "BEF_INV"), benefit_base_pp_at(t, "BEF_ROLLUP"),
phase_open(), rider_in_force_open()), and result_cf() is indexed from
entry_mth().
The anniversary’s eight processing steps are the notes’ own, all eight still annual and all
eight landing in the anniversary month, and each intermediate value is reachable through a
timing argument rather than being buried inside one formula:
index credit and fixed interest —
index_credit_pp(),fixed_interest_ann_pp()rider charge on the opening benefit base —
rider_charge_pp()benefit base: rollup, stack, step-up —
rollup_pp(),stack_pp()lifetime and excess withdrawal —
lw_pp_at(),wd_pp()charges on the excess and the proportional reduction —
wd_reduction_rate()guaranteed minimum value roll —
mgsv_pp()phase transition including the depletion test —
phase()decrements —
pols_if_at()at"AFT_DECR"
Steps 1–3 are skipped in DEPLETED, steps 1–7 in TERMINATED. Step 8 is the one
that is not annual: it runs every month, on mort_rate_mth() and
lapse_rate_mth(). Steps 1 and 6 keep a monthly component — the fixed account accrues
at (1 + i_F)^(1/12) - 1 and the Model #805 floor at (1 + i_nf)^(1/12) — while their
annual figures, fixed_interest_ann_pp() and the anniversary deduction, stay whole.
Between anniversaries the contract is quiet: no withdrawal, no rider charge, no index credit, no rollup and no step-up. The indexed account is therefore flat between anniversaries, because the annual point-to-point segment locks only at maturity and “the credit … cannot be lost to later declines” [S1] is a statement about a credit that has not yet been earned. That is the sourced rule “withdrawals are not credited with index interest in the year they are taken” [S1] carried to mid-year deaths and surrenders [std]; crediting a part year would be the daily interim value variant the notes exclude.
Naming
Cells names follow MYGA_US_S — the deferred annuity chassis this
product sits on — and through it lifelib’s basiclife.BasicTerm_S and
savings.CashValue_SE: pols_* for policy counts, av_* for account values,
plural nouns for cash flows, *_rate for rates, *_pp for per-contract amounts,
*_at(t, timing) for a quantity read at a point inside the anniversary. The technical
notes use compact actuarial symbols instead. The mapping is:
Notes symbol |
Cells |
Meaning |
|---|---|---|
t |
(the projection index) |
Month index, 0-based |
(elapsed years) |
duration(t) |
Completed contract years at month t |
(elapsed months) |
duration_mth(t) |
Completed contract months; = t |
(the anniversary month) |
is_anniv(t) |
Last month of a contract year |
(that month’s index) |
anniv_mth(t) |
Anniversary closing month t’s year |
(the year’s opening month) |
year_open_mth(t) |
Anniversary that opened it |
(contract year) |
policy_year(t) |
Contract year containing t; duration + 1 |
x |
age_at_entry |
Issue age (ANB) |
x + duration(t) |
age(t) |
Attained age opening month t’s contract year |
(younger covered life) |
covered_age(t) |
Younger covered age opening that year |
x + duration(t) + 1 |
exercise_age(t) |
Covered age at the closing anniversary |
(none) |
policy_term |
Contract years from issue to maturity_age |
(none) |
proj_len |
Number of projected months; 12 x policy_term |
(in-force cell entry) |
entry_year |
Completed years at entry |
(none) |
entry_mth |
First projected month; 12 x entry_year |
av_initial |
av_pp_init |
AV at entry, else P x (1 + b) |
bb_initial |
benefit_base_pp_init |
BB at entry, else P |
mgv_initial |
mgsv_pp_init |
MGV at entry, else 0.875 x P |
(RB at entry) |
rollup_base_pp_init |
RB at entry, else P |
(LW at entry) |
lw_pp_init |
LW at entry, 0 before exercise |
(pi at entry) |
payout_rate_init |
Payout percentage locked at entry |
(phase at entry) |
phase_init |
Phase at entry |
P |
premium_pp |
Single premium |
b |
bonus_rate |
Premium bonus rate (7% [S5]) |
b/(1+b) |
bonus_factor |
Clawback factor – not b [S10] |
v(t) |
vest_rate(t) |
Vested bonus percentage [S5] |
alloc_indexed/alloc_fixed |
alloc_indexed / alloc_fixed |
Account allocation at issue |
I(y) |
index_level(y) |
Index level at anniversary number y |
R(t) |
index_return(t) |
I(y+1)/I(y) - 1 over month t’s year |
c |
cap_rate |
Declared annual cap (5.25% [S2]) |
c_min |
cap_rate_min |
Guaranteed minimum cap (0.25% [S4]) |
c(t) |
cap_rate_in_force() |
Cap actually applied |
f |
floor_rate |
Index credit floor (0%) |
p, s, d |
par_rate, spread_rate, trigger_rate |
Participation rate [R1]; spread and trigger, levels [std] |
cr(t) |
credit_rate(t) |
Credit rate for month t’s contract year |
(cr on a return) |
credit_rate_on(r, method) |
The crediting engine itself |
IC(t) |
index_credit_pp(t) |
Index credit, in the anniversary month |
FI(t) monthly |
fixed_interest_pp(t) |
Fixed account interest for month t |
FI(t) annual |
fixed_interest_ann_pp(t) |
The contract year’s, for the stack |
i_F, i_F,min |
fixed_rate, fixed_rate_min |
Declared / guaranteed fixed rate |
kappa |
av_int_factor |
Share of IC reaching the AV [S3] |
(IC x kappa + FI) |
inv_income_pp(t) |
Interest credited to the AV |
A(t) |
av_indexed_pp(t) |
Indexed account balance |
F(t) |
av_fixed_pp(t) |
Fixed account balance |
AV(t) |
av_pp(t) |
Account value closing month t |
AV(0), AV(1), AV(2), AV(t) |
av_pp_at(t, timing) |
BEF_INV / BEF_FEE / BEF_WD / EOY in order; BEF_PREM opens the month |
AV(0) of the contract year |
av_pp_year_open(t) |
Balance opening month t’s contract year |
F(0), A(0) of that year |
av_fixed_pp_year_open(t), av_indexed_pp_year_open(t) |
The fixed and indexed openings: the credit base and the fixed-interest base |
l(t) x AV(t) |
av_at(t, timing) |
In-force weighted account value |
(shortfall at exhaustion) |
av_depletion_pp(t) |
Withdrawal the AV could not fund |
phi |
rider_charge_rate |
Rider charge rate (0.95% [S9]) |
Phi(t) |
rider_charge_pp(t) |
Rider charge amount |
BB(t) |
benefit_base_pp(t) |
GLWB benefit base, closing |
BB(3), BB(4) |
benefit_base_pp_at(t, timing) |
BEF_ROLLUP/BEF_STEP_UP/BEF_WD/EOY |
RB(t) |
rollup_base_pp(t) |
Rollup base |
g(t) |
rollup_rate(t) |
Guaranteed simple rollup rate [S2] |
rollup(t) |
rollup_pp(t) |
Rollup dollar increment |
m |
stack_factor |
Stacking factor (1.50 [S8][S9]) |
stack(t) |
stack_pp(t) |
Stacking credit |
T_g |
in_growth_period(t) |
Benefit base still growing |
(the step-up) |
step_up_applies(t) |
Whether the ratchet is tested |
LW(t) |
lw_pp(t) |
Lifetime withdrawal amount, closing |
LW before/after step 5 |
lw_pp_at(t, timing) |
BEF_WD / EOY |
pi(a, basis) |
payout_rate(a, basis) |
Payout percentage by age band [S3] |
(pi locked at exercise) |
payout_rate_locked(t) |
The percentage actually in force |
h(a) |
activation_rate(a) |
Activation incidence, reported only |
G(t) |
wd_pp(t) |
Gross withdrawal requested |
min(G, LW) |
wd_guar_pp(t) |
Guaranteed portion |
E(t) |
wd_excess_pp(t) |
Excess above the guaranteed amount |
(unpayable withdrawal) |
wd_unfunded_pp(t) |
Requested but neither funded nor guaranteed, on TERMINATED |
(guaranteed portion paid) |
wd_guar_paid_pp(t) |
min(G, LW) less its share of it |
(excess portion paid) |
wd_excess_paid_pp(t) |
E(t) less its share of it |
FW(t) |
free_wd_allow(t) |
Free withdrawal amount |
0.10 x AV(0)(t) |
free_wd_base(t) |
Base of the free amount |
(FW consumed) |
wd_free_pp(t) |
Free-allowance portion of the withdrawal |
(FW remaining) |
free_wd_remain(t) |
Free amount left for the excess |
X(t) on a withdrawal |
wd_charge_base_pp(t) |
Amount exposed to charge and MVA |
X(t) on a surrender |
surr_charge_base_pp(t) |
Same, at a full surrender |
sc(t) |
surr_charge_rate(t) |
Surrender charge percentage [S5] |
SC(t) on a withdrawal |
wd_charge_pp(t) |
Surrender charge on the excess |
SC(t) on a surrender |
surr_charge_pp(t) |
Surrender charge on a surrender |
CB(t) on a withdrawal |
wd_clawback_pp(t) |
Non-vested bonus recovery |
CB(t) on a surrender |
surr_clawback_pp(t) |
Same, at a full surrender |
(the clawback formula) |
bonus_clawback_on(…) |
(1-A) x [B/(1+B)] x C [S10] |
MVA(t) on a withdrawal |
wd_mva_pp(t) |
Collared MVA on the excess |
MVA(t) on a surrender |
mva_pp(t) |
Collared MVA on a surrender |
(the MVA collar) |
mva_pp_on(t, base, gross) |
The collared MVA on any base |
(the MVA rate) |
mva_rate(t) |
[(1+i0)/(1+it)]^(n/12) - 1 [S10] |
i0 |
mva_ref_yield_at_issue |
Reference index at issue |
i_y |
mva_ref_yield(y) |
Reference index at anniversary number y |
n/12 |
mva_term(t) |
Years left in the MVA period |
(MVA applies at all) |
mva_in_force(t) |
Inside the MVA period |
rho(t) |
wd_reduction_rate(t) |
Proportional reduction factor |
(rho’s formula) |
wd_reduction_rate_on(…) |
The [S9] worked construction |
Wcum(t) |
wd_cum_pp(t) |
Cumulative gross withdrawals |
G - SC - CB + MVA |
wd_payment_pp(t) |
Cash paid on the withdrawal |
(pre-floor surrender value) |
surr_value_pp(t) |
AV - SC - CB + MVA |
CSV(t) |
surr_benefit_pp(t) |
Surrender benefit paid |
MGV(t) |
mgsv_pp(t) |
Model #805 guaranteed minimum |
i_nf |
mgsv_rate |
Nonforfeiture accumulation rate |
(the $50 charge) |
mgsv_charge_pp(t) |
Annual contract charge, 0 [std] |
(statutory i_nf) |
mgsv_rate_statutory(…) |
Model #805 4B/4C indexed rate |
phase(t) |
phase(t) |
Closing ACCUM/INCOME/DEPLETED/TERMINATED |
(phase during the year) |
phase_open(t) |
Phase steps 1-7 are processed under |
(first exercise) |
is_exercise(t) |
The first lifetime withdrawal |
rider_in_force(t) |
rider_in_force(t) |
Rider still alive closing month t [S9] |
rider_in_force(k-1) |
rider_in_force_open(t) |
Rider alive opening the contract year |
depletion_cause(t) |
depletion_cause(t) |
Excess / charge / negative MVA flag |
q(t) |
mort_rate(t) |
Annual mortality of month t’s contract year |
1 - (1-q)^(1/12) |
mort_rate_mth(t) |
The monthly rate actually applied |
(A/E deviation) |
mort_ae_factor |
Mortality A/E factor, 100% [std] |
w(t) |
lapse_rate(t) |
Annual surrender rate of that year |
1 - (1-w)^(1/12) |
lapse_rate_mth(t) |
The monthly rate actually applied |
w_base(t) |
lapse_rate_base(t) |
Base surrender table |
w_shock |
shock_lapse_rate(t) |
33% / 10% / 5% by rider state [R8] |
M_money(t) |
lapse_moneyness_factor(t) |
Moneyness suppression [std] |
l(k) at t = 12k |
pols_if(t) |
In-force opening month t |
(closing the month) |
pols_if_at(t, “AFT_DECR”) |
In-force at the end of month t |
l(0) |
pols_if_init |
In-force at entry |
(the four readings) |
pols_if_at(t, timing) |
BEF_DECR/BEF_MORT/BEF_LAPSE/AFT_DECR |
l q_m |
pols_death(t) |
Deaths in the month |
l (1-q_m) w_m |
pols_lapse(t) |
Full surrenders in the month |
(none) |
pols_maturity(t) |
Survivors at the horizon |
P at t = 0 |
premiums(t) |
Premium income |
min(G, LW) x l(t) |
wd_guar(t) |
Guaranteed withdrawal outgo, paid |
(E - SC - CB + MVA) l(t) |
wd_excess(t) |
Excess withdrawal outgo, paid |
LW while DEPLETED |
income_payments(t) |
Post-depletion income outgo |
(all three together) |
withdrawals(t) |
Total withdrawal outgo |
(ledger benefit lines) |
claims(t, kind) claim_pp(t, kind) claims_from_av(t, kind) claims_over_av(t, kind) |
Benefit outgo by kind Benefit per contract by kind Account value released by a claim Benefit paid above the account value |
(no separate commission) |
commissions(t) |
Acquisition commission, 0 [std] |
0.06 P; (80/12) x 1.025^(t/12) |
expenses(t) |
Acquisition and monthly maintenance |
premium tax |
premium_taxes(t) |
Premium tax, 0% [std] |
NetCF(t) |
net_cf(t) |
Net cash flow for the month |
(the annual summary) |
result_cf_annual() |
result_cf() summed into contract years |
Six names needed care.
pols_if(t) is the notes’ l(k) at the twelfth months. Across this library
pols_if(t) is the number in force at the start of t and is the weight carried
by that same row’s cash flows — Term_US_S has pols_if(0) == pols_if_init() and
savings.CashValue_SE has pols_if(t) equal to pols_if_at(t, "BEF_MAT"). The
notes define l(k) as the in-force probability at the end of contract year k,
which is anniversary k, which is where contract year k + 1 opens: on the monthly
index that is month 12k, so pols_if(12k) = l(k) with
pols_if(entry_mth()) = l(0) = 1 for a new issue. Because the monthly rates compound to
the annual ones this equality is exact, not approximate.
The one place the finer grid changes an answer rather than its resolution is the weight
on the anniversary’s own cash. A withdrawal, a rider charge or a surrender charge falls in
month 12k + 11 and is weighted by pols_if(12k + 11) — the contracts that actually
reach the anniversary — where the annual grid weighted it by l(k), the contracts that
entered the year. The second is an approximation the annual grid could not avoid: it pays a
full year’s guaranteed withdrawal to a contract that died in month three. The
reconciliation the convention buys is unchanged, and now holds row by row on the finer
grid: the pols_if column of result_cf() is the divisor of the cash flows on its
own row — result_cf()["wd_guar"][t] / wd_guar_paid_pp(t) is pols_if(t).
MGV is MGSV. The Model #805 floor is called MGV in these notes, after [S10], and
MGSV in products/fixed_deferred_annuity/, after its own specimen. Both source
files say in terms that this is one quantity under two labels and must not be modeled
as two. The chassis name mgsv_pp() is used here, so the two annuity models share it.
The recursion, however, is not the chassis’s: this product accretes and then deducts,
MGV(t) = max(0, MGV(t-1) x (1 + i_nf) - G(t)), while the chassis deducts and then
accretes, MGSV(t) = [MGSV(t-1) - d(t) - c(t)] x g. The worked example pins the FIA
ordering — 93,811.84 x 1.01 - 10,144.16 = 84,605.80 — and the chassis notes explicitly
warn against carrying their recursions across unexamined. Same name, same concept,
different arithmetic, on purpose.
E(t) is not the chassis’s E(t). On the chassis E(t) is the amount exposed to the
surrender charge and the MVA, and is named wd_excess_pp / surr_excess_pp. Here
E(t) is the notes’ excess withdrawal — the part of a gross withdrawal above the
guaranteed lifetime amount, the quantity that permanently reduces the guarantee and, at
exhaustion, destroys it. That is the product’s headline concept and it keeps the name
wd_excess_pp(). The chargeable amount, the notes’ X(t), becomes
wd_charge_base_pp() on the withdrawal path and surr_charge_base_pp() on the
surrender path. Reading a chassis formula across without renaming would silently charge a
surrender charge on the wrong base.
age(t) opens the contract year; exercise_age(t) closes it.
age(t) = age_at_entry() + duration(t) is the attained age at the anniversary that opens
month t’s contract year, exactly as in Term_US_S and MYGA_US_S, and
mort_rate() reads it directly — the annual rate it returns is then converted for the
month by mort_rate_mth(). Every transaction, however, falls at the closing
anniversary, one year older, and the payout percentage depends on that age: the anchor
cell’s first lifetime withdrawal, in contract year 8 from an issue age of 62, is taken at
attained age 70 and reads pi(70, single) = 5.20%. exercise_age() carries that age
— covered_age(t) + 1 — so the + 1 is named once rather than spelled at each use.
M_shock is absorbed into lapse_rate_base. The notes write
w(t) = min(0.35, w_base(t) x M_shock(t) x M_money(t)) but state the shock as three
absolute rates (33% / 10% / 5%) rather than as multipliers on the 6% ultimate. Carrying
M_shock as a separate factor would require inventing a denominator, so
lapse_rate_base() returns shock_lapse_rate() in the shock year and
lapse_rate() multiplies only by lapse_moneyness_factor(). The name
shock_lapse_rate follows Term_US_S — but the timing does not, and the
contrast is worth stating. There the notes put the shock “in full at the end of the final
level-period month”, a contractual date, so Term_US_S drops the whole shock in that
one month. Here the notes state it as the surrender rate of contract year 11, a year that
carries no surrender charge in any of its months, so there is no date inside the year for
the decision to cluster on and lapse_rate_mth() spreads it like any other annual
rate. The one surrender that is not spread is the deemed full surrender at termination,
which is a contractual event and lands whole on the anniversary.
d and c collide across the library. d is the performance-trigger rate in these
notes, deaths in Term_US_S and the floor’s withdrawal deduction on the chassis;
c is the declared cap here and the floor’s contract charge on the chassis. The names
trigger_rate, pols_death(), mgsv_charge_pp() and cap_rate()
keep the four apart.
One name is reused deliberately and reads across cleanly. credit_rate() is the
chassis’s declared effective annual rate i_cr(t) and here the index credit rate
cr(t) = max(f, min(c, R(t))). Different formulas, but the same concept — the rate at
which interest is credited for the contract year — so the name is kept rather than split.
Timing arguments
Account value, following CashValue_SE’s av_pp_at and named for the processing step
each precedes:
"BEF_PREM"the balance carried into month
tbefore the single premium: zero att = 0on a new-issue model point, and the same as"BEF_INV"everywhere else. It exists so that the account-value roll-forward closes on the first month too, the premium being a beginning-of-month flow rather than a row of its own."BEF_INV"the balance opening month
tafter the premium:av_pp_init()at the first projected month andAV(t-1)after it. In an anniversary month this is the notes’AV(0)only when the fixed allocation is zero; in general the notes’AV(0)of the contract year isav_pp_year_open(), eleven months earlier."BEF_FEE"AV(1), after the month’s interest — the fixed accrual every month, plus the index credit in an anniversary month — and before the rider charge."BEF_WD"AV(2), after the rider charge, before the withdrawal. Not floored at zero — the 0% floor is on the index credit, not on the account value [S7]."EOY"AV(t), after the withdrawal, floored at zero. Equal toav_pp().
Away from an anniversary the last three coincide, at the opening balance plus the month’s fixed accrual, because no contractual transaction falls there.
Benefit base, named for the same steps: "BEF_ROLLUP" is the base opening the contract
year, "BEF_STEP_UP" is BB(3) after rollup and stack, "BEF_WD" is BB(4)
after the annual step-up, and "EOY" is BB(t) after the proportional reduction. All
four steps are annual, so away from an anniversary every timing returns the opening base.
Lifetime withdrawal: "BEF_WD" is the amount payable at the contract year’s anniversary,
"EOY" the closing value after the same reduction; away from an anniversary both carry
the amount set at the last one, which is the income in force.
Policy counts, following the chassis: "BEF_DECR" is the count entering the month and
therefore equals pols_if() itself, "BEF_MORT" is the same (this product has no
annuitization decrement), "BEF_LAPSE" is after that month’s deaths, and "AFT_DECR"
is the closing count, which is also pols_if(t + 1). Both decrements are the monthly
rates.
Benefit kind arguments are "DEATH", "LAPSE" and "MATURITY". Any other
value of any of these raises ValueError.
The three phases, and why the cause of depletion matters
ACCUM is deferral. INCOME starts at the first lifetime withdrawal and lasts while
an account value remains. DEPLETED is what the product is sold for: the account value
is gone, the insurer pays LW from its own funds for the rest of the covered life, no
rider charge is deducted, no index credit is computed, the surrender value and the death
benefit are zero, and lapse is impossible, so lapse_rate() returns zero and
l(t+1) = l(t)(1 - q_m(t)). TERMINATED is the same exhaustion with the guarantee
destroyed — reached when the account value is driven to zero by an excess withdrawal, a
surrender charge or a negative MVA rather than by guaranteed withdrawals and rider charges
[S1][S5][S9]. depletion_cause() carries the attribution and is evaluated before
the depletion test, exactly as the notes require. A model testing only AV <= 0 would
either give the guarantee away after an excess withdrawal or destroy it after a legitimate
one. When the contract terminates, the survivors leave as a deemed full surrender —
lapse_rate() returns 1.0 for that contract year, and lapse_rate_mth() puts the
whole of it in the anniversary month rather than spreading it, because the contract “as
well as the rider will be considered Surrendered” [S5] on that date — so the in-force
roll-forward still closes.
The transition itself is annual and is tested only at the anniversary, which costs nothing:
the account value can reach zero only where a withdrawal or a charge is taken, and both
fall there. Between anniversaries phase() simply carries phase_open().
The asymmetry reaches the cash, not only the phase label. On the exhaustion
anniversary itself the withdrawal requested exceeds what the account value can meet. In
DEPLETED the insurer funds the whole shortfall, because that is the guarantee. On the
TERMINATED branch it funds none of it: the balance is gone and the rider that would
have covered the rest is destroyed by the very withdrawal being paid, and [S5] treats the
contract as surrendered at that point. wd_unfunded_pp() is that unpayable part, and
wd_payment_pp(), wd_guar() and wd_excess() are all net of it. The cap is
on the payment only — wd_pp() still carries the amount requested, so the excess
still sets depletion_cause(), still drives rho to 1 and still takes the benefit
base to zero.
pols_maturity and the projection horizon
The technical notes state no projection horizon; the DEPLETED liability is a life
annuity, so the model runs through the final month of the contract year entered at
attained age maturity_age = 120 [std], the terminal age of the shipped mortality
table — proj_len() = 12 * policy_term() months. The survivors of the last month leave
through pols_maturity(), zero at every other t, so that
pols_if(t) - pols_if(t+1) = pols_death(t) + pols_lapse(t) + pols_maturity(t)
holds for every t, including the last, t = proj_len() - 1, where
pols_if(proj_len()) is zero. Under the shipped table q reaches 1.000000 at age 120,
hence a monthly rate of 1.0 in the first month of that contract year, so the projection
closes itself and the term is numerically zero; it is kept because a substituted table with
no terminal age would make it bite, and because without it the last month would appear to
lose lives with no cause. The name follows BasicTerm_S.pols_maturity and the
construction follows Term_US_S.
Cells Descriptions#
- tax_status()[source]#
Tax status of the contract, NQ or Q.
Reported only. The base run is non-qualified [std]; no RMD module is implemented, though the notes make the RMD age a behavioural input through
activation_rate()and thermd_ageReference.
P: the single premium per contract.
- entry_year()[source]#
The completed contract years behind the model point when it enters the projection.
An elapsed count of whole years, which
entry_mth()turns into the index of the model point’s first projected month,12 * entry_year().0for a new issue, whose month0carries the premium, the acquisition expense and the notes’ Initialisation block as its opening state and beginning-of-month flows. A positive value enters the contract in force on balances stated in the model point table, which is what the worked example does: its anniversary-7 balances are described as illustrative and broadly consistent with a seven-year deferral [std], not derived from one, so deriving them would mean retuning assumptions to force a match. Every recursion opens here.
- entry_mth()[source]#
The model point’s first projected month,
12 * entry_year().The frame is
t = entry_mth() … proj_len() - 1.0for a new issue, whose month0carries the premium, the acquisition expense and the notes’ Initialisation block as its opening state and beginning-of-month flows. Elapsed time is stated in completed contract years, so the frame always opens on an anniversary and every recursion opens here.
- alloc_indexed()[source]#
The share of the account value allocated to the indexed account; 100% [std].
- glwb_basis()[source]#
singleorjoint.The joint column of the payout table is the single column less 0.50%, read on the younger covered person [S1][S3]. Joint-life survivorship is not implemented: the notes specify the joint payout percentage but no second-life mortality basis.
- income_start_age()[source]#
The attained age at which the base run takes its first lifetime withdrawal.
The deterministic run activates here rather than on the
h(a)incidence table, which the notes say clusters at the RMD age but which cannot be applied to a single deterministic cell; seeactivation_rate().
- utilization_intensity()[source]#
The fraction of
LWactually withdrawn once income starts.1.00 in the base run [std]; the majority of users withdraw 95%-105% of the maximum [R1]. The 1.05 case is an excess withdrawal and routes through the proportional reduction of step 5, which is why efficiency and excess-withdrawal assumptions cannot be set independently.
- credit_method()[source]#
The crediting method:
cap,par,par_cap,spreadortrigger.All five are implemented in
credit_rate_on(). The notes’ sixth variant, monthly sum with a monthly cap, is not implemented: it needs a monthly grid, which the notes exclude, and its floor convention is itself flagged as ambiguous [S4][R1].
- cap_rate()[source]#
c: the declared annual cap, 5.25% [S2].
A non-guaranteed element captured as of 07/01/2022, revisable under ASOP No. 2 [R6][REG-R26]. Holding it constant for forty years is a strong implicit assumption; re-declaration against the option budget is not implemented because the notes give the target but no option-pricing function.
- stack_factor()[source]#
m: the stacking factor on realised dollar credits, 150% [S8][S9].
Zero gives the pure-rollup design (a); with
rollup_ratezero it gives the pure stacking design (b), where one carrier’s 250% election credits 250% to the benefit base [S3][S4].
- av_int_factor()[source]#
kappa: the share of the index credit that reaches the account value [S3][S4].
1.00 on the blended baseline. 0.50 is the 250% election documented at one carrier, which credits 250% of index interest to the benefit base but only 50% to the account value, deliberately starving the account value. The stacking factor
mapplies to the gross index credit, not tokappa x IC.
- av_pp_init()[source]#
AV at entry: the stated in-force balance, else
P x (1 + b)[S5].The bonus is credited to the account value at issue and earns index credits from day one [S5]; it does not enter the benefit base [S9] or the nonforfeiture base [S10].
- av_fixed_pp_init()[source]#
F at entry: the fixed account share of
av_pp_init(), allocated as premium.
- benefit_base_pp_init()[source]#
BB at entry: the stated in-force base, else
P– the bonus stays out [S9].
- mgsv_pp_init()[source]#
MGV at entry: the stated in-force floor, else 87.5% of premium [S10][R2].
87.5% of the single premium excluding the bonus [S10]; the worked example’s
93,811.84 = 87,500 x 1.01^7is that value rolled forward seven years.
- policy_term()[source]#
Contract term in years [std]: through the year entered at
maturity_age.maturity_age= 120 is the terminal age of the mortality basis, where the annual rate is 1.000000, so the projection closes itself rather than being truncated: the last contract year is the one entered at that age, hence the+ 1. The notes state no horizon, and theDEPLETEDliability is a life annuity, so stopping earlier would silently drop the tail the product is sold for.
- proj_len()[source]#
The number of contract months projected,
12 * policy_term().The exclusive end of the frame counted from
t = 0:result_cf()runst = entry_mth() … proj_len() - 1, so its last row is the final month of the contract year entered at attained agematurity_age.
- policy_year(t)[source]#
The contract year month
tfalls in:duration(t) + 1, the 1-based label.Derived from
t, never indexed by. It is the key that reads the surrender charge, the vesting vector and the rollup schedule, all of which the sources state by contract year, and it is the year whose annual decrement ratesmort_rate()andlapse_rate()return.
- duration_mth(t)[source]#
Completed contract months at the start of month
t:titself.The cells exists so the monthly vocabulary reads the same here as in
Term_US_Sandsavings.CashValue_SE; an in-force model point opens the frame atentry_mth()rather than re-basingt.
- duration(t)[source]#
Completed contract years at the start of month
t,duration_mth(t) // 12.Every contractual schedule in this product is annual, so this is what the attained age, the surrender charge, the vesting vector, the rollup schedule and the scenario tables are read at.
- is_anniv(t)[source]#
True in the last month of a contract year, where every annual event lands.
duration_mth(t) % 12 == 11. All eight of the notes’ processing steps are contractually annual — the point-to-point index credit [S2][S4][S10], the rider charge [S9], the benefit base rollup, stack and step-up [S9], the lifetime withdrawal, the charges and the phase transition — so all eight happen here and nowhere else. What the finer grid carries between anniversaries is the fixed-account accrual, the Model #805 roll, the decrements and the maintenance expense.
- anniv_mth(t)[source]#
The month that closes the contract year of month
t:12 * duration(t) + 11.Equal to
titself whenis_anniv()is true. It is where the annual quantities of that contract year are evaluated — which is what makeslapse_rate()a property of the year rather than of the month.
- year_open_mth(t)[source]#
The month whose closing value opens the contract year of month
t.12 * duration(t) - 1, the anniversary closing the previous contract year. It falls belowentry_mth()in the first projected contract year, where the notes’ Initialisation values stand in — which is the test every annual state cells makes.
- age(t)[source]#
x + duration(t): the attained age (ANB) opening the contract year of month t.
The library convention of
Term_US_SandMYGA_US_S, somort_rate()reads this age directly for the contract year of mortality it covers. Age changes on the anniversary, not on the birthday and not monthly. The transactions of that contract year fall at its closing anniversary and are one year older: that age isexercise_age(), which is what reads the lifetime withdrawal percentage table.
- covered_age(t)[source]#
The attained age of the covered life opening the contract year of month t.
The annuitant’s own age on a single-life basis; the younger covered person’s on a joint-life basis [S1][S3]. Timed like
age(), at the opening anniversary; the payout percentage and the minimum exercise age are read atexercise_age().
- exercise_age(t)[source]#
covered_age(t) + 1: the covered age at the anniversary closing the contract year.All transactions occur at the anniversary and are processed as the last events of the contract year ending there [std], so a lifetime withdrawal taken in the contract year of month
tis taken one year older than the age opening it. This is the age that reads the payout percentage band and that clears the contractual minimum exercise age of 50: the anchor cell’s exercise in contract year 8, from issue age 62, is at attained age 70 and reads the 70-79 band.
- scenario_value(y, name)[source]#
Step-function lookup of column
namein the model point’s scenario at anniversaryy.The argument is an anniversary number, not the frame’s month index. The
tcolumn of rate_scenario.csv is an anniversary number,0at issue, and the file’s keys are read unshifted; callers passduration(t)for the anniversary opening the contract year of monthtandduration(t) + 1for the one closing it. Each row states the level that holds from its own anniversary until the next row of the same scenario, so a flat path is one row. Anniversaries before the first row take the first row’s level.
- index_level(y)[source]#
I(y): the index level at anniversary
y.Keyed by anniversary number, not by the frame’s month index — a time-point reading, so the return over a contract year differences this level against the next anniversary’s. The S&P 500 price index in the composite; dividends are excluded [S2][S6][R1].
- index_return(t)[source]#
R(t) = I(y+1)/I(y) - 1 with
y = duration(t): the return over the contract year.The point-to-point segment runs from the anniversary opening the contract year of month
tto the one closing it, where it matures. The return is a property of the contract year, not of the month, and is the same for every month inside it.
- cap_rate_in_force()[source]#
c(t): the annual cap actually applied.
The declared 5.25% snapshot held level [std], never below the guaranteed minimum cap of 0.25% [S4]. Set
use_guaranteed_scale = Trueto run the contract on its guaranteed minimums instead — the notes insist the guaranteed and current scales are different assumption classes and “must not be mixed in the code”.
- fixed_rate_in_force()[source]#
i_F: the fixed account rate applied, 2.30% declared over a 1.00% guarantee.
Declared [S2] and guaranteed minimum [S10];
use_guaranteed_scaleswitches to the guarantee, as for the cap.
- credit_rate_on(r, method)[source]#
cr: the credit rate for an index return
rundermethod.The engine the notes require, all branches floored at
f= 0%:cap[std]max(f, min(c, R))[S2][S4][S10][R1] — the composite’s baseline.parmax(f, p x R)[S4][S10][R1].par_capmax(f, min(c, p x R)), worked at [R1] asmin(80% x 10%, 6%) = 6%— which is wherepar_rate= 80% comes from, and the casetest_crediting_engine_reproduces_the_R1_worked_caseasserts.spreadmax(f, p x R - s), the index-margin form [S8][R1].triggerd x 1{R >= 0}, a declared rate credited whenever the return is non-negative [R1]; the floor applies when it is not.
The notes declare the two levels these last branches need nowhere, so both are [std]. They print the forms —
san index margin,da performance-trigger rate — and neithertechnical-notes.mdnorproduct-spec.mdstates a value for either, unlike the cap (5.25% [S2]) and the participation rate (80% [R1]). The shippedspread_rate= 2.00% [std] andtrigger_rate= 4.50% [std] are illustrative levels chosen only to exercise the branch, and must not be read as sourced parameters of the composite.index_cost_rateis deducted fromRbefore any cap or participation rate, which is where a volatility-controlled index’s embedded servicing cost belongs [S2][S10]; it is 0 in the base run [std]. The monthly-sum method is not implemented — seecredit_method().
- credit_rate(t)[source]#
cr(t): the credit rate the segment of month t’s contract year matures at.
A property of the contract year, like
index_return(); it is applied once, at the anniversary where the segment matures.
- index_credit_pp(t)[source]#
IC(t) = A(0) x cr(t): the index credit on the segment maturing at month t.
One annual segment per indexed account, created at the anniversary opening the contract year with the balance opening it and maturing at the anniversary closing it; the credit locks at maturity and cannot be lost to later declines [S1], and it is not earned before then — which is why this is zero in every month but the anniversary, and why the indexed balance is flat between anniversaries. That is the sourced rule “withdrawals are not credited with index interest in the year they are taken” [S1], carried to mid-year deaths and surrenders [std]; crediting a part year would be the daily interim value variant the notes exclude.
The credit base is the segment’s opening balance less withdrawals from that account during the segment — the “Interest Credit Basis” [S6] — which collapses to the opening balance here because every transaction happens at an anniversary [std]. Zero in
DEPLETEDandTERMINATED, where steps 1-3 are skipped.
- fixed_interest_pp(t)[source]#
FI(t): interest credited to the fixed account in month t.
The declared rate is an annual effective one, so the month accrues at
(1 + i_F)^(1/12) - 1and twelve of them compound back to exactlyi_F— nothing else touches the fixed account between anniversaries, because every contractual transaction falls at one.fixed_interest_ann_pp()is the annual figure the benefit-base stack is computed on.
- fixed_interest_ann_pp(t)[source]#
FI over the contract year closing at the anniversary in month
t:F(0) x i_F.On the balance opening that contract year. The twelve monthly accruals of
fixed_interest_pp()compound to exactly this, so the annual figure is computed directly rather than accumulated — which is what keeps the benefit-base stack, and through it the whole guarantee, identical to the annual grid’s.
- inv_income_pp(t)[source]#
Interest credited to one contract’s account value in month t.
kappa x IC(t) + FI(t): the fixed accrual every month, and the index credit only in the anniversary month where the segment matures.kappastarves the account value in the pure-stacking design [S3]; the benefit-base stack instack_pp()uses the gross index credit, which is the whole point of that design.
- rider_charge_pp(t)[source]#
Phi(t) = phi x BB(0): the GLWB rider charge, deducted once a year [S9].
On the benefit base, not the account value, and taken after index credits are added — the notes’ ordering, which is why the base in the formula is the opening base. In the worked example the base closes at 1.59 times the account value, so charging on the account value would understate the deduction by a growing margin. Deducted from the fixed account first and then proportionately across indexed accounts [S9].
phiis fixed for fifteen contract years and never exceeds 1.50% [S9]; re-declaration after that is not implemented. Once the account value is exhausted the charge stops — there is nothing to deduct it from and income continues [S9].The charge is annual by contract [S9], so on the monthly grid it lands whole on the anniversary rather than being spread over the year; the monthly deduction documented at one carrier is a variant this composite does not adopt [std].
- av_pp_at(t, timing)[source]#
AV per contract in month t, read at the point given by
timing."BEF_PREM"is the balance carried into the month before the single premium, zero att = 0on a new issue;"BEF_INV"is the balance opening the month after it, which isav_pp_init()at the first projected month andAV(t-1)after that;"BEF_FEE"is after the month’s interest — the fixed accrual every month, plus the index credit in an anniversary month;"BEF_WD"is after the rider charge;"EOY"is after the withdrawal. In a month that is not an anniversary the last three coincide, at the opening balance plus the fixed accrual, because every contractual transaction falls at an anniversary.Only
"EOY"is floored at zero: the 0% floor is on the index credit, not on the account value [S7], so"BEF_WD"may legitimately sit below the opening balance or below zero when the rider charge exceeds the credit. Flooring it would silently remove the charge drag that produces depletion.
- av_pp_year_open(t)[source]#
AV(0): the account value opening the contract year containing month
t.The balance the annual index credit and the free withdrawal allowance are computed on: the closing value of the anniversary before, or the Initialisation value in the first projected contract year. On an annual grid this would simply be the previous row’s close; on the monthly grid the previous month is not the previous year, which is what this cells exists to keep straight.
- av_fixed_pp_year_open(t)[source]#
F(0): the fixed account balance opening the contract year containing month
t.
- av_indexed_pp_year_open(t)[source]#
A(0): the indexed balance opening the contract year — the segment’s credit base.
- av_fixed_pp_at(t, timing)[source]#
F per contract in month t; see
av_pp_at()fortiming.The fixed account is the one balance that moves between anniversaries: it accrues at
(1 + i_F)^(1/12) - 1every month. The rider charge comes out of it first and only then proportionately across the indexed accounts [S9]. The notes give no allocation rule for withdrawals, so they are taken pro rata across the two accounts [std]; with the baseline 100% indexed allocation neither rule is visible.
- av_indexed_pp_at(t, timing)[source]#
A per contract in month t:
AV - Fat the same timing, by construction.
- av_indexed_pp(t)[source]#
A(t): the indexed account balance per contract closing month t.
Flat between anniversaries — the segment credits only at maturity — and stepped at each anniversary by that year’s index credit net of its share of the charge and the withdrawal.
- av_depletion_pp(t)[source]#
The part of month t’s withdrawal the account value could not fund.
Zero until the account value runs out, then the shortfall between the withdrawal requested and the balance available to meet it. It is the term that makes the account value roll-forward close across the depletion anniversary, where
AV(t)is floored at zero.It is not the same thing as an amount paid. Whether the shortfall is a payment depends on which exhaustion branch the anniversary closes on: in
DEPLETEDthe guarantee is alive and the insurer funds it from its own funds [S1][S3][S9][R1], on theTERMINATEDbranch there is neither balance nor promise behind it and it is not paid at all.wd_unfunded_pp()carries that half, and only that half is kept out of the ledger.
- surr_charge_rate(t)[source]#
sc(t): the surrender charge percentage of month t’s contract year [S5].
9.1, 9, 8, 7, 6, 5, 4, 3, 2, 1% over the ten-year charge period and zero thereafter; the last row of the table holds for every later year. The table is keyed by the contractual 1-based contract year,
policy_year(t), so the rate is the same in every month of a year.
- vest_rate(t)[source]#
v(t): the vested percentage of the premium bonus in month t’s contract year [S5].
0, 10, …, 100% over eleven contract years, read at
policy_year(t). On death 100% vests immediately [S5], which is why the death benefit carries no clawback.
- rollup_rate(t)[source]#
g(t): the guaranteed simple rollup rate of month t’s contract year [S2][S9].
Read as a step function of the contract year
policy_year(t)from the model point’s schedule: the blended baseline is 5.00% in years 1-10, 2.00% in years 11-20 and zero after [S2]; another documented design is a flat 3.00% over fifteen anniversaries [S9].
- payout_rate(a, basis)[source]#
pi(a, basis): the lifetime withdrawal percentage at attained age
a[S3].Five inclusive attained-age bands; the joint column is the single column less 0.50% [S1][S3]. Zero below the first band, because no lifetime withdrawal is permitted there; the last band holds above its upper age.
- payout_rate_locked(t)[source]#
The payout percentage in force in the contract year of month t.
Locked at the attained age of the first lifetime withdrawal,
exercise_age(), and not re-read afterwards [std].is_exercise()is a property of the contract year, so the lock holds for every month of the year it is set in and is then carried from anniversary to anniversary. Documented alternatives: one carrier reads the band from the age at the most recent anniversary, letting it step up [S3]; another makes it depend on both issue age and the youngest covered person’s age at exercise [S9]; a third uses sex-distinct factors [S5].
- activation_rate(a)[source]#
h(a): the GLWB activation incidence at attained age
a[std].0below 60, 5% from 60 to the RMD age, 40% at it and 15% above [R1][REG-R64].rmd_ageis a configurable Reference and must not be hard-coded: the statutory age is set by IRC 401(a)(9) as amended by SECURE 2.0 and finalized in T.D. 10001 [REG-R57][REG-R58] and is not printed in the retrieved research material.Reported only. A single deterministic cell cannot activate a fraction of itself, so the base run exercises at the model point’s
income_start_ageinstead; this cells exists so the incidence assumption is visible and testable rather than implied.
- is_exercise(t)[source]#
True through the contract year whose closing anniversary carries the first LW.
Requires an in-force rider, the
ACCUMphase opening the year and anexercise_age()at or above both the contractual minimum of 50 [S2][S3][S9] and the model point’sincome_start_age. It depends only on the state opening the contract year, which is what lets the phase, the benefit base and the withdrawal be evaluated without a circular reference — and what makes it constant across the year, so every month of the exercise year reads the same phase and the same locked payout percentage.
- phase_open(t)[source]#
The phase the annual steps of month t’s contract year are processed under.
The phase opening the contract year —
phase_init()in the first projected year and the closing phase of the previous anniversary after that — promoted toINCOMEwhen the first lifetime withdrawal falls in this year. Constant across the twelve months, because every one of the eight steps belongs to the year rather than to the month. Steps 1-3 are skipped when this isDEPLETEDand steps 1-7 when it isTERMINATED.
- depletion_cause(t)[source]#
True when a charge, an excess withdrawal or a negative MVA touched the AV in month t.
The attribution test of step 5, evaluated before the depletion test: an account value run to zero by an excess withdrawal, a surrender charge or a market value adjustment loses the guarantee entirely, while one run to zero by guaranteed withdrawals and rider charges keeps it [S1][S5][S9]. One carrier’s confinement and terminal illness waivers are themselves excess withdrawals that terminate the income rider [S1] — a trap if waivers are added.
- phase(t)[source]#
The phase closing month t, after step 7’s transition at the anniversary.
Step 7 is annual and the account value can only reach zero at an anniversary — nothing between them takes a withdrawal or a charge — so away from one this simply carries
phase_open(), and the transition is tested at the anniversary itself.ACCUM -> INCOMEat the first lifetime withdrawal;INCOME -> DEPLETEDwhen the account value reaches zero with nodepletion_cause(), which is where the economic value of the guarantee sits;INCOME -> TERMINATEDwhen it reaches zero with one; andany -> TERMINATEDwhen the benefit base reaches zero [S9]. An account value exhausted inACCUMterminates rather than depletes [std]: the notes define the depleted state only out ofINCOME, and before exercise there is noLWto pay.
- rider_in_force_open(t)[source]#
Whether the GLWB rider is alive opening the contract year of month t.
glwb_elected()in the first projected contract year — an in-force model point enters on the rider state its row states — andrider_in_force()at the previous anniversary after that. Kept as a cells of its own, likephase_open(), because four formulas need the opening rider state and none of them may reach for a closing one.
- rider_in_force(t)[source]#
Whether the GLWB rider is still alive at the end of month t [S9].
It terminates on the earliest of death of the covered person, the benefit base reduced to zero, termination of the base contract, assignment, owner cancellation on or after the earliest cancellation date, or a change in a covered person — with no refund of past charges [S9]. Death is a decrement here, and cancellation and assignment are not modelled, so what survives is the base-reaching-zero and contract-termination legs.
- in_growth_period(t)[source]#
T_g: whether the benefit base still rolls up and stacks in month t’s contract year.
To the earlier of the first lifetime withdrawal and contract year 20 [S1][S2]. The year of exercise itself is still inside the window — the worked example credits both the rollup and the stack in contract year 8, the year income starts — which is why the test is on the phase opening the year.
- step_up_applies(t)[source]#
Whether the annual step-up
BB <- max(BB, AV)is tested at month t.Annual by construction, so it is tested only at the anniversary.
A [std] generalisation. No retrieved document describes an automatic annual ratchet during deferral; documented instead are an at-exercise step-up to the contract value [S5], an annual benefit amount computed on the greater of base and account value at exercise [S9], and a never-decreasing income amount once withdrawals begin [S3].
step_up_mode = "at_exercise"reduces the model to those designs;"annual"is the superset and the baseline. Under the blended baseline it rarely binds — a dollar of credit adds $1 to the account value and $1.50 to the base — but rarely is not never: on a new issue the bonus opens contract year 1 with an account value of107,000against a benefit base of100,000, so a first contract year with a zero index credit gives an account value of106,050against a base of105,000and the step-up binds.
- rollup_pp(t)[source]#
rollup(t) = g(t) x RB(0): the guaranteed rollup increment, once a year.
A flat dollar increment, not simple interest on the grown base. One carrier computes it on premium less withdrawals [S2] and another on the adjusted initial base [S9]; the latter’s fifteen-year table confirms a constant $3,000 a year on a $100,000 adjusted initial base [S9]. Compounding it inflates the base and every downstream charge and payment.
- stack_pp(t)[source]#
stack(t) = m x max(0, IC(t) + FI(t)): the stacking credit at the anniversary.
On realised dollar credits, net of any strategy fee (zero here) and floored at zero [S8][S9] — one specimen’s separately named stacking credit. The gross index credit is used, so the pure stacking design can credit 250% to the base while
kappasends only 50% to the account value [S3][S4].FIhere is the annual fixed interest of the contract year,fixed_interest_ann_pp(), not the anniversary month’s own accrual.
- benefit_base_pp_at(t, timing)[source]#
BB per contract in month t, read at the point given by
timing."BEF_ROLLUP"is the base opening the contract year —benefit_base_pp_init()in the first projected year and the base at the previous anniversary after it;"BEF_STEP_UP"is after the rollup and the stack;"BEF_WD"is after the annual step-up and is the base the lifetime withdrawal is computed on;"EOY"is after step 5’s proportional reduction. All four steps are annual, so away from an anniversary every timing returns the opening base and the benefit base is flat.The base is notional: it has no cash value, cannot be withdrawn and cannot be taken as a lump sum [S1][S9].
- rollup_base_pp(t)[source]#
RB(t): the rollup base closing month t.
Reduced in the same proportion as the benefit base under the baseline [std] convention [S9], and only at an anniversary, where the reduction happens. Set
rb_wd_convention = "dollar"for the alternative documented at another carrier,RB(t) = max(0, RB(0) - G(t))— “Premium minus Withdrawals” [S2].
- lw_pp_at(t, timing)[source]#
LW per contract in month t, read at the point given by
timing."BEF_WD"is the amount payable at this contract year’s anniversary, after step 4’s ratchet;"EOY"is the closing value, after step 5’s proportional reduction. The ratchet is annual, so away from an anniversary this carries the amount set at the last one — the income in force, which is what a mid-year reading of the rider state means.At exercise
LW = pi x BB(4); afterwards the ratchetLW = max(LW(0), pi x BB(4))applies so income never decreases [S3]. UnusedLWdoes not carry forward [S9]; one carrier is the exception, accumulating the shortfall without interest [S3]. InDEPLETEDthe amount is simply carried: there is no base to recompute it from.
- wd_scheduled_pp(t)[source]#
The ad hoc gross withdrawal scheduled at the anniversary of month t’s year, else zero.
Read from withdrawal_table.csv, which is not a step function: a contract year with no row takes nothing. Its key column is an elapsed contract year count, not the frame’s month index — a row keyed
yis a withdrawal at the anniversary closing contract yeary + 1— so it is read atduration(t)and the file is unchanged by the move to a monthly grid. Lifetime withdrawals are generated by the rider, not scheduled here.
- wd_pp(t)[source]#
G(t): the gross withdrawal taken at the anniversary in month t.
Zero in every other month: both the lifetime withdrawal and the ad hoc schedule are contractually annual, so the finer grid moves no cash between anniversaries. In
INCOME,utilization_intensity() x LWplus any scheduled ad hoc amount; inDEPLETED, exactlyLW, paid by the insurer from its own funds; inACCUM, only the scheduled amount. Gross by construction: a contract promising a stated net check would need a gross-up solve, which is not implemented.
- wd_guar_pp(t)[source]#
min(G(t), LW(t)): the guaranteed portion of month t’s withdrawal.
A withdrawal is applied first against the guaranteed annual amount; that portion reduces the account value dollar for dollar and leaves the benefit base and the income amount unchanged [S9].
- wd_excess_pp(t)[source]#
E(t) = max(0, G(t) - LW(t)): the excess withdrawal in month t.
The quantity that permanently reduces the guarantee, and that destroys it entirely if it exhausts the account value [S1][S5][S9]. Note this is not the chassis’s
wd_excess_pp, which is the amount exposed to the surrender charge; that iswd_charge_base_pp()here. Before exerciseLWis zero, so the whole withdrawal is an excess.
- wd_unfunded_pp(t)[source]#
The part of G(t) that neither the account value nor the guarantee pays.
G(t) - min(G(t), max(0, AV(2)(t)))in a month whose closing phase isTERMINATED; zero everywhere else. The two exhaustion branches are not symmetric, and this is where they part. InDEPLETEDthe account value is gone but the guarantee is alive, so the insurer paysLWfrom its own funds for the rest of the covered life [S1][S3][S9][R1] and nothing is unfunded. On theTERMINATEDbranch the account value is driven to zero by an excess withdrawal, a surrender charge or a negative MVA, and “an account value run to zero by an excess withdrawal loses the guarantee entirely” [S1][S5][S9] — [S5] is explicit that the contract “as well as the rider will be considered Surrendered”. Beyond the account value there is then nothing to pay from: no balance and no promise. Paying the requested amount in full would honour the guarantee in the very year the withdrawal destroys it, which is the trap the notes’ attribution test exists to avoid.The notes write step 4 as
AV(5)(t) = AV(2)(t) - G(t)with no cap because they write it for the funded case. The cap here is on the payment, not on the withdrawal:wd_pp()still carries the amount requested, so the excess still setsdepletion_cause()and still drivesrhoto 1 and the benefit base to zero. Onlywd_payment_pp()and the three ledger lines are reduced.
- wd_guar_paid_pp(t)[source]#
The guaranteed portion of month t’s withdrawal that is actually paid.
min(G, LW)less whatever ofwd_unfunded_pp()the excess could not absorb. The account value funds the withdrawal in the order the notes compose it — the firstLWdollars are the guaranteed portion and the remainder is the excess [S9] — so an under-funded withdrawal leaves the excess unpaid first and eats into the guaranteed portion only after that [std], the notes being silent on a withdrawal the account value cannot fund. Equal towd_guar_pp()in every month except a terminating anniversary.
- wd_excess_paid_pp(t)[source]#
The excess portion of month t’s withdrawal that is actually paid.
max(0, E(t) - wd_unfunded_pp(t)): the excess is the first thing an under-funded withdrawal loses, being the part with no promise behind it. Equal towd_excess_pp()in every month except a terminating anniversary.
- wd_cum_pp(t)[source]#
Wcum(t): cumulative gross withdrawals from entry to the end of month t.
A running total over months, though only the anniversary months add to it.
- free_wd_base(t)[source]#
The base of the free withdrawal amount: the AV opening the contract year of month t.
10% of the account value at the anniversary that opens the contract year, available from contract year 1 and with no carry-forward [S1][S3][S5][S6][S9][S10]; the combination is [std]. Fixing the base at a known prior value is what lets the chargeable amount be evaluated without a fixed point, and it is what makes the allowance a property of the contract year rather than of the month.
- free_wd_allow(t)[source]#
FW(t) = 0.10 x AV(0): the free withdrawal amount for month t’s contract year.
- wd_free_pp(t)[source]#
The free-allowance portion of the anniversary’s withdrawal: the part of FW(t) it uses.
The chassis name for this quantity (
MYGA_US_S,UL_US_S,RILA_US_S), so the library spells the free-allowance portion of a withdrawal one way everywhere. Zero away from the anniversary, where no withdrawal is taken and the whole allowance therefore remains against a mid-year surrender.A [std] choice the notes flag as open. [S9] says only that withdrawals up to the annual benefit amount carry no charge “even if greater than the Free Withdrawal Amount”; it does not say whether they exhaust it. The convention here — the guaranteed amount consumes the free amount — is the insurer-favourable reading and is what the worked example uses, leaving
12,800.00 - 10,144.16 = 2,655.84against the surrender. The alternative leaves the wholeFW(t)available against the excess.
- free_wd_remain(t)[source]#
The free withdrawal amount left after the contract year’s guaranteed withdrawal.
The whole allowance away from an anniversary, where no withdrawal has been taken yet — which is what a mid-year surrender is charged against.
- wd_charge_base_pp(t)[source]#
X(t): the part of month t’s withdrawal exposed to charge, clawback and MVA.
max(0, G(t) - FW(t))before exercise andmax(0, E(t) - remaining free)after it [std] — withdrawals up toLWcarry no surrender charge, no MVA and no bonus clawback even when ``LW`` exceeds the free withdrawal amount [S9]. Zero once the account value is gone: post-depletion income is not a chargeable withdrawal.
- surr_charge_base_pp(t)[source]#
X(t) at a full surrender in month t:
AV(t)less the free amount left.The chassis calls this
surr_excess_pp; renamed here only for symmetry withwd_charge_base_pp(), becauseE(t)already names a different quantity in these notes. The construction is the chassis’s and the source is the same [S10].
- bonus_factor()[source]#
b/(1+b): the factor that strips the bonus out of a bonus-inclusive account value.
The clawback factor is b/(1+b), not b [S10] — the account value already contains the bonus, so using
bover-recovers by(1+b).
- bonus_clawback_on(base, vested, bonus)[source]#
CB = (1 - A) x [B/(1+B)] x C: the non-vested bonus recovery [S10].
Ais the vested percentage for the contract year,Bthe bonus percentage andCthe gross withdrawal less the free withdrawal amount. Worked verbatim at [S10]: contract year 5, bonus 16%, gross $100,000, free $7,000 gives0.70 x 0.1379 x 93,000 = 8,979. Written as a function of its three arguments so that arithmetic is testable directly.
- mva_ref_yield(y)[source]#
i_y: the MVA reference index level at anniversary
y, from the scenario table.Keyed by anniversary number, like
index_level(), so the level in force at a transaction closing the contract year of monthtismva_ref_yield(duration(t) + 1). A declared investment-grade corporate bond yield index; generic here [std], and named as Barclay’s US Credit Index in the linear-form products [S6][S7].
- mva_term(t)[source]#
n/12: the years remaining in the MVA period at the end of month t.
The MVA period is the ten-year surrender charge period [S7][S10], and the notes state the term in months — which is what the monthly grid can now say exactly:
surr_charge_period - (t + 1)/12, a transaction in monthtbeing settled at its end. At the worked example’s anniversary 8 — month 95, the close of contract year 8 — that is10 - 96/12 = 2years, then = 24months the notes quote, so every anniversary value is the annual grid’s; a surrender six months earlier now carries the 30 months it actually has instead of being rounded to the anniversary. The remaining term reaches zero at anniversary 10, so a transaction carries a live adjustment through contract year 9 and none in contract year 10.
- mva_in_force(t)[source]#
Whether an MVA applies to a transaction in month t.
MVA = 0outside the MVA period and on the death benefit [S5][S6][S7][S10]; the second is handled where the death benefit is valued.
- mva_rate(t)[source]#
The market value adjustment rate,
[(1+i0)/(1+it)]^(n/12) - 1[S10].Signed, and negative when the reference yield has risen [S10]. This is the ratio-of-yield-factors family, which is naturally bounded; the linear family
(i0 - it) x Tadopted by the fixed-deferred chassis [S6][S7] is unbounded and must be collared separately. The FIA composite restates the MVA rather than inheriting it, which is why the chassis’smva_familyswitch is absent here.The reference yield is read at the anniversary closing the contract year of month
t,duration(t) + 1, which is the transaction date the adjustment applies at.
- mva_pp_on(t, base, gross)[source]#
The collared MVA on a currency
basewithdrawn asgrossin month t.|MVA| <= max(0, G - SC - CB - MGV)[S10], so a negative MVA combined with the surrender charge and the clawback can never push the proceeds below the guaranteed minimum value, and the maximum positive adjustment cannot exceed the maximum negative one. In the worked example’s surrender trace the limit ismax(0, 122,865.84 - 5,965.56 - 84,605.80) = 32,294.48and the raw-1,158.64sits well inside it.The notes are silent on how a surrender-value collar applies to a partial withdrawal, and both readings are shipped. The limit is stated on the gross withdrawal, and its stated purpose is that the adjustment “never reduces the surrender value below the guaranteed minimum value” — a full-surrender concept, and the only case the worked example demonstrates. Read literally, a partial withdrawal smaller than the floor gives a non-positive limit and therefore no adjustment at all.
mva_collar_basisselects:"gross"[std] defaultthe notes’ literal text,
reference = G(t)."surrender_value"the test applied to the contract rather than to the payment,
reference = AV(t), so a partial withdrawal carries the adjustment its rate produces up to what the remaining floor allows.
The two are identical on the surrender path, where
G(t) = AV(t), so the worked example reproduces under either; they differ only where the notes say nothing.
- wd_payment_pp(t)[source]#
The cash paid on month t’s withdrawal,
G - unfunded - SC - CB + MVA.The surrender charge and the clawback are internal transfers within the account value, not fee income: the account value falls by the gross
G(t)while the holder receives this. Reporting them as income while also projecting the account value net of them double-counts.wd_unfunded_pp()is zero in every month except a terminating anniversary, where it strips out the part of the request the account value could not fund and the destroyed guarantee does not cover. On theDEPLETEDbranch it stays zero and the whole ofLWis paid, which is the guarantee.
- wd_reduction_rate_on(av, lw, gross)[source]#
rho for a gross withdrawal of
grossagainstavwith guaranteed amountlw.E / (AV - LW), the post-exercise construction stated verbatim at [S9]: account value $100,000, base $200,000, annual benefit amount $10,000, withdrawal $28,000 gives denominator $90,000, excess $18,000, reduction 20%, base to $160,000 and benefit amount to $8,000. Passinglw = 0gives the pre-exercise formG / AV[S1][S3][S5][S9] — the two denominators differ by exactly LW, which is the pitfall the notes name.rho = 1when the denominator is non-positive: the base goes to zero and the rider terminates [S9].
- wd_reduction_rate(t)[source]#
rho(t): the proportional reduction applied to BB, LW and RB in month t.
Pre-exercise the denominator is the gross account value after the rider charge; post-exercise it is that value net of the guaranteed amount [S9]. Zero when there is no excess: a withdrawal inside
LWleaves the guarantee untouched.
- surr_value_pp(t)[source]#
The surrender value before the nonforfeiture floor,
AV - SC - CB + MVA.The composition order is account value, then charge and clawback and MVA computed on the pre-deduction excess, then the floor — the chassis’s order, and the one contractual element the FIA notes inherit rather than restate.
- surr_benefit_pp(t)[source]#
CSV(t) = max(AV - SC - CB + MVA, MGV): the surrender benefit paid [S1][S6][S10].
Zero in
DEPLETED: there is no account value and no surrender value [S1][S9]. A binding floor is not a separate cash flow — it raises the benefit, andMGV - SVis a reconciliation quantity only.
- mgsv_charge_pp(t)[source]#
The annual contract charge deducted from the Model #805 floor, at the anniversary.
Model #805 4.A permits $50 a year, accumulated at the nonforfeiture rate, together with premium tax actually paid and indebtedness [R2]. All are zero here [std] because no retrieved product declares an actual annual policy fee, which makes the modeled floor slightly conservative.
- mgsv_pp(t)[source]#
MGV(t): the Model #805 guaranteed minimum value closing month t.
The floor accretes every month at
(1 + i_nf)^(1/12) - 1, so twelve months compound to exactly the annual nonforfeiture rate and the anniversary values are the annual grid’s; the withdrawal is deducted at the anniversary, where it is taken. Accrete, then deduct — the worked example pins the ordering at93,811.84 x 1.01 - 10,144.16 = 84,605.80. The fixed-deferred chassis deducts and then accretes; the two are different arithmetic on the same concept, which is exactly what that file warns against carrying across.Accruing monthly rather than once at the anniversary is what makes the floor mean something for a mid-year death or surrender, which is where it most often binds. The opening value is
0.875 x Pexcluding the bonus at issue [S10][R2].rider_charge_from_mgsvswitches on the treatment documented at two carriers, one deducting the rider charge from the floor and the other its allocation charge [S1][S2][S3][S4]; the composite does not [std].
- mgsv_rate_statutory(cmt5, option_cost)[source]#
The Model #805 4.B/4.C indexed nonforfeiture rate [R2][R3].
max(0.0015, min(0.03, round(CMT5 to 1/20 of 1%) - 0.0125 - delta))wheredeltais the equity-index reduction of 4.C: available only when the annualized option cost of the guaranteed index features is at least 25 basis points, and then equal tomin(100 bp, option cost), certified annually [R3].Two traps the notes name. The 4.B floor is 15 basis points, not 1% — the composite’s 1.00% is a [std] pick inside the 0.15%-3% corridor, not the statutory floor. And whether the 15 bp floor survives the 4.C reduction is not stated in the retrieved text [unverified]; the specimen contract language, “the interest rates will range between 0.15% and 3%”, suggests it does [S10], which is the reading implemented. The statute defines the minimum: the contract rate must satisfy
mgsv_rate >= mgsv_rate_statutory(...), which is whatmgsv_rate_is_compliant()tests, not the reverse inequality.
- mgsv_rate_is_compliant(cmt5, option_cost)[source]#
True when the contract nonforfeiture rate meets the statutory minimum [R2][R3].
- mort_rate(t)[source]#
q(t): the annual mortality rate of the contract year containing month t.
Read at
age(t), the attained age opening that contract year — the library convention ofTerm_US_SandMYGA_US_S. The rate actually applied to a month ismort_rate_mth(); this cells stays annual so the table is read the way it is published and so the assumption is visible at the frequency it is set at.The shipped table is the same illustrative Makeham annuitant curve as
products/fixed_deferred_annuity[std], not a published basis. The prescribed basis is the 2012 IAM Basic / 2012 IAR generational family with Projection Scale G2,q_x^(2012+n) = q_x^(2012) x (1 - G2_x)^n, rounding applied from the 2012 period rate each time and never by compounding an already rounded rate [REG-R59][REG-R60]; it may not be redistributed here, so swap it in by repointingData.mort_table_file. Generational projection is not implemented for the same reason.mort_ae_factorcarries the A/E deviation, 100% [std] against the 2020-2024 payout experience study [REG-R61]; the spelling is the library’s shared one, so the A/E factor reads the same in every model that has one.
- mort_rate_mth(t)[source]#
The monthly mortality rate,
1 - (1 - q)^(1/12).The uniform-force conversion the library uses everywhere: twelve of these compound to exactly the annual rate of the contract year, so the anniversary in-force numbers are the annual grid’s and only their distribution through the year changes. Dividing by twelve instead would overstate the decrement, and the error grows with the rate.
- shock_lapse_rate(t)[source]#
w_shock: the surrender rate in the year the surrender charge expires [R8].
The single most important behavioral fact in the product. 33% without a GLWB rider against 10% with one in force but not activated, and 5% [std] once it is activated, extrapolated from the finding that contracts with GLWBs lapse less than those without and that activated GLWBs lapse least [R1][R8]. Applying a plain fixed-deferred shock lapse — roughly 52%-56% for fixed-rate deferred annuities [REG-R63, unverified] — to an FIA with an in-force rider materially understates the tail the product is sold for.
- lapse_rate_base(t)[source]#
w_base(t): the base annual surrender rate of month t’s contract year [std].
2% in years 1-3, 3% in 4-6, 4% in 7-9, 5% in year 10, the shock in the year the surrender charge expires, and 6% thereafter — the shape [R1] describes: low early, rising through the charge period, spiking at expiry, then falling back but staying above pre-shock levels. The notes’ separate
M_shockmultiplier is absorbed here, because the shock is stated as an absolute rate rather than as a factor on the ultimate; see the Space docstring.
- lapse_moneyness_factor(t)[source]#
M_money(t) = clamp(1 - 0.6 max(0, BB/AV - 1), 0.2, 1.0) [std].
Surrender is suppressed when the guarantee is in the money, because a rational surrender destroys a guarantee worth
BB - AVin benefit-base terms. The observed direction is documented [R1][R8]; the functional form is not.Evaluated on the state closing the contract year, at
anniv_mth(), so the factor is a property of the year like the base rate it multiplies. Reading it month by month would let the fixed-account accrual drift the ratio within the year and make the annual surrender assumption depend on where in the year it is sampled.
- lapse_rate(t)[source]#
w(t): the annual surrender rate of the contract year containing month t.
min(0.35, w_base(t) x M_money(t)), and zero in DEPLETED — with no account value there is nothing to surrender, so lapse is impossible [S1][S9] and leaving the decrement on would silently truncate the most expensive part of the liability. In the contract year the contract terminates, the survivors leave as a deemed full surrender [S5][S9], so this returns 1.0 there and the in-force roll-forward closes.Evaluated on the phase closing the contract year, at
anniv_mth(), so it is one rate for the whole year;lapse_rate_mth()is what a month actually applies.
- lapse_rate_mth(t)[source]#
The monthly surrender rate,
1 - (1 - w)^(1/12).The same uniform-force conversion as
mort_rate_mth(), so twelve months compound to exactly the contract year’s annual rate — including the shock in the year the surrender charge expires, which is spread. That is deliberate and is the opposite ofTerm_US_S, where the notes state the shock as a rate “applied in full at the end of the final level-period month”: here the notes state it as the surrender rate of contract year 11, a year that carries no surrender charge in any month, so there is no contractual date inside it for the decision to cluster on.The one rate that is not spread is the deemed full surrender at termination. That is a contractual event, not a behavioral assumption: the contract “as well as the rider will be considered Surrendered” [S5] at the anniversary the account value is destroyed, so the survivors leave in that month and not before.
- pols_if(t)[source]#
The in-force probability at the start of month t.
The library convention, set by
Term_US_Sandsavings.CashValue_SE: this is the count entering the month, before its decrements, and it is the weight carried by every cash flow reported on the same row ofresult_cf(). At an anniversary month12k + 11it is the count that reaches the anniversary and therefore the weight the year’s withdrawal and charges carry — on the annual grid that weight was the count entering the year, which is the one place the finer grid changes the answer rather than only the resolution.pols_if(entry_mth()) = pols_if_init(), the recursion runspols_if(t + 1) = pols_if(t)(1 - q_m(t))(1 - w_m(t))with death before surrender [std], and it is zero fromproj_len()on, where the survivors of the last projected month have left throughpols_maturity(). Because the monthly rates compound to the annual ones,pols_if(12k)is exactly the annual-grid model’spols_if(k): the notes’l(k).
- pols_if_at(t, timing)[source]#
In-force in month t read at the point given by
timing."BEF_DECR"and"BEF_MORT"are both the count entering the month, which ispols_if()itself — this product has no annuitization decrement, so the chassis’s two timings coincide."BEF_LAPSE"is after deaths, and"AFT_DECR"is the count at the end of month t and thereforepols_if(t + 1). Both decrements are the monthly rates.
- pols_maturity(t)[source]#
Survivors leaving at the projection horizon, non-zero only at
proj_len() - 1.Not a decrement — the horizon runs out — but needed for the in-force roll-forward to close. Numerically zero under the shipped mortality table, whose annual rate reaches 1.000000 at age 120, hence a monthly rate of 1.0, so the projection closes itself; see the Space docstring.
- claim_pp(t, kind)[source]#
The benefit paid per contract at the end of month t by
kind."DEATH"ismax(AV(t), MGV(t))with 100% bonus vesting, no surrender charge and no MVA [S1][S2][S5][S10], and is never below the cash surrender benefit [R2 6]. Note the FIA composite restates this rather than inheriting the chassis’s full account value floored at the surrender benefit."LAPSE"is the surrender benefit."MATURITY"is the account value floored at the guaranteed minimum at the horizon. All three are zero in DEPLETED: there is no account value, no surrender value and no death benefit, and the only exit is death [S1][S9].
- claim_from_av_pp(t, kind)[source]#
The account value released per contract by a claim of
kind.AV(t)for all three kinds; the difference fromclaim_pp()isclaims_over_av(), positive when the Model #805 floor binds and negative when the surrender charge and a negative MVA bite.
Premium income: the single premium, at the start of month 0 on a new issue.
There is no issue-instant row, so the premium is a beginning-of-month flow of the first projected month rather than a row of its own. An in-force model point paid its premium before the projection starts, so this is zero throughout for it — as are the acquisition expense and the premium tax that key off it.
- prem_to_av_pp(t)[source]#
Premium and bonus credited to the account value per contract, at issue only.
- wd_guar(t)[source]#
Guaranteed withdrawal outgo in month t, weighted by
pols_if(t).The count entering the month, which is the in-force number reported on the same row of
result_cf(); at an anniversary that is the count which reaches it. Onwd_guar_paid_pp(), not on the amount requested, so a terminating anniversary cannot pay a guaranteed withdrawal the account value could not fund and the destroyed rider no longer covers. Zero inDEPLETED, where the same payment is reported asincome_payments()so the two lines partition the total rather than overlap.
- wd_excess(t)[source]#
Excess withdrawal outgo in month t:
E - unfunded - SC - CB + MVA.Weighted by
pols_if(t), the count entering the month, and onwd_excess_paid_pp(): the excess is the first part of an under-funded withdrawal to go unpaid.
- income_payments(t)[source]#
Post-depletion income outgo:
LWat the anniversary whilephase = DEPLETED.This is the guarantee. There is no account value behind it, no rider charge is deducted, and it runs for the rest of the covered life [S1][S3][S9][R1].
Annual like every other withdrawal, so it falls in the anniversary month and is weighted by the contracts that reach it. Paying it in each of the twelve months would multiply the guarantee twelvefold and break the partition
withdrawals = wd_guar + wd_excess + income_paymentsthatresult_cf()documents.
- withdrawals(t)[source]#
Total withdrawal outgo in month t,
wd_payment_pp(t) x pols_if(t).Equal to
wd_guar()+wd_excess()+income_payments()in every month, the three lines partitioning it by the notes’ ledger categories. All four are published byresult_cf(), so summing every column of that frame double-counts the withdrawal; the ledger identity is on the total, and the split is there because the notes report the three categories separately.
- claims_over_av(t, kind=None)[source]#
Benefit paid less the account value released,
claims - claims_from_av.Signed and a reconciliation quantity only: positive exactly when the Model #805 floor binds, negative when the surrender charge, the clawback and a negative MVA bite. A binding floor does not add a top-up cash flow — it raises the benefit.
- commissions(t)[source]#
Acquisition commission, zero [std].
The technical notes fold the whole acquisition cost into a single 6.0%-of-premium acquisition expense and give no separate commission, so
comm_rate_acqis 0 and this line exists for shape only. It is kept rather than dropped because every model in the library carries the same cash flow vocabulary.
Premium tax on the single premium, 0% on the composite state basis [std].
- inflation_factor(t)[source]#
The expense inflation factor in month t,
1.025^(t/12).A fractional power of the annual rate, so twelve months of it compound to exactly one year of inflation and the factor at each anniversary is the annual grid’s.
- expenses(t)[source]#
Insurer expenses: acquisition at issue and inflating maintenance monthly [std].
6.0% of the single premium in month 0 on a new issue, and $80 per contract per year inflating at 2.5% — one twelfth of it a month, weighted by the in-force at the start of the month. Spreading the maintenance charge is the point of the finer grid for this line: it is an insurer cost accruing continuously, not a contractual event tied to the anniversary, so it now falls where it is incurred and is weighted by survivors who have not yet left.
premiums(t)is zero everywhere but the first month, so the acquisition term simply drops out elsewhere. Both are standardizations: no retrieved document discloses FIA acquisition cost or per-contract maintenance.
- net_cf(t)[source]#
Net cash flow in month t.
The index credit, the rider charge, the surrender charge, the bonus clawback and the movement of the Model #805 floor are internal accounting entries: they drive the account value, the benefit base and the benefit amount but are never ledger lines of their own. Only amounts paid to or received from the contract holder, and the insurer’s own expenses, appear here.
- av_at(t, timing)[source]#
The in-force weighted account value in month t; see
av_pp_at().Every timing inside the month carries
pols_if(t)— the count entering it — because all processing happens before the decrements."EOY"carries the count leaving the month,pols_if(t + 1): zero at the horizon, wherepols_maturity()has taken the survivors out.
- wd_from_av(t)[source]#
The account value released by month t’s withdrawals, gross of charge and MVA.
- av_change(t)[source]#
The change in the block’s account value over month t.
Closing less opening, the opening being read at
"BEF_PREM"so that the single premium of a new issue’s month 0 is a movement rather than part of the balance brought in. Away from the first monthav_at(t, "BEF_PREM")is exactly the previous month’s closing value.
- check_av_roll_fwd_resid(t)[source]#
Account value roll-forward residual for month t; the signed float.
AV(t) - AV(0)(t) = premium in + interest credited - rider charges - withdrawals + the part of a withdrawal the account value could not fund - the account value released by each claim kind. The cash paid on a surrender may differ from the account value released — by the charge, the clawback, the MVA and any binding Model #805 floor — and that difference isclaims_over_av(), deliberately not part of this identity. It closes month by month on the finer grid, where the interest term is the month’s accrual and the claim terms are that month’s exits.The per-
tresidual is kept because it is what a debugging session wants whencheck_av_roll_fwd()returnsFalse; the boolean is defined in terms of it.
- check_av_roll_fwd()[source]#
Check the account value roll-forward:
Truewhen it closes at every projected t.No argument and a bool, following
savings.CashValue_SEand the rest of this library, so one test can call the same check across every model. The signed residual for a single month ischeck_av_roll_fwd_resid().The tolerance is absolute and loose enough for an account value of order $100,000 accumulated over a century of months; it is not a modelling assumption.
- check_pols_roll_fwd_resid(t)[source]#
In-force roll-forward residual for month t; the signed float.
pols_if(t) - pols_if(t+1) = deaths + surrenders + horizon exits. Zero to floating point for everyt, including the last,t = proj_len() - 1, wherepols_if(proj_len())is zero andpols_maturity()carries the survivors out.
- check_pols_roll_fwd()[source]#
Check the in-force roll-forward:
Truewhen it closes at every projected t.No argument and a bool, as for
check_av_roll_fwd(); the signed residual for a single month ischeck_pols_roll_fwd_resid().
- result_cf()[source]#
Result table of cashflows, indexed by the month
tfromentry_mth().The frame runs
t = entry_mth() … proj_len() - 1, one row per projected month and no issue-instant row: the first row of a new-issue model point carries the premium and the acquisition expense as beginning-of-month flows alongside that month’s own activity.result_cf_annual()sums it into contract years.pols_ifis the in-force count at the start of montht, which is the weight every cash flow on the same row carries — dividing a row’s cash flow by its per-contract amount returns this column exactly. Every withdrawal and benefit driven by the contract falls in an anniversary month, so those columns are zero in eleven rows out of twelve; deaths, surrenders and maintenance expense fall in every row.withdrawalsis the library-wide column for partial withdrawal payments and is the total; the three columns after it —wd_guar,wd_excessandincome_payments— partition that total into the notes’ own ledger categories. They are published alongside it, not instead of it, so summing every column of the frame double-counts the withdrawal.net_cfis income-positive, as everywhere in this library.
- result_pols()[source]#
Result table of in-force movements, indexed by the month t.
pols_ifopens the row andpols_if_aft_decrcloses it, and the two decrement columns are the monthly rates actually applied; the annual rates they are converted from aremort_rate()andlapse_rate(), constant across each contract year. The closing column is the opening figure of the next row in every month but the last, wherepols_maturity()takes the survivors out and the projection stops. The identitycheck_pols_roll_fwd_residasserts is thereforepols_if(t) - pols_if(t+1) = pols_death + pols_lapse + pols_maturity.
- result_av()[source]#
Result table of the per-contract account value and surrender trace, indexed by month.
The first eight columns walk the worked example’s account value rows, now month by month:
fixed_interest_ppaccrues in every row,index_credit_pp,rider_charge_ppandwd_pponly in anniversary rows. The rest are the surrender trace, available in every month rather than only at the anniversaries the notes tabulate — which is the reading a mid-year surrender needs.
- result_glwb()[source]#
Result table of the GLWB rider state per contract, indexed by the month t.
The benefit base is notional — no cash value, not withdrawable, not payable as a lump sum [S1][S9] — so none of these columns is a cash flow. They are the drivers of the rider charge, the lifetime withdrawal and, in the end, the post-depletion income. Every one of them is annual: the rider state is flat between anniversaries and steps at each one, so the rows of interest are the anniversary rows
t = 12k + 11.
- result_cf_annual()[source]#
result_cf()summed into contract years, indexed bypolicy_year.Every cash flow column is the total of its twelve months;
pols_ifis the count at the start of the contract year,pols_if(12 * duration), which is the number the annual-step model carried on the same row.Against the annual grid this agrees exactly on
pols_if,premiums,commissionsandpremium_taxes, the last three being the single premium and two rates on it. It does not agree on the withdrawal columns, the claims or the expenses, and so not onnet_cf: a withdrawal taken at the anniversary is now weighted by the contracts that reach it rather than by those that entered the year, claims fall in the month of exit, and maintenance expense accrues monthly. That gap is the point of the finer grid — see the Space docstring.