Technical Notes#
Status: Draft, 2026-08-29 (access date for every citation below).
Scope note. These notes specify a reference liability cash-flow projection model — model name
Riester_DE_S, monthly grid over an annual contract — for the standardized composite German klassische
Riester-Rentenversicherung defined in product-spec.md (same directory). This is not any single
insurer’s product; no carrier level was established at any house for any year — three retrieved
wordings now fix the shapes [S2] [S4] [S6], but one tariff is not a market — so every carrier
parameter below is std and every statutory one is cited. These notes were drafted with no
retrieval and no search available and have since been re-verified against the primary documents:
every statutory citation below was checked against the canonical XML, and twenty-six of the
forty-two entries in sources.md now record Retrieved: yes. [S#]/[R#] tags refer to that source
list (numbering carried from _research/riester_rente.md; frozen); [REG-R#] tags refer to the
cross-product reference library references/regulatory-and-actuarial-references.md (its own frozen
R1–R56 numbering). unverified now marks a claim this re-verification did not reach — a carrier
level, a market figure, a behavioural rate, a historic vintage. Parameter values are identical to
those in
product-spec.md. Cells names, model-point columns and CSV headers are English lower_snake_case;
German terms of art keep their German form in prose.
Model scope and conventions#
Purpose. Project gross best-estimate liability cash flows, undiscounted — the saver’s Eigenbeitrag, the state Zulage, death, surrender, transfer, lump-sum, commutation and annuity benefits, expenses and commission — for a single-policy model point on an expected (probability-weighted) basis, together with the two state variables that make the product what it is: the account (Deckungskapital plus Überschussguthaben) and the Beitragsgarantie accumulator. Discounting, the Deckungsrückstellung, the Zinszusatzreserve, Solvency II technical provisions, the risk margin and capital are out of scope and are referenced rather than specified (see Valuation and reserve pointers).
Projection grid: monthly, over a contract that is annual. The model runs on two clocks and the argument of a cells says which.
tcounts projection months from the valuation date and is 0-based:t = 0 … proj_len() − 1withproj_len() = 12 × proj_len_y().k = proj_year(t) = t // 12counts projection years and is the annual-step model’s ownt. The contractual contract year isduration_y(k) + 1 = duration_init + k + 1, which isk + 1only on a point projected from its own inception (duration_init = 0). The valuation date is 1 January 2027 std — the first day on which the product is closed to new business REG-R44 — socalendar_year_y(k) = 2027 + kand the calendar year steps on the anniversary. The contract is annual in every respect the annual clock carries: the Zulage is an annual entitlement determined on a calendar year and paid once by the ZfA R9 R10 R11, the Überschuss is declared annually, the two charges and the interest credit fall once a year, and the Beitragsgarantie is tested once. The Eigenbeitrag keeps it too, because the Ratenzuschlag prices a fractionated payment mode by loading the amount rather than by moving the contribution year.What the monthly clock is for. The in force, the three decrements, the claims, the expenses, the commission and the Rente instalments. The decrements carry the library’s two speeds —
mort_rate,lapse_rateandtransfer_rateare the annual rates of the year the month falls in,mort_rate_mth,lapse_rate_mthandtransfer_rate_mththe geometric twelfths the recursion applies — so twelve months compound back to each annual rate exactly andpols_if(12k)is the annual-step model’spols_if(k)to the last bit. The whole accumulation is therefore unchanged, and what the grid buys is the monthly Leibrente the AltZertG requires, together with a dated split of the three accumulation exits; both are quantified below.proj_len()is the number of projected periods, the exclusive end of the frame, per the library ruling asserted intests/test_model_conventions_de.py:result_cf().index[-1] == proj_len() − 1andlen(result_cf()) == proj_len().proj_len_y() = omega_age − age(0) + 1, withage(0) = issue_age + duration_initandomega_age = 110std. The frame is contiguous0 … proj_len() − 1on every model point, including a point that commutes at Rentenbeginn and therefore carries zeros to the end — a uniform frame is what lets two model points be read side by side, and truncating a commuted point is a numbered pitfall.Two phases in one projection.
k_conv() = rentenbeginn_age − age(0)is the conversion year andt_conv() = 12 · k_conv()the conversion month.is_accum(t)holds fort < t_conv(),is_payout(t)fort ≥ t_conv(), withis_accum_y(k)andis_payout_y(k)the annual readings. The accumulation recursions stop atk_conv(); the annuity liability runs fromt_conv()toproj_len() − 1. A model that stops at Rentenbeginn has not modelled a lifelong annuity, which is the benefit the AltZertG requires R1 REG-R43.Timing conventions std. The Eigenbeitrag and any unsubsidised contribution are received in the first month of the projection year; the Zulage earned in year
k − 1is credited in that same month of yeark, alongside that year’s own contribution; charges are deducted from the contribution there; interest is credited at the end of the year on the account plus the year’s Sparbeitrag; decrements act at the end of each month, and death, surrender and transfer benefits are struck onav_total_pp(k + 1)— the annual end-of-year account value, which is where the account is struck, so an exiting policy still takes the full year’s interest and a contract year’s exits release exactly what the annual-step model released. Conversion happens att_conv(), after the final Zulage has been credited and before any payout-phase mortality. Annuity instalments are paid monthly in advance.The monthly Leibrente, which is why the grid is monthly. The contract pays a monthly Leibrente in advance R1 and the Rentenfaktor is quoted in euro a month. The annual-step model these notes were first written for paid twelve instalments as one annual amount at the start of the payout year, to those alive at the start: for a life dying during the year it paid a full year where the contract pays only the instalments falling due, an overstatement of roughly
½ · q(x) · 12Ra year, about 0,7 % of the annuity at attained age 70 on the shipped proxy. That approximation is gone —annuity_month_pp()is paid to whoeverpols_annuity_pay(t)says is paid that month — and it is worth 361,74 € of the anchor’s payout phase and 573,50 € of model point 12’s, which carries no Rentengarantiezeit. Inside a guarantee window the two grids agree to the cent, the count being fixed there. The level of the annuity was always right, the conversion factor carrying the Woolhouse−11/24correction.Age basis. Age last birthday,
age_y(k) = issue_age + duration_init + k, stepping on the anniversary so the twelve months of a projection year share one rate. Riester tariffs are unisex from a 2006 vintage R23 REG-R34, sosexis carried for reporting only and must not enter any rate.Currency, sign and rounding. EUR throughout.
net_cf(t)is income-positive — contributions and Zulagen positive, benefits and expenses negative — with the outgo-positive orientation published asliability_cf(t) = −net_cf(t). Intermediate values at full precision; displayed cash flows to the cent,pols_ifto six decimals std.Out of scope, and said so rather than left to be discovered. No unit-linked funds and no rebalancing algorithm (that chassis is
fondsgebundene_rentenversicherung); no Auszahlungsplan mit Restverrentung; no Wohn-Riester in either limb — no Eigenheimbetrag withdrawal decrement, no certified Darlehen, no Wohnförderkonto R13 R19; no Berufsunfähigkeits- Zusatzversicherung liability (only the guarantee carve-out its premium creates); no Versorgungsausgleich; no surplus in payment; no Günstigerprüfung and no policyholder tax of any kind; and no apportionment of investment return between the two contribution pools, which a real Leistungsmitteilung must perform R12.
Model inputs#
Inputs are external CSVs beside run.py, in the annuallife/TradLife_A layout: the model folder
holds __init__.py, _system.json and the two Space directories and nothing else. Data holds
input_dir(), one reader cells per file and one *_file string Reference per file, takes no
parameters, and is therefore read once per model rather than once per model point; Projection
reaches it through a data Reference and holds no *_file Reference and no input_dir.
File |
Index columns |
Value columns |
|---|---|---|
|
|
the twenty-six attributes tabulated below |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Every file except model_point_table.csv carries a per-row provenance column, delib’s second
ruling: a model point is a configuration, every other row is an assumption and says where its number
came from. The two decrement tables are std proxies for proprietary DAV tables that this
library does not ship REG-R47 REG-R48 REG-R49, anchored so that the worked example reproduces
exactly; what a replacement must preserve is stated in assumption class (c) and in sources.md.
Cells vocabulary#
Data publishes input_dir, model_point_table, mort_table_accum, annuity_mort_table,
lapse_table, zulage_schedule, income_schedule, surplus_scenario and freq_loading.
Projection publishes the library’s shared names — model_point, proj_len, age, pols_if,
mort_rate, claims, expenses, net_cf, result_cf — plus, in the same lifelib spelling:
pols_if_init, pols_if_at, pols_death, pols_lapse, pols_transfer, pols_conv,
pols_annuity_pay; mort_rate_at_age, annuity_mort_rate, lapse_rate, transfer_rate;
duration, duration_y, duration_mth, contract_year, calendar_year, calendar_year_y,
proj_len_y, proj_year, is_anniv, prem_due, k_conv, t_conv, is_accum, is_accum_y,
is_payout, is_payout_y; mort_rate_mth, lapse_rate_mth, transfer_rate_mth; income_ref,
zulage_entitlement_pp, zulage_granted_pp, zulage_pp, zulage_cum_pp,
mindesteigenbeitrag_pp, eigenbeitrag_pp, eigenbeitrag_paid_pp, contrib_total_pp;
acq_charge_pp, admin_charge_pp, prem_to_av_pp; dk_pp, surplus_acct_pp, av_total_pp,
av_total_pp_at, av_total_at, int_guar_pp, int_surplus_pp, int_credited_pp, decl_rate;
guar_pp, guar_carve_out_pp, garantieluecke_pp, pool_gefoerdert_pp, pool_ungefoerdert_pp;
slueb_pp, bewres_pp, account_conv_pp, capital_conv_pp, garantieluecke_conv_pp,
ann_factor, rentenfaktor_curr, rentenfaktor_applied, annuity_month_pp, is_kleinbetrag,
teilkapital_pp, annuity_capital_pp, commutation_pp, annuity_pp; db_pp, cv_pp,
transfer_value_pp, exit_charge_pp; premiums, zulagen, int_credited, commissions,
liability_cf, result_cf_annual; and the six check_* cells with their check_*_resid
companions — four of which take a projection year, because the account, the guarantee
accumulator, the conversion and the ZfA lag move once a year. claims(t, kind)
takes an uppercase kind in {DEATH, LAPSE, TRANSFER, LUMPSUM, COMMUTATION, ANNUITY} and produces
the claims_<lowercase kind> columns. No retired name is used: there is no lapse_rate_ann, no
prem_net_pp, no mort_ae_factor, no check_pols_if, no claims_wd and no bare claims column.
Model point attributes#
model_point_table.csv is indexed by point_id and carries the columns below. It is the one input
file exempt from the provenance rule, because a model point is a configuration rather than an
assumption. The right-hand column names the points that exercise each attribute away from its base
value; the thirteen points are described under Worked example.
Attribute |
Type |
Meaning |
Exercised by |
|---|---|---|---|
|
int |
Row key; |
all |
|
enum {M, F} |
Reporting only. Pricing, the conversion and every rate are unisex R23 |
all |
|
int |
Attained age at conclusion of the contract |
all |
|
int |
Completed contract years at the valuation date; 0 for a point projected from issue |
2, 6, 13 at 0 or 1 |
|
float |
Policies represented; |
all |
|
int |
Attained age at which the payout phase starts; bounded below by 62 for a contract concluded from 2012 R1 |
13 (at the statutory floor, 62) |
|
float |
The tariff’s guaranteed rate, at or below the Höchstrechnungszins of the vintage R22 REG-R15 |
3 (0,90 %), others 0,25 % |
|
EUR |
The Beitragssumme fixed at conclusion; the acquisition-charge and initial-commission base |
all |
|
enum {mindest, fixed} |
|
5, 8 |
|
EUR p.a. |
The level contribution under |
5 (60,00), 8 |
|
float |
Fraction of the Mindesteigenbeitrag actually paid; drives the proportional Kürzung R10 |
7 (0.50) |
|
EUR p.a. |
Unsubsidised contribution above the § 10a ceiling; enters the account and the guarantee, draws no Zulage R12 |
8 (900,00) |
|
EUR p.a. |
Contribution applied to a biometric rider. Not a cash flow of this model; it appears only in the guarantee carve-out, capped at 20 % of total contributions REG-R43 |
9 (400,00) |
|
str |
Key into |
all |
|
EUR |
Contribution-liable earnings in the calendar year before the projection starts; the reference income for |
all |
|
str |
Key into |
all |
|
EUR |
The Zulage credited at |
6 (375,00, including the bonus) |
|
enum {annual, half_yearly, quarterly, monthly} |
Payment frequency; keys |
3, 4, 6, 7, 10, 13 |
|
int |
The 0-based period index |
10 ( |
|
EUR |
Deckungskapital at the valuation date |
all |
|
EUR |
Überschussguthaben at the valuation date |
all |
|
EUR |
Beitragsgarantie accumulator at the valuation date |
all |
|
float |
Elected Teilkapitalauszahlung, 0 to the statutory 0.30 R1 |
12 (0.00) |
|
float |
Guaranteed Rentenfaktor, € of monthly annuity per 10 000 € of capital, struck at inception |
all |
|
int |
Rentengarantiezeit; payments continue to beneficiaries for this many years from Rentenbeginn |
12 (0) |
|
str |
Key into |
11 ( |
Three of these are the ones a reader from another market is most likely to mis-set. zulage_init_pp
exists only because the Zulage arrives a year late R11, so an in-force point opens owing one;
rider_prem_pp is a contribution the model deliberately does not see as cash; and
contrib_ratio is not a lapse or a premium holiday but the § 86 proportional Kürzung, which reduces
the subsidy and not only the contribution.
The thirteen model points#
Between them they exercise both contribution forms, all four payment frequencies, every option the contract carries, an at-issue point beside the in-force ones, and four boundary cases.
# |
Cell |
What it exercises |
|---|---|---|
1 |
Anchor — F, issue age 47 in 2024, in force at duration 3, attained 50, Rentenbeginn 67, 0,25 %, one child born 2010, annual |
The worked example. A live acquisition-charge window, a falling Zulage step, the 2 100 € ceiling binding from |
2 |
The same contract at its own inception — |
Acquisition charge from contract year 1, the acquisition expense and initial commission cash at issue, and the reconciliation of point 1’s opening balances |
3 |
Family with children born 2006 and 2010 — M, issue age 38 in 2018, 0,90 %, monthly |
Both Kinderzulage rates running simultaneously (660,00 € entitlement); an older Rechnungszins vintage; the monthly frequency loading |
4 |
§ 86 case D — income 20 000 €, two post-2008 children, quarterly |
The Sockelbeitrag floor binding (boundary); a 12,92× subsidy multiple; and a Kleinbetragsrente commutation at Rentenbeginn |
5 |
Mittelbar eligible spouse — |
The |
6 |
Berufseinsteiger — M, issue age 23 in 2026, attained 24, monthly |
The once-in-a-lifetime 200 € bonus inside |
7 |
Under-payer — |
The § 86 proportional Kürzung: half the contribution, half the Zulagen |
8 |
Two pools — |
|
9 |
Rider carve-out at the cap — |
The 20 % cap on the biometric carve-out binding (boundary) |
10 |
Beitragsfreistellung — |
The book’s dominant exit as a state change: guarantee frozen, Zulagen stopped, account rolling, acquisition charge still biting |
11 |
Low declared rate on a short deferral — F, issue age 57 in 2024, in force at duration 3, attained 60, Rentenbeginn 67, income 60 000 € so the 2 100 € ceiling binds, |
A positive Garantielücke at Rentenbeginn — the product’s signature output. The deferral is seven years rather than seventeen because on the anchor’s own term 0,50 % still does not open a gap; that result is reported under Worked example as the sensitivity it is |
12 |
No lump sum, no guarantee period — |
The pure lifelong annuity, and the invariance of |
13 |
Late entrant at the statutory floor — issue age 60 in 2026, Rentenbeginn 62, monthly |
The earliest certifiable payout age for a post-2012 contract (boundary); the shortest accumulation and the least guarantee headroom |
Model point 1 is the worked example’s anchor cell and is Projection[1].
State variables#
Variable |
Description |
Updated |
|---|---|---|
|
Number of projected years, |
once per model point |
|
Number of projected months, |
once per model point |
|
The projection year of month |
within year |
|
The conversion year, |
once |
|
Attained age, completed contract years at the start of projection year |
annual, stepping on the anniversary |
|
Policies in force at the start of month |
monthly recursion |
|
|
within month |
|
Expected deaths, surrenders and Anbieterwechsel exits in month |
monthly |
|
Policies reaching Rentenbeginn; policies on which an annuity instalment is actually paid, which during the Rentengarantiezeit is |
annual |
|
The previous calendar year’s contribution-liable earnings driving year |
annual (lag 1) |
|
Full § 84/85 entitlement; entitlement after the § 86 proportional Kürzung; the amount actually credited in year |
annual (lag 1) |
|
The § 86 minimum; the contribution before the frequency loading; the amount actually collected |
annual |
|
The Sparbeitrag — the part of the contribution credited to the account, after charges. May be negative in a beitragsfrei year |
annual |
|
Deckungskapital, Überschussguthaben, and their sum at the start of year |
annual recursion |
|
|
within year |
|
Guaranteed interest at the Rechnungszins, declared surplus above it, and their sum |
annual |
|
The Beitragsgarantie accumulator; the biometric carve-out capped at 20 %; the running shortfall |
annual |
|
Cumulative subsidised and unsubsidised contributions credited. Contributions only — the model does not apportion investment return between the pools and says so |
annual |
|
Cumulative Zulagen credited: the ZfA-reclaimable limb of the Rückzahlungsbetrag. A diagnostic, never netted from a benefit |
annual |
|
Conversion capital and the Garantielücke the insurer funds at Rentenbeginn — the product’s signature output |
once, at |
|
|
once |
|
The commutation test and its consequences |
once |
|
Death benefit, Rückkaufswert, Anbieterwechsel transfer value, and the Stornoabzug plus transfer charge the insurer retains |
annual |
Assumption inputs#
Three classes, and the split is not cosmetic: class (a) is what the contract or the statute obliges, class (b) is what the insurer decides afresh each year, class (c) is the modeller’s view. On this product class (a) is unusually large — most of the product is statute — and class (b) is unusually consequential, because the declared rate is what decides whether the guarantee costs anything.
(a) Contractual and guaranteed elements (cited)#
Input |
Value |
Basis |
|---|---|---|
Grundzulage |
175.00 per year — § 84 Satz 1 EStG, “ab dem Beitragsjahr 2018 jährlich 175 Euro” |
|
Kinderzulage |
185.00 for a child born before 1 Jan 2008; 300.00 for one born on or after — § 85 Abs. 1 Sätze 1 and 2, keyed to Kindergeld being festgesetzt |
|
Berufseinsteiger-Bonus |
200.00, “einmalig”, 25th year not completed at the start of the contribution year, first year a Zulage is claimed — § 84 Sätze 2 and 3 |
|
Mindesteigenbeitrag rate, ceiling, floor |
4 % of the previous year’s contribution-liable earnings, capped at the § 10a Abs. 1 Satz 1 Höchstbetrag of 2 100.00, less the entitlement, floored at the 60.00 Sockelbeitrag — § 86 Abs. 1 Sätze 2, 4 and 5 |
|
Proportional Kürzung |
The Zulage is reduced in the ratio of the contribution paid to the Mindesteigenbeitrag — never lost outright |
|
Zulage cash lag |
Contribution year |
|
Beitragsgarantie |
At Rentenbeginn, at least “die bis dahin gezahlten Beiträge und die uns zugeflossenen staatlichen Zulagen” must be available for the agreed benefits — statutory as to the test, contractual as to the Zulagen |
R1 REG-R43 for the test; [S2] § 1 Abs. 10, [S4] § 1 Abs. 2, [S6] for the Zulagen limb |
Guarantee carve-out |
Biometric-rider contributions excluded, “bis zu 20 Prozent der Gesamtbeiträge” — AltZertG § 1 Abs. 1 Satz 1 Nr. 3, drafted at [S2] § 1 Abs. 10 |
|
Earliest Rentenbeginn |
Completed 62nd year — § 1 Abs. 1 Satz 1 Nr. 2. The 60th for contracts concluded before 1 Jan 2012 is the transitional rule of § 14 Abs. 2, not § 1 |
|
Teilkapitalauszahlung cap |
30 % of “des zu Beginn der Auszahlungsphase zur Verfügung stehenden Kapitals” — § 1 Abs. 1 Satz 1 Nr. 4 Buchst. a |
|
Acquisition-cost spreading |
“gleichmäßig mindestens auf die ersten fünf Vertragsjahre …, soweit sie nicht als Prozentsatz von den Altersvorsorgebeiträgen abgezogen werden” — § 1 Abs. 1 Satz 1 Nr. 8. The qualifier is why the charge on a Zulage is taken once at inflow in every retrieved wording |
R1 REG-R43 [S2] [S4] [S6]; Höchstzillmersatz 25 ‰, DeckRV § 4 Abs. 1 REG-R16 |
Kleinbetragsrente threshold |
The statutory rate is 1,5 %, not 1 %: § 93 Abs. 3 Satz 2 Nr. 1 EStG, aggregated across the saver’s contracts at that provider (Satz 3). On the 3 955.00 monthly Bezugsgröße used here that is 59.33. |
|
Rückkaufswert floor |
“mindestens der Betrag des Deckungskapitals, das sich bei gleichmäßiger Verteilung der angesetzten Abschluss- und Vertriebskosten auf die ersten fünf Vertragsjahre ergibt” — § 169 Abs. 3 VVG; satisfied by construction here, and both retrieved wordings compute it that way |
REG-R28 [S2] [S4] |
Annuity form |
Lifelong, monthly, “gleich bleiben oder steigen” over the whole payout phase; up to twelve monthly payments may be combined into one |
|
Unisex |
“eine lebenslange und unabhängig vom Geschlecht berechnete Altersversorgung” — § 1 Abs. 1 Satz 1 Nr. 2, and in the wordings at [S2] § 1 Abs. 1, [S4] § 1 Abs. 1 and a “geschlechtsunabhängige Sterbetafel” at [S6]. The dates — 1 Jan 2006 for Riester, 21 Dec 2012 for the general market — are |
Gap 6 is closed and this footnote’s premise no longer holds. § 90 Abs. 2 EStG has the ZfA pay the provider, who “hat die erhaltenen Zulagen unverzüglich den begünstigten Verträgen gutzuschreiben”; § 89 Abs. 1 and Abs. 3 put the application and the provider’s data transmission in the year after the contribution year at the earliest; and AltvPIBV § 9 Abs. 3 fixes the crediting date for every disclosure calculation at 15 May of that year R5. Reversals are settled quarterly — § 90 Abs. 3, remittance “bis zum zehnten Tag des dem Kalendervierteljahr folgenden Monats” — within a two-year recognition window. What remains std is only the compression of a mid-May credit onto the first month of the projection year; the frequency of reversals is established, their rate is experience data and is not (gap 16).
The statute settles it, and against the model. § 93 Abs. 3 Satz 2 Nr. 1 EStG defines a Kleinbetragsrente as one that “1,5 Prozent der monatlichen Bezugsgröße nach § 18 des Vierten Buches Sozialgesetzbuch nicht übersteigt” R15. On the Bezugsgröße this file uses the threshold is 59,33 €, and
kleinbetrag_threshold_mth = 39.55is a third of the way below it. Raising it would make more contracts commute and shorten the liability, so the direction of the error is toward a longer tail. This is a model change and has not been made (see the note under Model-relevant contradictions below). Two further points stand unchanged: the threshold is held flat in nominal terms while the Bezugsgröße is reset annually, which understates the commutation rate on a long deferral (sensitivity 7); and the test is applied after the elected lump sum, which the GDV model wording forbids [S2] — also a model change, also deferred. What is now settled in the model’s favour is that commutation is the provider’s option [S2] [S4].
(b) Insurer-discretionary current elements (snapshot; revisable annually)#
Input |
Value |
Basis |
|---|---|---|
Rechnungszins |
0,25 % on the anchor, a 2024-vintage tariff; 0,90 % on one older point |
cap R22 REG-R14 REG-R15. Two carrier choices are now established — 1,25 % on a 01.15 tariff [S4], 0,9 % on a 01.01.2025 tariff [S6] — but neither is the anchor’s vintage, so the level stays std (3) |
Laufende Verzinsung |
Scenario path in |
std (4) |
Surplus system in accumulation |
Verzinsliche Ansammlung: declared surplus accrues in a second account beside the Deckungskapital and bears the declared rate |
market practice; level std (4) |
Risikoüberschuss and Kostenüberschuss |
Zero in the base run |
std (5) |
Schlussüberschussanteil |
2,0 % of contributions credited, declared at Rentenbeginn, and counted toward the guarantee |
std (6), gap 9 |
Bewertungsreserven share |
1,0 % of the account at Rentenbeginn, the hälftige participation of § 153 Abs. 3 VVG |
|
Acquisition charge |
2,5 % of |
R1 REG-R16; level std (7) — against 1,0 % of the Eigenbeiträge at the one carrier now in hand [S4] |
Administration charge |
4,0 % of each contribution credited, Zulagen included, plus a fixed 12,00 per year |
Charging the Zulagen is confirmed [S2] [S4] [S6] [S9], gap 14 closed; the rate is contradicted — 2,1 % on contributions against 6,0 % on Zulagen at [S4] — and the levels stay std (7) |
Frequency loading |
1.0000 / 1.0100 / 1.0200 / 1.0300 for annual / half-yearly / quarterly / monthly, treated as a charge and never credited to the account |
std (7). One scale is now observed and has a different mechanic: +1,0 / +2,0 / +3,0 percentage points on the administration rate for half-yearly / quarterly / monthly [S4] |
Risikobeitrag |
Zero — the death benefit is the account value, so there is no sum at risk |
design consequence std |
Stornoabzug; transfer charge |
2,0 % of the account on surrender; 50,00 flat on an Anbieterwechsel, with no Stornoabzug |
§ 169 Abs. 5 VVG requires a deduction to be “vereinbart, beziffert und angemessen” REG-R28. The transfer-charge ceiling is 150,00 and gap 8 closes — AltZertG § 1 Abs. 1 Satz 3 R1; 50,00 is what one fund provider charges [S9] and one insurer charges nothing [S4]. Levels std (7) |
Rentenfaktor margin |
30 % off the actuarially fair factor, carrying the Sicherheitsabschlag and the whole payout-phase loading |
std (8). The construction — per 10 000 €, monthly, higher of guaranteed and current — is now established in a Riester wording [S6]; the margin is not |
Annuitisation interest basis |
1,00 %, the Höchstrechnungszins in force from 1 January 2025 |
The Höchstzinssatz caps the rate at which the Deckungsrückstellung is computed, not the rate a policy guarantees R22 REG-R14; a tariff may guarantee less, and DeckRV § 2 Abs. 2 fixes whatever rate was used at conclusion “für die gesamte Laufzeit des Vertrages”, which is why
rechnungszinsis a model point attribute. A retrieved wording now proves the “may guarantee less” limb: Debeka’s 1 January 2025 Riester tariff uses 0,9 % where the cap of that vintage is 1,00 % [S6]. Using the cap of the vintage remains the highest defensible value and so makes the guarantee cheapest; a lower tariff rate widens the Garantielücke.No declared rate was established for any Riester tariff at any carrier (gap 12). 2,30 % is a round number in the region German life insurers declared in the mid-2020s REG-R53
[unverified], and 0,50 % is a stress, not a forecast. This is the single most consequential std in the file, because — as the product spec argues — the guarantee’s realised cost is a declared-rate question, not a Rechnungszins question, and model point 11 exists to make that visible.The accumulation-phase risk result is nil by construction here (no sum at risk), and no cost result was established. Setting both to zero keeps the surplus mechanic to the one component the corpus does establish, the Zinsüberschuss, and states the omission rather than burying it.
Which surplus components may close a guarantee shortfall is still not established (gap 9), and this pass can now say precisely why rather than merely that. AltZertG § 1 Abs. 5 does define the gebildetes Kapital for an insurance contract as the Deckungskapital “zuzüglich bereits zugeteilter Überschussanteile, des übertragungsfähigen Werts aus Schlussüberschussanteilen sowie der nach § 153 Abs. 1 und 3 des Versicherungsvertragsgesetzes zuzuteilenden Bewertungsreserven” R1 — but that definition governs the transfer value, and the guarantee of § 1 Abs. 1 Satz 1 Nr. 3 speaks only of what must “für die Leistungserbringung zur Verfügung stehen”. The GDV model wording repeats the guarantee without naming components [S2] § 1 Abs. 10, and uses the § 1 Abs. 5 list only for the transfer value at its own § 11 Abs. 2. So the retrieved documents are silent on the point rather than absent, which is a different and more useful kind of gap. The model counts all of them, the provider-favourable reading; counting only the vested Deckungskapital and Überschussguthaben raises the projected guarantee cost, and that variant is sensitivity 4.
Charge figures now exist, and this footnote’s premise is withdrawn. One complete tariff basis is in hand — CosmosDirekt LA 1005 A § 11 [S4]: acquisition 1,0 % of the Eigenbeiträge spread over at least five years; administration 2,1 % of each Eigenbeitrag, 2,1 % of capital transferred in and 6,0 % of each Zulage; a sub-annual loading of +3,0 / +2,0 / +1,0 percentage points; 0,13 % of the accumulated Beitragssumme taken monthly pro rata from the Deckungskapital, also when paid up; 1,5 % of the annual annuity in payment; and nil Stornoabzug and nil transfer charge. Two disclosed totals are in hand too — Effektivkosten of 1,45 and 1,33 Prozentpunkte at a fund house [S9]. Every level in this table nonetheless stays std, for a changed reason: one tariff is not a range, and the one observation differs from the composite in level, in base and in mechanic. It is recorded here so that the next calibration starts from a document rather than from a round number.
German market Rentenfaktoren sit materially below the actuarially fair factor — a proposition the 0,1 % interest basis behind Debeka’s guaranteed factor makes concrete [S6]. Rather than deduct a percentage from each annuity payment and apply a conservative factor, which double-counts, the whole loading sits in the factor, and the insurer’s real payout-phase administration is a per-policy expense cash flow — which is not what the market does: AltZertG § 2a Satz 1 Nr. 1 Buchst. f permits a charge as a percentage of the benefit paid and one carrier levies 1,5 % of the annual annuity [S4]. The consequence to check is unchanged:
rentenfaktor_curr()and the annuity table are consistent by construction whilerentenfaktor_guaris an independent contract term, and the higher applies when they disagree. That rule is no longer std by default — Debeka drafts it in terms, “Die höhere Rente wird ausgezahlt (Günstigerprüfung)” [S6] — but the level of both factors is, and the design is not universal: neither the GDV model wording nor the CosmosDirekt wording uses a Rentenfaktor at all [S2] [S4] (gap 9).
Model-relevant contradictions found in the 2026-08-30 provenance pass#
Three retrieved documents contradict rules this model implements. None of them has been applied, because each is a model change: it moves the worked example below and the golden tests with it. They are set out here so that a reader of the anchor’s numbers knows which of them rest on a rule the documents now show to be wrong.
What the model does |
What the retrieved document says |
Direction of the error |
|---|---|---|
|
§ 93 Abs. 3 Satz 2 Nr. 1 EStG: “eine monatliche Rente …, die 1,5 Prozent der monatlichen Bezugsgröße nach § 18 des Vierten Buches Sozialgesetzbuch nicht übersteigt” R15. On the 3 955,00 € used here, 59,33 € |
The threshold is a third too low, so too few model points commute and the projected liability is too long-tailed. Model points 4, 5, 10 and 13 already commute; on a 59,33 € threshold others would join them |
|
[S2] § 1 Abs. 3: “Eine Abfindung erfolgt nicht, wenn die Leistung nur aufgrund einer Teilkapitalauszahlung gemäß Absatz 4 auf eine Kleinbetragsrente sinkt.” The test belongs on the annuity the whole conversion capital would buy |
The test trips less often than the wording allows, in the same direction as the threshold error and compounding it on any point that elects the 30 % lump sum |
Administration charge of 4,0 % applied to the Eigenbeitrag and the Zulage at the same rate |
[S4] § 11 Abs. 2: 2,1 % of each Eigenbeitrag and 6,0 % of each Zulage — the Zulagen charged at nearly three times the rate |
The composite undercharges the Zulagen relative to the one tariff observed, which matters most on the low-income cells where the Zulagen are the majority of the contribution |
Two further differences are not contradictions but are worth recording beside them: the model’s frequency loading is a multiplicative factor on the contribution where the observed one is an addition to a charge rate [S4]; and the model’s flat 2,0 % Stornoabzug cannot express the interest-linked market-value adjustment one carrier uses [S6]. Both are std choices whose mechanic, not only whose level, now has an observed alternative.
(c) Behavioural and experience assumptions (the modeller’s view)#
Every input in this class is std. No behavioural rate was established for any German Riester book, for any year — no Stornoquote, no Beitragsfreistellung rate, no transfer-out rate, no commutation take-up (gap 16). Each rationale below is an argument from the statutory consequences, not from data.
Input |
Value |
Rationale |
|---|---|---|
Accumulation mortality |
std proxy standing in for DAV 2008 T REG-R48, applied with |
The DAV tables are proprietary and not redistributed REG-R47. A death-benefit basis carries no improvement projection, because for death cover improvement favours the insurer |
Annuity mortality |
std generational proxy standing in for DAV 2004 R REG-R49: |
The one structural property that is not optional is that the basis is two-dimensional in age and calendar year; a period-table proxy understates a twenty-year-deferred annuitisation by a margin that dwarfs every other assumption REG-R49 |
Why two factors, in opposite directions |
0.80 on the death basis, 1.15 on the annuity basis |
The direction of prudence forks by product REG-R47: a first-order death table assumes mortality higher than expected, a first-order annuity table lower. The best estimate therefore sits below the one and above the other |
Surrender |
0,8 % p.a. at contract durations 1–5, 0,6 % at 6–10, 0,4 % from 11 |
Materially below a Schicht-3 rate, because a Kündigung repays all Zulagen and all § 10a relief (§ 93 Abs. 1 Satz 1) and taxes the growth (§ 22 Nr. 5 Satz 3) R14 REG-R42, and because EStG § 97 makes the subsidised capital non-transferable and ZPO § 851 Abs. 1 therefore unattachable R16 REG-R40 |
Transfer out |
1,2 % p.a. at durations 1–5, 0,9 % at 6–10, 0,6 % from 11 |
Set above surrender, because the Wechselrecht is free of subsidy consequences (§ 93 Abs. 2 Satz 1 EStG) R1 R14 and is therefore the rational exit; the ceding provider may charge at most 150,00 € for it and one retrieved insurer charges nothing [S4]. A model carrying only a lapse rate has mis-specified the book |
Beitragsfreistellung |
A model-point switch ( |
(9) |
Income growth |
2,0 % p.a. on the anchor’s |
A round real-plus-inflation number; it decides when the 2 100 € ceiling binds and so the shape of the contribution stream |
Commutation take-up |
Computed, not assumed — the model tests the annuity against the threshold |
The one behavioural quantity here that does not need a rate |
Teilkapitalauszahlung take-up |
30 % on the anchor, 0 % on model point 12 |
German commentary reports the lump sum as usual |
Expenses |
30.00 p.a. per in-force policy inflating at 2,0 %; 24.00 p.a. per annuitant; 80.00 per claim; 150.00 + 2,0 % of |
No German insurer publishes a unit cost. The per-policy maintenance figure carries the Zulage administration — the Dauerzulageantrag (§ 89 Abs. 1a), the annual data transmission (§ 89 Abs. 3), the quarterly reclaim remittance (§ 90 Abs. 3), the Leistungsmitteilung (§ 22 Nr. 5 Satz 7, due on first receipt and on change rather than annually) and the separate annual information duty of AltZertG § 7a R4 R11 R12 — which is a real and product-specific cost |
Commission |
2,5 % of |
The initial rate is set at the Höchstzillmersatz REG-R16 REG-R20. The cash leaves at issue while the charge is recovered over five years R1; that gap is the new-business strain and it is carried by the insurer |
Beitragsfreistellung is the German Riester book’s dominant exit R25, and the model represents it as a switch on the model point rather than as a decrement. The reason is structural, not laziness: a paid-up policy and a premium-paying one have different account values and different guarantee accumulators from the moment they diverge, so a Beitragsfreistellung rate would require the projection to carry two account values and two guarantee accumulators per model point, and then four, and so on. A scalar single-model-point projection cannot do that without doubling every recursion. The honest representation is a dedicated model point (10) that goes paid-up at
t = 3, plus this statement that a real book needs a paid-up cohort split. It is listed again under Key sensitivities.
Cash flow components and recursions#
Notation, defined once and used throughout#
Symbol |
Cells |
Meaning |
|---|---|---|
|
— |
Projection month, 0-based: |
|
|
Projection year, |
|
|
The conversion year; |
|
|
Attained age, calendar year, completed contract years at the start of projection year |
|
|
Policies in force at the start of month |
|
|
Annual decrement rates of the year month |
|
|
Their geometric twelfths — the rates the recursion applies |
|
|
Reference income; the Eigenbeitrag before the frequency loading |
|
|
The § 86 minimum own contribution |
|
|
Full entitlement; entitlement after the Kürzung; the amount credited in year |
|
|
Frequency loading, a charge and not a credit |
|
|
|
|
|
Acquisition and administration charges |
|
|
The Sparbeitrag, |
|
|
Deckungskapital, Überschussguthaben, and |
|
|
Guaranteed rate; declared laufende Verzinsung, with |
|
|
The Beitragsgarantie accumulator; the biometric carve-out |
|
|
The Garantielücke funded at Rentenbeginn |
|
|
The conversion capital |
|
|
|
|
|
Applied, guaranteed and current Rentenfaktor |
|
|
The annual annuity, a reporting figure: twelve monthly instalments |
|
|
The monthly instalment, which is what is paid |
The subsidy chain#
The whole chain is annual and takes k: the entitlement is determined per contribution year
and the ZfA pays the provider once, in the following one.
Y(k) = income_init for k = 0
= income(k − 1) from income_schedule for k ≥ 1
Z*(k) = 175·unmittelbar(k) + 185·n_pre(k) + 300·n_post(k) + 200·bonus(k)
M(k) = max( 60 , min( 0.04 · Y(k) , 2 100 ) − Z*(k) )
E(k) = contrib_ratio · M(k) (contrib_form = mindest)
= contrib_fixed_pp (contrib_form = fixed)
= 0 (k ≥ bfs_year ≥ 0, or k ≥ T)
Ẑ(k) = Z*(k) · min( 1 , E(k) / M(k) )
Z(k) = zulage_init_pp for k = 0; Ẑ(k − 1) for 1 ≤ k ≤ T; 0 for k > T
On the monthly frame both the Eigenbeitrag and the Zulage fall in the first month of the
projection year — prem_due(t), t % 12 == 0 — and in no other: the Ratenzuschlag prices a
fractionated payment mode by loading the amount rather than by moving the contribution year, and
the ZfA does not fractionate at all.
Two lags, and they are different lags. Y(k) looks back one calendar year because the statute
says the base is the previous year’s earnings R10; Z(k) looks back one projection year because
the ZfA pays in arrear R11. Collapsing them into one is pitfall 1. Note also that Z(T) is
non-zero — the final contribution year’s Zulage lands in the conversion year and must be
credited, guaranteed and converted before the guarantee is tested (pitfall 2).
Contributions, charges and the Sparbeitrag#
All of it is annual and takes k: one contribution, two charges, one Sparbeitrag a year.
B(k) = E(k) + Z(k) + contrib_extra_pp · 1{is_accum_y(k)} charge base, unloaded
C(k) = E(k)·φ + Z(k) + contrib_extra_pp · 1{is_accum_y(k)} cash actually received
K_a(k) = acq_charge_rate · beitragssumme / 5 if d(k) < 5 and k ≤ T, else 0
K_v(k) = admin_charge_prem_rate · B(k) + admin_charge_fixed + E(k)·(φ − 1)
S(k) = C(k) − K_a(k) − K_v(k)
= B(k) − K_a(k) − admin_charge_prem_rate · B(k) − admin_charge_fixed
E(k)·(φ − 1) is the frequency loading: the saver pays E(k)·φ and only E(k) reaches the
Sparbeitrag base, so the loading is a charge and never enlarges the account or the guarantee
(pitfall 11). C(k) is the cash received and therefore carries the loading, which K_v(k)
then takes straight back out; the administration charge’s percentage base B(k) is the
unloaded contribution. The second line above is the algebraic consequence: S(k) is
independent of φ, which is what pitfall 11 asserts — and it is why the contribution keeps the
annual grid on a monthly frame, φ pricing a fractionated mode by loading the amount rather than
by moving the contribution year. An earlier draft of these notes wrote
S = C − K_a − K_v with an unloaded C and a K_v that already carried E(φ − 1), and so
deducted the loading twice; see Changes the model stage made to these notes. K_a continues for its five contract years whether or not contributions are paid,
so on a beitragsfrei contract S(k) is negative and the Deckungskapital falls — which is the
mechanic model point 10 exists to show. The administration charge falls on the Zulagen as well as
the Eigenbeitrag, and gap 14 is closed: German tariffs do charge them. The GDV model wording
permits a charge on “jeder Zulage und Zuzahlung” and takes the acquisition-cost element “einmalig zum
Zeitpunkt des Zuflusses” [S2]; Debeka drafts the same [S6]; Union Investment discloses acquisition
cost as a percentage “der eingezahlten Beiträge (inkl. Zulagen)” [S9]; and CosmosDirekt puts a number
on it, 6,0 % of each Zulage against 2,1 % of each Eigenbeitrag [S4]. The model charges
both at the same rate, which that one observation contradicts — see Model-relevant contradictions
above. It is material for the reason the note always gave: in the low-income cases the Zulagen are
the majority of C(k). The model’s std is now a level, not a structural guess.
The account: two balances, one credited rate#
Both balances are annual, credited once a Versicherungsjahr, and take k.
D(0) = dk_pp_init, U(0) = surplus_pp_init, A(k) = D(k) + U(k)
int_guar_pp(k) = i · ( D(k) + S(k) )
int_surplus_pp(k) = ( j(k) − i ) · ( D(k) + S(k) ) + j(k) · U(k)
int_credited_pp(k)= int_guar_pp(k) + int_surplus_pp(k)
D(k + 1) = ( D(k) + S(k) ) · ( 1 + i )
U(k + 1) = U(k) + int_surplus_pp(k)
A(k + 1) = A(k) + S(k) + int_credited_pp(k)
The split is guarantee accounting, not two investment strategies: the whole account grows at
j(k), and D is carved out of it as the part the Rechnungszins guarantees. The German
arithmetic error this prevents is adding the declared laufende Verzinsung to the
Rechnungszins: j already includes i, and j − i is the laufende
Zinsüberschussbeteiligung REG-R53 (pitfall 10). Within-year points are
av_total_pp_at(k, "BEF_PREM") = A(k), av_total_pp_at(k, "AFT_PREM") = A(k) + S(k) and
av_total_pp_at(k, "AFT_INT") = A(k + 1), with
av_total_at(k, timing) = av_total_pp_at(k, timing) · l(12k) — the count at the start of the
year, which is where the contribution is credited.
The Beitragsgarantie accumulator#
Annual, like the contributions it counts, and never accruing: the guarantee is nominal.
κ(k) = min( rider_prem_pp , 0.20 · ( E(k) + Z(k) + contrib_extra_pp + rider_prem_pp ) )
G(0) = guar_pp_init
G(k + 1) = G(k) + E(k) + Z(k) + contrib_extra_pp·1{is_accum_y(k)} − κ(k) for k ≤ T
= G(T + 1) for k > T
garantieluecke_pp(k) = max( 0 , G(k) − A(k) ) diagnostic only
Three things this encodes and a test asserts. The accumulator counts Zulagen credited, in the
year they are credited, not entitlements in the year they are earned R1. It counts
unsubsidised contributions too, because the guarantee is on the Altersvorsorgebeiträge paid in
and does not distinguish the pools R1 (pitfall 9). And the biometric carve-out is capped at
20 % of total contributions REG-R43, so raising rider_prem_pp beyond the cap does not
shrink the guarantee further (pitfall 8). garantieluecke_pp(k) is published because it is
positive in the early durations of any charged contract and closes later — a fact about the product
that a reader should see — but it is a diagnostic: the guarantee is tested once, at T.
Conversion at Rentenbeginn#
account_conv_pp() = D(T) + S(T) + U(T) + slueb_pp() + bewres_pp()
slueb_pp() = slueb_rate · ( G(T + 1) − guar_pp_init + contributions credited before t = 0 )
bewres_pp() = bewres_rate · ( D(T) + S(T) + U(T) )
V = max( account_conv_pp() , G(T + 1) )
Λ = max( 0 , G(T + 1) − account_conv_pp() )
ä = Σ_{k ≥ 0} v^k · k p( x(T), τ(T) ) − 11/24, v = 1 / (1 + annuity_rechnungszins)
R_c = ( 1 − rentenfaktor_margin ) · 10 000 / ( 12 · ä )
R = max( R_g , R_c )
monthly test annuity = ( 1 − teilkapital_share ) · V / 10 000 · R
is_kleinbetrag() = monthly test annuity ≤ kleinbetrag_threshold_mth
if is_kleinbetrag(): teilkapital_pp() = 0 ; annuity_capital_pp() = 0 ; commutation_pp() = V
else: teilkapital_pp() = teilkapital_share · V ;
annuity_capital_pp() = V − teilkapital_pp() ; commutation_pp() = 0
annuity_month_pp() = annuity_capital_pp() / 10 000 · R the instalment, paid monthly
a(k) = 12 · annuity_month_pp() for is_payout_y(k) and not commuted
k p(x, τ) is survivorship on the first-order annuity basis — the same basis the market’s
Rentenfaktor is struck on — while the projection’s own survivorship uses the second-order
basis, annuity_mort_rate(x, τ) · annuity_mort_be_factor. The wedge between them is the
Risikoüberschuss in payment REG-R47, which this model does not distribute (assumption class (b),
footnote 5). The commutation test is applied to the annuity actually payable after the elected
lump sum. The statute does not settle the point, but the GDV model wording does, and against this
reading: “Eine Abfindung erfolgt nicht, wenn die Leistung nur aufgrund einer Teilkapitalauszahlung
gemäß Absatz 4 auf eine Kleinbetragsrente sinkt” [S2] § 1 Abs. 3. The alternative — testing the
annuity the whole capital would buy — is therefore the drafted rule rather than merely a variant, and
it remains sensitivity 6 because changing it is a model change (gap 7). If the contract commutes there is no Teilkapitalauszahlung: the whole capital is one
payment. a(k) is a reporting figure and nobody’s payment: the Rentenfaktor is quoted in euro a
month, and what the contract pays — and the model books — is annuity_month_pp(), one
instalment at a time.
Decrements#
The ledger is monthly and the rates it applies are the geometric twelfths of the year’s annual
ones, q_mth = 1 − (1 − q)^(1/12) and likewise for w and θ:
Accumulation (t < 12T):
pols_death(t) = l(t) · q_mth(t)
pols_lapse(t) = l(t) · ( 1 − q_mth(t) ) · w_mth(t)
pols_transfer(t) = l(t) · ( 1 − q_mth(t) ) · ( 1 − w_mth(t) ) · θ_mth(t)
l(t + 1) = l(t) − pols_death(t) − pols_lapse(t) − pols_transfer(t)
Payout (t ≥ 12T):
pols_death(t) = l(t) · q_mth(t) ; pols_lapse(t) = pols_transfer(t) = 0
l(t + 1) = l(t) − pols_death(t) and 0 at t = 12T if commuted
pols_conv() = l(12T)
pols_annuity_pay(t) = pols_conv() if 0 ≤ t − 12T < 12 · rentengarantie_years
= l(t) otherwise
with q(t) = mort_rate_at_age(x(t)) · mort_be_factor in accumulation and
annuity_mort_rate(x(t), τ(t)) · annuity_mort_be_factor in payout, and q(t) = 1 at x = omega_age
so the closure identity closes exactly — the certainty falling in the terminal year’s last month.
Twelve geometric twelfths compound back to each annual rate exactly, so l(12k) is the annual-step
model’s l(k) to the last bit; q(t)/12 would close nothing.
The lapse and transfer decrements are applied in that order to the survivors of mortality, a stated std ordering — now within each month rather than once at a year end. That is the one thing the finer grid changes about the exits: in the annual model mortality took the whole cohort as its base and the transfer took what two decrements had already thinned, while month by month the three compete. The survivorship at every anniversary is unchanged and only the split moves — 5,62 € off the anchor’s death outgo and 2,64 € off its surrender outgo onto 8,30 € of transfers.
pols_annuity_pay is the whole
of the Rentengarantiezeit, now measured in 12m instalments: the guarantee period changes
who is paid, never how much (pitfall 17).
Benefits, expenses and the cash flow statement#
The per-policy benefit amounts are annual, struck at the end of the contract year where the
account is struck; the cash flows that pay them are monthly, with k = proj_year(t).
db_pp(k) = A(k + 1) death, gross
cv_pp(k) = A(k + 1) · ( 1 − stornoabzug_rate ) surrender, gross
transfer_value_pp(k)= max( 0 , A(k + 1) − transfer_charge ) Anbieterwechsel
exit_charge_pp(t) = stornoabzug_rate · A(k + 1) · pols_lapse(t)
+ min( transfer_charge, A(k + 1) ) · pols_transfer(t)
claims(t, "DEATH") = db_pp(k) · pols_death(t)
claims(t, "LAPSE") = cv_pp(k) · pols_lapse(t)
claims(t, "TRANSFER") = transfer_value_pp(k) · pols_transfer(t)
claims(t, "LUMPSUM") = teilkapital_pp() · pols_conv() at t = 12T only
claims(t, "COMMUTATION") = commutation_pp() · pols_conv() at t = 12T only
claims(t, "ANNUITY") = annuity_month_pp() · pols_annuity_pay(t)
premiums(t) = ( E(k)·φ + contrib_extra_pp·1{is_accum_y(k)} ) · l(t) if prem_due(t), else 0
zulagen(t) = Z(k) · l(t) if prem_due(t), else 0
expenses(t) = expense_acq · 1{t = 0 and duration_init = 0}
+ expense_maint / 12 · (1 + expense_infl)^d(t) · l(t) · 1{is_accum(t)}
+ expense_annuity / 12 · pols_annuity_pay(t)
+ expense_claim · ( pols_death(t) + pols_lapse(t) + pols_transfer(t) )
commissions(t)= comm_rate_init · beitragssumme · l(0) · 1{t = 0 and duration_init = 0}
+ comm_rate_renew · ( E(k) + Z(k) ) · l(t) in the month the contribution falls
net_cf(t) = premiums(t) + zulagen(t)
− claims_death(t) − claims_lapse(t) − claims_transfer(t)
− claims_lumpsum(t) − claims_commutation(t) − claims_annuity(t)
− expenses(t) − commissions(t)
liability_cf(t) = − net_cf(t)
Death and surrender benefits are published gross of the Rückzahlungsbetrag: the provider
withholds all Zulagen and all § 10a relief and remits them to the ZfA R14, but that is a tax
collection, not a reduction in the insurer’s obligation, and netting it would understate the outgo
(pitfall 18). zulage_cum_pp(k) publishes the reclaimable Zulage limb as a diagnostic; the § 10a
limb depends on the saver’s marginal rate and cannot be computed from contract data at all.
A per-event cost such as expense_claim falls whole in the month of the event; a per-year
cost is a twelfth in each month, so a policy exiting in the fourth month of a contract year bears
four twelfths of that year’s maintenance rather than all of it.
result_cf() returns a DataFrame indexed by the projection month t
(df.index.name == "t"), contiguous, 0 … proj_len() − 1, so it carries proj_len() rows, with
these columns in this order:
pols_if, pols_annuity_pay, premiums, zulagen,
claims_death, claims_lapse, claims_transfer, claims_lumpsum, claims_commutation,
claims_annuity, expenses, commissions, net_cf, liability_cf
int_credited is a state movement, reported and not summed into net_cf — money moving inside
the account, not across the insurer’s boundary — and on the monthly grid it is not a column of this
frame at all: it moves once a Versicherungsjahr, like the two balances it moves between, so it
lives in result_acct() with them. result_cf_annual() sums the frame into projection years and is
the view this worked example prints. The separation of zulagen from premiums is the
single most important reporting decision in this model: the Zulage is a contribution with a
different payer R8, and a statement that folds it into premiums cannot answer the one question
the product is about.
The check identities the model publishes#
The residual’s argument follows its cells’ clock. Two take a month and four a projection year, because the account, the guarantee accumulator, the conversion and the ZfA lag move once a Versicherungsjahr and have nothing to say about a month.
Check |
Clock |
Identity |
|---|---|---|
|
month |
On |
|
month |
The decrement recursion closes each month, at the monthly rates, and |
|
year |
|
|
year |
|
|
year |
|
|
year |
|
Each returns a bool over the whole projection and has a check_*_resid companion, and the
conventions suite calls all six on every model point.
Processing order#
The order is stated per Versicherungsjahr, because that is the order the contract happens in;
the months sit inside it. For k = 0 … proj_len_y() − 1, and within each year for
t = 12k … 12k + 11, in this order. The order is a std decision — no source in this
corpus fixes the ordering of premium credit, charge deduction and interest accrual inside a period —
and it is stated here so that an implementation can be compared against it line by line.
Set
x(k),d(k),τ(k). Decideis_accum_y(k)/is_payout_y(k)fromk_conv(), take the year’s annual ratesq(12k),w(12k)andθ(12k), and form their geometric twelfths.Accumulation only. Read
Y(k)—income_initatk = 0, otherwise the schedule’sincome(k − 1). Compute the entitlementZ*(k)from the Zulage schedule and the statutory rates, thenM(k), thenE(k)from the contribution form,bfs_yearandcontrib_ratio, then the granted entitlementẐ(k).Credit the Zulage earned last year:
Z(k) = zulage_init_ppatk = 0, elseẐ(k − 1). This happens before anything else touches the account, and it happens in the conversion year too.Form
C(k), deductK_a(k)andK_v(k), and credit the SparbeitragS(k)to the account:av_total_pp_at(k, "AFT_PREM") = A(k) + S(k). Collectpremiums(t)andzulagen(t)onl(t)in the year’s first month,t = 12k, and in no other: a fractionated payment mode is priced by loading the amount, and the ZfA pays once a year.Roll the guarantee accumulator:
G(k + 1) = G(k) + E(k) + Z(k) + contrib_extra_pp − κ(k), and the two contribution pools alongside it.Charge the insurer’s own expenses and commission: the acquisition expense and initial commission at
t = 0on a point issued at the valuation date, the renewal commission in the month the contribution falls, and a twelfth of the annual per-policy maintenance in each month.If
k = k_conv(): strikeaccount_conv_pp(),V,Λ; computeä,R_c,R; apply the Kleinbetragsrente test; payclaims_lumpsumorclaims_commutationonpols_conv()att = t_conv(); and fix the instalmentannuity_month_pp(). The account is extinguished —av_total_pp(k) = 0fork > k_conv(). Nothing in steps 8 and 9 applies to the account after this point.Accumulation only, end of year. Credit interest:
int_guar_pp(k)atiandint_surplus_pp(k)atj(k) − ionD(k) + S(k), plusj(k)onU(k);av_total_pp_at(k, "AFT_INT") = A(k + 1). A policy that exited during the year has been credited the whole of it, which is the annual-step convention preserved.Accumulation, end of each month. Apply the decrements to
l(t): mortality first, then surrender on the survivors, then transfer on the survivors of both, all three at the monthly rates. Strikeclaims_death,claims_lapseandclaims_transferon the annualA(k + 1), and retainexit_charge_pp(t).Payout, each month. Pay
claims_annuity(t) = annuity_month_pp() · pols_annuity_pay(t)in advance, charge a twelfth ofexpense_annuityon the same count, then apply annuitant mortality at the end of the month:l(t + 1) = l(t) · (1 − q_mth(t)).Assemble
expenses(t),commissions(t),net_cf(t)andliability_cf(t), in every month.
At t = proj_len() − 1 the projection ends: q is 1 in the terminal year and q_mth places that
certainty in its last month, so l(proj_len()) = 0 — the one index beyond the frame — and the
closure identity is exact.
Known modeling pitfalls#
These are the specific ways an implementation of this product looks right and is wrong. Each one
becomes a test in tests/test_riester_rente_de.py.
Collapsing the two subsidy lags into one. The entitlement looks back one calendar year for income R10; the cash arrives one projection year late R11. Assert
income_ref(0) = income_init,income_ref(k) = income_schedule[k − 1], andzulage_pp(k) = zulage_granted_pp(k − 1)— two distinct offsets, not one applied twice. Both are annual and the monthly grid gives the payment a month, not a different lag.Dropping the final contribution year’s Zulage. Contributions stop at
k_conv() − 1; the Zulage they earned is credited atk_conv(). Assertzulage_pp(k_conv()) > 0on the anchor, that it entersguar_pp(k_conv() + 1), and that it is insideaccount_conv_pp(). Stopping the Zulage with the contribution silently removes a full year’s subsidy from both.Treating the Mindesteigenbeitrag as a cliff. § 86 reduces the Zulage in proportion to the shortfall R10 REG-R42. Assert on model point 7 that
contrib_ratio = 0.50gives exactly0.50 × zulage_entitlement_pp(k)— not zero, and not the full amount.Treating the Zulage as a benefit, or netting it against the contribution. It is a contribution paid by the ZfA to the provider R8 R11. Assert
zulagen(t) > 0as a separate positive column, that it never appears with a negative sign, and thatpremiums(t)excludes it.Modelling the Günstigerprüfung top-up as a contract cash flow. Only the Zulage reaches the policy; the § 10a advantage is a personal tax refund R6 REG-R42. Assert that no cells and no column corresponds to it.
Using a single Kinderzulage rate. The 185 € / 300 € split is a permanent birth-cohort rule, not a transition R9 R19. Assert on model point 3 that both rates run simultaneously at
k = 0andk = 1, givingzulage_entitlement_pp = 175 + 185 + 300 = 660,00 €.Testing the Beitragsgarantie anywhere but at Rentenbeginn. It is tested once R1. Assert that
db_pp(k),cv_pp(k)andtransfer_value_pp(k)are not floored atguar_pp, and that the anchor hasgarantieluecke_pp(0) > 0— an account below the contributions paid — without that affecting any benefit.Enlarging the guarantee with a rider premium, or forgetting the 20 % cap. Assert on model point 9 that
guar_carve_out_pp(k) = 0.20 × (E + Z + extra + rider)and is strictly less thanrider_prem_pp = 400,00 €, and that raisingrider_prem_ppfurther does not reduceguar_ppfurther.Excluding unsubsidised contributions from the guarantee. The guarantee is on the Altersvorsorgebeiträge paid in and does not distinguish the pools R1. Assert on model point 8 that
guar_pp(t + 1) − guar_pp(t)includescontrib_extra_pp, whilezulage_entitlement_pp(t)is unaffected by it.Adding the declared rate to the guaranteed rate.
decl_rateincludes the Rechnungszins REG-R53. Assertint_credited_pp(k) = j(k) · (D(k) + S(k)) + j(k) · U(k)exactly, and that settingj = imakesint_surplus_pp(k)zero on the Deckungskapital leg.Crediting the frequency loading to the account. The Ratenzuschlag is a charge. Assert that on model point 3 (monthly)
premiums(t)exceeds the annual-mode amount by exactlyE(k) · 0.03whileprem_to_av_pp(k),guar_pp(k)and every benefit are unchanged. It is also why the contribution keeps the annual grid on a monthly frame: φ prices the mode by loading the amount, soprem_due(t)puts the whole year’s contribution in one month and a model that also split the cash into instalments would charge for the deferral twice.Charging acquisition costs in one year, or stopping them on Beitragsfreistellung. The AltZertG requires spreading over at least five years R1. Assert
acq_charge_pp(t)is equal in contract years 1 to 5 and zero afterwards, and on model point 10 that it continues afterbfs_year, drivingprem_to_av_pp(k)negative.Collapsing Anbieterwechsel into surrender. A transfer is a full-value exit with no Stornoabzug R1. Assert
transfer_value_pp(k) = A(k + 1) − 50,00 €whilecv_pp(k) = 0.98 · A(k + 1), and that the two decrements are separate columns. Both are struck on the annual end-of-year account value, so the month of the exit decides when it is paid and not how much.Treating Beitragsfreistellung as a termination. It is a state change R14 REG-R28. Assert on model point 10 that
pols_if(t)is continuous acrossbfs_year, thatguar_ppfreezes, thatzulage_ppgoes to zero, and thatav_total_ppkeeps rolling.Using one mortality table for both phases, or a period table for the annuity. The direction of prudence forks by product REG-R47, and DAV 2004 R is generational REG-R49. Assert that
mort_rate(t)switches basis att_conv(), thatannuity_mort_rate(x, τ)depends on both arguments, and thatannuity_mort_rate(x, τ + 1) < annuity_mort_rate(x, τ). Assert too thatmort_rate_mthis the geometric twelfth of the year’s annual rate, so(1 − q_mth)^12 = 1 − qexactly and the annual survivorship is reproduced;q/12closes nothing.Testing the Kleinbetragsrente on the wrong annuity, or hiding the flat threshold. The test is applied after the elected lump sum std, and the threshold is held flat in nominal terms std. Assert both explicitly, assert that model points 4 and 5 commute while the anchor does not, and that a commuted point pays
claims_commutationand noclaims_lumpsumand noclaims_annuity.Applying the Rentengarantiezeit to the annuity amount, or paying a year of it at once. The guarantee period changes the payment count, never the payment. Assert
pols_annuity_pay(t) = pols_conv()fort − t_conv() < 12 · rentengarantie_years— the window is12minstalments — and= pols_if(t)afterwards, and thatannuity_month_pp()is invariant torentengarantie_years: model point 12, at zero, must pay the same instalment to a falling count. Assert also that the instalment is monthly —claims_annuity(t) = annuity_month_pp() · pols_annuity_pay(t)and12 · annuity_month_pp() = annuity_pp(k)— because booking a year at the start of the payout year on that year’s opening count pays a life that dies in its first month for the whole of it.Netting the Rückzahlungsbetrag out of a benefit. It is a tax collection the provider withholds and remits R14. Assert
claims_death(t) = A(k + 1) · pols_death(t)gross, thatzulage_cum_pp(t)is published and never subtracted from a claim, and that no cells attempts a § 10a repayment, which contract data cannot support.
Policyholder behaviour modelling#
Every formula here is std; there is no German Riester calibration evidence for any of them (gap 16), and each rests on an argument from the statutory consequences.
Surrender is deliberately small and flat-ish. 0,8 % / 0,6 % / 0,4 % by duration band. A Kündigung repays all Zulagen and all § 10a relief and taxes the accumulated growth on the subsidised part R14 REG-R42, against a surrender value that is already below the contributions paid in the early years. The German market’s own description is that a Riester contract is effectively unsurrenderable in economic terms, and the assumption says so numerically.
Transfer out is set above surrender. 1,2 % / 0,9 % / 0,6 %. The Wechselrecht is free of subsidy consequences R1, so it dominates surrender for any saver who wants out but not out of the system. A model carrying only a lapse rate has mis-specified this book, and the ordering
transfer_rate > lapse_rateat every duration is itself an assertion worth making.No dynamic behaviour is modelled, and the omission is deliberate. There is no rate-driven surrender function, because there is nothing to arbitrage into: the subsidy, not the credited rate, is what holds the contract. There is no Teilkapitalauszahlung take-up model, because the decision is a tax comparison the model does not perform — the lump sum is taxed in full in its year with no Fünftelregelung R12 R15 — and a fixed take-up rate standing in for a tax calculation should be labelled as such rather than dressed up.
What is computed rather than assumed. The Kleinbetragsrente commutation. The model tests the annuity it has actually produced against the statutory threshold, so the commutation rate on a book is an output, not an input. Given how much of the German Riester book runs at the Sockelbeitrag, that is the right way round.
What a real book needs and this model does not have. A Beitragsfreistellung decrement moving policies from a premium-paying to a paid-up cohort, each with its own account value and guarantee accumulator (assumption class (c), footnote 9). Model point 10 shows the mechanic on one policy; a book-level projection needs the split.
Worked example#
Configuration. Model point 1, the anchor: an in-force klassische Riester-Rentenversicherung at
the 1 January 2027 valuation date. point_id = 1; sex = F (reporting only — the tariff and the
conversion are unisex R23); issue_age = 47, the contract having been concluded on 1 January
2024; duration_init = 3, so age(0) = 50, duration(0) = 3 — contract year 4 — and
calendar_year(0) = 2027;
pols_if_init = 1.0; rentenbeginn_age = 67; rechnungszins = 0.0025, the Höchstrechnungszins of
the 2024 vintage R22 REG-R15; beitragssumme = 33,600.00; contrib_form = mindest with
contrib_fixed_pp = 0.00; contrib_ratio = 1.00, the full Mindesteigenbeitrag paid;
contrib_extra_pp = 0.00, so the two contribution pools coincide; rider_prem_pp = 0.00, so the
guarantee carries no carve-out; income_id = grow2 and income_init = 42,000.00;
zulage_id = k1_2010, a household with one child born in 2010 drawing Kindergeld to 2028, so
the entitlement is 475,00 € in contribution years 2027 and 2028 and 175,00 € thereafter;
zulage_init_pp = 475.00, the Zulage earned in 2026 and credited at t = 0;
prem_freq = annual, so prem_freq_load = 1.0000; bfs_year = −1 (never); dk_pp_init = 3,860.50;
surplus_pp_init = 150.48, so av_total_pp(0) = 4,010.98; guar_pp_init = 4,369.92 — three
Eigenbeiträge on the same income path plus the two Zulagen of 475,00 € credited in 2025 and 2026 —
which is above the account, so the anchor opens with a positive garantieluecke_pp(0) of
358,94 €;
teilkapital_share = 0.30, the statutory maximum lump sum; rentenfaktor_guar = 29.00;
rentengarantie_years = 10; and scenario_id = base. Hence t_conv() = 67 − 50 = 17, so
accumulation runs t = 0 … 16 (attained ages 50 to 66, calendar 2027 to 2043), conversion falls at
t = 17 (age 67, calendar 2044), the payout phase runs t = 17 … 60, and
proj_len() = 110 − 50 + 1 = 61 periods. The opening balances are std seeds produced by the
same charge basis over contract years 2024 to 2026. Model point 2 is this contract projected from
its own inception. It reconciles the two account seeds to the cent — dk_pp_init to 3 860,499285 €
and surplus_pp_init to 150,483132 € — and from its own t = 3 onward reproduces every
per-policy quantity of the anchor’s t = 0 onward exactly; it does not reconcile
guar_pp_init, because the two seeds were struck on different income paths. The discrepancy is
195,08 € and is set out in full under Changes the model stage made to these notes.
Assumptions, each tagged. Grundzulage 175,00 €, Kinderzulage 300,00 € for the child
born in 2010, no Berufseinsteiger-Bonus — all R9 REG-R42 [unverified]. Mindesteigenbeitrag
4 % of the previous calendar year’s contribution-liable earnings, capped at 2 100,00 €, less
the entitlement, floored at the 60,00 € Sockelbeitrag, with the Kürzung proportional — R10
REG-R42 [unverified]. Zulage cash lag one year R11 REG-R42, the one-year convention
std. Income path 2,0 % p.a. from income_init = 42 000,00 € std, so the 2 100 €
ceiling first binds at t = 12. Rechnungszins 0,25 % R22 REG-R15, the carrier’s
own choice std. Laufende Verzinsung 2,30 % level on the base scenario std, so
int_surplus_pp runs at 2,05 % above the guaranteed leg. Acquisition charge 2,5 % of the
33 600,00 € Beitragssumme — 840,00 €, in five equal instalments of 168,00 € in contract years
1 to 5, so t = 0 and t = 1 carry it and t = 2 onward do not — R1 REG-R16, level
std. Administration charge 4,0 % of each contribution credited, Zulagen included
[std] — charging them is now established [S2] [S4] [S6] [S9] and only the rate is standardized —
plus a fixed 12,00 € a year std. Frequency loading 1.0000 (annual)
std. Risikobeitrag zero, the death benefit being the account value. Schlussüberschuss
2,0 % of contributions credited and Bewertungsreserven share 1,0 % of the account, both at
Rentenbeginn, both counted toward the guarantee — REG-R24, levels and the counting convention
std (gap 9). Accumulation mortality: the shipped std proxy for DAV 2008 T REG-R48
at mort_be_factor = 0.80. Annuity mortality: the shipped std generational proxy for
DAV 2004 R REG-R49, q(x, τ) = qx_base(x) · (1 − improvement(x))^(τ − 2027), at
annuity_mort_be_factor = 1.15 for the projection and at 1.00 — the first-order basis — inside
ann_factor(). Annuitisation interest 1,00 % REG-R15 std, with the Woolhouse
−11/24 correction std; Rentenfaktor margin 30 % std; guaranteed Rentenfaktor
29,00 € per 10 000 € per month std (gap 9). Kleinbetragsrente threshold 39,55 € per
month std REG-R42 REG-R46 — below the 59,33 € the statute implies R15, a discrepancy
recorded under Model-relevant contradictions and deliberately not fixed here. Surrender
0,8 % / 0,6 % / 0,4 % and transfer out 1,2 % / 0,9 % / 0,6 % by duration band, both
std; Stornoabzug 2,0 % REG-R28 std; transfer charge 50,00 € std,
now known to sit inside a statutory ceiling of 150,00 € R1 and to be the figure one fund
provider actually charges [S9] (gap 8 closed). Expenses std: maintenance 30,00 € per in-force policy per year inflating at 2,0 %,
annuity administration 24,00 € per annuitant per year, claim expense 80,00 € per death, surrender or
transfer; no acquisition expense and no initial commission, because duration_init = 3 puts them in
the past. Renewal commission 1,5 % of the contributions credited std. omega_age = 110
std, with q = 1 at that age so the decrements close exactly.
All amounts in euros; pols_if and pols_annuity_pay to six decimals, cash flows to the cent.
Totals are summed at full precision and then rounded, not summed from rounded cells.
The cash flow statement — Projection[1].result_cf(), accumulation and conversion#
Transcribed from the model’s own output. claims_commutation is 0.00 at every t on this
cell — the anchor’s annuity clears the Kleinbetragsrente threshold — and is omitted for space;
it is a required column of result_cf(). liability_cf is omitted for the same reason: it is
−net_cf exactly. pols_annuity_pay is zero throughout the accumulation and is carried in the
payout table below.
k |
pols_if |
premiums |
zulagen |
int_credited |
claims_death |
claims_lapse |
claims_transfer |
claims_lumpsum |
claims_annuity |
expenses |
commissions |
net_cf |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 |
1.000000 |
1,205.00 |
475.00 |
125.21 |
6.62 |
43.39 |
65.90 |
0.00 |
0.00 |
33.21 |
25.20 |
1,505.67 |
1 |
0.978920 |
1,212.49 |
464.99 |
158.37 |
9.21 |
54.88 |
83.52 |
0.00 |
0.00 |
33.14 |
25.16 |
1,471.56 |
2 |
0.958169 |
1,507.08 |
455.13 |
201.64 |
12.93 |
52.48 |
79.96 |
0.00 |
0.00 |
32.75 |
29.43 |
1,754.65 |
3 |
0.942478 |
1,515.34 |
164.93 |
239.74 |
16.91 |
62.39 |
95.15 |
0.00 |
0.00 |
32.85 |
25.20 |
1,447.77 |
4 |
0.926909 |
1,523.36 |
162.21 |
278.17 |
21.59 |
72.38 |
110.47 |
0.00 |
0.00 |
32.93 |
25.28 |
1,422.92 |
5 |
0.911451 |
1,531.11 |
159.50 |
316.90 |
27.05 |
82.45 |
125.90 |
0.00 |
0.00 |
33.02 |
25.36 |
1,396.83 |
6 |
0.896093 |
1,538.55 |
156.82 |
355.91 |
33.42 |
92.59 |
141.44 |
0.00 |
0.00 |
33.10 |
25.43 |
1,369.38 |
7 |
0.880824 |
1,545.66 |
154.14 |
395.18 |
40.91 |
68.62 |
104.84 |
0.00 |
0.00 |
32.90 |
25.50 |
1,427.04 |
8 |
0.869997 |
1,560.24 |
152.25 |
436.87 |
49.75 |
75.86 |
115.91 |
0.00 |
0.00 |
33.14 |
25.69 |
1,412.15 |
9 |
0.859103 |
1,574.53 |
150.34 |
479.17 |
60.03 |
83.19 |
127.15 |
0.00 |
0.00 |
33.37 |
25.87 |
1,395.26 |
10 |
0.848126 |
1,588.46 |
148.42 |
522.04 |
71.94 |
90.62 |
138.53 |
0.00 |
0.00 |
33.60 |
26.05 |
1,376.14 |
11 |
0.837051 |
1,602.01 |
146.48 |
565.45 |
85.71 |
98.14 |
150.05 |
0.00 |
0.00 |
33.83 |
26.23 |
1,354.54 |
12 |
0.825864 |
1,589.79 |
144.53 |
608.79 |
101.51 |
105.64 |
161.54 |
0.00 |
0.00 |
34.04 |
26.01 |
1,305.57 |
13 |
0.814546 |
1,568.00 |
142.55 |
651.80 |
119.55 |
113.08 |
172.94 |
0.00 |
0.00 |
34.25 |
25.66 |
1,245.07 |
14 |
0.803079 |
1,545.93 |
140.54 |
694.42 |
140.11 |
120.45 |
184.22 |
0.00 |
0.00 |
34.44 |
25.30 |
1,181.95 |
15 |
0.791444 |
1,523.53 |
138.50 |
736.58 |
163.47 |
127.73 |
195.38 |
0.00 |
0.00 |
34.62 |
24.93 |
1,115.90 |
16 |
0.779621 |
1,500.77 |
136.43 |
778.20 |
189.98 |
134.91 |
206.38 |
0.00 |
0.00 |
34.79 |
24.56 |
1,046.59 |
17 |
0.767588 |
0.00 |
134.33 |
0.00 |
0.00 |
0.00 |
0.00 |
10,536.61 |
855.57 |
18.81 |
0.00 |
−11,276.67 |
Total, k = 0 … 60 |
25,631.84 |
3,627.10 |
7,544.45 |
1,150.72 |
1,478.78 |
2,259.27 |
10,536.61 |
19,793.08 |
1,057.57 |
436.87 |
−7,453.96 |
The table is result_cf_annual() — the monthly frame summed into projection years — with
int_credited read from result_acct(), which is where the annual state lives. Its accumulation
rows are the annual-step model’s to the last bit on the contribution, the Zulage, the commission
and both balances; what moved when the grid did is the split of the exits between the three
decrements, the annuity, and the expenses.
The Total row covers all sixty-one years, not only the eighteen displayed, and is summed
at full precision and then rounded. Ten of its eleven columns differ from the sum of the
already-rounded cells: premiums 25 631,84 € against 25 631,85 €, zulagen 3 627,10 € against
3 627,09 €, int_credited 7 544,45 € against 7 544,44 €, claims_death 1 150,72 € against
1 150,69 €, claims_lapse 1 478,78 € against 1 478,80 €, claims_transfer 2 259,27 € against
2 259,28 €, claims_annuity 19 793,08 € against 19 793,06 €, expenses 1 057,57 € against
1 057,53 €, commissions 436,87 € against 436,86 €,
and net_cf −7 453,96 € against −7 453,97 €. Only claims_lumpsum agrees. Assert the
full-precision totals.
What the monthly grid moved, against the annual-step model this replaced. The contribution
(25 631,84 €), the Zulage (3 627,10 €), the interest credited (7 544,45 €), the commission
(436,87 €) and the lump sum (10 536,61 €) are unchanged, as are both balances, the guarantee
accumulator, the capital at Rentenbeginn and the Kleinbetragsrente verdict. The annuity falls
from 20 154,82 € to 19 793,08 €, because the instalment now stops with the month of death rather
than being paid for the whole year of it; the expenses fall from 1 069,29 € to 1 057,57 €, because a
mid-year exit bears only the months it was there; and the exits redistribute — 1 156,35 € to
1 150,72 € of death, 1 481,42 € to 1 478,78 € of surrender, 2 250,97 € to 2 259,27 € of transfer —
because the three decrements now compete month by month instead of running in sequence at a year
end. net_cf moves from −7 827,39 € to −7 453,96 €.
Four things to read off before the checks. zulagen steps down between k = 2 and k = 3,
455,13 € to 164,93 €, while premiums rises: Kindergeld for the child born in 2010 stops
after the 2028 contribution year, so the entitlement falls at k = 2 and the credit follows one
year later at k = 3, while the Eigenbeitrag jumps at k = 2 because the § 86 minimum is 4 %
of income less the entitlement — a Zulage that stops is a contribution the saver must make
good. Two lags, two offsets, one table: pitfall 1. The acquisition charge stops after k = 1,
contract year 5; it never appears in the frame, being a deduction before the account, but
168,00 € of the 488,90 € rise in the Sparbeitrag between k = 1 and k = 2 is the charge
ending rather than the contribution rising, and it is why garantieluecke_pp(k) peaks at
567,69 € at k = 2 and reaches zero at k = 6. claims_transfer exceeds claims_lapse
at every k by about half again, because the Anbieterwechsel rate is set above the surrender
rate at every duration and a transfer pays the full account less a flat 50,00 € against a
surrender’s 98 %; both fall at k = 7, where contract duration passes 10 and the bands step
down. And net_cf is positive in every accumulation year before −11 276,67 € in the
conversion year: an in-force Riester cell is a positive cash flow to the insurer for as long as
it accumulates, and the whole liability is the conversion year and the annuity tail.
On the monthly frame the same year is a saw-tooth: the whole year’s contribution and Zulage land in its first month and nothing else does, so month 0 nets +1 642,25 € while each of the other eleven carries a twelfth of the maintenance expense and that month’s exits and nets about −12,50 €.
The payout phase — selected rows, k = 17 … 60#
premiums, int_credited, claims_death, claims_lapse and claims_transfer are 0.00 at
every k from 17 onward: the account is extinguished at conversion, so there is no interest to
credit and a death pays nothing outside the Rentengarantiezeit. zulagen is 134,33 € at
k = 17 — the final contribution year’s subsidy, landing in the conversion year — and zero
thereafter. The counts are read at the start of the year; the instalments inside it are paid
monthly.
k |
age |
pols_if |
pols_annuity_pay |
claims_annuity |
expenses |
net_cf |
|---|---|---|---|---|---|---|
17 |
67 |
0.767588 |
0.767588 |
855.57 |
18.81 |
−11,276.67 |
18 |
68 |
0.762677 |
0.767588 |
855.57 |
18.85 |
−874.43 |
26 |
76 |
0.701403 |
0.767588 |
855.57 |
19.33 |
−874.91 |
27 |
77 |
0.690013 |
0.690013 |
762.71 |
17.42 |
−780.13 |
28 |
78 |
0.677530 |
0.677530 |
748.18 |
17.20 |
−765.39 |
34 |
84 |
0.574463 |
0.574463 |
628.63 |
15.35 |
−643.98 |
44 |
94 |
0.273819 |
0.273819 |
286.52 |
9.02 |
−295.54 |
54 |
104 |
0.016013 |
0.016013 |
13.95 |
0.85 |
−14.81 |
60 |
110 |
0.000079 |
0.000079 |
0.09 |
0.01 |
−0.10 |
Subtotal, k = 18 … 60 |
17.024474 |
17.314559 |
18,937.51 |
468.77 |
−19,406.28 |
The Rentengarantiezeit is the whole of the difference between the two count columns. From
k = 17 to k = 26 — 120 instalments from Rentenbeginn, t = 204 … 323 —
pols_annuity_pay is frozen at
pols_conv() = 0.767588 while pols_if decays to 0.701403, so claims_annuity is exactly
855,57 € in each of those ten years although a tenth of the annuitants have died. Those ten years
are also the annual-step model’s to the cent: inside a guarantee window the count is fixed, and
120 monthly instalments on a fixed count are ten annual payments on it,
120 × 92,885458 × 0,767588 = 8 555,73 €. From k = 27
the columns join and the outgo falls with the survivors — and there the two grids part, 762,71 €
against the annual model’s 769,11 €, because the instalment now stops with the month of death
rather than being paid for the whole year of it. Over the payout phase that is 361,74 €.
What is paid is annuity_month_pp() = 92,885458 €, one instalment a month, level for life;
annuity_pp(k) = 1 114,625493 € is the annual figure the twelve sum to, and it is the same in
every payout year, guarantee period or not — the guarantee changes who is paid, never how much
(pitfall 17). The subtotals say the same in aggregate: 17.314559 instalment-years paid against
17.024474 policy-years in force.
Independent checks#
The first projected month, t = 0, rebuilt from the statute up, in one pass. The reference
income is the previous calendar year’s, so Y(0) = income_init = 42 000,00 €. The entitlement is
the Grundzulage plus one post-2008 Kinderzulage, Z*(0) = 175,00 + 300,00 = 475,00 €. The § 86
minimum is max(60, min(0,04 × 42 000, 2 100) − 475) = max(60, 1 680 − 475) = 1 205,00 €, and
contrib_ratio = 1.00 pays it in full, so E(0) = 1 205,00 €; the frequency is annual, so
φ = 1 and — the contribution being an annual event that falls in the year’s first month —
premiums(0) = 1 205,00 €. The Zulage credited in year 0 is the one earned in
2026, zulage_init_pp = 475,00 €, so zulagen(0) = 475,00 €. Charges:
K_a = 0,025 × 33 600 / 5 = 168,00 € (contract year 4, inside the five-year window),
K_v = 0,04 × 1 680,00 + 12,00 = 79,20 €, so S(0) = 1 680,00 − 168,00 − 79,20 = 1 432,80 €.
Interest at the declared 2,30 % on the Deckungskapital plus the Sparbeitrag plus the
Überschussguthaben: 0,023 × (3 860,50 + 1 432,80 + 150,48) = 0,023 × 5 443,78 = 125,206940 €,
the table’s 125,21 €, and A(1) = 5 568,986940 €. All of that is annual and falls on the year’s
clock.
The decrements are monthly. At attained age 50, contract
year 4 (d(0) = 3, the band read at d(0) + 1 = 4), the annual rates are
q = 0,001500 × 1,10⁰ × 0,80 = 0,001200, w = 0,008 and θ = 0,012; their geometric twelfths are
q_mth = 1 − (1 − 0,001200)^(1/12) = 0,000100055, w_mth = 0,000669124 and
θ_mth = 0,001005543, applied in that order within the month, so
pols_death(0) = 0,000100055, pols_lapse(0) = (1 − q_mth) × 0,000669124 = 0,000669057 and
pols_transfer(0) = (1 − q_mth)(1 − w_mth) × 0,001005543 = 0,001004769. Benefits struck on the
annual A(1), the end-of-year account every exit of that contract year takes:
claims_death(0) = 5 568,986940 × 0,000100055 = 0,557205 €;
claims_lapse(0) = 0,98 × 5 568,986940 × 0,000669057 = 3,651449 €;
claims_transfer(0) = (5 568,986940 − 50,00) × 0,001004769 = 5,545308 €. Expenses: a twelfth
of 30,00 × 1,02³ = 31,836240 € of maintenance, inflated on contract duration and not on
projection year, plus 80,00 × (0,000100055 + 0,000669057 + 0,001004769) = 0,141911 € of claim
expense, which is a per-event cost and falls whole — 2,794930 €. Commission
0,015 × (1 205,00 + 475,00) = 25,20 €, in the month the contribution falls. And
1 680,00 − 0,557205 − 3,651449 − 5,545308 − 2,794930 − 25,200000 = 1 642,251108 €, the frame’s
net_cf(0) = 1 642,25 €. The other eleven months of the year carry no contribution and net about
−12,50 € each; the year sums to the annual table’s 1 505,67 €.
And the year’s exits are the annual rates, compounded. Over the twelve months the cohort loses
0,001189015 to death, 0,007950812 to surrender and 0,011940288 to transfer. The annual-step
model’s sequential split at one year end was 0,001200, 0,007990 and 0,011890: the total is the
same to the last bit — 1 − (1 − q)(1 − w)(1 − θ) either way, which is why pols_if(12) is
0,9789198848 on both — and only the split moves, from the decrement applied first toward the
one applied last.
The conversion year rebuilt a different way. At k = 17 the Deckungskapital is
36 172,815098 €, the Überschussguthaben 8 224,490372 €, and the Sparbeitrag is the last
Zulage net of its charge, 175,00 − (0,04 × 175,00 + 12,00) = 156,00 € — the acquisition charge
is long over. The raw account is therefore 44 553,305470 €. On top of it the
Schlussüberschussanteil is 2 % of the contributions credited over the life of the contract,
which is exactly the guarantee accumulator: 0,02 × 37 877,2308 = 757,544616 €; and the
Bewertungsreserven share is 1 % of the raw account, 445,533055 €. So
account_conv_pp() = 45 756,383140 €. The guarantee itself can be rebuilt without the recursion:
guar_pp_init + pool_gefoerdert_pp(17) = 4 369,92 + 33 507,3108 = 37 877,2308 €, which is
7 879,15 € below the account, so capital_conv_pp() = 45 756,383140 € and the
Garantielücke is zero on the base scenario. Every one of those figures is the annual-step
model’s to the last bit, the account being an annual construction. The annuity factor at age 67 in
calendar 2044 on the first-order generational basis is ä = 20,8722287915, so the current
Rentenfaktor is
0,70 × 10 000 / (12 × 20,8722287915) = 7 000 / 250,466746 = 27,947822, below the
guaranteed 29,00, and the guaranteed factor applies. The lump sum is
0,30 × 45 756,383140 = 13 726,914942 €, leaving 32 029,468198 € to annuitise; the monthly
instalment is 32 029,468198 / 10 000 × 29,00 = 92,885458 €, comfortably above the 39,55 €
Kleinbetragsrente threshold the model uses — and above the 59,33 € the statute implies, so this
cell is unaffected by that error — so the contract annuitises. That instalment is paid monthly,
in advance, from t = t_conv() = 204; annuity_pp(17) = 12 × 92,885458 = 1 114,625493 € is the
annual figure it sums to. Weighted on pols_conv() = 0,7675876849, that is
claims_lumpsum(204) = 10 536,61 € and, over the conversion year’s twelve months — all inside the
guarantee window, so all on the same frozen count — claims_annuity of 855,57 €: the table’s
row 17.
The aggregate account rolls forward, and the charge the insurer keeps is what closes it. The
account at the start of year 1 is A(1) × l(12) = 5 568,986940 × 0,9789198848 = 5 451,592054 €.
Rebuilt from year 0’s own published parts: the opening account 4 010,98 €, plus the Sparbeitrag
1 432,80 €, plus the interest 125,206940 €, less the year’s three exit benefits — 6,621611 €,
43,392406 € and 65,898295 €, each the sum of its twelve months — less the exit charge the
insurer retains, 1,482574 € of Stornoabzug and transfer charge over the same twelve months,
gives 5 568,986940 − 117,394886 = 5 451,592054 €. The two agree to the last printed digit, and
they agree whatever the split of the year’s exits between the three decrements, because all three
release the same annual end-of-year account value — which is what lets the monthly grid move the
split without touching the account. Dropping
the exit charge — which looks like income rather than like account released — leaves a residual
of 1,48 € at k = 0, and is the usual way this identity fails.
Closure: the decrements sum to one. Over the whole 732-month projection, expected deaths
in accumulation are 0,04110900, deaths in payout 0,76758768, surrenders 0,07648390
and transfers out 0,11481942. They sum to 1,00000000 exactly, and pols_if(732) = 0
because mort_rate is forced to 1 at omega_age = 110 and mort_rate_mth places that certainty
in the terminal year’s last month. Nothing is left in force and no exit is
counted twice. Note what the split says about the product: 23,24 % of the cohort leaves before
Rentenbeginn, and of those, 49,4 % leave by Anbieterwechsel against 32,9 % by Kündigung
and 17,7 % by death — half again as many transfers as surrenders, at every duration and in
aggregate. A book modelled with a lapse rate alone would have mis-specified where the money goes
as well as how much of it goes.
Closure: the statement reconciles. On the Total row,
25 631,84 + 3 627,10 − 35 218,47 − 1 057,57 − 436,87 = −7 453,96 €, where 35 218,47 € is the
sum of all six claims_* columns. int_credited of 7 544,45 € is not in that sum: it moves
money inside the account rather than across the insurer’s boundary — and on the monthly grid it is
not a column of the cash flow frame at all — and adding it would report
the cell’s undiscounted deficit as 90,49 € instead of 7 453,96 €. This is check_net_cf(),
delib’s first ruling, evaluated on the totals rather than month by month.
Variant 1 — the low scenario and a binding Beitragsgarantie (model point 11)#
scenario_id = low declares 0,50 % a year instead of 2,30 %. Model point 11 is a shorter
deferral than the anchor and that is deliberate: on a seventeen-year accumulation even 0,50 %
does not open a Garantielücke, and the reason is worth stating rather than hiding. Model
point 11 is F, issue_age = 57, duration_init = 3, so age(0) = 60 and
k_conv() = 7; income_id = grow2_60k with income_init = 60 000,00, so the 2 100 € ceiling
binds from k = 0 and E(k) = 2 100 − Z*(k); zulage_id = k1_2010 and
zulage_init_pp = 475,00 as on the anchor; beitragssumme = 17 500,00; prem_freq = annual;
opening balances dk_pp_init = 4 900,00, surplus_pp_init = 200,00, guar_pp_init = 5 825,00,
so the cell opens 725,00 € under water; teilkapital_share = 0.30,
rentenfaktor_guar = 29,00, rentengarantie_years = 10; proj_len_y() = 51 years and
proj_len() = 612 months.
k |
pols_if |
premiums |
zulagen |
int_credited |
claims_death |
claims_lapse |
claims_transfer |
claims_lumpsum |
claims_annuity |
expenses |
commissions |
net_cf |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 |
1.000000 |
1,625.00 |
475.00 |
35.08 |
21.75 |
54.89 |
83.51 |
0.00 |
0.00 |
33.34 |
31.50 |
1,875.01 |
1 |
0.977045 |
1,587.70 |
464.10 |
43.81 |
29.87 |
68.53 |
104.44 |
0.00 |
0.00 |
33.21 |
30.78 |
1,784.97 |
2 |
0.954320 |
1,837.07 |
453.30 |
53.94 |
40.55 |
63.36 |
96.64 |
0.00 |
0.00 |
32.76 |
34.36 |
2,022.69 |
3 |
0.936516 |
1,802.79 |
163.89 |
62.58 |
51.76 |
73.50 |
112.18 |
0.00 |
0.00 |
32.79 |
29.50 |
1,666.97 |
4 |
0.918697 |
1,768.49 |
160.77 |
70.91 |
64.50 |
83.25 |
127.13 |
0.00 |
0.00 |
32.80 |
28.94 |
1,592.64 |
5 |
0.900842 |
1,734.12 |
157.65 |
78.90 |
78.95 |
92.62 |
141.48 |
0.00 |
0.00 |
32.81 |
28.38 |
1,517.53 |
6 |
0.882930 |
1,699.64 |
154.51 |
86.57 |
95.28 |
101.59 |
155.23 |
0.00 |
0.00 |
32.80 |
27.81 |
1,441.44 |
7 |
0.864938 |
0.00 |
151.36 |
0.00 |
0.00 |
0.00 |
0.00 |
5,449.11 |
442.47 |
21.28 |
0.00 |
−5,761.50 |
8 |
0.858363 |
0.00 |
0.00 |
0.00 |
0.00 |
0.00 |
0.00 |
0.00 |
442.47 |
21.33 |
0.00 |
−463.80 |
19 |
0.731563 |
0.00 |
0.00 |
0.00 |
0.00 |
0.00 |
0.00 |
0.00 |
369.87 |
18.84 |
0.00 |
−388.71 |
50 |
0.000061 |
0.00 |
0.00 |
0.00 |
0.00 |
0.00 |
0.00 |
0.00 |
0.03 |
0.01 |
0.00 |
−0.04 |
Total, k = 0 … 50 |
12,054.81 |
2,180.59 |
431.80 |
382.67 |
537.73 |
820.61 |
5,449.11 |
9,937.96 |
765.94 |
211.26 |
−3,869.89 |
Again the Total is summed at full precision and then rounded; the two differ on zulagen,
claims_death, claims_lapse, claims_annuity, int_credited, expenses, commissions and
net_cf. Every accumulation figure here is the annual-step model’s; the annuity falls from
10 121,79 € to 9 937,96 € for the reason the anchor’s does, and the exits redistribute the same
way.
The guarantee binds, and this is the number the product exists to produce. At k = 7 the
raw account is 19 863,088636 €; the Schlussüberschussanteil adds 420,00 € and the
Bewertungsreserven share 198,630886 €, giving account_conv_pp() = 20 481,719523 €. The
guarantee accumulator is guar_pp(8) = 21 000,000000 € — the ceiling binds in every contribution
year, so the contributions credited are a round 2 100,00 € a year and the accumulator lands on a
round number. So capital_conv_pp() = 21 000,000000 € and
garantieluecke_conv_pp() = 518,280477 €: the insurer funds 518,28 € per policy out of its
own resources, 2,5 % of the capital, so that the saver receives at least what was paid in. The
annuity is then struck on the guaranteed capital rather than on the account —
teilkapital_pp() = 6 300,00 €, annuity_capital_pp() = 14 700,00 €, monthly instalment
14 700 / 10 000 × 29,00 = 42,63 € paid monthly, 511,56 € a year — and
claims_lumpsum(t_conv()) = 6 300,00 × 0,8649383502 = 5 449,11 €.
Two sensitivities follow, both reproducible by flipping scenario_id in
model_point_table.csv. On base this same cell’s account reaches 22 271,80 € against the same
21 000,00 € guarantee, so the Garantielücke is zero: 1,80 percentage points of declared
interest over seven years is the whole difference between a guarantee that costs nothing and one
that binds — sensitivity 1, made arithmetic. And on the anchor’s seventeen-year deferral the
low scenario still does not bind, but only just: the raw account at conversion is 37 370,67 €
against a guarantee of 37 877,23 €, a raw shortfall of 506,56 € closed only by the
Schlussüberschussanteil of 757,54 € and the Bewertungsreserven share of 373,71 €. Counting
those two toward the Beitragserhaltungszusage is the provider-favourable reading of an
unsettled question (gap 9); on the conservative reading the anchor’s own low-rate Garantielücke
is 506,56 € rather than zero. That is sensitivity 4, and on this cell it is the larger of the
two.
Variant 2 — the fixed contribution form (model point 5, the mittelbar spouse)#
The second contribution form, at the economically extreme corner of the book: contrib_form = fixed with contrib_fixed_pp = 60,00, the Sockelbeitrag, and income_id = zero because a
mittelbar zulageberechtigt spouse has no contribution-liable earnings of their own — so
M(k) = max(60, min(0, 2 100) − 175) = 60,00 €, the floor binds by construction, E(k) = M(k)
and the full Grundzulage is granted. F, issue_age = 50, duration_init = 6, so
age(0) = 56 and k_conv() = 11; beitragssumme = 1 020,00; opening balances 1 150,00 €,
60,00 € and 1 400,00 €; proj_len_y() = 55 years and proj_len() = 660 months.
claims_lumpsum and claims_annuity are 0.00
throughout and claims_commutation replaces them.
k |
pols_if |
premiums |
zulagen |
int_credited |
claims_death |
claims_lapse |
claims_transfer |
claims_commutation |
expenses |
commissions |
net_cf |
|---|---|---|---|---|---|---|---|---|---|---|---|
0 |
1.000000 |
60.00 |
175.00 |
32.74 |
3.07 |
8.52 |
12.60 |
0.00 |
34.88 |
3.52 |
172.40 |
1 |
0.982960 |
58.98 |
172.02 |
37.75 |
3.90 |
9.82 |
14.60 |
0.00 |
34.96 |
3.46 |
164.24 |
10 |
0.856985 |
51.42 |
149.97 |
81.96 |
20.01 |
14.21 |
21.50 |
0.00 |
36.10 |
3.02 |
106.55 |
11 |
0.843758 |
0.00 |
147.66 |
0.00 |
0.00 |
0.00 |
0.00 |
3,828.31 |
0.00 |
0.00 |
−3,680.65 |
12 |
0.000000 |
0.00 |
0.00 |
0.00 |
0.00 |
0.00 |
0.00 |
0.00 |
0.00 |
0.00 |
0.00 |
54 |
0.000000 |
0.00 |
0.00 |
0.00 |
0.00 |
0.00 |
0.00 |
0.00 |
0.00 |
0.00 |
0.00 |
Total, k = 0 … 54 |
609.80 |
1,926.26 |
631.80 |
108.18 |
123.53 |
185.58 |
3,828.31 |
388.54 |
35.83 |
−2,133.91 |
The saver pays 609,80 € over the whole projection and the state pays 1 926,26 € — the Zulage
is 76 % of the contribution, which is why a statement that folded zulagen into premiums
would be describing a different product. The contract never produces an annuity: at k = 11 the
capital is 4 537,217342 €, and the annuity after the elected 30 % lump sum would be
0,70 × 4 537,217342 / 10 000 × 29,00 = 9,21 € a month against the model’s 39,55 € threshold — and
it would fail the statutory 59,33 € threshold too, so this cell is likewise unaffected — so the
Kleinbetragsrente test commutes it and the whole capital is paid as an Abfindung,
3 828,31 € = 4 537,217342 × 0,84375772. There is no Teilkapitalauszahlung beside it,
pols_if is zero from t_conv() + 1 because the Abfindung discharges the contract outright — an
exit check_pols_roll_fwd() counts as a commuted cohort rather than as a decrement — and the
frame carries zeros to t = 659 rather than being truncated. Every figure of this cell’s
accumulation, and the Abfindung itself, is the annual-step model’s: a commuted contract pays no
annuity, so the one thing the monthly grid buys does not arise here, and only the split of the
exits and the expenses move.
Changes the model stage made to these notes#
Six, each because the model and the notes as drafted disagreed and the model was right.
The frequency loading was deducted twice. The drafted
S = C − K_a − K_vhad an unloadedCand aK_valready carryingE(t)(φ − 1), soprem_to_av_ppfell with the payment frequency, contradicting pitfall 11.C(t)is now the cash received and the administration charge’s percentage base is the unloadedB(t); model point 3 (monthly) now haspremiumslarger by exactlyE(k) × 0,03and an identicalprem_to_av_pp,guar_ppand benefit set.check_conversion()’s third identity was inconsistent with the Rentenfaktor margin.12 · annuity_month_pp() · ann_factor() = annuity_capital_pp()cannot hold when the factor carries a 30 % loading — it is short by exactly that margin. It is replaced byrentenfaktor_curr() · 12 · ann_factor() = (1 − rentenfaktor_margin) · 10 000, which says the same thing about the annuity basis, holds on every model point rather than only where the current factor applies, and still catches a Woolhouse correction applied twice.check_pols_roll_fwd()did not account for a commuted cohort. An Abfindung discharges the contract, sopols_if(t_conv() + 1) = 0with no decrement having removed the population. The identity now carriespols_conv()as a fourth exit in the conversion month of a commuted contract; without it the check is false on model points 4, 5, 10 and 13.The guarantee accumulator’s unsubsidised limb is gated on
is_accum_y(k), matchingpremiums(t). As drafted it addedcontrib_extra_ppin the conversion year, in which no contribution is paid.Model point 11 is a shorter-deferral cell than first drafted, and its row in the model point table has been rewritten. Specified as the anchor with
scenario_id = low, it did not bind: on that cell seventeen years of 0,50 % interest plus the two terminal surplus components exceed the charges by 624,69 €. The anchor-at-lowfigures are reported in Variant 1 as the sensitivity they are, because the 506,56 € raw shortfall they show is the more interesting of the two results.Model point 2 reconciles the anchor’s account seeds and not its guarantee seed. Projected from its own inception on the contract-clock income path
grow2_pre, it reproducesdk_pp_initas 3 860,499285 € against 3 860,50 €,surplus_pp_initas 150,483132 € against 150,48 € andav_total_pp(0)as 4 010,982418 € against 4 010,98 €, and from itsk = 3onward every per-policy quantity coincides with the anchor’s fromk = 0. Its guarantee accumulator at the same point is 4 565,00 € against the seed’s 4 369,92 €. The two seeds were struck on different income paths — the account seed on earnings level at 42 000 € over the three pre-valuation contribution years, which reproduces 3 860,50 € to the cent, and the guarantee seed on a 2 %-declining back-path, which reproduces 4 369,92 € to the cent — and they cannot both be right. The seeds are kept as specified, because they are std opening balances of an in-force cell rather than derived quantities and becausegarantieluecke_pp(0) = 358,94 €depends on the pair; the 195,08 € discrepancy is recorded rather than papered over, and a calibration pass should restrike both on one path.
A seventh was settled later, when the model moved from an annual step to a monthly one.
The grid is monthly and the contract is not.
tcounts months andk = t // 12projection years, and a cells’ argument says which clock it is on. The whole subsidy chain, both charges, both account balances, the guarantee accumulator and the conversion stay annual — they are annual terms of the statute and the contract, and the Ratenzuschlag is how a fractionated payment mode is priced without moving the contribution year — so the accumulation is bit-identical to the annual-step model’s on all thirteen model points, the Garantielücke and the Kleinbetragsrente verdict included. What the finer grid was adopted for is the monthly Leibrente the AltZertG requires: pitfall 17’s compression is gone, the Rentengarantiezeit is12minstalments, and the anchor’s payout phase falls 361,74 €. It also dates the three accumulation exits, which now compete month by month instead of running in sequence at a year end, moving 5,62 € off the anchor’s death outgo and 2,64 € off its surrender outgo onto 8,30 € of transfers.
Valuation and reserve pointers#
This library projects gross best-estimate-style liability cash flows, undiscounted, on a declared grid. The valuation layers consume them and are cited, never reproduced.
The German statutory Deckungsrückstellung. Prospective, computed on the Rechnungsgrundlagen erster Ordnung of the premium calculation — the tariff’s own Rechnungszins and its first-order biometric basis — under § 341f HGB and the DeckRV REG-R14 REG-R54. It is not the Solvency II best estimate, and the whole German picture depends on keeping the two apart: an insurer carries two liability measures, and the Überschussbeteiligung, the Zinszusatzreserve and the Bewertungsreserven test all run on the HGB side.
dk_pp(t) × pols_if(t)is this model’s contribution to the first of them; the second-order path above is what feeds the Solvency II side.The Zinszusatzreserve. Where the § 5 Abs. 3 DeckRV Referenzzins falls below a contract’s tariff rate, an additional HGB reserve arises REG-R17. On a 0,25 % tariff it is small or nil; on the 1,75 % and 2,25 % vintages that dominate the older Riester book it is not, which is one reason a model of this product should carry
rechnungszinsas a model-point attribute rather than a library constant.The guarantee is an option, and this projection prices none of it. The Beitragsgarantie is a written put on the accumulation, struck at the contributions paid and exercisable once. The deterministic path above reports the Garantielücke on one declared-rate scenario; a time-value-of-options-and-guarantees calculation re-evaluates the crediting rule and the guarantee test per stochastic scenario, and the two scenarios shipped (
base,low) are a sensitivity, not a distribution.Solvabilität II. Best estimate plus risk margin under the Directive as transposed by §§ 74–110 VAG REG-R5 REG-R6, with EIOPA publishing the curves.
BEL = Σ_t v(t) · liability_cf(t)over the recursion above. The 6 % cost-of-capital rate is now read from the instrument — Art. 39 of the Delegierte Verordnung (EU) 2015/35, one sentence, retrieved and quoted in full in the cross-product reference library — but no risk-free curve value, volatility adjustment or standard-formula shock in this library was read from a retrieved instrument, so every such figure would still be std.Contract boundary. A Riester contract’s future contributions are not unilaterally variable by the insurer, and the Wechselrecht is the policyholder’s R1 — but whether the Solvency II boundary extends to the whole future contribution stream is still not determined here. The Delegated Regulation itself was retrieved in the re-verification pass, but only its risk-margin articles were read; its contract-boundary articles were not, and no delib document states a figure from them. The model’s posture is to project the full stream and publish it; a boundary-truncated view is obtained by truncating
result_cf().The surplus regulations. The MindZV puts an arithmetic floor under the transfer to the Rückstellung für Beitragsrückerstattung REG-R18 REG-R19 and § 153 VVG gives the individual entitlement and the hälftige participation in the Bewertungsreserven REG-R24. This model takes
decl_rateas an exogenous management action and does not derive it from a distributable surplus;frlib/products/assurance_vie_euro/derives its credited rate from a statutory account, and the difference between the two treatments is a real difference between the two jurisdictions’ surplus law, not a modelling shortcut.IFRS 17. A participating contract of this kind would be measured under the variable fee approach REG-R55; the same expected-cash-flow engine feeds it, and grouping, the CSM and the risk adjustment are out of scope.
Key sensitivities and model risks#
In rough order of leverage on a German Riester block.
The declared laufende Verzinsung. It is the largest single lever in the model and the least supported: it sets the account’s growth, hence whether the Garantielücke is positive at all, hence the whole cost of the product’s defining feature. Moving the
basescenario from 2,30 % to thelowscenario’s 0,50 % is the difference between a guarantee that costs nothing and one that binds — model point 11 exists to show it. No declared rate at any carrier was established (gap 12).The charge basis, and the rate the Zulagen are charged at. Every charge level is still std, but the question has narrowed. Gap 14 is closed: the Zulagen are charged, in the GDV model wording and at three carriers [S2] [S4] [S6] [S9]. What is now in doubt is the rate, and the one tariff in hand charges the Zulagen at 6,0 % against 2,1 % on the Eigenbeitrag [S4] where the model charges both at 4,0 %. On the low-income model points the Zulagen are the majority of the contribution, so the gap between 4,0 % and 6,0 % moves the account value on exactly the cells the product was designed for — and the gap between the composite’s 2,5 % acquisition charge on a Zulagen-inclusive Beitragssumme and the observed 1,0 % on Eigenbeiträge alone moves it further. A calibration against [S4] is the highest-value next step in this file.
The annuity basis and its generational structure. A twenty-year deferral means the conversion happens on
τ = 2044mortality. The improvement function, not the base table’s level, is what decides the annuity factor, and it is entirely std REG-R49. Therentenfaktor_marginof 30 % compounds the same uncertainty in the opposite direction.Which surplus components close the guarantee. Counting the Schlussüberschussanteil and the Bewertungsreserven share toward the Beitragsgarantie is the provider-favourable reading and is unestablished (gap 9). Excluding them raises
garantieluecke_conv_pp()by their whole amount on any cell where the guarantee binds.The absence of a Beitragsfreistellung decrement. The dominant exit in the real book is represented as a per-model-point switch. A book projection built from these model points will therefore over-state future contributions and Zulagen unless the point weights carry the paid-up share — and there is no official statistic for that share at all (gap 2).
The Kleinbetragsrente test — now a known error rather than an open question. The threshold is 1,5 % of the monthly Bezugsgröße, § 93 Abs. 3 Satz 2 Nr. 1 EStG R15, and the model uses a 1 % figure; and the test belongs on the annuity before the elected lump sum, the GDV model wording excluding a commutation caused only by the Teilkapitalauszahlung [S2]. Both of the model’s choices push toward fewer commutations and a longer-tailed liability, and both are wrong in that direction. Neither has been changed here — see Model-relevant contradictions — so this remains the largest single correction outstanding against the model.
Holding the Kleinbetragsrente threshold flat in nominal terms. The Bezugsgröße is reset annually; on a seventeen-year deferral a flat threshold understates the commutation rate, and the direction of the error is stated rather than hidden.
This risk is retired: the Leibrente is paid monthly. The annual grid paid a full year to a life that died in the payout year, overstating the annuity outgo by roughly
½ · q(x) · 12Ra year — small at 67 and growing with attained age. The monthly step pays one instalment at a time to whoever is alive that month, which removes it: 361,74 € of the anchor’s payout phase and 573,50 € of model point 12’s. What remains std is vorschüssig against nachschüssig, worth about one month’s interest on the annuity.This risk is retired. Gap 4 is closed. Every statutory paragraph number in this file was checked against the canonical XML on 2026-08-30, with the instrument’s Stand recorded at each entry in
sources.md, and the two most consequential figures in the whole subsidy — the 175 € / 185 € / 300 € Zulagen and the 4 % / 2 100 € / 60 € arithmetic — are read verbatim in §§ 84, 85, 86 and 10a EStG rather than corroborated at one remove R6 R9 R10. Three citations were wrong and are corrected: the 60th-year Rentenbeginn is AltZertG § 14 Abs. 2 and not § 1; the Pfändungsschutz is ZPO § 851 Abs. 1 and not EStG § 97; the Effektivkosten are AltvPIBV § 8 Nr. 3 and not the AltZertG, which never uses the word. What still requires a calibration pass before quantitative use is the carrier half: the charge levels, the declared rate and the Rentenfaktor, for which one tariff [S4] and one disclosed cost total [S9] now exist where none did.