The Projection Space#
The only Space in the Term_US_A model; holds all formulas and data.
The Space is parameterized by point_id, so Projection[1] is an ItemSpace
projecting model point 1:
>>> Projection[1].result_cf() # the anchor cell
>>> 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/term_life/, read at run time rather than stored inside the
model. The model folder therefore holds nothing but formulas — no _data/, no
IOSpec, no embedded values — so a diff of the model shows logic changes only, and an
input can be edited or swapped without rewriting the model. This follows
annuallife.TradLife_A; contrast basiclife.BasicTerm_S, which keeps its inputs
inside the model through modelx’s IOSpec machinery.
The consequence worth knowing: the model is not portable on its own. Copying the
Term_US_A folder without its parent’s CSVs produces a model that reads and then
fails on first evaluation. A test asserts this by round-tripping the model together
with its inputs.
input_dir() resolves the directory from _model.path.parent at run time, so
the model works wherever the repository is checked out. Each table has a filename
Reference and a reader Cells:
Reference |
Cells |
File |
|---|---|---|
model_point_file |
data.model_point_table() |
model_point_table.csv |
premium_rates_file |
data.premium_rates() |
premium_rates.csv |
mort_table_file |
data.mort_table() |
mort_table.csv |
class_factor_file |
data.class_factor_table() |
class_factor_table.csv |
shock_lapse_file |
data.shock_lapse_table() |
shock_lapse_table.csv |
To swap in a licensed mortality basis, replace mort_table.csv with a same-schema
file, or point mort_table_file at a different name. No formula changes.
Naming
Cells names follow lifelib’s basiclife.BasicTerm_S wherever that model has an
analogue — pols_* for policy counts, plural nouns for cash flows, *_rate for
rates, *_pp for per-policy amounts. The technical notes use compact actuarial
symbols instead. The mapping is:
Notes symbol |
Cells |
Meaning |
|---|---|---|
x |
age_at_entry |
Issue age (ANB) |
x + t - 1 |
age(t) |
Attained age in policy year t |
n |
policy_term |
Level period in years |
F |
sum_assured |
Face amount |
t = 1..95-x |
proj_len |
Last policy year |
l(t) |
pols_if(t) |
In-force at start of year t |
(l(1)) |
pols_if_init |
In-force at issue |
d(t) |
pols_death(t) |
Deaths in year t |
s(t) |
pols_surv(t) |
Survivors to end of year t |
x(t) |
pols_lapse(t) |
Lapses at end of year t |
c(t) |
pols_conv(t) |
Conversions at end of year t |
(none) |
pols_maturity(t) |
Expiries at attained age 95 |
q(t) |
mort_rate(t) |
Mortality, all factors applied |
(q_base) |
mort_rate_base(t) |
Base table rate before factors |
w(t) |
lapse_rate(t) |
Lapse rate, incl. the shock |
w(n) |
shock_lapse_rate |
Shock lapse at level-period end |
cv(t) |
conv_rate(t) |
Conversion rate |
M(d) |
plt_mort_factor(d) |
PLT mortality deterioration |
M(1) |
plt_mort_factor_init |
M(1) actually used |
(M(1) rule) |
plt_mort_factor_init_formula The notes’ formula for M(1) |
|
J |
jump_ratio |
AP(n+1)/AP(n), fee included |
AP(t) |
premium_pp(t) |
Guaranteed annual premium |
G(t) |
premiums(t) |
Premium income |
K(t) |
commissions(t) |
Commission |
k(t) |
comm_rate(t) |
Commission rate |
X(t) |
premium_taxes(t) |
Premium tax |
E(t) |
expenses(t) |
Acquisition + maintenance |
DC(t) |
claims(t) |
Death claims |
CV(t) |
conv_credits(t) |
Conversion credit outflow |
NetCF(t) |
net_cf(t) |
Net cash flow |
phase(t) |
phase(t) |
LEVEL / PLT / EXPIRED |
conv_elig(t) |
conv_elig(t) |
Conversion eligibility |
Three notes on the mapping. The notes write deaths as d(t) while also using d
as the post-level-term duration index in M(d); the pols_death / plt_mort_factor
split removes that collision. The notes’ x(t) (lapses) and X(t) (premium tax)
differ only by case, which pols_lapse and premium_taxes separate. And
pols_maturity has no symbol in the notes at all — see below.
pols_maturity
The notes give the roll-forward as l(t+1) = l(t)(1-q)(1-cv)(1-w) and, separately,
the rule l(t) = 0 for x+t-1 >= 95. Those do not reconcile in the final policy year:
its survivors neither die, lapse nor convert — their coverage simply runs out. Without
a term for that, the roll-forward appears to lose lives with no cause.
pols_maturity(t) names it, zero in every year but the last, so that
pols_if(t) - pols_if(t+1) = pols_death(t) + pols_lapse(t) + pols_conv(t) + pols_maturity(t)
holds for every t. It is bookkeeping determined by the notes’ own rules, not an
added assumption. The name follows BasicTerm_S.pols_maturity.
Cells Descriptions#
Guaranteed annual gross premium per policy in year t, policy fee included.
- plt_mort_factor_init_formula()[source]#
The notes’ rule for M(1): min(8.0, 1 + 0.55*(J-1)) [std].
Returns 3.4514 for the anchor cell, where the worked example uses 3.50. Not used unless the model point leaves plt_mort_factor_override blank.
- plt_mort_factor_init()[source]#
M(1) actually used: the model point’s override if given, else the formula.
- plt_mort_factor(d)[source]#
Post-level-term mortality deterioration at PLT duration d; grades to 2.00 [std].
- lapse_rate(t)[source]#
Lapse rate in policy year t [std], including the shock at the level-period end.
Level period: 6%, 5%, 4% for years 3..n-2, 6% anticipatory at n-1, shock at n. Post-level term: 30%, 15%, then 10%.
- pols_surv(t)[source]#
Number of policies surviving to the end of year t, before voluntary decrements.
- pols_maturity(t)[source]#
Number of policies whose coverage ends at attained age 95.
Non-zero only in the final policy year. Not a decrement - the contract runs out - but needed for the in-force roll-forward to close; see the Space docstring.
- comm_rate(t)[source]#
Commission rate [std]: 80% in year 1, 5% to the end of the level period, 2% after.
Premium income in policy year t, at the beginning of the year.
Premium tax in policy year t [std].
- expenses(t)[source]#
Acquisition (year 1) and inflating maintenance expenses in policy year t [std].