# Financial perspectives

> Subject, covered, gross, retained, and net: the same trial losses seen from each side of a contract, and which metrics decompose exactly across them.

Source: https://reinsurance.dev/financial-modelling/perspectives/

## Where the dollars go

We have defined the financial terms and [composed contracts](https://reinsurance.dev/financial-modelling/composition/) from them, and every one of those contracts does the same thing: it turns a stream of subject losses into a gross loss. But that gross loss is only half of what a contract produces: the same transformation also fixes what the cedent retains. [Foundations](https://reinsurance.dev/foundations/products-and-contracts/#perspectives-on-loss) named these loss perspectives in business terms; here we attach the canonical notation and ask which of them we can actually compute with a single contract in hand.

| Perspective | Notation | Definition |
| --- | --- | --- |
| **[Subject](https://reinsurance.dev/glossary/#subject-loss)** | $L_j^{\text{subject}}$ | The contract's input: everything the cedent's book presents in trial $j$, before any term applies |
| **[Covered](https://reinsurance.dev/glossary/#covered-loss)** | $L_j^{\text{cov}}$ | The covered, in-period slice left after the contract's [filter](https://reinsurance.dev/financial-modelling/terms/filter/) and [contract period](https://reinsurance.dev/financial-modelling/terms/contract-period/) |
| **[Gross](https://reinsurance.dev/glossary/#gross-loss)** | $L_j^{\text{gross}} = C(L_j^{\text{subject}})$ | What the reinsurer assumes after the full composition $C$ |
| **[Cedent retained](https://reinsurance.dev/glossary/#retained-loss)** | $L_j^{\text{ret}} = L_j^{\text{subject}} - L_j^{\text{gross}}$ | The part of the subject loss the contract did not absorb: what the cedent keeps |

:::note[Where is "net"?]
Foundations also lists the reinsurer's **[net loss](https://reinsurance.dev/glossary/#net-loss)** (gross minus its own recoveries). Net needs outward protection (retrocession, [industry loss warranties (ILWs)](https://reinsurance.dev/glossary/#ilw-industry-loss-warranty), cat bonds), and a single contract has none of its own, so its gross equals its net. Retrocession attaches through [forwarding](https://reinsurance.dev/financial-modelling/programs/#when-layers-reference-one-another) (one contract's gross loss becoming another's subject loss, the relationship a retro layer has to the portfolio it protects); for a single contract, the four perspectives above are the whole story.
:::

Subject and covered differ whenever the filter is not the identity, and conflating them mislabels real dollars. On Trial 9, SunCoast presents a \$272.1M subject, and Contract 1's Florida-hurricane filter (SunCoast's \$30M xs \$10M Florida-hurricane [catastrophe excess of loss (CatXoL)](https://reinsurance.dev/financial-modelling/contracts/catxol/) contract) keeps \$216.8M of it, the covered loss. Neither quantity is new: $C$ is the composition the [dissection](https://reinsurance.dev/financial-modelling/dissection/) built up, its first two terms are the filter and the period, and the covered loss is their output, the point in the pipeline two terms short of the gross. Subtracting the gross from the subject gives the cedent's retained loss, and the coverage boundary splits it in two:

$$
L_j^{\text{subject}} = \underbrace{\left(L_j^{\text{subject}} - L_j^{\text{cov}}\right)}_{\text{never covered}} + \underbrace{\left(L_j^{\text{cov}} - L_j^{\text{gross}}\right)}_{\text{covered, kept}} + \underbrace{L_j^{\text{gross}}}_{\text{ceded}}
$$

Every trial's subject loss splits, dollar for dollar, into three parts: what the contract never covered, what it covered but did not absorb, and what the reinsurer took. The first two together are the cedent's retained loss $L_j^{\text{ret}}$. The never-covered part carries no information about the contract: the filter and period drop it by construction, whatever the amounts. What the transforming terms (the occurrence layer and the aggregate limit) did is recorded entirely in how the covered loss divides between kept and ceded. That division is measured on the covered loss $L^{\text{cov}}$ (for Contract 1, SunCoast's Florida-hurricane loss) and its kept part, written $L^{\text{ret,cov}} = L^{\text{cov}} - L^{\text{gross}}$. [The split](https://reinsurance.dev/financial-modelling/perspectives/#what-the-split-gives-you) is what shows what a contract does: how much of the risk it covers moved.

## What the split gives you

Because the perspectives divide the same dollars, a metric on one constrains the others, but how it constrains them depends on the metric.

*[Interactive figure: Perspectives chart. See the web page: https://reinsurance.dev/financial-modelling/perspectives/]*

**Expected loss splits exactly.** [Expected loss (EL)](https://reinsurance.dev/glossary/#el-expected-loss) is an average, and averaging is linear, so the covered stream's expected loss is precisely the sum of the ceded and kept expected losses:

$$
\text{EL}(L^{\text{cov}}) = \text{EL}(L^{\text{gross}}) + \text{EL}(L^{\text{ret,cov}})
$$

For Contract 1 across SunCoast's [20-trial demo tier](https://reinsurance.dev/toolkit/trials/#demo-scale), that is $43.9\text{M} = 17.4\text{M} + 26.5\text{M}$: the layer absorbs about 40% of SunCoast's expected covered (Florida-hurricane) loss, and SunCoast keeps the rest, along with everything the filter never covered.

*[Interactive figure: Perspectives chart. See the web page: https://reinsurance.dev/financial-modelling/perspectives/]*

**Tail risk does not.**

:::caution[A tail is not a difference]
It is tempting to measure the cedent's residual tail risk as $\text{TVaR}_\alpha(L^{\text{cov}}) - \text{TVaR}_\alpha(L^{\text{gross}})$ ([Tail Value at Risk](https://reinsurance.dev/toolkit/metrics/tail-value-at-risk/), from the toolkit). Resist it. $\text{TVaR}_\alpha(L^{\text{gross}})$ averages gross over the trials in which gross is worst; $\text{TVaR}_\alpha(L^{\text{cov}})$ averages over the trials in which the covered loss is worst. Those are generally different trials, so the subtraction nets two averages taken over mismatched tails.

How wrong it is depends on the data. At $\alpha = 90\%$, Contract 1's two worst covered trials (Trials 9 and 19) happen to be its two worst gross trials too, so the subtraction gives the right answer, $112.3\text{M}$. Drop to $\alpha = 80\%$ and the tails diverge (the covered tail is trials 2, 6, 9, and 19, while the gross tail is trials 3, 6, 9, and 19), and the subtraction, $84.6\text{M}$, no longer matches the exact value, $85.8\text{M}$. A formula that is right only when the tails coincide is not a formula.

The exact residual subtracts a co-measure, not a second tail: $\text{TVaR}_\alpha(L^{\text{cov}}) - \text{Co-TVaR}_\alpha^{\text{cov}}(L^{\text{gross}})$, where the [Co-TVaR](https://reinsurance.dev/glossary/#co-tvar-contribution-to-tvar) averages the gross loss over the covered stream's own worst trials. Both terms are then taken over one set of trials, and that is where the $85.8\text{M}$ comes from.
:::

The two tails are different sets of trials, and that is the whole argument. At $\alpha = 80\%$ the covered stream's four worst trials are 2, 6, 9, and 19; the gross stream's are 3, 6, 9, and 19. Trial 2 is a heavy Florida-hurricane year in which the layer paid \$30M, and Trial 3 a lighter one in which it paid \$34.6M across more storms. The gross ranks them the other way round from the covered loss.

*Figure (interactive on the web page): Contract 1 across the 20 demo-tier trials: one cell per trial for the covered stream (top) and the gross stream (bottom), with each stream's own worst four trials at α = 80% filled. The filled sets differ in one cell (trial 2 against trial 3), and that one cell is the difference between the wrong subtraction and the exact split; hover a cell for the trial's loss.*

The correct decomposition fixes one tail (the covered stream's worst $k$ trials) and adds the ceded and kept losses within it. Conditioning on a single fixed set makes expectation linear again, so the split is exact. This is a **[Co-TVaR](https://reinsurance.dev/glossary/#co-tvar-contribution-to-tvar)** (Euler) allocation,[^euler] the co-measure that portfolio capital attribution is built on, a subject the [portfolio analytics story](https://reinsurance.dev/applications/portfolio-analytics/) marks out and does not yet work through:

$$
\text{TVaR}_\alpha(L^{\text{cov}}) = \text{Co-TVaR}_\alpha^{\text{cov}}(L^{\text{gross}}) + \text{Co-TVaR}_\alpha^{\text{cov}}(L^{\text{ret,cov}})
$$

where $\text{Co-TVaR}_\alpha^{\text{cov}}(\cdot)$ averages its argument over the trials in the covered stream's tail. The cedent's residual tail risk on the covered stream, conditional on its own worst trials, is $\text{TVaR}_\alpha(L^{\text{cov}}) - \text{Co-TVaR}_\alpha^{\text{cov}}(L^{\text{gross}})$, exact, with nothing left over.

*[Interactive figure: Perspectives chart. See the web page: https://reinsurance.dev/financial-modelling/perspectives/]*

A metrics store that keeps per-perspective summaries (EL, [Value at Risk (VaR)](https://reinsurance.dev/glossary/#var-value-at-risk), and TVaR per contract per perspective) cannot produce the residual tail at all, because the co-measure needs the trial-aligned vectors of both streams: which trials are in the covered tail, and what the gross was in those trials. The covered and gross columns have to survive together, keyed by trial, to the point of measurement; summarise either one first and the split is gone.

At the demo tier's $N = 20$, the $\alpha = 90\%$ tail is $k = 2$ trials, which is why the subtraction happens to work there and fails one step lower. Production loss sets run 10,000 to 1,000,000+ trials, where the two tails routinely diverge; the [1,000-trial tier](https://reinsurance.dev/toolkit/trials/#demo-scale) shows the same mechanism at a resolution closer to production.

A different but equally valid question is "how bad can the kept loss get on its own?" That is $\text{TVaR}_\alpha(L^{\text{ret,cov}})$: the [metrics](https://reinsurance.dev/toolkit/metrics/) from the toolkit applied to the kept distribution, whose tail is its own worst trials. For Contract 1 at $90\%$ that is $124.7\text{M}$, larger than the $112.3\text{M}$ kept slice of the covered tail, because the kept loss peaks in different trials than the covered loss does. Each number has a job. The Co-TVaR slice attributes an agreed total: it says how much of the covered tail the contract removed and how much it left, and the parts reconcile exactly. It is the right frame for judging the contract's tail relief, and the frame portfolio capital allocation builds on. The standalone figure sizes the retained position itself: the cedent's balance sheet suffers the kept loss's own worst trials whether or not the covered total was extreme in them, so capital and risk appetite for the retained loss are set from $\text{TVaR}_\alpha(L^{\text{ret,cov}})$. Attribution takes the conditional number; holding the residual takes the standalone one.

The generator below reproduces every figure on this page (the per-trial covered split, the exact EL decomposition, and the Co-TVaR identity at both $90\%$ and $80\%$):

Python (`python/caldera_re/perspectives.py`, runnable on the web page):

```python
"""Derived loss perspectives for Contract 1 (SunCoast FL HU CatXoL).

Subject is everything the cedent presents; the contract's filter and contract
period select the COVERED loss, and the remaining terms produce the gross.
The interesting split is of the covered stream, trial by trial:

    L_kept[s] = L_covered[s] - L_gross[s]

This is the reconciliation source for the "Financial perspectives" section of
the Financial modelling page. It shows two things:

  * EL splits EXACTLY (expectation is linear):
        EL(covered) = EL(gross) + EL(kept)

  * TVaR does NOT subtract. TVaR(covered) - TVaR(gross) averages over two
    DIFFERENT tail sets (each perspective's own worst trials). The cedent's
    residual tail risk is a Co-TVaR (Euler) allocation conditioned on the
    covered tail:
        TVaR(covered) = Co-TVaR_cov(gross) + Co-TVaR_cov(kept)

Run with:
    cd python && PYTHONPATH=. uv run --with numpy --with pandas --with pyyaml \
        python3 caldera_re/perspectives.py
"""

import numpy as np

from caldera_re.catxol import catxol
from caldera_re.data import cedents
from caldera_re.loss_filter import loss_filter
from caldera_re.contract_period import contract_period
from caldera_re.report import fields, table
from caldera_re.utils import ep_index

PERIOD = ('2024-01-01', '2024-12-31')

N = 20
A, L, REINST = 10.0, 30.0, 1
CRIT = dict(peril='HU', geography_id='FL')

def trial_array(result, column, n=N):
    """Collapse a contract's YELT output to a length-n per-trial array
    indexed by trial_id (1..n), filling absent trials with 0."""
    arr = np.zeros(n)
    for tid, value in result.groupby('trial_id')[column].sum().items():
        arr[int(tid) - 1] = value
    return arr

TIE_DECIMALS = 9

def tail_indices(values, alpha):
    """Indices of the worst k trials of `values`, k = ep_index(N, alpha).
    Matches the site's VaR/TVaR convention (mean of the worst k).

    Two trials whose values agree to TIE_DECIMALS are a tie, and a tie goes
    to the later trial (stable ascending sort, last k taken). The rounding
    is the tie rule: a layer that pays its limit in two trials can produce
    30.0 in one and 29.999999999999996 in the other, and without it the
    JavaScript twin (src/lib/perspectives.js) could pick a different trial.
    """
    k = ep_index(len(values), alpha)
    return np.argsort(np.round(values, TIE_DECIMALS), kind='stable')[len(values) - k:]

if __name__ == '__main__':
    # Covered = the contract's covered, in-period loss per trial: the subject
    # (everything SunCoast presents) after the filter and contract period.
    covered_rows = contract_period(loss_filter(cedents.suncoast, **CRIT), *PERIOD)
    cov_by_trial = covered_rows.groupby('trial_id')['loss'].sum()
    covered = np.zeros(N)
    for tid, v in cov_by_trial.items():
        covered[int(tid) - 1] = v

    # Gross = the contract output. Standalone gross is reported at 100%
    # (participation applied at roll-up).
    result = catxol(cedents.suncoast, attachment=A, limit=L,
                    reinstatements=REINST, **CRIT)
    gross = trial_array(result, 'gross_loss')

    # Kept = covered - gross, trial by trial: the covered loss the cedent
    # keeps. (The cedent also keeps everything the filter never covered.)
    kept = covered - gross

    print("Contract 1 - per-trial perspectives (FL HU, 30M xs 10M, 1 reinst.)")
    table(['Trial', 'Covered', 'Gross', 'Kept'],
          [(s + 1, covered[s], gross[s], kept[s])
           for s in range(N) if covered[s] > 0],
          fmt=['{}', '{:.1f}M', '{:.1f}M', '{:.1f}M'])

    # --- EL splits exactly (EL is linear) ---
    el_covered, el_gross, el_kept = covered.mean(), gross.mean(), kept.mean()
    print(f"\nExpected loss (mean over {N} trials):")
    fields([
        ('EL(covered)', el_covered),
        ('EL(gross)', el_gross, f"{el_gross / el_covered:.0%} of the covered "
                                f"loss ceded in expectation"),
        ('EL(kept)', el_kept),
    ], indent=2, sep=' = ')
    print(f"  check: EL(gross) + EL(kept) = {el_gross + el_kept:.1f}M "
          f"= EL(covered)  -> exact (EL is linear)")

    # --- TVaR does NOT subtract ---
    for alpha in (0.90, 0.80):
        k = ep_index(N, alpha)
        cov_tail = tail_indices(covered, alpha)
        gross_tail = tail_indices(gross, alpha)

        tvar_covered = covered[cov_tail].mean()
        tvar_gross = gross[gross_tail].mean()
        tvar_kept = kept[tail_indices(kept, alpha)].mean()

        # Co-TVaR conditioned on the COVERED tail (the correct additive split).
        co_gross = gross[cov_tail].mean()
        co_kept = kept[cov_tail].mean()

        print(f"\nTail risk at alpha = {alpha:.0%}  (k = {k} worst trials):")
        print(f"  covered tail = trials {sorted((cov_tail + 1).tolist())}")
        print(f"  gross   tail = trials {sorted((gross_tail + 1).tolist())}"
              f"{'  (same set)' if set(cov_tail) == set(gross_tail) else '  (DIFFERENT set)'}")
        fields([
            ('standalone TVaR(covered)', tvar_covered),
            ('standalone TVaR(gross)', tvar_gross),
            ('standalone TVaR(kept)', tvar_kept, "kept's OWN worst trials"),
        ], indent=2, sep=' = ')
        print(f"  WRONG  TVaR(covered) - TVaR(gross) = "
              f"{tvar_covered - tvar_gross:6.1f}M")
        print(f"  Co-TVaR split on the covered tail (exact):")
        fields([('Co-TVaR_cov(gross)', co_gross),
                ('Co-TVaR_cov(kept)', co_kept)], indent=4, sep=' = ')
        print(f"    check {co_gross:.1f} + {co_kept:.1f} = {co_gross + co_kept:.1f}M"
              f" = TVaR(covered)  -> exact")
        print(f"  => cedent residual tail risk (in the covered stream's worst trials)")
        print(f"     = TVaR(covered) - Co-TVaR_cov(gross) = "
              f"{tvar_covered - co_gross:.1f}M = Co-TVaR_cov(kept)")
```

---

We have dissected one CatXoL, formalised the building blocks, recomposed the canonical contract types, and seen how a single contract partitions risk. The final step is to combine many contracts: the [portfolio roll-up](https://reinsurance.dev/financial-modelling/portfolios/) shows where diversification emerges, and the [portfolio analytics story](https://reinsurance.dev/applications/portfolio-analytics/) reads it as a business position.

[^euler]: Dirk Tasche, ["Capital Allocation to Business Units and Sub-Portfolios: the Euler Principle"](https://arxiv.org/abs/0708.2542), arXiv:0708.2542, 2008. Gives the Euler contribution to expected shortfall as the average of the component over the outcomes in which the portfolio total is in its own tail, an elementary conditional expectation whose contributions sum to the portfolio figure. Rodney Kreps, ["Riskiness Leverage Models"](https://www.casact.org/sites/default/files/database/proceed_proceed05_05041.pdf), *Proceedings of the Casualty Actuarial Society*, 2005, names such additive components co-measures and derives TVaR's as "the average value of the variable of interest in the situations where the total is greater than" the quantile. Gary G. Venter, ["A Survey of Capital Allocation Methods with Commentary"](https://actuaries.org/app/uploads/2025/07/Venter2_Berlin2003.pdf), ASTIN Colloquium Berlin, 2003, Appendix 3, gives the name this site uses and the continuous form of the definition, "the mean loss for the ith unit in the case where total losses are over the qth quantile"; John A. Major and Stephen J. Mildenhall, [*Introduction to Capital Modeling and Portfolio Management*](https://www.casact.org/sites/default/files/2026-01/CAS_Monograph_15_-_Intro_to_Capital_Modeling.pdf), CAS Monograph 15, Casualty Actuarial Society, 2026, §3.3, gives the Euler gradient of TVaR and notes it is "often called the coTVaR". Tasche derives the general form under smoothness conditions that imply a density; the rank-based version used here fixes the tail set instead, so the components add exactly on a discrete trial set.
