The Data Space#
Input data shared by every by-policy projection.
The seven input CSVs are read here, once per model, and referenced from
Projection as data. Projection is
parameterized by point_id, so each Projection[N] is a separate ItemSpace with its
own cells cache; if the readers lived there, every model point would re-read every file.
Holding them in an unparameterized Space reads each file once no matter how many policies
are projected.
Inputs are external files: plain CSVs in the model folder’s parent directory,
products/basisrente/, rather than data 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
Basis_DE_S folder without its parent’s CSVs produces a model that reads and then
fails on first evaluation.
input_dir() resolves the directory from _model.path.parent at run time, so the
model works wherever the repository is checked out. Each table has a filename Reference
and a reader Cells:
Reference |
Cells |
File |
|---|---|---|
model_point_file |
model_point_table() |
model_point_table.csv |
mort_table_file |
mort_table() |
mort_table.csv |
surplus_file |
surplus_table() |
surplus_table.csv |
rentenfaktor_file |
rentenfaktor_table() |
rentenfaktor_table.csv |
charge_file |
charge_table() |
charge_table.csv |
behaviour_file |
behaviour_table() |
behaviour_table.csv |
option_file |
option_table() |
option_table.csv |
Every file but ``model_point_table.csv`` carries a final ``provenance`` column, one tag per row — delib’s second ruling, asserted by the conventions suite. A model point is a configuration rather than an assumption, which is why it is the single exemption.
The mortality table is a [std] proxy, and here is its anchor
mort_table.csv is not DAV 2004 R. DAV 2004 R is the property of the Deutsche
Aktuarvereinigung, is not public, and is not redistributed here; it is cited by name in
sources.md and in the technical notes, and what ships instead is a shaped proxy:
qx(age) = min(1.0, 0.014000 x 1.085^(age - 67))over ages 20 to 121, withqx(121) = 1.0and a flat improvementtrend = 0.015at every age applied frommort_base_year = 2005.
The anchor a replacement must preserve is ``qx(67) = 0.014000`` exactly, because the notes’ worked example converts at attained age 67 and every figure in the payout phase of that example is struck off it. A replacement must also preserve three structural properties, or the model stops being a model of this product:
it must be generational — DAV 2004 R is a Generationentafel, with the improvement inside the table rather than applied on top of it, which is why
mort_rate_at_agetakes a calendar year as well as an age and whycal_year(t)is carried at all;it must be first order, carrying the DAV’s prudential margins, because the guaranteed Rentenfaktor is struck on that basis and the projection’s own
mort_be_factorsteps down from it to a best estimate;it must run to a terminal age at which
qxis 1.0, becauseproj_len()is derived from the last age in this file and the projection has no tail state.
The 1.085 slope and the 1.5 % flat trend are [std] with nothing behind them: DAV 2004 R’s own trends are age-dependent, and no Basisrente-specific decrement evidence exists anywhere in the delib corpus.
What the other six files are
surplus_table.csv is the insurer’s discretionary path in the Aufschubphase and the
Rentenphase, keyed on the projection index t itself, 0-based like the frame:
decl_rate is the declared laufende Verzinsung, which in German
practice is the total credited rate including the Rechnungszins and not a spread
over it, and ann_bonus_rate is the Überschussrente uplift. It is a scenario, not a
forecast, and the base path is set above the 1,00 % Höchstrechnungszins so the
guarantee does not bind on the anchor.
rentenfaktor_table.csv is the aktueller Rentenfaktor by conversion age and
scenario, in euro of monthly annuity per 10 000 € of capital. No Rentenfaktor level,
range or time series exists anywhere in the delib corpus, so both this table and the
guaranteed factors on the model points are [std]; the low scenario exists so that
model point 13 exercises the other branch of max(garantiert, aktuell).
charge_table.csv holds one row per tariff: the four charges struck against the
policyholder’s Deckungskapital (the Zillmerung rate, the premium charge β, the
reserve charge γ and the Stückkosten), the Schlussüberschussanteil rate, and the
insurer’s own expense and commission scale. Two tariffs ship, differing only in
zill_rate: 25 ‰ of the Beitragssumme for business written from 1 January 2015 and
40 ‰ for the pre-LVRG in-force cohorts.
behaviour_table.csv holds the two behavioural assumptions that vary by duration —
the Beitragsfreistellung rate and the Zuzahlung take-up. Its ``dur`` index is the
policy year, ``duration(t) + 1``, so the notes’ “durations 1–5” reads off the file
directly; duration(t) itself is completed policy years and is 0 in the first year.
option_table.csv holds one multiplicative factor per contractual option:
prem_mode is the Ratenzahlungszuschlag applied to the laufender Beitrag alone,
and guarantee_period and survivor are reductions in the Rentenfaktor, because a
German tariff pays for those covers out of the annuity rather than by scaling the death
benefit.
model_point_table.csv is the thirteen policies, indexed by point_id, which is
Projection’s only parameter.
Cells Descriptions#
- input_dir()[source]#
The directory holding the input CSVs: the model folder’s parent.
Inputs are external files, not data stored inside the model, so the model folder is pure formulas. The path is resolved at run time from where the model was read, following
annuallife.TradLife_A.
- model_point_table()[source]#
The model point table, read from model_point_table.csv.
Indexed by
point_id. The single input file exempt from delib’s provenance rule: a model point is a configuration — one policy’s own terms — rather than an assumption.
- mort_table()[source]#
The first-order annual death rates and improvement trends by age.
Read from mort_table.csv, indexed by
age:qxis the rate at the base calendar yearmort_base_yearandtrendthe annual improvement that makes the basis generational. A [std] proxy anchored atqx(67) = 0.014000, not DAV 2004 R; see the Space docstring for what a replacement must preserve.
- surplus_table()[source]#
The declared surplus path by scenario and projection year.
Read from surplus_table.csv, indexed by
scenario_idand the 0-based projection yeart, whose first row ist = 0:decl_rateis the declared laufende Verzinsung in the Aufschubphase — the total credited rate including the Rechnungszins, not a spread over it — andann_bonus_ratethe Überschussrente uplift in the Rentenphase.
- rentenfaktor_table()[source]#
The aktueller Rentenfaktor by scenario and conversion age.
Read from rentenfaktor_table.csv, indexed by
rf_scenario_idandage:rf_curris euro of monthly annuity per 10 000 € of capital at Rentenbeginn. Entirely [std] — no Rentenfaktor level, range or time series exists anywhere in the delib corpus.
- charge_table()[source]#
The charge, expense and commission scale by tariff, from charge_table.csv.
Indexed by
tariff_id. The first four columns are deductions from the policyholder’s Deckungskapital and are therefore insurer income; the last five are the insurer’s own outgo. Booking a charge as both is the fourth listed modeling pitfall, and keeping the two groups in one file is what makes the split visible.
- behaviour_table()[source]#
The duration-varying behavioural assumptions, from behaviour_table.csv.
Indexed by
beh_table_idanddur, where ``dur`` is the policy year,duration(t) + 1.bf_rateis the Beitragsfreistellung rate — the product’s only behavioural exit, and not a lapse — andzuz_take_upthe utilisation rate of the Zuzahlung, which is paid out of a profit not known until the year end and is therefore behavioural rather than contractual. Both are [std] with no calibration evidence of any kind.
- option_table()[source]#
One multiplicative factor per contractual option, from option_table.csv.
Indexed by
option_idandoption_key.prem_modegives the Ratenzahlungszuschlag, which multiplies the laufender Beitrag and nothing else;guarantee_periodandsurvivorgive the reduction in the Rentenfaktor that pays for a Rentengarantiezeit and a Hinterbliebenenrente.