Skip to content
Property-cat reinsurance analytics for software engineers

Financial Modelling · Section 8

Programs

What a reinsurance program is: the structured set of protections bought on one exposure, typically excess-of-loss layers stacked into a "tower", sometimes beside a quota share. Why the contracts in most programs are independent, and how some add inuring between them.

A cedent rarely transfers its risk with a single contract. It assembles a program: the structured set of reinsurance protections bought to cover one set of exposure (a property-catastrophe book, a casualty account, a single large risk). A program is the container for everything a placement needs: the exposure being protected, the contracts structured on top of it, and the terms that govern them. It is the unit a cedent buys, a broker places, and a reinsurer prices and renews.

Programs span a wide spectrum of uses. A regional insurer buys a property-catastrophe program to protect its homeowners book; a reinsurer buys a retrocession program to protect the portfolio it has assumed; two carriers enter a risk-sharing agreement; a cedent sponsors a cat bond to move peak risk into the capital markets. The structures differ, but the idea is constant: a coordinated set of protections on one defined exposure.

Most programs share a common shape, a tower of excess-of-loss layers, sometimes placed beside a quota share on the same exposure; some add relationships between their contracts.

The common shape is a stack of excess-of-loss layers, each covering a band of loss above the one below it. The industry calls the stack a tower.1 A cedent that retains the first $10M of any catastrophe might buy a $10M xs $10M layer, a $30M xs $20M layer above it, and a $50M xs $50M layer above that: three layers covering loss from $10M up to $100M, each placed (often with a different panel of reinsurers) as its own contract.

A three-layer tower: $10M xs $10M, $30M xs $20M, $50M xs $50M
$0M$20M$40M$60M$80M$100MOccurrence loss ($M)RetentionRetention $10MLayer 1$10M xs $10MLayer 1 exhausts $20MLayer 2$30M xs $20MLayer 2 exhausts $50MLayer 3$50M xs $50MExhaustion $100M

One occurrence loss read from the bottom: the cedent retains the first $10M, layer 1 covers the next $10M, layer 2 the $30M above that, and layer 3 the $50M band up to the $100M exhaustion point.

Read the tower from the bottom: an occurrence loss fills the retention first, then layer 1, then layer 2, and only a loss above $50M reaches layer 3. Every layer reads the same occurrence and responds to its own band of it.

In a vanilla tower the layers are independent. Each one filters the subject loss, applies its layer, and computes its gross loss without reference to any other layer: every layer reads the same exposure, each at a different band. Evaluate them in any order, or all at once; the program’s total ceded loss is the sum. This is the single-contract evaluation from earlier in the chapter, repeated once per layer and added up.

The independence ends where one layer’s result changes another layer’s subject, and an evaluation order follows.

Some programs add relationships between contracts, where one contract’s result changes what another contract sees:

  • Inuring: one contract’s recoveries are subtracted from another’s subject, so the same loss is not recovered twice, as a catastrophe cover’s wording usually provides. A quota share that inures to the benefit of the catastrophe layers, so they cover only the loss the cedent retains, is the common case.
  • Forwarding: one layer’s gross loss becomes another’s subject (the retrocession case).
  • Top & drop: a single block of limit responds at a high attachment or drops down to a lower one, depending on how the year unfolds.2

Of the three, inuring and forwarding change a contract’s subject stream; top & drop changes a layer’s attachment, not its input.

These are optional features, not part of the definition: a tower with none of them is still a program. But when present, they make the contracts interdependent: a contract can no longer be evaluated in isolation, because its subject depends on another contract’s output. SunCoast’s program uses inuring, so this page treats inuring in depth; forwarding and top & drop are out of scope for this page.

The risk-profiling story characterised SunCoast’s subject loss: $275.6M of expected annual loss on the 20-trial demo tier, hurricane-dominated, with exposure spread across the Gulf. SunCoast protects that book with three layers:

LayerTypeCoversStructurePremium
C1CatXoLFlorida hurricane, per occurrence$30M xs $10M, 1 reinstatement$14M
C2AggXoLCA/AZ earthquake, annual aggregate$10M xs $15M$5M
C3AggXoLAll-US, annual aggregate, net of C1, C2$50M xs $300M$13M

Two of these are ordinary, independent layers: C1 caps individual Florida hurricanes, C2 caps a bad year of California quakes. The inuring relationship is the one addition: C3 is a whole-book backstop that responds only in a genuinely catastrophic year, and only for loss C1 and C2 have not already absorbed. That “net of C1 and C2” clause is an inuring relationship. SunCoast’s program is not exotic: it is a standard catastrophe program with a single inuring edge on top of an otherwise vanilla structure. C1 is a catastrophe excess of loss (CatXoL) layer; C2 and C3 are aggregate excess of loss (AggXoL) layers.

