This calculang example is based on nested.py, a "minimum reproduceable nested model" by Lewis Fodgen. It ties back exactly, but implementations are different.
It's an example using modularity, input inference and overriding: key technical features in calculang that permit flexibility and reusability in models ♻️
nested.py implements a Term base class and PrudentTerm and RealisticTerm subclasses: extending Term modelling logic with prudent assumptions and capital requirement calculations respectively.
At each time point RealisticTerm initialises and runs an inner projection of it's sibling class PrudentTerm to estimate prudent capital requirements.
Similar to with the Term base class, the calculang model centralises common modelling logic in term.cul.js (itself a simple calculang model).
capital-requirements.cul.js is a calculang model that imports the term.cul.js model, but "overriding" specific behavior for capital requirement calculations.
Notably, the q_x formula is overriden to apply a prudence factor or not: depending on new projection inputs. Then, capital_requirements formula definition can call appropriate cashflow projection formulas, applying appropriate new projection input values relating to prudence.
🤔 Related formula definitions
export const q_x = () => {
  if (t() >= t_inner()) return q_x_() * prudence_factor();
  else return 0;
};
export const capital_requirement = () =>
  (fut_claims({ t_in: t() + 1, t_inner_in: t(), prudence_factor_in: 1.2 }) +
    fut_premiums({ t_in: t(), t_inner_in: t(), prudence_factor_in: 1.2 })) *
  num_pols_if();Input inference & multipurpose models ♻️
Although the q_x formula is explicitly overridden to use new inputs and the logic in term.cul.js has no notion about them, the calculang compiler infers that num_deaths all the way to fut_claims in term.cul.js should use the new inputs.
Input inference explains why there is a lot of empty/minimalistic brackets in calculang functions and calls (which I might remove in future). Input inference promotes very general specification of modelling logic, so that it can be shared across lots of different exercises on models.
calculang aims to make models that are multipurpose in the extreme (and transparent and communicable), and where this follows naturally from the language design.
Input inference clearly helps formulas to be more concise, but flexibility and reusability is it's real purpose ♻️
Use this link to run in the Actuarial Playground UI Click '💬' to show model formulas and use dropdown to select .cul.js files
Tip: Use the mouse wheel to zoom in and out of the Playground visualization, and hold shift to zoom on the y axis only (to control the aspect ratio).
Tip 📌: there is a semi-transparent '🥚' in the Actuarial Playground UI; there you can turn on graphs and an improved (more responsive) tooltip over visualization elements, as well as a legend.
Note: Especially when model code is loaded from a URL (by following the instructions above; either approach), there are some bugs around editing directly in the Actuarial Playground UI: especially when you switch .cul.js files, you probably lose custom changes.
./minimal achieves the same results but without comments or redundant formulas: for analysis of the calculang logic/implementation itself.
Load in the Actuarial Playground. Click '💬' to show model formulas and use dropdown to select .cul.js files
npm install
npm run model-outputThis creates ./output/output.txt which should match ./output/nestedpy-output.png.
Alternatively, run run.js directly:
npm install
node ./output/run.jsThe repo includes a snapshot test that runs the model and compares against ~reviewed static output, to run:
npm run testTo update the snapshot, run:
npm run test:updateFeedback/Discussion: I'm really interested in early reactions about the calculang features applied to this problem. I aim to provide more helpful material for actuaries about how I apply the specific calculang features, and early reactions will help to ground that work.
Nested actuarial modelling approaches are open for discussion with the Actuarial Open Source Community here and a specific discussion about this implementation is posted here. Please participate there!
This month I'm also happy to meet and discuss with members of the Actuarial Open Source Community who have notable experience applying Python, Julia, R for actuarial modelling in practice. I'm specifically interested to discuss extensibility of actuarial models in practice.
More Information: The '❓' tab in ActuarialPlayground.com mentions other instances where I apply the same functionality in calculang. The calculang README has separate wording for some of the calculang features applied here. A buggy UI that surfaces exactly what the calculang compiler outputs is here.
For information purposes, output folders in this repository include some additional calculang output files; some details are included in their corresponding README files.
