The Projection Space#
The by-policy projection of the EC_FR_S model.
The Space is parameterized by point_id, so Projection[1] is an ItemSpace
projecting model point 1:
>>> Projection[1].result_provisions() # the worked example, Chassis A
>>> Projection.point_id = 2 # Chassis B, same asset path
The time index
t counts policy months, 0-based, the clock basiclife.BasicTerm_S and the five
monthly models of this library run on: t = 0 is the issue month, month t runs
from time t to time t + 1, and the frame is
range(proj_start(), proj_len()) with proj_len() = 12 x policy_term() the
number of policy months projected — 120 on the worked example’s ten-year term. Its
last row, proj_len() - 1, is the month that ends at the échéance. A new-business
cell opens at proj_start() = 0, where the initial versement net of the entry charge
creates the rights and the two provisions are first struck — that is the opening
state of month 0, reached as own_assets_at(0, "BOM") and its siblings, and not a row
of its own. An in-force cell opens at proj_start() = 12 x duration_ifo: elapsed time
is recorded in whole policy years, so the frame always opens in the first month of a
policy year (shipped point 7 at t = 48), where the extract’s assets, parts and
guaranteed amount are seeded and the provision mathématique is re-derived rather than
read.
Everything contractual about this product is nevertheless on an annual cycle, so the
policy year is derived and used as a lookup key throughout: duration(t) = t // 12 is
the completed policy years at the start of month t, policy_year(t) = duration(t) +
1 is the contractual 1-based label, and the attained age is age(t) = issue_age() +
duration(t), stepping on the anniversary rather than on the birthday. The anniversary
is the last month of a policy year, is_anniv(t), t ≡ 11 (mod 12). The frame is
indexed by t; the policy year is never indexed by.
A handful of cells are indexed by a month boundary m rather than by a month:
m = 0 at issue and m = 12 n at the échéance, and rem_term(),
tec_rate(), i_pm() and disc_factor() are of that kind, so month t
reads them at t for its opening and at t + 1 for its end-of-month striking.
rem_term(m) = (proj_len() - m) / 12 is the remaining term in years, fractional
between anniversaries.
Two speeds: annual assumptions on a monthly grid
The two-speed structure that follows is the library’s convention, asserted by
tests/test_model_conventions_fr.py. mort_rate(t), lapse_rate(t),
wd_rate(t) and asset_return(t) are the annual rates of the policy year
containing month t — the vectors the technical notes tabulate — and
mort_rate_mth(t), lapse_rate_mth(t), wd_rate_mth(t) and
asset_return_mth(t) are the rates actually applied in the month:
1 - (1 - q)^(1/12) for a decrement and (1 + r)^(1/12) - 1 for a return, so twelve
compound back to exactly the annual figure.
A monthly grid is not a monthly product. Every contractual mechanic stays where the contract puts it: the R. 134-3 base 4° parts levy and a scheduled versement in the first month of a policy year; the striking of the compte de participation aux résultats and with it the base 5° performance levy, a free versement and the R. 134-12 apport d’actifs on the anniversary. What the finer grid adds is what A. 134-5 already required and the annual grid could not express: the intermediate re-striking of the diversification provision in every month in which the participation account is not struck, a forward part value for an exit, mortality and rachat falling in the month they happen, and maintenance expense accruing where it is incurred.
Anniversary equivalence, and the three places it does not hold
Because the monthly decrements and the monthly return compound back to the annual ones,
because the twelve monthly invest_income sum to the year’s A_a r where no cash
moves inside the year, and because the parts levy and the top-up land at the same instant
on both grids, every anniversary-dated value is what the annual-step model this one
replaced carried on the corresponding row — own_assets, pm, prov_div,
parts, part_value, mg, cum_prem_net, insurer_contribution, pgt,
pcdd, provision_value, surrender_value, death_value, death_payout,
maturity_value, conversion_headroom, gate_revalue_ok, parts_levy and
perf_levy at t = 12k + 11, and pols_if at t = 12k. Measured against a
pre-conversion snapshot of all eleven shipped model points, the largest absolute
difference is 1.3e-10 EUR on figures of order 10,000.
Three things do not reproduce, and each is the point of the exercise rather than a defect:
the cash flows, which now fall where they happen — a claim at the end of the month of exit rather than of the year, a versement in its own month;
expenses(), where maintenance now accrues at one twelfth a month on the month’s own provision and in-force, and the annual grid’s extra opening-striking charge is gone: -0.2% to -1.3% over a whole projection on the shipped cells, and +0.9% on point 9, whose annual versements step the provision up at the start of each of its first five years;on a cell with
wd_factor > 0— shipped point 5 alone — the asset-fed values, becausewd_rate_mth()spreads the rachat partiel instead of taking it all at the start of the year, so more capital earns return early:own_assetsat the anniversaries runs 0.21 to 3.05 EUR above the annual model’s, at most 0.031%,part_valueat maturity is 25.097 against 25.0768, and total rachats are 0.23% higher. What still matches exactly there is everything whose run-down is purely multiplicative —mg,cum_prem_net,pm,partsandpols_if— because(1 - w_pm)^12 = 1 - w_p.
Input data
Inputs are external files: plain CSVs living in the model folder’s parent
directory, products/eurocroissance/, 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
EC_FR_S folder without its parent’s CSVs produces a model that reads and then fails
on first evaluation.
Each table has a filename Reference and a reader Cells, both on Data,
reached here through the data Reference:
Reference |
Cells |
File |
|---|---|---|
model_point_file |
data.model_point_table() |
model_point_table.csv |
mort_table_file |
data.mort_table() |
mort_table.csv |
lapse_table_file |
data.lapse_table() |
lapse_table.csv |
scenario_table_file |
data.scenario_table() |
scenario_table.csv |
tec_curve_file |
data.tec_curve() |
tec_curve.csv |
Naming
Cells names follow lifelib’s basiclife.BasicTerm_S wherever that model has an
analogue — pols_* for policy counts, plural nouns for cash flows, *_rate for
annual rates and *_rate_mth for the monthly ones derived from them, *_pp for
per-policy amounts, claims(t, kind) and claim_pp(t, kind)
with an uppercase kind string, and the duration_mth / duration /
policy_year triple the other monthly models of this library carry. The technical
notes use compact symbols instead. The mapping is:
Notes symbol |
Cells |
Meaning |
|---|---|---|
engagement_modality |
chassis() |
euro_and_parts or parts_only |
(the 1° test) |
is_euro_leg() |
True on Chassis A |
t |
(the cells argument) |
Policy month, 0-based |
m |
(the cells argument) |
Month boundary, m = 0 at issue |
(none) |
duration_mth(t) |
Months elapsed at BOM, = t |
dur(t) |
duration(t) |
Completed policy years, t // 12 |
y |
policy_year(t) |
Policy year of month t, dur + 1 |
(the anniversary) |
is_anniv(t) |
True where t % 12 == 11 |
(the anniversary) |
anniv_mth(t) |
Month that ends that policy year |
n - m/12 |
rem_term(m) |
Remaining term in years, at m |
x |
issue_age() |
Entry age (âge atteint) |
x + dur(t) |
age(t) |
Age entering the policy year |
x + dur(t) + 1 |
age_anniv(t) |
Age attained at the anniversary |
duration_ifo |
duration_inforce() |
Completed years at valuation |
(none) |
proj_start() |
First projected month, 12 x above |
n |
policy_term() |
Years to the échéance |
(none) |
proj_len() |
Months projected, = 12 n |
g |
guarantee_rate() |
Share of net versements guaranteed |
P_0 |
premium_initial_pp(t) |
Initial versement, opening state |
P_net,0 |
prem_init_after_charge() |
Net of the R. 134-3 1° charge |
P(t) |
premium_gross_pp(t) |
Scheduled versement, BOM of a year |
P_net(t) |
prem_after_charge_pp(t) |
Net of the R. 134-3 1° charge |
(free versement) |
premium_top_up_gross_pp(t) |
Free versement, on the anniversary |
(free versement, net) |
premium_top_up_net_pp(t) |
Net of the entry charge |
f_e |
entry_charge_rate() |
Entry charge, base 1° |
f_p |
parts_charge_rate() |
Parts levy p.a., base 4° |
f_perf |
perf_charge_rate() |
Performance levy, base 5° |
f_x |
exit_charge_rate() |
Exit charge, base 6° |
(indemnity) |
surrender_indemnity(t) |
|
mg(t) |
mg(t) |
Guaranteed amount at n |
(the steps) |
mg_at(t, timing) |
mg inside month t |
(versement split, BOM) |
parts_added_bom(t) |
Parts a BOM versement buys |
(versement split, anniv) |
parts_added_top_up(t) |
Parts the free versement buys |
(cumulative net premiums) |
cum_prem_net(t) |
Death-floor base |
(opening) |
cum_prem_net_at(t, “BOM”) |
Its opening value |
TEC(rem) |
tec_rate(m) |
Interpolated TEC at boundary m |
i_pm(m) |
i_pm(m) |
90% of TEC, floored at zero |
(discount factor) |
disc_factor(m) |
(1 + i_pm(m))^-rem_term(m) |
r(t) |
asset_return(t) |
Annual asset return of the year |
r_m(t) |
asset_return_mth(t) |
(1 + r)^(1/12) - 1, the month’s |
A(t) |
own_assets(t) |
Account assets, excluding C(t) |
(the steps) |
own_assets_at(t, timing) |
The asset roll inside month t |
pm(t) |
pm(t) |
Provision mathématique |
(opening, pre-versement) |
pm_at(t, timing) |
PM opening and at the striking |
pd(t) |
prov_div(t) |
Provision de diversification |
(opening, pre-versement) |
prov_div_at(t, timing) |
PD opening and at the striking |
N(t) |
parts(t) |
Number of parts |
(the steps) |
parts_at(t, timing) |
Parts inside month t |
u(t) |
part_value(t) |
Valeur de la part |
(opening, pre-versement) |
part_value_at(t, timing) |
u opening and at the striking |
u_min |
min_part_value() |
Contractual floor on u |
L(t) |
parts_levy(t) |
Levy at the BOM of a year, base 4° |
I(t) |
invest_income(t) |
Financial performance of month t |
(year to date) |
invest_income_ytd(t) |
I accumulated since the year opened |
F(t) |
perf_levy(t) |
Anniversary levy, base 5° |
(entry) |
entry_charge(t) |
Base 1° charge on a versement |
C(t) |
insurer_contribution(t) |
|
G(t) |
pgt(t) |
Provision pour garantie à terme |
D(t) |
pcdd(t) |
Provision collective de div. différée |
(apport d’actifs) |
apport(t) |
|
(A. 134-3 tests) |
gate_revalue_ok(t) |
Whether a revaluation is permitted |
(A. 134-4 headroom) |
conversion_headroom(t) |
Parts convertible into PM |
(surrender base) |
provision_value(t) |
pm(t) + pd(t) |
(opening) |
provision_value_at(t, “BOM”) |
Its opening value |
surrender_value(t) |
surrender_value(t) |
|
death_value(t) |
death_value(t) |
The current provision value |
death_payout(t) |
death_payout(t) |
After any garantie décès plancher |
rider_claim(t) |
rider_claim_pp(t) |
The floor’s cost, outside the account |
maturity_value(n) |
maturity_value(t) |
|
(payouts) |
claim_pp(t, kind) |
Payout per claim by kind |
q(x+dur(t)+1) |
mort_rate(t) |
Annual mortality rate |
q_m(t) |
mort_rate_mth(t) |
The monthly rate actually applied |
w(t) |
lapse_rate(t) |
Annual full surrender rate |
w_m(t) |
lapse_rate_mth(t) |
The monthly rate actually applied |
(table) |
lapse_rate_base(t) |
Table full surrender rate |
(partial rachat) |
wd_rate(t) |
Annual partial surrender rate |
w_pm(t) |
wd_rate_mth(t) |
The monthly rate actually applied |
(partial rachat) |
wd_pp(t) |
Partial surrender paid |
(partial rachat, gross) |
wd_gross_pp(t) |
Taken from the provision |
(none) |
pols_if(t) |
In force at the start of month t |
l(t) |
pols_if_at(t, “AFT_DECR”) |
In force at the end of month t |
(none) |
pols_if_at(t, timing) |
BEF_DECR / BEF_LAPSE / AFT_DECR |
(none) |
pols_death(t) |
Deaths in month t |
(none) |
pols_lapse(t) |
Full surrenders in month t |
(none) |
pols_maturity(t) |
Survivors reaching the échéance |
(cash flows) |
premiums, claims, withdrawals |
Probability-weighted flows |
E(t) |
expenses(t) |
Acquisition and maintenance |
charges_taken(t) |
charges_taken(t) |
Insurer income, reported apart |
CF(t) |
liability_cf(t) |
The notes’ outgo-positive stream |
(none) |
net_cf(t) |
Its negative, income positive |
(none) |
model_point() |
The selected row as a Series |
(none) |
result_cf_annual() |
result_cf() summed into years |
result_cf_annual() is the frame regrouped, never a second projection: every cash
flow column is the total of its twelve months and pols_if is the count entering the
policy year. It exists so the annual-step model this one replaced can be laid beside this
one row for row — pols_if and premiums agree on it exactly, and expenses and
the claim columns deliberately do not.
Nine names needed care.
pols_if is the count at the start of month t — the exposure every cash flow
on that same result_cf() row is weighted by — so result_cf()["pols_if"].iloc[0]
is pols_if_init() on every model point. This model first published the notes’ own
l(t), the count at the end of the period, under that name, which put the exposure
column one period ahead of the flows beside it: a reader dividing claims_death by that
row’s pols_if to recover a per-policy payout got a stale answer, and nothing
raised. The end-of-period quantity survives unchanged and unrenamed in substance — it is
now reached as ``pols_if_at(t, “AFT_DECR”)``, the CashValue_SE timing form this
library uses for every other intra-period state — and every number in result_cf()
except the pols_if column is what it was before the change. The notes, model.md
and the test module index l(t) the same way.
The *_at(t, timing) cells open on ``”BOM”``, the beginning of the month. It was
"BOY" while the step was a policy year and moved with the grid; the retired spelling
raises rather than being silently accepted, which is the cheapest guard against a
half-finished conversion. The other timings — "AFT_LEVY", "AFT_EXIT",
"AFT_PREM", "AFT_RETURN", "AFT_PERF", "AFT_STRIKE", "AFT_TOP_UP",
"BEF_DECR", "BEF_LAPSE", "AFT_DECR" — are unchanged, because they name a step
of the recursion rather than a length of time.
parts_added_bom and parts_added_top_up are the two versement splits, named for
where they land rather than for BOY and EOY. They are two different rules, not one
rule at two times: the first prices at the opening part value and splits at
disc_factor(t), the second prices at the part value just struck and splits at
disc_factor(t + 1).
age is the age entering the policy year of month t and age_anniv the age
attained at the anniversary that closes it. The mortality assumption is read at
age_anniv, which is the notes’ q(x + t + 1): the age rule belongs to the annual
assumption and moving it to the entering age would shift every decrement by a year of age
and break the anniversary equivalence outright. age is published anyway, because the
library’s monthly vocabulary expects it and because the âge atteint convention is stated
on it.
pm_ifo appears in the notes’ model point attribute table but is not an input the
projection reads. The provision mathématique is re-struck from mg and the current
i_pm every month, so an in-force cell that supplied one would be asserting a number
the rule already determines. The column is shipped and check_pm_restruck() compares
it against the re-strike — which is how a reader discovers that an extract was built by
accumulating the PM instead.
lapse_rate is the full surrender (rachat total) and wd_rate the partial
one (rachat partiel). They are different events with different consequences: a full
surrender removes the policy, a partial one runs the guarantee, the parts and the assets
down pro rata and leaves the contract in force. Sharing one name would have merged a
decrement with an owner election.
wd_gross_pp and wd_pp differ by the base 6° exit charge — what leaves the
provision and what reaches the saver. Both are needed, because the provision run-down
keys off the gross amount and the cash flow off the net one.
provision_value is pm + pd, the base of R. 134-5 and R. 134-6. It is the same
expression on both chassis because pm is identically zero on Chassis B, so the
surrender and death rules are one formula rather than two.
pd is the one notes symbol this model could not keep. pd is pandas in every
model in this library, and shadowing it inside the one Space that has to build a
DataFrame is not worth a two-letter symmetry, so the provision de diversification is
prov_div() here while the provision mathématique keeps pm(), whose symbol
was free. The displayed formulas below stay in the notes’ notation; the table above is
what maps them.
There is no av_pp_at in this model. A eurocroissance engagement is not an account
value: the saver’s rights are a number of parts whose value is common to every
engagement of the auxiliary account, plus — on Chassis A — a share of a provision
mathématique that is a discounted promise rather than a fund. Naming either of them the
library’s account value would assert something false about the contract.
The provision mathématique is re-struck, never accumulated
pm(t) = mg(t) (1 + i_pm(t+1))^-rem_term(t+1) Chassis A
pm(t) = 0 Chassis B
pm(t) is the closing PM of month t, struck at its month end — boundary t + 1,
where the remaining term is the fractional (12n - t - 1)/12 years. i_pm(m) is
90% of the TEC, floored at zero
(A. 134-1), read here at the remaining maturity — a [std] reading of the
article’s index maturity, which tec_rate() sets out. It is not the A. 132-1
maximum technical rate and not the
A. 132-3 guaranteed rate ceiling, which are different and stricter objects. Rolling pm(t-1) forward at
last year’s rate would silently remove the rate effect: in the notes’ worked example
that is +587.44 of the +824.18 move over policy year 6, t = 59 to t = 71, against
a time effect of only +236.74.
The monthly re-strike is a decision, and it is [std]. R. 134-2 defines the PM as the
guaranteed amount discounted at the A. 134-1 rate, a definition with a value at every
instant; A. 134-5 requires the diversification provision to be re-struck at an
intermediate value at least monthly, which on Chassis A is impossible without a PM for the
residual to be taken against. Holding the PM flat between strikings would make it a step
function and push a year of time effect onto the anniversary, so the intermediate part
value would be wrong in exactly the direction A. 134-5 exists to prevent. It is the same
article being read at a finer frequency as the n - k remaining-term reading, and it is
recorded in the same paragraph of the notes. It also makes
check_guarantee_funding() hold month by month rather than only at anniversaries.
The finer grid splits the policy-year-6 move in two, which the annual grid could not: the
PM accretes from 10,541.34 at t = 60 to 10,738.63 at t = 70 at the unchanged 2.25%
— the time effect — and jumps to 11,346.00 at t = 71, where the TEC curve is
re-published at 1.00% — the rate effect, +607.37 in one month. The year-on-year
+236.74 / +587.44 decomposition is unchanged.
At the échéance the discount factor is 1, so pm(12n-1) = mg(12n-1) identically and
the Chassis A guarantee is pre-funded by construction. check_guarantee_funding()
asserts it at every t, and it is the model’s headline check.
The monthly re-striking and the annual participation account
L(t) = f_p pd_open(t) 1{t % 12 == 0} A_a = A_open(t) - L(t) - W(t) + P_net(t)
I(t) = A_a r_m(t) F(t) = f_perf max(I_ytd(t), 0) 1{is_anniv(t)}
A(t) = A_a + I(t) - F(t) N(t) = N_open(t)(1 - f_p 1{BOM})(1 - w_pm) + ...
pd(t) = max(A(t) - pm(t), N(t) u_min) u(t) = pd(t)/N(t)
C(t) = max(pm(t) + pd(t) - A(t), 0)
A_open(t) is own_assets_at(t, "BOM") and its siblings: A(t-1) in every month
but the first projected one, and in that one the state the initial versement — or the
in-force extract — creates. That is where the issue instant lives; it is not a row of the
frame.
Two of the six R. 134-3 bases keep an annual rhythm inside this monthly recursion, and
for two different reasons. The base 4° levy L(t) falls in the first month of each
policy year because product-spec.md states it taken there on the opening part value:
it is a contract term, not an assumption, and spreading it would change the cash it takes
even though the parts count would compound back. The base 5° levy F(t) falls on the
anniversary on the year’s accumulated performance I_ytd because R. 134-3 5° is a levy
on the balance of the participation account and R. 134-4 strikes that account at least
annually; a monthly levy would tax a positive month inside a losing year, which the
asymmetric max(., 0) exists not to do, and would have taken money in policy year 6. A
policy exiting between anniversaries therefore pays no performance levy for the part year,
which is what the article’s annual striking implies.
The diversification provision takes the residual and stops at the parts’ contractual
floor. Where the floor binds, the two provisions together exceed the assets, and the
excess is exactly C(t) — the contribution the insurer must make under L. 134-3 to
complete the representation. The surrender value therefore exceeds the account’s own
assets by exactly ``C(t)`` while the contribution is outstanding: at the anniversary of
the notes’ policy-year-6 shock, month t = 71, 12,384.73 paid against assets of
10,250.65. The monthly grid says when that starts, which the annual grid could not: the
part-value floor first binds in month 66, and the contribution starts there at 141.96
and climbs to 2,134.08 by the anniversary.
C(t) carries no return to the savers: own_assets() rolls forward from
A(t-1), not from pm(t-1) + prov_div(t-1). Rolling the topped-up balance forward would
manufacture investment return out of the insurer’s capital, and the shipped worked
example is the case that catches it — the policy-year-7 asset roll, month t = 72,
starts from 10,250.65 and not from 12,384.73.
The Chassis B surrender value is not guaranteed
This is the single most important product fact. Before the échéance a 2° engagement
pays parts × part value and nothing else (R. 134-5). The guarantee bites only at
the échéance — the end of the last projected month, t = proj_len() - 1 — and only
there does maturity_value() take max(parts × u, mg). At the anniversary of the
notes’ policy-year-6 shock, month t = 71, Chassis B surrenders for 9,899.22 —
84.18% of
net versements against a guarantee of 11,760.00. An implementation that floors the
surrender value at the guarantee, or at the discounted guarantee, is modelling a contract
that does not exist. check_own_funds_not_paid() asserts that no benefit before the
term exceeds the two provisions.
The monthly grid makes the same point sharper, and honours A. 134-5 in doing so: a saver surrendering in month 65 receives 11,430.63, the striking of the month the request falls in, and not the 9,899.22 the anniversary reports. That is the forward part value the article requires, and delivering it is the one place this conversion removes a documented simplification rather than adding one.
The shortfall against the guarantee is carried instead as the provision pour garantie à
terme, pgt() — the insurer’s own funds, computed per auxiliary account on the
A. 132-18 tables at a rate at most 90% of the TEC, counting no cash flows other than
guarantee maturities and mortality. It sits outside the participation account, it is
not part of any benefit, and a model must not “improve” its deliberately narrow basis by
adding lapses or expenses to it. Of the article’s two admitted drivers this model
implements only the guarantee maturity: pgt() applies no survival factor, a
prudent [std] simplification that the cells docstring quantifies. Struck monthly like
everything else, it shows the provision being constituted: on the worked example’s
Chassis B it first becomes positive in month 68, at 61.48, and reaches 1,446.78 by the
anniversary at month 71.
The death benefit is not the maturity guarantee
Chapter IV of the regulatory part contains no death valuation article. The death benefit
is the current provision value, and any garantie décès plancher is a complementary
guarantee provisioned outside the auxiliary account (R. 134-7). death_payout()
therefore floors the payout at cumulative net versements where the model point elects
the rider, and rider_claim_pp() reports the difference separately — 1,860.78 on the
notes’ policy-year-6 Chassis B death at month t = 71, which is not the account’s money.
The charge bases are not interchangeable
R. 134-3 permits six bases and no others, and base 3° — a levy on the encours of the
diversification provision — is available only in an auxiliary account holding no 1°
engagements. No base permits a levy on the provision mathématique at all. The recurring
charge here is therefore base 4°, a levy in number of parts: parts_levy() is
f_p × prov_div_at(t, "BOM") in the first month of each policy year, and
parts_at() cancels f_p of the parts there and nothing in the other eleven
months. On the worked example’s Chassis A that is 15.64 opening policy year 1,
t = 0. An encours
levy on pm + pd would have been 78.40 — five times as much, and unlawful in a 1°
account.
Behaviour, and what is not modelled
All dynamic shapes are [std]: no eurocroissance lapse experience is public and the product is too small and too young to have any. Three overlays sit on the base full surrender rate:
a guarantee-imminent suppression of 0.5 over every month of the two policy years before the échéance on Chassis B, and only while the guarantee is in the money — a saver who surrenders in that state gives up the entire guarantee, which is the strongest exit deterrent the product creates. The in-the-money test is read on the current month’s striking, which is what the behavioural statement says and which on every shipped model point agrees with the anniversary reading in every month;
a duration-8 spike of 1.5 over policy year 8 where
n > 8, because the assurance-vie annual abattement becomes available at eight years; anda lock-up, where
lock_up_years > 0bars surrender entirely, the L. 132-23 hardship exits not being separately modelled.
All three are multipliers on the annual rate, applied before the monthly conversion,
so each grades once a year as the behaviour it stands for does and not once a month. The
non-surrender period and the échéance-year exclusion are likewise read on
duration(t), not on the month, so the monthly grid opens no month the annual grid
closed.
Out of scope, and held at zero or absent by design: the PCDD piloting rule (run the
fund at 30 bp above the insurer’s own euro fund and carry the rest to the PCDD) and the
PCDD’s release back into the participation account — pcdd() accumulates the
R. 134-12 apport d’actifs and nothing else; the conversion of parts into PM under
A. 134-4, whose headroom conversion_headroom() computes without exercising; the
revaluation of guarantees out of the participation account, whose two A. 134-3 gates
gate_revalue_ok() tests without exercising; the rente viagère option at the
échéance, which annuity_option_flag() rejects by name; and the statutory
arbitrage into an SRI ≤ 2 support that A. 134-6 makes the maturity default.
What a single-policy model cannot say
The part value, the PCDD, the PGT and the apport d’actifs are all account-level quantities. The part value in particular is common to every engagement of an auxiliary account, so savers with different maturities and different guarantee levels in one account earn the same rate and differentiation is possible only through the number of parts. A per-policy model can only approximate that, and the mémoire records that pooling two maturity cohorts in one account produces no mutualisation benefit at all. Model points 1 and 2 are two separate accounts on the same asset path, and their part values duly diverge; two engagements of one account would not.
The deterministic single scenario is the other limit. The maturity guarantee is a put on the auxiliary account, its cost is convex in the asset shock and in the level of rates, and a deterministic run understates it. What this model produces is exactly the per-scenario cash flow vector a market-consistent stochastic valuation consumes.
Cells Descriptions#
- chassis()[source]#
euro_and_parts(1° engagement) orparts_only(2° engagement).L. 134-1 defines exactly these two modalities, and R. 134-2 to R. 134-6 give each of them its own provision structure, surrender value and maturity amount. A value outside the pair is a data error and raises rather than defaulting to one of them.
- is_euro_leg()[source]#
True on Chassis A, the 1° engagement that carries a provision mathématique.
On Chassis B
pmis identically zero, the whole engagement is expressed in parts, and the guarantee is carried by the insurer’s own funds until the échéance.
- issue_age()[source]#
x: the entry age of the model point, âge atteint (age last birthday) [std].
A. 335-1 applies the homologated tables with the annexed décalages d’âge rather than fixing a model age basis, so the basis is a standardization.
- sex()[source]#
The sex (M / F) of the model point.
A. 132-18 requires the mortality basis to be by sex, so the decrement table is sex-distinct even though the tariff itself may not be.
- policy_term()[source]#
n: the years from issue to the échéance, at which the guarantee is payable.
The retrieved market range is 8 to 40 years; the worked example uses 10.
- duration_inforce()[source]#
Completed policy years at the valuation date; 0 on a new-business cell.
An in-force cell is seeded from its extract’s assets, parts and guaranteed amount and carries no accumulated provision mathématique — see
pm_init().
- guarantee_rate()[source]#
g: the share of cumulative net versements guaranteed at the échéance.
100% in the worked example; the retrieved market range is 80% to 100%, chosen by the saver. This is the product’s single largest dial: it sets how much of the account is locked into the guaranteed leg and therefore how much of it can bear risk.
The initial gross versement paid at issue; nil on an in-force cell.
The scheduled annual gross versement paid at the start of each policy year.
Zero on a single-versement cell, which is the ordinary eurocroissance shape.
The number of policy years over which the scheduled versement is paid.
The free additional gross versement, paid at the end of a stated policy year.
The worked example’s is €2 000.00 at the end of policy year 3, and it is what makes the versement split rule visible: paid immediately after the year’s striking, it buys parts at the part value just struck and raises the guaranteed amount by
gtimes its net amount.
The policy year at whose end the free additional versement is paid; 0 if none.
- entry_charge_rate()[source]#
f_e: the entry charge on each versement, R. 134-3 base 1° [std].
2.00% in the reference configuration; 4.50% is the only published maximum retrieved for any eurocroissance support. It is deducted before rights are created, which is why the guarantee is a percentage of net versements — see
mg().
- parts_charge_rate()[source]#
f_p: the recurring levy in number of parts p.a., R. 134-3 base 4° [std].
0.80% p.a., taken at the start of the policy year on the opening part value. Base 4° is a levy in number of parts, not on an encours: R. 134-3 3° permits an encours levy only in an auxiliary account holding no 1° engagements, and no base permits any levy on the provision mathématique.
- perf_charge_rate()[source]#
f_perf: the levy on positive financial performance, R. 134-3 base 5° [std].
10% of the policy year’s positive financial-management performance, taken on the anniversary, and nothing at all on a negative one — which is why the worked example’s policy-year-6 performance levy, at month
t= 71, is zero.
- exit_charge_rate()[source]#
f_x: the exit charge on amounts leaving the account, R. 134-3 base 6° [std].
Zero in the reference configuration — the code permits it and neither retrieved insurer shows one.
- surrender_indemnity_rate()[source]#
The indemnité de rachat rate on a full surrender [std].
Zero in the reference configuration. R. 132-5-3 caps it at 5% of the present value of the mutual engagements and permits the contract to charge none at all once it has been in force more than ten years — a permission, not a prohibition.
surrender_indemnity()takes that permission up unconditionally [std].
- part_value_init()[source]#
u(0): the valeur de la part at the auxiliary account’s inception.
€10.0000 in the reference configuration. It is a denomination rather than an assumption: what matters is the ratio of the part value to its floor, since that is how far the diversification provision can fall before the floor binds.
- min_part_value()[source]#
u_min: the contractual minimum valeur de la part, R. 134-1 [std].
€5.0000 in the reference configuration, and nowhere published for any insurer. A debit balance on the participation account may reduce the part value only within the limit of its minimum (R. 134-4), so this level sets the floor of the diversification provision — and therefore both the Chassis A maturity payout and the point at which the insurer must start contributing assets. Without it the worked example’s Chassis A
prov_divwould go to -1,095.35 at the anniversary of policy year 6,t= 71.
- lock_up_years()[source]#
The non-surrender period in years; capped at
min(n, 8)by R. 134-5.Zero in the reference configuration. The L. 132-23 hardship exits are not separately modelled [std].
- death_floor_flag()[source]#
Whether the model point carries a garantie décès plancher.
A complementary guarantee provisioned outside the auxiliary account (R. 134-7), floored at cumulative net versements. It is not the maturity guarantee and does not become payable because the saver died before the échéance.
- annuity_option_flag()[source]#
Whether the model point elects conversion into a rente viagère at the échéance.
R. 134-6 permits it, and it is out of scope here: an annuity conversion needs the TGH05 / TGF05 generational tables, which are cited by arrêté and never shipped, and a projection that continues past the échéance. No shipped model point elects it, and a cell that did raises rather than being paid a lump sum in silence.
- wd_factor()[source]#
The multiplier on the table partial-surrender rate; 0 switches rachats partiels off.
The worked example takes none, which is what lets its provision path be read as the cash flow path.
- apport_rate()[source]#
The R. 134-12 apport d’actifs, as a fraction of the diversification provision.
Capped at 10% by the article. It enters the auxiliary account at realisation value and endows the PCDD; it is never credited to the savers’ diversification provision, and switching it on changes no policyholder value by one cent.
- decrement_basis()[source]#
tableornone: whether mortality and full surrender are applied.noneis not a modelling shortcut but the worked example’s stated configuration: withmort_rate = 0andlapse_rate = 0the in-force probability stays at 1 and the per-policy provision path is the cash flow path, which is what makes the notes’ two tables readable as provisions rather than as expected values.
- scenario()[source]#
The asset-return path and TEC curve the model point runs on.
Both the return and the discount curve are drawn from the same scenario name, because the two move together: the policy-year-6 double shock in the worked example — months
t= 60 to 71, equities down and rates down at once — is what makes the rebalancing visible, and pairing an equity fall with an unchanged curve would understate the provision mathématique by the whole rate effect.
- own_assets_init()[source]#
A: the auxiliary-account assets attributable to the policy at the valuation date.
At realisation value (R. 134-8) and excluding any outstanding insurer contribution, which is not the savers’ money. Zero on a new-business cell, where
own_assets()seeds from the initial net versement instead.
- pm_init()[source]#
The provision mathématique the in-force extract reports; not an input.
It is read by
check_pm_restruck()alone. R. 134-2 makes the PM the guaranteed amount discounted at the current A. 134-1 rate, so an extract cannot supply it and a projection cannot roll it forward — it is re-derived every year, and comparing the two is how a reader discovers an extract built by accumulation.
- cum_prem_net_init()[source]#
The cumulative net versements at the valuation date: the death-floor base.
- proj_start()[source]#
The first projected month:
12 x duration_inforce().Zero on a new-business cell, where month
t = 0is the issue month and opens on the initial versement, which creates the rights and strikes both provisions. On an in-force cellduration_ifois the completed policy years at the valuation date — an elapsed count, already 0-based — so twelve times it is the first month of the policy year the extract opens. Shipped point 7 hasduration_ifo = 4and therefore opens att = 48. Elapsed time is recorded in whole policy years, so the frame always opens in the first month of a policy year.
- proj_len()[source]#
The number of policy months projected:
12 x policy_term().The exclusive end of the frame, so the frame is
range(proj_start(), proj_len())and the last projected month isproj_len() - 1, the month that ends at the échéance. 120 on the worked example’s ten-year term. The projection stops there because that is where the contract’s guarantee is discharged. A model point electing the rente viagère option would have to run past it, which is whyannuity_option_flag()rejects one.policy_term()stays in years, because the contract states the échéance in years; the 12 lives here and inproj_start().
- duration_mth(t)[source]#
Months elapsed from issue at the start of month t; equal to
t.tis 0-based and counts from the contract’s inception even on an in-force cell, whose frame simply opens later atproj_start(), so the identity is trivial - the cells exists so the monthly models in this library share one vocabulary.
- duration(t)[source]#
Completed policy years at the start of month t:
duration_mth(t) // 12.0-based, as
durationis throughout lifelib: 0 through the first policy year. It is what the versement schedule, the lock-up, the surrender indemnity and the last-policy-year exclusions are read on, all of which the contract states in years.
- policy_year(t)[source]#
y: the contractual policy year containing month t; 1 for t = 0..11.
The 1-based label
duration(t) + 1, derived from the 0-basedtand never indexed by. It is whatlapse_table.csvis keyed by - both the rachat total and the rachat partiel columns - and whatpremium_top_up_tandapport_tname.
- is_anniv(t)[source]#
True in the last month of a policy year,
duration_mth(t) % 12 == 11.The policy anniversary, and the date every contractually annual event of this product lands on: the striking of the compte de participation aux résultats and with it the R. 134-3 base 5 deg performance levy, the free versement, and the R. 134-12 apport d’actifs. The base 4 deg parts levy is the exception and falls at the opening of the policy year,
duration_mth(t) % 12 == 0, becauseproduct-spec.mdstates it taken at the start of each policy year.
- anniv_mth(t)[source]#
The month index of the anniversary that ends the policy year containing t.
12 x duration(t) + 11, which istitself whereis_anniv()is true. It is what a reader lays beside the annual-step model this one replaced: the anniversary month’s closing values are that model’s row for the same policy year.
- rem_term(m)[source]#
The remaining term to the échéance, in years, at month boundary
m.(proj_len() - m) / 12, and fractional between anniversaries: A. 134-1’s index maturity really does shorten continuously, so the maturity the TEC curve is interpolated at and the exponent the guarantee is discounted over both move month by month. Zero atm = proj_len(), the échéance, where the discount factor is 1.A month boundary rather than a month: month
topens atm = tand is struck atm = t + 1, which is the argumentdisc_factor()is read at for the striking.
- age(t)[source]#
x + dur(t): the attained age (âge atteint) entering the policy year of month t.
Age steps on the policy anniversary, not on the birthday and not monthly, which is the âge atteint convention the whole model is built on [std]. The decrement is read one year later, at
age_anniv(), because the annual mortality assumption this model converts is the rate of the age attained at the year’s end - seemort_rate().
- age_anniv(t)[source]#
x + dur(t) + 1: the age attained at the anniversary that closes the policy year.
The age
mort_rate()reads the notes’q(x + t + 1)at. Keeping the annual assumption on the end-of-year age rather than moving it to the entering age is what makes the in-force at every anniversary reproduce the annual-step model exactly; the age rule is part of the assumption, and the finer grid changes only when within the year the decrement falls.
- asset_return(t)[source]#
r(t): the annual gross asset return of the policy year containing month t [std].
Net of asset management fees, which is the basis the notes quote it on. A scenario level rather than a best estimate: the guarantee is a put on the account and its cost is convex in this number, so a deterministic run understates it.
The annual return of the policy year containing month t;
asset_return_mth()is the return actually credited in the month.scenario_table.csvis keyed by the elapsed year end at which the return is credited, so the policy year of month t, which ends atduration(t) + 1years after issue, reads rowduration(t) + 1; its row 0 is the inception placeholder and is never read. The last row is held beyond the table.
- asset_return_mth(t)[source]#
r_m(t) =
(1 + r(t))^(1/12) - 1: the return credited in month t [std].Derived geometrically from the policy year’s annual return and not by dividing by twelve, so that twelve months of it compound back to exactly that return - which is what makes the account assets at every anniversary identical to the annual-step model’s. On the worked example’s path 4.00% a year is 0.327374% a month, -25.00% is -2.368842% and 6.00% is 0.486755%.
The conversion is [std]: no retrieved French source states a within-year shape for a scenario return, and a constant force is the only shape that leaves the annual figure intact.
- tec_rate(m)[source]#
The taux de l’échéance constante at month boundary m, at maturity
rem_term(m).A month boundary:
m = 0at issue andm = 12 nat the échéance, and monthtreadstec_rate(t)for its opening andtec_rate(t + 1)for its end-of-month striking.The curve is read in two speeds, and the split is the point.
tec_curve.csvpublishes one curve per elapsed year, so the row ism // 12— the most recently published curve, which is what A. 134-1’s dernier TEC publié says [std]; interpolating a curve level between published years would invent data the file does not contain. The remaining maturity, by contrast, shortens continuously, so the interpolation across maturities runs at the fractionalrem_term(m). The consequence is that the provision mathématique’s time effect accrues month by month and its rate effect lands whole on the anniversary.From A. 134-1: linear interpolation between the two bracketing maturities of the published curve, the longest rate held beyond the end of the curve, and the shortest held below its start — which is what
k = nreaches, where the discount factor is 1 and the rate is immaterial. The method choice is irreversible per auxiliary account under the article; this model uses method 1°, the per-engagement one, throughout.The index maturity is [std]. The article as retrieved fixes it as the holder’s guarantee maturity (method 1°) or the auxiliary account’s 1°-engagement duration (method 2°), and says nothing about how that maturity is re-read at valuation dates after inception. This model takes the remaining term
n - k, the horizon the guarantee is actually discounted over; holdingnfixed at the original term would discount a one-year promise at a ten-year constant-maturity rate on the échéance.technical-notes.mdstates the reading and is the source of truth for it;product-spec.mdstates the article as retrieved. The two readings differ only on a sloped curve, which is what shipped model point 10 exercises.
- i_pm(m)[source]#
The A. 134-1 discount rate for the provision mathématique: 90% of the TEC, floored.
max(0, 0.90 x TEC(rem_term(m)))at month boundary m, the 90% haircut and the zero floor from the article and the remaining-maturity reading ofn[std] — seetec_rate(). A month boundary, like the curve it reads: month t is struck ati_pm(t + 1). This is not the A. 132-1 maximum technical rate and not the A. 132-3 guaranteed-rate ceiling; those are different and stricter objects that apply to a tariff, while this one is a valuation ceiling for a provision the saver has no right to withdraw at. The zero floor matters where the curve is negative: a model that leti_pmgo negative would report a provision mathématique larger than the guarantee it discounts.
- disc_factor(m)[source]#
(1 + i_pm(m))^-rem_term(m): the factor that turns the guarantee into the PM.A month boundary, like the rate it is built from: a beginning-of-month versement splits at
disc_factor(t)and the end-of-month striking of month t discounts atdisc_factor(t + 1). The exponent is the fractional remaining term in years, so the PM is re-struck at an intermediate value in every month, which is what A. 134-5 requires and an annual grid could not express [std]. It is one atm = proj_len(), the échéance, by construction, which is the whole point — seecheck_guarantee_funding().
The initial gross versement, paid at the contract’s inception.
It falls at the very start of the first projected month on a new-business cell — month 0, the issue month — where it creates the rights, and is nil on an in-force cell, whose versement was paid before the valuation date.
It is the first projected month’s opening state rather than a step in its roll forward:
own_assets_at(t, "BOM"),mg_at(t, "BOM")and their siblings already carry it net of the entry charge, which is whyown_assets_at(t, "AFT_PREM")adds only the scheduled versement. It is nonetheless a cash flow of month t, so it is intotal_premium_pp()and reachespremiums(),entry_charge()andexpenses()from there.
- prem_init_after_charge()[source]#
The initial versement net of the R. 134-3 1° entry charge.
The account’s opening balance on a new-business cell, and
gtimes it is the opening guaranteed amount — seemg().
P(t): the scheduled gross versement, received in the first month of a policy year.
A contractual annual term, so it lands whole on the policy-year opening rather than being spread:
product-spec.mdgives no modal factor and no retrieved eurocroissance document shows one, so there is no fractionnement to collect it on. Apremium_modecolumn with sourced modal factors is the natural extension, and is exactly whatWholeLife_US_Sadded when its own sources published the factors.Payable in the months where
duration_mth(t) % 12 == 0forpremium_regular_years()policy years from the first projected one, so the last is the first month of policy yearduration_inforce() + premium_regular_years(). On shipped point 9 that is months 0, 12, 24, 36 and 48. The initial versement is not here: it is the opening state of the first projected month,premium_initial_pp().
- prem_after_charge_pp(t)[source]#
P_net(t): the beginning-of-month scheduled versement net of the R. 134-3 1° charge.
This is the base of the guarantee. The guarantee is a percentage of versements net of the entry charge, so a 2.00% charge on €12 000.00 of gross versements leaves a guaranteed amount of 11,760.00 and not 12,000.00.
The free additional gross versement, paid on the anniversary of a policy year.
premium_top_up_tis the contractual policy year at whose end it falls, so on the monthly grid the test isis_anniv(t) and policy_year(t) == premium_top_up_year()— the single montht = 12 x premium_top_up_year() - 1, 35 on the worked example. Zero is the “no top-up” sentinel and matches no month.It stays whole on the anniversary because it is a discrete contractual act and because the split rule prices it on the striking it immediately follows,
disc_factor(t + 1)andpart_value_at(t, "AFT_STRIKE"); on the anniversary that striking is the participation account’s own. A mid-year variant would need apremium_top_up_monthcolumn the composite has no basis to populate.
The free additional versement net of the entry charge.
Every gross versement of month t: the initial one, the scheduled one and any free one.
- parts_added_bom(t)[source]#
The parts a beginning-of-month versement buys, at the opening part value.
The versement splits under R. 134-2:
g P_netdiscounted at thei_pmof the month’s own opening — them = tboundary — goes to the provision mathématique and the remainder buys parts at the opening part value. On Chassis B nothing goes to the PM, so the whole net versement buys parts.
- parts_added_top_up(t)[source]#
The parts a free versement buys on the anniversary, at the part value just struck.
Paid immediately after the month’s striking, so it is priced on
u(t)before the top-up rather than on the opening value, and split at the striking’s owndisc_factor(t + 1). In the worked example the top-up on the anniversary that closes policy year 3 — montht= 35 — pays 1 960.00 net, which splits into1 960.00 x 1.0225^-7 = 1,677.31of PM and 282.69 of diversification provision, buying282.69 / 12.8688 = 21.9672parts on Chassis A — and the whole 1 960.00 buying1 960.00 / 11.1193 = 176.2694parts on Chassis B.
- wd_rate_base(t)[source]#
The table annual partial-surrender rate of the policy year containing month t [std].
6% of the provision in policy years 1-2 and 3% thereafter; the mémoire observes 6% then 2%-4%.
lapse_table.csvis keyed by the contractual policy year, read here atpolicy_year(t); policy years beyond the table take its last row.
- wd_rate(t)[source]#
w_p(t): the annual rachat partiel rate of the policy year containing month t.
The rate the technical notes tabulate;
wd_rate_mth()is the rate actually applied in the month. Nil while the decrements are switched off, inside a non-surrender period — policy years 1 tolock_up_years, soduration(t) < lock_up_years()— and in the whole of the last policy year, which ends at the échéance, where the contract is discharged in full instead. That last exclusion is onduration(t) >= policy_term() - 1and not on the final month: the annual grid never let a rachat out of the échéance year, and restating the test on the month would quietly move a year of exits.Expressed as a fraction of the provision rather than as a cash amount, because a partial surrender takes the same proportion of every element of the engagement — the parts, the guaranteed amount and the death-floor base all run down pro rata with it.
- wd_rate_mth(t)[source]#
w_pm =
1 - (1 - w_p)^(1/12): the rachat partiel rate applied in month t [std].Derived geometrically and not by dividing by twelve, so that twelve months of it run the engagement down by exactly the annual factor
1 - w_p: 6.00% a year is 0.514301% a month. That is what keepsmg(),cum_prem_net()andparts()— whose run-down is purely multiplicative — identical to the annual-step model at every anniversary.Spreading is a decision, and it is the one that costs exact equivalence. The sourced basis is a rate on average encours [R13], a partial surrender is an owner election that can be made in any month, and A. 134-5 prices such an exit on the next intermediate value, which the monthly grid now strikes. What it costs is that the exit cash leaves in twelve instalments rather than one, so more capital earns return early: on shipped point 5, the only cell with
wd_factor > 0, the anniversaryown_assetsrun 0.21 to 3.05 EUR above the annual model’s, at most 0.031%, and total rachats over fifteen years are 0.23% higher. Gating it to the first month of the policy year at the full annual rate would restore bit-exactness and lose the realism; the technical notes record the choice.
- wd_gross_pp(t)[source]#
W(t): the amount a rachat partiel takes out of the provision, before the exit charge.
Taken at the beginning of month t, so it is a fraction of the opening provisions, at the month’s own rate
wd_rate_mth().
- wd_pp(t)[source]#
The rachat partiel actually paid to the saver, net of the base 6° exit charge.
An owner election, not a claim: the contract stays in force and the engagement continues on the reduced parts and the reduced guarantee. It has its own cash flow column for that reason.
- mg_at(t, timing)[source]#
mg at a point inside month t.
"BOM"the opening guaranteed amount:
mg(t - 1)in every month but the first projected one, and in that onegtimes the initial net versement on a new-business cell or the extract’smg_ifoon an in-force one. This is where the issue instant lives."AFT_EXIT"after a rachat partiel has run the guarantee down pro rata, at the month’s own
wd_rate_mth()."AFT_PREM"after a beginning-of-month scheduled versement has raised it by
g P_net. This is the amount the month-end striking discounts."AFT_TOP_UP"after any free versement on the anniversary; the closing guaranteed amount, and the same number as
mg().
- mg(t)[source]#
mg(t): the amount guaranteed at the échéance, as at the end of month t.
gtimes cumulative versements net of the R. 134-3 1° entry charge, run down pro rata to any rachat partiel. It is constant between versements in a single-policy expected-value projection: full surrenders and deaths remove the policy rather than the guarantee, so they reach the cash flows throughpols_ifinstead.
- cum_prem_net_at(t, timing)[source]#
The cumulative net versements at a point inside month t.
"BOM"the opening base:
cum_prem_net(t - 1)in every month but the first projected one, and in that one the initial net versement on a new-business cell or the extract’scum_prem_net_ifoon an in-force one.
- cum_prem_net(t)[source]#
The cumulative net versements at the end of month t: the death-floor base.
Equal to
mg(t) / ghere, and kept separate because they are different objects: the guaranteed amount is a contractual promise at a stated term and this is the base of a complementary death guarantee provisioned outside the account. They coincide only becausegis constant.
- parts_levy(t)[source]#
L(t): the R. 134-3 base 4° levy, taken in the first month of the policy year.
f_p x prov_div_at(t, "BOM")in the months whereduration_mth(t) % 12 == 0, and nil in the other eleven — a levy in number of parts, valued at the opening part value. It is a contractual annual term and not an assumption:product-spec.mdstates it “0.80% p.a. of parts, taken at the start of each policy year on the opening part value”, so it lands whole where the contract puts it. Spreading it at(1 - f_p)^(1/12)would leave the parts count unchanged over a year but would change the cash, because the levy is valued on the then-currentprov_div.Base 3°, a levy on the encours of the diversification provision, is available only in an auxiliary account holding no 1° engagements, and no base permits a levy on the provision mathématique at all. On the worked example’s Chassis A the levy opening policy year 1 — month
t= 0 — is 15.64; an encours levy onpm + pdwould have been 78.40.
- invest_income(t)[source]#
I(t): the month’s financial performance, on the balance after its opening steps.
own_assets_at(t, "AFT_PREM") x r_m(t). Twelve of these compound the account up by exactly the policy year’s annual return, and — where no cash moves inside the year — they sum to the annual model’sA_a r, which is what makes the anniversary performance levy reproduce it.
- invest_income_ytd(t)[source]#
The financial performance accumulated since the policy year opened, through month t.
I(t)in the first month of the policy year andI(t) + invest_income_ytd(t - 1)in the other eleven, so it resets on everyduration_mth(t) % 12 == 0. It exists because the R. 134-3 base 5° levy is struck once a year on the compte de participation aux résultats, so the levy needs the year’s balance and not the month’s.
- perf_levy(t)[source]#
F(t): the R. 134-3 base 5° levy on positive financial performance, on the anniversary.
f_perf x max(invest_income_ytd(t), 0)whereis_anniv(), and nil in the other eleven months. It is an event of the striking, not of the month: R. 134-3 5° is a levy on the balance of the compte de participation aux résultats, R. 134-4 strikes that account at least annually, and R. 134-12 III fixes affectations to the striking dates. A monthly levy would also be a different charge — it would tax a positive month inside a losing year, which the asymmetricmax(., 0)exists not to do, and would have taken money in the worked example’s policy year 6.Nothing at all in a year of negative performance, which is why the worked example’s performance levy on the anniversary closing policy year 6, month
t= 71, is zero on both chassis. A policy exiting between anniversaries pays no performance levy for the part year, which is what the article’s annual striking implies.
- own_assets_at(t, timing)[source]#
The account assets at a point inside month t.
"BOM"the opening assets:
A(t-1)in every month but the first projected one, and in that one the initial versement net of the entry charge on a new-business cell orown_assets_ifoon an in-force one. This is where the issue instant lives — it is not a row of the frame."AFT_LEVY"less the base 4° parts levy, which falls only in the first month of a policy year.
"AFT_EXIT"less any rachat partiel, taken gross of the exit charge because the charge stays in the account.
"AFT_PREM"plus a beginning-of-month scheduled versement net of the entry charge. This is the balance the month’s return accrues on.
"AFT_RETURN"after the month’s asset return, at
asset_return_mth()."AFT_PERF"after the base 5° performance levy, which is nil except on the anniversary; the balance the two provisions are struck against.
"AFT_TOP_UP"plus any free versement on the anniversary; the closing assets, and the same number as
own_assets().
The steps are exposed individually because their order is fixed by R. 134-4 and R. 134-12 III — asset affectations completing the representation are made on the dates the participation account is struck, after its balance has been allocated — rather than being arithmetic convenience.
- own_assets(t)[source]#
A(t): the auxiliary-account assets attributable to the policy at the end of month t.
At realisation value (R. 134-8) and excluding any outstanding L. 134-3 contribution, which is the insurer’s capital and not the savers’ money. That exclusion is the point of the cells:
own_assets_at()rolls forward fromA(t-1)and never frompm(t-1) + prov_div(t-1), so the contribution earns nothing for the savers. In the worked example the policy-year-7 roll — montht= 72 — starts from 10,250.65, not from the 12,384.73 the contract would have surrendered for.
- parts_at(t, timing)[source]#
The number of parts at a point inside month t.
"BOM"the opening count:
N(t-1)in every month but the first projected one, and in that one the parts the initial net versement buys atpart_value_init()on a new-business cell, orparts_ifoon an in-force one."AFT_LEVY"N_open(t)(1 - f_p)in the first month of a policy year, where the base 4° levy falls, andN_open(t)unchanged in the other eleven. The levy cancels parts rather than reducing their value."AFT_EXIT"after a rachat partiel has cancelled its pro-rata share, at the month’s own
wd_rate_mth()."AFT_PREM"plus the parts a beginning-of-month versement bought. This is the count the month-end striking divides by.
"AFT_TOP_UP"plus the parts a free versement bought on the anniversary at the just struck part value; the closing count, and the same number as
parts().
- parts(t)[source]#
N(t): the number of parts de provision de diversification at the end of month t.
The saver’s rights are expressed in a number of parts, and R. 134-2 makes the insurer’s commitment the number and not the value. On the worked example the count closes on
212.8127 x 0.992^7 = 201.1774: seven years of the base 4° levy and nothing else.
- pm_at(t, timing)[source]#
The provision mathématique inside month t: opening, and at the month-end striking.
"BOM"the opening PM:
pm(t-1)in every month but the first projected one, and in that one the opening guaranteed amount discounted at the boundary-trate. On an in-force cell this is the numbercheck_pm_restruck()compares against the extract’spm_ifo."AFT_STRIKE"the guaranteed amount as it stands after the month’s opening steps, discounted at the rate of the month-end striking,
i_pm(t + 1). In eleven months of twelve this is A. 134-5’s valeur intermédiaire; in the twelfth it is the striking of the participation account itself."AFT_TOP_UP"the same after any free versement on the anniversary; the closing PM, and the same number as
pm().
Identically zero on Chassis B, where the guarantee is not provisioned inside the account at all.
- pm(t)[source]#
pm(t): the provision mathématique at the end of month t.
mg(t) (1 + i_pm(t+1))^-rem_term(t+1)on Chassis A and identically zero on Chassis B (R. 134-2) — the closing guaranteed amount discounted from the échéance back to the month’s end, boundaryt + 1, over a fractional number of years. Re-struck every month, never accumulated. Rollingpm(t-1)forward at last year’s rate removes the rate effect: in the worked example that is +587.44 of the +824.18 move over policy year 6,t= 59 tot= 71, against a time effect of +236.74.The monthly re-strike splits that move in two, which the annual grid could not: the PM accretes from 10,541.34 at
t= 60 to 10,738.63 att= 70 at the unchanged 2.25% — the time effect — and jumps to 11,346.00 att= 71, where the TEC is re-published at 1.00% — the rate effect, +607.37 in one month.In the last projected month the discount factor is 1, so
pmequalsmgidentically and the Chassis A guarantee is pre-funded by construction.
- prov_div_at(t, timing)[source]#
The provision de diversification inside month t: opening, and at the striking.
The residual of the account’s assets over the provision mathématique, floored at the parts’ minimum value: R. 134-4 permits a debit balance to reduce the part value only within the limit of its minimum. Where the floor binds the two provisions together exceed the assets, and the excess is exactly the L. 134-3 contribution.
"BOM"is the opening provision —prov_div(t-1)in every month but the first projected one, and in that one the residual the initial versement, or the in-force extract, leaves over the opening PM. It is the base of the parts levy in the months that carry one.
- prov_div(t)[source]#
prov_div(t): the provision de diversification at the end of month t.
The savers’ individualised rights (R. 343-3 9°), and the only part of the engagement that bears investment risk. On the worked example’s policy-year-6 shock, at the anniversary month
t= 71, the raw residual on Chassis A is10,250.65 - 11,346.00 = -1,095.35and the floor binds instead at207.7460 x 5.0000 = 1,038.73. The monthly grid shows where that starts: the floor first binds in month 66, not at the anniversary.
- part_value_at(t, timing)[source]#
The valeur de la part inside month t: opening, and at the month-end striking.
"BOM"is the opening value —u(t-1)in every month but the first projected one, and in that onepart_value_init()on a new-business cell (the initial versement buys parts at it) or the extract’spd / Non an in-force one. It is what a beginning-of-month versement buys parts at."AFT_STRIKE"is what a free versement on the anniversary buys parts at.
- part_value(t)[source]#
u(t): the valeur de la part at the end of month t,
prov_div(t) / N(t).Struck every month: in the eleven months of a policy year in which the participation account is not struck this is the valeur intermédiaire A. 134-5 requires, and it is what an exit falling in the month is priced on.
Common to every engagement of the auxiliary account (R. 134-2), so savers with different maturities and different guarantee levels in one account earn the same rate; differentiation is possible only through the number of parts or through a differentiated PCDD distribution. A per-policy model can only approximate that — the shipped model points are separate accounts, and their part values diverge as separate accounts’ would.
- provision_value(t)[source]#
pm(t) + prov_div(t): the base of the R. 134-5 and R. 134-6 values.One expression on both chassis, because
pmis identically zero on Chassis B. It equalspm(t) + N(t) u(t), which is how the articles write it.
- provision_value_at(t, timing)[source]#
pm + prov_divat a point inside month t."BOM"the opening provisions — the base a beginning-of-month rachat partiel takes its pro-rata share of.
- insurer_contribution(t)[source]#
C(t): the outstanding L. 134-3 contribution completing the representation.
max(pm(t) + prov_div(t) - A(t), 0), and nil on Chassis B, where the shortfall against the guarantee is carried as a PGT instead. It is the insurer’s capital: it carries no return to the savers and is releasable as soon as the account’s own assets cover the two provisions. The surrender value exceeds the account’s own assets by exactly this amount while it is outstanding — 2,134.08 at the anniversary montht= 71 of the worked example’s policy-year-6 shock.Struck monthly, which is where the finer grid earns its keep on this cell: the contribution starts at 141.96 in month 66, the month the part-value floor first binds, and climbs to 2,134.08 by the anniversary. The annual grid could only report the anniversary figure.
- apport(t)[source]#
The R. 134-12 apport d’actifs, made on the anniversary of a stated policy year.
Capped at 10% of the diversification provision by the article. It enters the account at realisation value and endows the PCDD; it is never credited to
prov_div, so it changes no policyholder value by one cent.apport_tis the contractual policy year at whose end it falls, so the test isis_anniv(t) and policy_year(t) == apport_year()— the single montht = 12 x apport_year() - 1; zero is the “no apport” sentinel and matches no month. It stays on the anniversary because R. 134-12 III fixes asset affectations to the dates the participation account is struck. On the worked example’s Chassis B a statutory-maximum apport on the anniversary closing policy year 6 — montht= 71 — is 989.92 and cuts the PGT from 1,446.78 to 456.86.
- pcdd(t)[source]#
D(t): the provision collective de diversification différée (R. 343-3 10°).
Collective, with no individual rights, and released into the participation account within fifteen years (A. 132-16) — against eight for a euro fund’s provision pour participation aux bénéfices. This model accumulates the apport d’actifs into it and nothing else: the mémoire’s piloting rule, which runs the fund at 30 bp above the insurer’s own euro fund and carries the rest here, is a fund-level discretion a single-policy model cannot express, and holding it at zero understates the smoothing the real product delivers.
- pgt(t)[source]#
G(t): the provision pour garantie à terme (A. 134-2, R. 343-3 11°).
max(mg(t) (1 + i_pm(t+1))^-rem_term(t+1) - prov_div(t) - D(t), 0)on Chassis B and nil on Chassis A, struck at the end of every month. Funded from the insurer’s own funds and held outside the participation account, on a deliberately narrow basis: the A. 132-18 mortality tables at a rate at most 90% of the TEC, counting no cash flows other than guarantee maturities and mortality. A model must not “improve” that basis by adding lapses or expenses to it, and must not let the provision reach a benefit or feed the profit-sharing computation.Mortality, one of the article’s two admitted drivers, is not implemented [std]. The present value above applies no survival factor, so it is the amount for a guarantee certain to be reached: prudent, since it overstates the provision, and invisible on the worked example, where
mort_rateis zero. It is live on the decrement-bearing cells — on model point 6 at the anniversary closing policy year 7, montht= 83, this returns 2,739.35 against 2,477.36 with the five-year survival factor 0.972660 the shipped table gives. In a single-policy model the decrement reaches the projection throughpols_ifinresult_cf()instead; a fund-level implementation should carry the survival factor inside the present value, summed over the account’s 2° engagements.On the worked example’s Chassis B the monthly striking shows the provision being constituted: the PGT first becomes positive in month 68, at 61.48, and reaches 1,446.78 by the anniversary at month 71.
- gate_revalue_ok(t)[source]#
Whether both A. 134-3 tests permit revaluing the guarantees out of the account.
Test 1: the diversification provision exceeds 1.5 times the excess of the guaranteed amounts over the provision mathématique. Test 2: the diversification provision less the parts at their minimum value exceeds 10% of the provision mathématique. Both must pass. Informational here — the reference credit-balance route raises the part value instead — but computed, because a model that revalued guarantees without testing the gates would be exercising a discretion the article does not allow. Evaluated on the month’s own striking, so it is answered every month rather than once a year. On the worked example both pass at
t= 59, the anniversary closing policy year 5, and the second fails att= 71, where the part-value floor has taken the headroom to nil.
- conversion_headroom(t)[source]#
The parts convertible into provision mathématique under A. 134-4.
The article requires the diversification provision, net of the conversion and of the parts at their minimum value, to remain at least 15% of the resulting PM, and imposes a five-year cooling period besides. Solving
pd - C - N u_min = 0.15 (pm + C)givesC = (pd - N u_min - 0.15 pm) / 1.15— 474.52 on the worked example att= 59. Computed, never exercised: the conversion is out of scope, and the 0.50% frais de conversion the market shows would take 2.37 of that.
- surrender_indemnity(t)[source]#
The R. 132-5-3 indemnité de rachat applying to a full surrender in month t.
The article caps the indemnity at 5% of the present value of the mutual engagements (20% or 10% in narrow unlisted-asset cases) and permits the contract to provide for no indemnity at all once it has been in force more than ten years. That is a permission, not a prohibition: the article does not forbid an indemnity beyond ten years. The reference contract charges none at any duration, and this model returns zero once
indemnity_max_yearspolicy years have elapsed — fromduration(t) = indemnity_max_yearson, the eleventh policy year, montht = 120on a longer term — unconditionally, which is the permission taken up [std] rather than the article applied. The test is on the completed policy years, because that is the unit R. 132-5-3 states.
- surrender_value(t)[source]#
The R. 134-5 valeur de rachat at the end of month t.
pm(t) + N(t) u(t)on Chassis A andN(t) u(t)on Chassis B, less the base 6° exit charge and any surrender indemnity.There is no guarantee in it before the *échéance*. On the worked example’s policy-year-6 shock, at the anniversary month
t= 71, Chassis A surrenders for 12,384.73 — 105.31% of net versements, because its provision mathématique has already been marked up by the fall in rates — while Chassis B surrenders for 9,899.22, 84.18%, against a guarantee of 11,760.00 that does not apply. A model that floors this atgtimes premiums, or at the discounted guarantee, is modelling a contract that does not exist.A surrender is priced on the forward part value A. 134-5 requires — the striking of the month in which the request falls, which is the next striking or intermediate value after it. The monthly grid delivers that rather than standardizing it away: a Chassis B saver surrendering in month 65 receives 11,430.63, not the 9,899.22 the anniversary striking at month 71 reports.
- death_value(t)[source]#
The current provision value, which is what a death before the échéance pays.
Chapter IV contains no death valuation article, so the death benefit is the value of the engagement and the maturity guarantee does not apply. No exit charge: the base 6° charge is on amounts the saver elects to take out.
- death_payout(t)[source]#
The death benefit actually paid, after any garantie décès plancher.
max(death_value(t), cum_prem_net(t))where the model point carries the rider. The floor is a complementary guarantee provisioned outside the auxiliary account (R. 134-7), not the maturity guarantee arriving early: it happens to equalmghere only becausegis 100%, and atg= 80% the two would differ.
- rider_claim_pp(t)[source]#
The part of the death benefit the garantie décès plancher funds, per claim.
death_payout(t) - death_value(t)— 1,860.78 on the worked example’s policy-year-6 Chassis B death, montht= 71. Reported apart from the auxiliary-account columns because it is not the account’s money: R. 134-7 puts complementary guarantees outside it.
- maturity_value(t)[source]#
The R. 134-6 amount payable at the échéance; nil at every other t.
The échéance is the end of the last projected month,
t = proj_len() - 1, and it really is one month rather than a policy year — which is why this test stays on the month while the rachat exclusions inlapse_rate()andwd_rate()moved to the policy year.pm + N uthere on Chassis A — more than the guarantee whenever the parts retain any value, 12,765.89 against 11,760.00 in the worked example — andmax(N u, mg)on Chassis B. Themaxexists only in that last month and only on Chassis B; applying it earlier, or on Chassis A at all, invents a guarantee the contract does not give.The statutory default at the échéance is in fact an arbitrage into an SRI <= 2 support unless the holder decides otherwise (A. 134-6); this model pays the amount out and stops, and a “roll into a low-risk support” variant is the natural extension.
- claim_pp(t, kind)[source]#
The payout per claim in month t, by kind.
"DEATH"death_payout()— the current provision value, floored at cumulative net versements where the rider is carried."LAPSE"surrender_value()— the R. 134-5 value, with no guarantee before the échéance."MATURITY"maturity_value()in the last projected month and nil elsewhere.
- mort_rate(t)[source]#
q(x + dur(t) + 1): the annual mortality rate of the policy year of month t [std].
The rate the technical notes tabulate;
mort_rate_mth()is the rate actually applied in the month. Read atage_anniv(), the âge atteint at the end of the policy year, which is the notes’ ownq(x + t + 1)restated on the monthly grid: the age rule belongs to the annual assumption, and the finer grid changes only where within the year the decrement falls. The shipped table rate timesmort_be_factor. Both are placeholders: the homologated tables TH 00-02 / TF 00-02 are cited by arrêté and never shipped, A. 132-18 permits an insurer’s own certified table besides, and the proxy is INSEE-shaped population mortality with a factor for insured lives being lighter than the population. Nil where the model point switches the decrements off, which is the worked example’s configuration.
- mort_rate_mth(t)[source]#
q_m =
1 - (1 - q)^(1/12): the monthly mortality rate applied in month t [std].Derived geometrically and not by dividing by twelve, which is what makes
(1 - q_m)^12 = 1 - qhold exactly - so twelve months of it leave the in-force at the anniversary identical to the annual-step model’s. On shipped point 6 the annual 0.00243005 becomes 0.00020273 a month, and twelve of those compound back to 0.00243005.The conversion carries [std] because no retrieved French source states a conversion convention for any decrement.
- lapse_rate_base(t)[source]#
The table annual full-surrender (rachat total) rate of the policy year of month t [std].
2.5% p.a. level; the mémoire observes 2%-3%.
lapse_table.csvis keyed by the contractual policy year, read here atpolicy_year(t); policy years beyond the table take its last row.
- guarantee_imminent(t)[source]#
0.5 in the two policy years before the échéance on Chassis B, while the guarantee bites.
The policy year of month t is
policy_year(t), so the years still to run at its close aren - policy_year(t)and the suppression applies over every month of a policy year where that is at mostguarantee_imminent_years. On shipped point 6 that is months 108 to 143.The in-the-money test is read on the current month’s striking rather than on the anniversary’s, because the behavioural statement is that a saver deciding to surrender looks at whether
N u < mgnow. It is a faithful reading rather than a free one: on every shipped model point the two readings agree in every month, the gate’s state being slow-moving relative to a month.The gate matters. A saver who surrenders a 2° engagement gives up the entire guarantee (R. 134-5), so the deterrent exists precisely while
N u < mgand is worth nothing otherwise; applying it unconditionally would invent behaviour where there is none. This is the strongest exit deterrent the product creates, and it is [std] — no eurocroissance lapse experience is public.
- duration8_spike(t)[source]#
1.5 over policy year 8 — every month with
policy_year(t) == 8— wheren > 8[std].The assurance-vie annual abattement becomes available at eight years, so surrender incentive spikes there — and only where the contract still has years to run, since a contract maturing at eight has no such choice to make. It is a multiplier on the annual rate, applied before the monthly conversion, so it grades once a year as the behaviour it stands for does and not once a month.
- lapse_rate(t)[source]#
w(t): the annual full-surrender rate of the policy year containing month t.
The rate the technical notes tabulate — the table rate times both behavioural overlays, capped at 1;
lapse_rate_mth()is the rate actually applied at the end of the month. Nil while the decrements are switched off, inside a non-surrender period — policy years 1 tolock_up_years, soduration(t) < lock_up_years()— and over the whole of the last policy year, which ends at the échéance, where the survivors take the maturity amount instead — the base run assumes 100% of them do, as the mémoire also assumes.That last exclusion is
duration(t) >= policy_term() - 1and not the last month. The annual grid never let a survivor lapse out of the échéance year; restating the test ast >= proj_len() - 1would open eleven months of it and move the whole maturity claim, which is the single most likely place for the conversion to introduce a silent error.
- lapse_rate_mth(t)[source]#
w_m =
1 - (1 - w)^(1/12): the full-surrender rate applied at the end of month t [std].Derived geometrically from the policy year’s annual rate, so
(1 - w_m)^12 = 1 - wexactly and the in-force at every anniversary is the annual-step model’s. The same conversionmort_rate_mth()takes, and [std] for the same reason: no retrieved French source states one.
- pols_if_at(t, timing)[source]#
The number of policies in force at a point inside month t.
"BEF_DECR"the start of the month, before any decrement — and the exposure every cash flow of the month is weighted by;
pols_if()."BEF_LAPSE"after deaths, before surrenders: the processing order is death before surrender [std].
"AFT_DECR"the notes’
l(t): the end-of-month count, and zero in the last projected month, where the survivors mature. This is the timing the end-of-month quantity is reached through, because the bare namepols_ifbelongs to the start-of-month count.
Both decrements are applied at their monthly rates, so a death or a surrender falls in the month it happens rather than at the anniversary — and twelve months of them compound back to exactly the policy year’s annual factors, which is why
pols_if(12k)is what the annual-step model carried for policy yeark + 1.
- pols_if(t)[source]#
The number of policies in force at the start of month t.
This is the library’s shared vocabulary:
pols_if(t)is the exposure at the start of month t and the weight on that sameresult_cf()row’s cash flows, so the opening row ispols_if_init()exactly — no decrement has been applied when a month opens.pols_if(12k)is the count the annual-step model this one replaced carried on its row for policy yeark + 1, to floating point, because the monthly decrements compound back to the annual ones.The notes’
l(t)is the end-of-month count, nil on the last projected row because everyone has matured by the end of it. That quantity is unchanged and is reached aspols_if_at(t, "AFT_DECR"); it is no longer published under this name, because doing so put the exposure column one period ahead of the flows printed beside it.
- pols_lapse(t)[source]#
Full surrenders at the end of month t, from the survivors of that month’s mortality.
- pols_maturity(t)[source]#
Survivors reaching the échéance; nil outside the last projected month.
The base run assumes 100% of them take the maturity amount [std], as the mémoire also assumes; it notes that modelling annuitisation or reinvestment instead could amplify or damp its results.
Versement income in month t, an inflow.
The initial versement where the month is the first projected one, a scheduled versement in a month that opens a policy year and a free one on an anniversary, gross of the entry charge — the charge is reported as insurer income in
charges_taken()rather than netted out of the premium line.
- withdrawals(t)[source]#
Rachats partiels paid at the beginning of month t.
An owner election rather than a claim, which is why it has its own name and column: the contract stays in force and continues on the reduced parts and reduced guarantee.
- claims(t, kind=None)[source]#
Benefit outgo in month t, by kind; the total when kind is omitted.
Deaths and surrenders are now settled in the month they happen, priced on that month’s own striking, rather than at the anniversary — which is what the finer grid was for, and why the claim columns do not reproduce the annual-step model.
"DEATH","LAPSE"and"MATURITY"weightclaim_pp()by the corresponding decrement. The death line includes the garantie décès plancher’s contribution, whichrider_claims()reports separately; it is a decomposition of this column and not a fourth kind.
- rider_claims(t)[source]#
The garantie décès plancher’s share of the month’s death outgo.
A memo line: it is already inside
claims_death, and it is published apart because R. 134-7 puts complementary guarantees outside the auxiliary account, so it is not paid out of the savers’ provisions.
- expenses(t)[source]#
E(t): the insurer’s own expenses in month t [std].
Acquisition at 5% of versements plus an acquisition commission of 2% of the initial one, and maintenance at 0.20% p.a. of the two provisions. All three levels come from the published mémoire, which is the only complete public parameterisation of this product. They are the insurer’s costs, not charges to the saver: the charges the contract permits are the six R. 134-3 bases, reported in
charges_taken().The acquisition components fall in the month their versement does and are weighted by the start-of-month exposure like every other flow. Maintenance accrues at one twelfth a month,
0.20% / 12of the month’s own striking of the two provisions, weighted by the count on the books at it,pols_if_at(t, "AFT_DECR").This is the one place the conversion changes an answer rather than its resolution, and it changes it in two ways. Twelve monthly accruals cover exactly the year the annual grid charged for once at its year end, so the extra opening-striking charge the annual model needed —
n + 1point-in-time charges to covernyears of service — is gone; and the charge is now borne by the in-force and the provision of each month rather than of the anniversary, so a decrementing block carries less of it and a block whose provision grows through the year carries less again. Over a whole projection that is -0.2% to -1.3% on the shipped cells, and +0.9% on point 9, whose five annual versements step the provision up in the first month of each of its first five policy years.
- charges_taken(t)[source]#
The R. 134-3 charges the insurer takes in month t: income, reported apart.
The base 4° parts levy, the base 5° performance levy, the base 1° entry charge and the base 6° exit charge together with any surrender indemnity. They are not in
net_cf: they are transfers inside the account from the savers’ provisions to the insurer, and the benefits they reduce are already net of them. Publishing them beside the flows is what makes the charge structure auditable against R. 134-3.
- liability_cf(t)[source]#
CF(t): the month’s liability cash flow, outgo positive, as the notes print it.
Claims and rachats partiels and expenses out, versements in. The two provisions appear nowhere in it — they are state variables, not cash flows — and neither do the insurer’s own-funds items, which are capital rather than benefit.
- net_cf(t)[source]#
The net cash flow of month t, income positive:
-liability_cf(t).The library’s sign convention, so that
result_cf()["net_cf"]can be compared and summed across products without checking which one it came from.
- check_assets_roll_fwd_resid(t)[source]#
The account-asset recursion residual in month t; zero everywhere.
A(t) - {[A_open(t) - L(t) - W(t) + P_net(t)](1 + r_m) - F(t) + top-up}, rebuilt in one expression rather than throughown_assets_at(), so that a mis-ordered step shows up here: a parts levy taken after the return instead of before it, a versement credited after the return rather than at the beginning of the month, or a performance levy struck on the wrong balance. The opening quantities are the"BOM"timings, so the check is live in the first projected month too, where they carry the initial versement or the in-force extract.Two of the three charges now enter by name rather than being rebuilt from their rates, and that is the conversion showing through: the base 4° levy falls only in the first month of a policy year and the base 5° levy only on the anniversary, on the year’s accumulated performance, so neither can be reconstructed from a month’s own balance. What the check still rebuilds independently is the order and the base, and the companion identity
invest_income(t) == base x asset_return_mth(t)— asserted intests/test_eurocroissance_fr.py— pins the balance the return accrues on.
- check_assets_roll_fwd()[source]#
True when the account-asset recursion closes in every projected month.
- check_parts_roll_fwd_resid(t)[source]#
The parts recursion residual in month t; zero everywhere.
N(t) - {N_open(t)(1 - f_p 1{BOM of a policy year})(1 - w_pm) + parts bought at BOM + parts bought at the top-up}, rebuilt in one expression. The base 4° levy cancels parts rather than reducing their value, so a levy applied to the part value instead of to the count would leave the count unchanged and show up here; so would a versement priced at the wrong striking, or a levy taken in a month that carries none. On the worked example the count closes on212.8127 x 0.992^7 = 201.1774.
- check_guarantee_roll_fwd_resid(t)[source]#
The guaranteed-amount recursion residual in month t; zero everywhere.
mg(t) - {mg_open(t)(1 - w_pm) + g x net versements of the month}, rebuilt in one expression. It is the check that catches the guarantee being computed on gross versements: with a 2.00% entry charge,mgafter the worked example’s top-up on the anniversary closing policy year 3 is 11,760.00 and not 12,000.00, and a model that used the gross figure would fail here in the month the top-up is paid rather than silently over-guaranteeing for seven years.
- check_guarantee_roll_fwd()[source]#
True when the guaranteed-amount recursion closes in every projected month.
- check_pols_roll_fwd_resid(t)[source]#
The in-force roll-forward residual in month t; zero everywhere.
The month opens at
pols_if(t)and closes atpols_if_at(t, "AFT_DECR"), the notes’l(t); the difference is the month’s deaths, full surrenders and maturities.
- check_guarantee_funding_resid(t)[source]#
pm(t)accumulated to the échéance less the guaranteed amount; zero on Chassis A.This is the model’s headline identity: the provision mathématique accumulated at the regulated rate reaches the guarantee exactly at the échéance, so
pm(t)(1 + i_pm(t+1))^rem_term(t+1) = mg(t)at every t — month t closes at boundaryt + 1, which is(T - t - 1)/12years short of the échéance — and the two coincide in the last projected month. On the monthly grid it holds month by month and not only at anniversaries, which is one of the reasons the PM is re-struck at a fractional remaining term rather than held flat between strikings.It is zero by construction under R. 134-2’s re-strike rule, and that is the point of publishing it: an implementation that accumulates the PM instead — rolling
pm(t-1)forward at last year’s rate — breaks it the first year the rate moves. On the worked example’s pathpm(59) x 1.0225 = 10,758.56against the 11,346.00 the re-strike gives, and the 587.44 difference is the rate effect it has silently dropped.Identically zero on Chassis B, where both sides are nil: a 2° engagement funds nothing inside the account against its guarantee, which is exactly why an early rachat there can pay less than the guaranteed amount. The Chassis B funding statement is
check_pgt_covers_guarantee()instead.
- check_guarantee_funding()[source]#
True when the provision mathématique funds the guarantee exactly, at every t.
- check_pgt_covers_guarantee_resid(t)[source]#
pd + G + Dless the discounted guarantee on Chassis B; non-negative in every month.A. 134-2 makes the PGT the shortfall of the diversification provision and the PCDD against the discounted guarantees, floored at zero, so the three together always cover it — exactly where the PGT is positive and with a surplus where it is not. It is the Chassis B counterpart of
check_guarantee_funding(), and what it asserts is that the guarantee is funded somewhere: on the savers’ side before a shock, and out of the insurer’s own funds after one.Identically zero on Chassis A, which constitutes no PGT: there the L. 134-3 contribution plays the analogous role and
insurer_contribution()carries it.
- check_pgt_covers_guarantee()[source]#
True when the diversification provision and the own-funds provisions cover the guarantee.
- check_part_value_floor_resid(t)[source]#
u(t) - u_min: how far the part value sits above its contractual floor.Non-negative everywhere. R. 134-4 permits a debit balance on the participation account to reduce the part value only within the limit of its minimum, and an implementation that omits the floor takes the worked example’s Chassis A diversification provision to -1,095.35 at the anniversary of policy year 6,
t= 71 — a negative provision, and with it a negative surrender value that every downstream number stays plausible enough to read past.
- check_part_value_floor()[source]#
True when the part value stays at or above its contractual minimum, every month.
- check_own_funds_not_paid_resid(t)[source]#
The excess of the month’s largest benefit over the two provisions; non-positive.
Before the échéance every benefit is bounded by
pm(t) + prov_div(t): the surrender value is that less charges and the death value is exactly it, the garantie décès plancher being funded outside the account and excluded here. Neither the L. 134-3 contribution nor the PGT may reach a policyholder, and on the shipped Chassis B cells the PGT is positive for four consecutive years, so the check is live rather than decorative: an implementation that floored the Chassis B surrender value at the guarantee would pay 11,760.00 against a bound of 9,899.22 and fail here.The residual is zero in the last projected month, the one that ends at the échéance, and that is not a gap. The maturity guarantee on Chassis B legitimately exceeds the account’s provisions, and paying it out of the PGT is precisely what the PGT was constituted for.
- check_own_funds_not_paid()[source]#
True when no benefit before the échéance exceeds the savers’ two provisions.
- check_pm_restruck_resid(t)[source]#
The in-force extract’s provision mathématique against the re-strike; zero.
R. 134-2 makes the PM the guaranteed amount discounted at the current A. 134-1 rate, so an extract cannot supply it independently: this compares what the extract reports against what the rule requires, at the valuation date.
Zero by construction on a new-business cell, where there is no extract to check, and on Chassis B, which has no PM at all. On the in-force cell it is a live cross-check, and what it catches is an extract built by accumulating the PM from issue rather than re-striking it — the same error
check_guarantee_funding()catches inside the projection, arriving from the data side instead.The comparison is against
pm_at(t, "BOM"), the opening PM of the first projected month — the extract’s own valuation date — and not against that month’s closing PM.proj_start()is a month now, 48 on shipped point 7, anddisc_factor(48)discounts overrem_term(48) = 6years, so the re-strike lands on the extract’s 8,575.24 exactly as it did on the annual grid.
- check_pm_restruck()[source]#
True when a shipped in-force provision mathématique agrees with R. 134-2.
- result_cf()[source]#
Result table of cashflows, indexed by the 0-based policy month t.
The frame is
range(proj_start(), proj_len()): one row per projected policy month — 120 on the worked example and 72 on the in-force point 7 — the first of which carries the initial versement and the acquisition costs it draws.pols_ifis the start-of-month count, which is the exposure the flows on that same row are weighted by; the notes’ end-of-monthl(t)ispols_if_at(t, "AFT_DECR")and is not published here.charges_takenandrider_claimsare memo lines outsidenet_cf— the first is a transfer inside the account from the savers to the insurer, and the second is already insideclaims_death.
- result_cf_annual()[source]#
result_cf()summed into policy years, indexed bypolicy_year.Every cash flow column is the total of its twelve months;
pols_ifis the count at the start of the policy year,pols_if(12 x (policy_year - 1)), which is the number the annual-step model this one replaced carried on the same row. It is the monthly frame regrouped, never a second projection, which is what lets the notes’ annual figures be laid beside the monthly ones and the difference read off.Laid beside the annual-step model this one replaced, the columns split three ways.
pols_ifandpremiumsagree exactly on every shipped model point: the opening in-force is what the monthly decrements compound back to, and a versement is collected in a month the contract names and weighted by the in-force of that month under either grid.withdrawalsagrees on every cell that takes no rachat partiel, which is all of them but point 5.charges_takenagrees wherever the decrements are switched off (points 1-4); elsewhere its surrender-indemnity term is weighted by the month of exit and moves with the claims.The rest do not agree, and are not meant to.
expensesmoves because maintenance now accrues at one twelfth a month on the month’s own provision and in-force and the annual grid’s extra opening-striking charge is gone — the largest single-year gap on the shipped cells is 33.28 EUR, on point 9. Theclaims_*columns move because a claim now falls at the end of the month of exit rather than of the year.liability_cfandnet_cfinherit both. That gap is the point of the finer grid.The frame opens on the policy year the model point’s first projected month opens, so an in-force cell is indexed from
duration_inforce() + 1rather than from 1.
- result_provisions()[source]#
Result table of the provision machinery, indexed by the 0-based policy month t.
Every column is a closing value of month t, or a rate applied within it. The account’s assets against the two provisions, the parts and their value, and the insurer’s own-funds items beside them — reported, and never in a benefit. The notes’ two worked-example tables are the anniversary rows of this frame,
t = 11, 23, ..., 119, whose opening state isown_assets_at(t, "BOM")and its siblings rather than a row of the frame. The other eleven rows of each policy year are the A. 134-5 intermediate valuations, which the annual grid could not report at all.i_pmis the rate the month’s provisions are struck at:i_pm(t + 1), the A. 134-1 rate at the month-end boundary, sincei_pm()is indexed by a month boundary.