Financial Modelling · Section 3
Contracts as compositions
The algebra of financial terms. How quota share, CatXoL, and AggXoL are each a composition of the same small set of building blocks.
The dissection translated Contract 1 into four terms applied in sequence, with participation booked at roll-up. Those same terms (with different parameters, and different blocks in different combinations) assemble every other Caldera Re contract too. Each is a catastrophe excess of loss (CatXoL), an aggregate excess of loss (AggXoL), or a quota share:
- Contract 5 (Baltica EU Windstorm Quota Share, 25%): filter to EU windstorm, check the contract period, scale every loss by 25%.
- Contract 3 (SunCoast All-US AggXoL, $50M xs $300M, net of C1+C2): filter to SunCoast’s US perils, subtract C1 and C2 gross losses (inuring), check the contract period, sum all occurrences per trial and apply an attachment and limit to the total.
Notice the reuse: a CatXoL applies an attachment and limit per occurrence, and an AggXoL applies the same operation to the aggregate; a quota share’s event limit is the CatXoL’s occurrence excess with zero attachment. The same five blocks recur (plus, in Contract 3, inuring, which is a relationship between contracts rather than a block). The parameters are the predicate , the window , the attachment , the limit , the number of reinstatements , and the scaling factor :
| Building block | Contract type | ||
|---|---|---|---|
| Quota Share | CatXoL | AggXoL | |
| Loss filter | ✓ (peril / geography) | ✓ (peril / geography) | ✓ (peril / geography) |
| Contract period | ✓ | ✓ | ✓ |
| Scaling | ✓ (cession %) | — | — |
| Occurrence excess | optional (event limit) | ✓ (, ) | — |
| Aggregate excess | optional (annual limit) | ✓ (, ) | ✓ (, ) |
The five building blocks
Section titled “The five building blocks”Each block is formalised in the term catalog, where you will find its formula, its effect on Trial 9 in isolation, a runnable implementation over the year event loss table (YELT), and the exceedance probability (EP) curves it produces across all 20 trials of the demo tier:
| Term | What it does | Signature |
|---|---|---|
| Loss filter | Keeps the rows for which is true and drops the rest; no loss value changes | |
| Contract period | Drops occurrences whose timestamp falls outside inception-to-expiry (a losses-occurring basis) | |
| Scaling | Multiplies every loss by a constant: a quota share's cession inside a composition, the participation share at roll-up; the distribution keeps its shape and every metric scales linearly | |
| Occurrence excess | Pays on each occurrence independently | |
| Aggregate excess | Applies the attachment and limit to the trial's running total, booking each occurrence's erosion of the layer as its output row |
All five obey the YELT in, YELT out principle: no block collapses the YELT to trial level. The filter, the contract period, and scaling act on each row. The occurrence excess acts on the occurrence total and splits its gross across the occurrence’s rows in proportion to their losses, so its output keeps geography and line of business. The aggregate excess satisfies the principle by tracking the layer’s erosion occurrence by occurrence and booking each occurrence’s contribution to the aggregate gross as its output row, so terms composed after it still receive rows at the resolution it was given. The aggregate excess page works through the mechanics. Optional terms such as triggers are defined in the glossary; the catalog does not cover them.
The five blocks are the within-contract vocabulary. Inuring (Contract 3’s subtraction of C1 and C2) is a relationship between two contracts’ outputs, not a sixth block. It takes one contract’s gross loss out of another’s subject loss before that contract’s own terms run, so C3’s subject is SunCoast’s loss net of C1 and C2. The Programs page covers it.
Composing contracts from the blocks
Section titled “Composing contracts from the blocks”A contract is a composition of terms: each contract type composes the same terms, differing only in which ones it uses and how they are parameterised.
We write a composition as : apply first, then to the result, and so on. Data flows left to right (we call the flow a pipeline, but that is not its formal term), while the formula reads right to left, following the mathematical convention for function composition. Every contract below begins, on the right, with a filter and a contract period selecting the losses it sees.
The three contract types are three compositions over the same five terms. Each leaves some terms out, and each gives the terms it keeps its own parameters:
In code the composition is a fold over the terms. Each term is a function from a YELT to a YELT, so compose takes them in the order the formula is written (rightmost applied first) and returns a function of the same shape, which is what lets a composed contract be composed again. Run on SunCoast’s YELT, Contract 1 written this way reproduces the dissection’s $60M on Trial 9 and the $17.39M expected loss the standalone pricing story prices C1 on:
from functools import partial, reduce
import pandas as pd
from caldera_re.aggregate_excess import aggregate_excess
from caldera_re.contract_period import contract_period
from caldera_re.data import cedents
from caldera_re.loss_filter import loss_filter
from caldera_re.occurrence_excess import occurrence_excess
def compose(*terms):
"""Compose financial terms the way the formula is written.
compose(T_k, ..., T_2, T_1)(yelt) == T_k(...T_2(T_1(yelt))): the argument
list reads right to left, as C = T_k o ... o T_1 does, and the data flows
left to right through the terms. Each term is a function YELT -> YELT, so
the result is itself a function YELT -> YELT and can be composed again.
"""
def contract(yelt: pd.DataFrame) -> pd.DataFrame:
return reduce(lambda acc, term: term(acc), reversed(terms), yelt)
return contract
if __name__ == '__main__':
# Contract 1, written as its formula reads:
# CatXoL(10, 30, 1) = agg_excess(0, 60) o occ_excess(10, 30)
# o period(2024-01-01, 2024-12-31) o filter(HU, FL)
# occurrence_excess writes 'gross_loss'; the aggregate cap chains on it.
contract_1 = compose(
partial(aggregate_excess, attachment=0, limit=60, loss_column='gross_loss'),
partial(occurrence_excess, attachment=10, limit=30),
partial(contract_period, period_start='2024-01-01', period_end='2024-12-31'),
partial(loss_filter, peril='HU', geography_id='FL'),
)
result = contract_1(cedents.suncoast)
by_trial = result.groupby('trial_id')['gross_loss'].sum()
N = 20
gross = by_trial.reindex(range(1, N + 1), fill_value=0.0)
print("Contract 1 as a composition of four terms (100% layer)")
print(f" Trial 9 gross: {gross[9]:.1f}M")
print(f" Gross EL: {gross.mean():.2f}M")
print()
print("Per-trial standalone gross, all 20 trials:")
for trial_id, g in gross.items():
print(f" trial {trial_id:2d}: {g:5.1f}M") Every composition defines its contract at 100%: the whole layer, however the placement is split among reinsurers. Participation is deliberately absent from the definitions: it is a scaling applied at portfolio roll-up, where Caldera Re books its share of each contract. Standalone contract metrics are reported at 100% for the same reason: the full-layer result isolates a contract’s own behaviour from how its placement happens to be split. An implementer who writes participation into the contract and then scales again at roll-up double-counts it. Both rules are indexed on Scope, conventions & assumptions.
The three signatures are rendered from each contract page’s own catalog entry, so they cannot drift from it:
| Contract | Signature |
|---|---|
| Quota share | |
| Catastrophe excess of loss | |
| Aggregate excess of loss |
Instantiated with Caldera Re’s parameters (attachments and limits in millions of dollars, each composition applied to its own cedent’s YELT, so no filter names the cedent):
The simplest structure: a fixed cession percentage behind a filter and a contract period. Contract 5 cedes a quarter of Baltica’s European windstorm losses:
Optional event and annual limits insert an occurrence excess and an aggregate excess before the scaling.
The occurrence excess clips each event; the aggregate excess caps the annual total (the limit encodes reinstatements). Contract 1 is $30M excess of $10M per Florida hurricane, with one reinstatement:
Drops the per-occurrence layer: the aggregate excess applies directly to the trial total. Contract 3 is $50M excess of $300M on SunCoast’s whole US book, net of C1 and C2 (the netting is the inuring relationship, applied to the subject before the composition runs):
The term catalog and contract catalog formalise each block and each contract in turn. Beyond the canonical types, one contract can also forward its output to another. The programs page covers the forwarding and inuring relationships that turn a stack of contracts into a graph. And every contract produces not only a gross loss but a full set of financial perspectives: subject, covered, gross, retained, and net.