C1 and C2 read the subject loss directly and can be evaluated in any order. C3 depends on both: it cannot be computed until they are, because its subject is defined in terms of their recoveries. Inuring defines C3’s subject, and dependency order determines when an engine can compute it.

Inuring is the relationship where one layer’s recoveries reduce the subject loss of another. “C1 and C2 inure to the benefit of C3” means C3 responds only to the loss left after C1 and C2 have paid. Its purpose is to prevent double recovery: the same dollar of loss being collected once by a lower layer and again by the backstop.

For SunCoast the netting is arithmetic on per-trial losses. Because C3 is an aggregate layer, the netting happens at the trial-aggregate level. Write LjL_j for SunCoast’s total loss in trial jj and Ci(Lj)C_i(L_j) for contract ii‘s gross loss on it; C1 and C2 apply to SunCoast’s loss before any netting. In the two formulas below LjsubjectL_j^{\text{subject}} is C3’s subject alone, the total minus what C1 and C2 recovered,

Ljsubject=Lj−C1(Lj)−C2(Lj)L_j^{\text{subject}} = L_j - C_1(L_j) - C_2(L_j)

and C3’s aggregate layer, with an attachment A3A_3 of $300M and a limit ℓ3\ell_3 of $50M, covers that net figure:

C3(Ljsubject)=min⁡ ⁣(max⁡(Ljsubject−A3,  0),  ℓ3)C_3\big(L_j^{\text{subject}}\big) = \min\!\big(\max(L_j^{\text{subject}} - A_3,\; 0),\; \ell_3\big)

No new financial term is involved. C3 is still an aggregate excess layer. Inuring changes only the loss it covers: the net aggregate rather than the gross one.

Netting only matters in the trials where it moves a payout. Across SunCoast’s 20-trial demo tier, C3’s $300M attachment is cleared by the gross aggregate in seven trials, but in two of them, subtracting the C1 and C2 recoveries pulls the subject back below attachment, and C3 pays nothing:

TrialGross aggregateC1 + C2 recoveriesNet aggregateC3 on gross basisC3 net of C1, C2
1$616.2M$8.2M$608.0M$50.0M$50.0M
2$489.1M$32.3M$456.8M$50.0M$50.0M
3$468.2M$42.3M$425.9M$50.0M$50.0M
4$309.2M$13.9M$295.3M$9.2M$0.0M
8$303.2M$0.0M$303.2M$3.2M$3.2M
11$305.3M$37.9M$267.4M$5.3M$0.0M
13$378.2M$22.3M$355.9M$50.0M$50.0M

Trial 4 is the clearest. SunCoast’s gross aggregate loss reaches $309.2M, slightly above C3’s $300M attachment, so a backstop applied to the gross aggregate would pay $9.2M. But C1 and C2 have already recovered $13.9M of that trial’s loss; net of those recoveries the aggregate is $295.3M, below attachment, and C3 correctly pays $0. The $9.2M a gross-basis backstop would have paid was loss the lower layers had already covered. Trial 11 behaves the same way. Without the inuring edge, SunCoast would recover those amounts twice.

caldera_re/program_ceded.py Python
"""SunCoast's reinsurance program: three layers, evaluated in dependency order.

The program is one cedent's coordinated placement, not a pile of independent
contracts:

    C1  Florida hurricane CatXoL ........ 30M xs 10M, 1 reinstatement
    C2  CA/AZ earthquake AggXoL ......... 10M xs 15M aggregate
    C3  All-US AggXoL ................... 50M xs 300M, net of C1 and C2

C3 is where the program stops being separable. Its subject is SunCoast's
*total* annual loss net of whatever C1 and C2 already paid -- so the same
dollar of loss is never recovered twice. That makes C3 depend on C1 and C2:
the three layers must be evaluated in order, not in isolation.

Each layer reuses the published terms from the Financial Modelling catalog
(filter, occurrence excess, aggregate excess) via the catxol/aggxol helpers.
The only new thing here is the inuring wiring, which is arithmetic on
per-trial gross losses -- no new financial term.
"""

import numpy as np
import pandas as pd

from caldera_re.aggxol import aggxol
from caldera_re.catxol import catxol
from caldera_re.data import cedents
from caldera_re.contract_period import contract_period
from caldera_re.report import heading, table

N = 20  # trial count of the Caldera Re demo tier


