Actuarial pricing and profitability model for YouthSave, a unit-linked endowment savings product designed for young formal-sector employees in Uganda. Includes multi-decrement modelling, premium pricing, surrender and TPD benefits, sensitivity analysis, batch analysis, and an interactive Streamlit dashboard.
# YouthSave Plan — Actuarial Pricing Engine
Python replication and generalisation of the YouthSave_Plan.xlsx multi-decrement
unit-linked endowment pricing/profit-testing model (Plans A and B).
## Build order (matches validation dependency chain)
1. `engine/decrements.py` — independent -> dependent decrements, survival, waiver annuity **[done, validated]**
2. `engine/unit_fund.py` — per-unit-premium fund projection **[done, validated]** — built ahead of
schedule vs. the original plan: SurrenderStrain's EPV needs projected fund
values, and pricing.py needs SurrenderStrain, so the per-unit-premium fund
projection had to exist before the premium could be solved at all. This
works because the fund recursion is homogeneous linear in P (F_0=0), so
fund-per-unit-premium can be computed with P=1 before P is known.
3. `engine/config.py` — YAML loader for Assumptions/PlanSpec **[done]** (not in the original
module list — needed once strains.py/pricing.py required typed config objects)
4. `engine/strains.py` — composable strain modules (death, TPD, surrender, expense,
commission, maturity, waiver) **[done, validated]**
5. `engine/epv.py` — aggregate EPV components per plan **[done, validated]**
6. `engine/pricing.py` — closed-form premium solve **[done, validated — matches Excel's
Goal Seek to ~1e-10, both plans, both genders]**
7. `engine/non_unit_fund.py`— non-unit cashflow / strain costs **[done, validated — profit
vector matches Excel to ~4.7e-9]**
8. `engine/profit_testing.py` — NPV, profit margin **[done, validated — NPV, PV premiums,
profit margin all match Excel]**
9. `engine/policy.py` — user input layer (DOB, gender, plan type, term, sum assured)
**[done]** — the only place these five inputs enter the engine; every other module
already takes entry_age/term/gender/sum_assured as plain arguments, so adding this
layer required no changes elsewhere.
10. `analysis/sensitivity.py` — automated stress testing **[done, validated — all 14 …