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#

model_point()[source]#

The selected model point as a Series.

age_at_entry()[source]#

The issue age (ANB) of the selected model point.

sex()[source]#

The sex of the selected model point.

rate_class()[source]#

The underwriting class of the selected model point.

plan()[source]#

The plan code of the selected model point (T10 / T20 / T30).

sum_assured()[source]#

The face amount of the selected model point.

pols_if_init()[source]#

Initial number of policies in-force.

band()[source]#

Face-amount band 1-4 [std]; the anchor cell is band 1.

policy_term()[source]#

The level premium period in years, from the plan code.

proj_len()[source]#

Projection length in policy years: coverage ends at attained age 95.

age(t)[source]#

The attained age at the start of policy year t.

premium_pp(t)[source]#

Guaranteed annual gross premium per policy in year t, policy fee included.

jump_ratio()[source]#

Initial premium jump ratio premium_pp(n+1)/premium_pp(n), 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].

class_factor()[source]#

Underwriting-class multiplier on the base mortality table [std].

mort_rate_base(t)[source]#

Base-table mortality rate at the attained age in policy year t.

mort_rate(t)[source]#

Mortality rate applied in year t: base x class factor x PLT deterioration.

shock_lapse_rate()[source]#

Shock lapse at the end of the level period, by jump-ratio bucket [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%.

conv_elig(t)[source]#

True while convertible: within the level period and attained age below 70.

conv_rate(t)[source]#

Conversion rate in policy year t [std]; zero outside the eligibility window.

phase(t)[source]#

LEVEL, PLT or EXPIRED in policy year t.

pols_if(t)[source]#

Number of policies in-force at the start of policy year t.

pols_death(t)[source]#

Number of deaths occurring in policy year t.

pols_surv(t)[source]#

Number of policies surviving to the end of year t, before voluntary decrements.

pols_conv(t)[source]#

Number of conversions at the end of policy year t.

pols_lapse(t)[source]#

Number of lapses at the end of policy year t, including the shock lapse.

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.

inflation_factor(t)[source]#

The expense inflation factor in policy year t.

premiums(t)[source]#

Premium income in policy year t, at the beginning of the year.

commissions(t)[source]#

Commission in policy year t [std].

premium_taxes(t)[source]#

Premium tax in policy year t [std].

expenses(t)[source]#

Acquisition (year 1) and inflating maintenance expenses in policy year t [std].

claims(t)[source]#

Death claims incurred in policy year t, paid at the end of the year.

conv_credits(t)[source]#

Conversion credit outflow: one annual premium per conversion, after year 1.

net_cf(t)[source]#

Net cash flow in policy year t.

result_cf()[source]#

Result table of cashflows.