def _per_trial(result: pd.DataFrame, column: str = 'gross_loss') -> np.ndarray:
    """Collapse a contract's YELT output into a length-N per-trial array."""
    arr = np.zeros(N)
    for tid, value in result.groupby('trial_id')[column].sum().items():
        arr[int(tid) - 1] = value
    return arr


def suncoast_program(yelt: pd.DataFrame | None = None) -> dict:
    """Evaluate SunCoast's three-layer program on the locked YELT.

    Returns a dict of length-N per-trial gross (ceded-to-Caldera) arrays:
    {'C1', 'C2', 'C3', 'program', 'subject_agg', 'net_agg'}.
    """
    sc = cedents.suncoast if yelt is None else yelt

    # C1: Florida hurricane CatXoL, 30M xs 10M, 1 reinstatement (agg cap 60M).
    c1 = _per_trial(catxol(sc, attachment=10.0, limit=30.0, reinstatements=1,
                           peril='HU', geography_id='FL'))

    # C2: CA/AZ earthquake AggXoL, 10M xs 15M on the annual EQ aggregate.
    c2 = _per_trial(aggxol(sc, attachment=15.0, limit=10.0, peril='EQ'))

    # C1 and C2 inure to the benefit of C3: its subject is SunCoast's total
    # annual loss net of the C1 and C2 recoveries, so losses those layers paid
    # cannot be recovered again. Per trial:
    #   net_agg = total_subject - C1_gross - C2_gross
    #   C3_gross = clip(net_agg - 300, 0, 50)
    subject = contract_period(sc, '2024-01-01', '2024-12-31')
    subject_agg = (subject.groupby('trial_id')['loss'].sum()
                   .reindex(range(1, N + 1), fill_value=0.0).to_numpy())
    net_agg = subject_agg - c1 - c2
    c3 = np.clip(net_agg - 300.0, 0.0, 50.0)

    return {
        'C1': c1, 'C2': c2, 'C3': c3,
        'program': c1 + c2 + c3,
        'subject_agg': subject_agg, 'net_agg': net_agg,
    }


if __name__ == '__main__':
    p = suncoast_program()

    heading("SunCoast program: per-trial ceded loss by layer (AEP, $M)")
    table(['Trial', 'Subject', 'C1', 'C2', 'C3', 'Program'],
          zip(range(1, N + 1), p['subject_agg'], p['C1'], p['C2'], p['C3'],
              p['program']),
          fmt=['{}'] + ['{:.1f}M'] * 4 + ['{:.2f}M'])

    print(f"\n{'Layer EL:':<12} "
          f"C1 {p['C1'].mean():.2f}M | C2 {p['C2'].mean():.2f}M | "
          f"C3 {p['C3'].mean():.2f}M | Program {p['program'].mean():.2f}M")

    # --- The inuring check: where does netting actually bind? -------------
    # In any trial whose subject aggregate clears 300M, ask what C3 would
    # have paid on the GROSS aggregate versus the net-of-C1/C2 aggregate.
    print()
    heading("Inuring: gross-basis vs net-basis C3 (prevents double pay)")
    rows = []
    for t in range(N):
        subj = p['subject_agg'][t]
        if subj <= 300.0:
            continue  # C3 cannot trigger on either basis
        c3_gross_basis = np.clip(subj - 300.0, 0.0, 50.0)
        recoveries = p['C1'][t] + p['C2'][t]
        rows.append((t + 1, subj, recoveries, p['net_agg'][t],
                     c3_gross_basis, p['C3'][t]))
    table(['Trial', 'Subject', 'C1+C2', 'Net', 'C3 gross-basis', 'C3 net'],
          rows, fmt=['{}'] + ['{:.1f}M'] * 5)

    print("\nTrials 4 and 11 are where the netting binds. In trial 4 the gross")
    print("aggregate (309.2M) clears the 300M attachment and would pay 9.2M,")
    print("but C1 and C2 have already absorbed 13.9M, dropping the net")
    print("aggregate to 295.3M -- below attachment, so C3 net of inuring pays 0.")
    print("Trial 11 is the same story (305.3M gross, 267.4M net). Without")
    print("inuring, SunCoast would recover those losses twice.")
C1 · FL hurricane CatXoL C2 · CA/AZ earthquake AggXoL C3 · All-US AggXoL (net of C1, C2)

SunCoast's program ceded to Caldera Re, trial by trial. C1 tracks Florida hurricane trials; C2 pays on the earthquake aggregate in most trials; C3 — the All-US aggregate, net of C1 and C2 — hits its $50M limit in the four heaviest whole-book trials (trials 1, 2, 3, 13), pays $3.2M in trial 8, and otherwise pays nothing — including trial 4, where the gross book cleared its attachment but netting C1 and C2 pulled it back under. The layers peak in different trials, which is why the program's capital is lower than the sum of the layers'.

Trial by trial, the three layers’ recoveries rarely reach their maximum together. How the layers are structured (here including the inuring edge) is what determines the capital the program demands, which the standalone pricing story works out.

A vanilla tower imposes no evaluation order: its layers are independent, so an engine can run them in any order. An inuring (or forwarding) edge changes that. For the SunCoast program, contract C3 cannot be computed until contracts C1 and C2 are evaluated, because C3’s subject is defined net of their recoveries. A correct evaluator processes a program in dependency order, a topological sort over its edges. In SunCoast’s program, C1 and C2 (no incoming edges) run first, in parallel; C3 waits for both.

The contract definitions determine the stages. Each contract names the contracts it is net of, so the edges come from those clauses, and the stages are a topological sort over them. The snippet derives both for SunCoast’s program and yields the evaluation order:

interactive snippet Python
# A program as its contracts define it: each contract names what it is net of.
program = {
  "C1": {"type": "CatXoL", "net_of": []},
  "C2": {"type": "AggXoL", "net_of": []},
  "C3": {"type": "AggXoL", "net_of": ["C1", "C2"]},
}

# Edges are derived from the inuring clauses rather than declared separately:
# an edge upstream -> downstream for every contract the downstream is net of.
edges = [(up, down) for down, c in program.items() for up in c["net_of"]]
print("edges:", edges)

# Topological sort into stages (Kahn's algorithm): a stage holds every
# contract whose upstream contracts have all been evaluated. Contracts in
# one stage are independent and run in parallel, across all trials.
remaining = dict(program)
stages = []
while remaining:
  ready = sorted(
      name for name, c in remaining.items()
      if all(up not in remaining for up in c["net_of"])
  )
  if not ready:
      raise ValueError("cycle: a contract is net of itself, directly or indirectly")
  stages.append(ready)
  for name in ready:
      del remaining[name]

for i, stage in enumerate(stages, start=1):
  print(f"stage {i}: {stage}")

For three layers the order can be verified by inspection. For a real placement (more than a dozen separately placed tranches, retrocessions forwarding off the gross portfolio, layers inuring to one another),3 it is the difference between a correct evaluation and a subtly wrong one. The per-trial independence the toolkit established still holds within each stage, so the expensive part (running each layer across 10,000 to 1,000,000+ trials) stays embarrassingly parallel. Only the edges between layers impose order.

The sort is linear in the number of contracts and edges, and the standalone pricing story shows how it orders the per-trial evaluation at production scale.

A program is a bundle of contracts on a shared exposure, the unit a cedent buys to cover a defined risk. Most programs are towers of independent excess-of-loss layers, sometimes beside a quota share, each contract a composition of financial terms evaluated on its own, with their losses summed. Some add relationships between contracts: inuring (recoveries netted out of a downstream subject), forwarding (one layer’s gross becoming another’s subject), or top & drop (one limit, two attachment points). These make the contracts interdependent and impose an evaluation order, without changing what any single contract is.

Pricing asks what the whole program is worth: the ceded distribution its layers produce and the capital their structure demands. Portfolio roll-up asks what the program does to a reinsurer’s wider portfolio (the next page in this chapter). Pricing is taken up in the Applications chapter.

  1. RAA, Fundamentals of Reinsurance and Glossary of Reinsurance Terms, on layering: a cedent “may purchase numerous treaties until the desired level of reinsurance protection is achieved”, and “at the time a claim comes due, the reinsurers respond in a predetermined sequence, as necessary, to cover the loss”. Steve Evans, “IAG renews $10bn catastrophe reinsurance tower, expands quota share to 35%”, Artemis, January 2026, uses “catastrophe reinsurance tower” without explanation as the trade name for such a stack. ↩

  2. Ivelin Zvezdov, “Top and Drop: A Reusable and Customizable Reinsurance Solution”, Verisk, September 2016. The clause lets the reinsured reuse “the top excess-of-loss layer in the reinsurance tower if the retention of this top layer is not breached by the first loss event”, after which that layer “acts as a reinstatement on one or more of the lower layers”. ↩

  3. Citizens Property Insurance Corporation, 2025 Risk Transfer Program, Board of Governors, June 2025. Its $4.49 billion program is five named layers placed as thirteen separate single-year and multi-year tranches across the traditional and capital markets, with the sliver layer working “in tandem with the mandatory coverage provided by the FHCF” and Layer 1 sitting above both. Citizens is a residual-market insurer whose program is published in this detail. ↩