# Scaling

> The term that multiplies every loss by a constant (a cession percentage or participation share), preserving distribution shape and scaling each metric linearly.

Source: https://reinsurance.dev/financial-modelling/terms/scaling/

[Step 5 of the catastrophe excess of loss (CatXoL) walkthrough](https://reinsurance.dev/financial-modelling/dissection/#step-5-participation-at-roll-up) applied scaling as Caldera Re's participation. The scaling term multiplies every loss by a constant factor $f$:

$$
L^{\text{gross}}_{j,t,e} = f \cdot L^{\text{subject}}_{j,t,e}
$$

It is pointwise: each row on its own, with no state across rows.

This single operation serves two distinct business purposes:

- **[Cession percentage](https://reinsurance.dev/glossary/#cession-percentage)** ($f = q$): the proportion of every loss that the cedent transfers to the reinsurer, as in a [quota share](https://reinsurance.dev/glossary/#quota-share). A contract term: it sits inside the [composition](https://reinsurance.dev/financial-modelling/composition/).
- **[Participation share](https://reinsurance.dev/glossary/#participation)** ($f = p$): the reinsurer's share of a layer, [used when multiple reinsurers split a contract](https://reinsurance.dev/foundations/products-and-contracts/#participation). Not a contract term: [contracts are defined at 100%](https://reinsurance.dev/financial-modelling/composition/#composing-contracts-from-the-blocks), and participation scales each contract's gross loss at [portfolio roll-up](https://reinsurance.dev/financial-modelling/portfolios/#the-roll-up-participation-then-sum).

The mathematics are identical. The business context determines what the factor means, and where it is applied.

Where the factor is applied matters as much as its value. Scaling commutes with itself and with every pointwise term ($\text{scale}(a) \circ \text{scale}(b) = \text{scale}(ab)$, and a [loss filter](https://reinsurance.dev/financial-modelling/terms/filter/) or [contract period](https://reinsurance.dev/financial-modelling/terms/contract-period/) keeps the same rows on either side of it). It also distributes over the roll-up sum, which is why one participation can be applied to a contract's whole gross loss rather than to each row. It does not commute with a limit: $q \cdot \min(L, \ell) \ne \min(q \cdot L, \ell)$ unless the limit is rescaled with the loss, which is why a [quota share's event limit](https://reinsurance.dev/financial-modelling/contracts/quota-share/#with-event-limit) sits before the cession and a ceded-side limit converts as $\ell_e = \ell / q$. The failure mode is the double count: a participation written into the composition as a second scaling and applied again at roll-up books $p^2$ of the layer, quietly. The [composition page](https://reinsurance.dev/financial-modelling/composition/#composing-contracts-from-the-blocks) states the rule that prevents it.

Applied to Trial 9 at $f = 0.25$, every occurrence shrinks to a quarter of its subject loss. The shape of the trial is unchanged, only the magnitude:

*Figure (interactive on the web page): Scaling Trial 9 by 0.25. Every bar is a quarter of its subject height; the \$102.4M September hurricane becomes \$25.6M, the \$80.8M October storm \$20.2M.*

| Occurrence / total | Subject | Gross (×0.25) |
| --- | ---: | ---: |
| Sep 6, FL hurricane | \$102.4M | \$25.6M |
| Oct 5, FL hurricane | \$80.8M | \$20.2M |
| 28 other occurrences | \$89.0M | \$22.2M |
| **Trial 9 total** | **\$272.1M** | **\$68.0M** |

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

```python
import pandas as pd

from caldera_re.data import cedents
from caldera_re.contract_period import contract_period
from caldera_re.report import table

def scale(
    loss: pd.DataFrame,
    factor: float,
    input_column: str = 'loss',
    output_column: str = 'gross_loss',
) -> pd.DataFrame:
    """Scale losses by a constant factor.

    Multiplies every row's loss by the factor. Used for cession
    percentages (quota share) and participation shares (XoL).

    Parameters
    ----------
    loss : pd.DataFrame
        YELT with the specified input column.
    factor : float
        Scaling factor (e.g. 0.25 for 25% cession).
    input_column : str
        Column to scale (default: 'loss').
    output_column : str
        Name for the scaled column (default: 'gross_loss').

    Returns a copy with the output column added.
    """
    result = loss.copy()
    result[output_column] = result[input_column] * factor
    return result

if __name__ == '__main__':
    # Demo: scale all SunCoast subject losses by 0.25, applied directly to
    # the subject (the building-block illustration on Trial 9 et al.).
    subject = contract_period(cedents.suncoast, '2024-01-01', '2024-12-31')
    result = scale(subject, factor=0.25)

    print("Scale(0.25) applied to SunCoast subject losses")

    lines = []
    for tid in sorted(result['trial_id'].unique()):
        rows = result[result['trial_id'] == tid]
        subj = rows['loss'].sum()
        gross = rows['gross_loss'].sum()
        lines.append((tid, subj, gross))
    table(['Trial', 'Subject', 'Gross'], lines,
          fmt=['{:.0f}', '{:.1f}M', '{:.1f}M'])

    total_subject = result['loss'].sum() / 20
    total_gross = result['gross_loss'].sum() / 20
    print(f"\nSubject EL: {total_subject:.2f}M")
    print(f"Gross EL:   {total_gross:.2f}M")
    print(f"Factor:     {total_gross/total_subject:.0%}")
```

The cost is one multiplication per row: $O(R)$ over the $R$ input rows, with no sort, no grouping, and no state, and a cost that does not depend on where the term sits in a composition.

Across all 20 trials of the [demo tier](https://reinsurance.dev/toolkit/trials/#demo-scale), the gross curve is the subject curve scaled vertically by 0.25 at every return period:

*Figure (interactive on the web page): Scaling EP curves: SunCoast subject vs 25% of every loss. The gross curve is a vertical scaling of the subject: the distribution's shape is preserved.*

:::tip[Key Insight]
Scaling preserves the shape of the loss distribution: only the magnitude changes. "Shape" here is checkable: the quantile function is multiplied by $f$, so every scale-invariant statistic (the coefficient of variation, the skewness, the ratio between any two return-period losses) is unchanged.

Every metric scales linearly. For $f > 0$, multiplying every row by $f$ multiplies each trial's total by $f$. Multiplication by a positive constant preserves the ranking, so the $r$-th largest loss of the scaled distribution is $f$ times the $r$-th largest of the original. The tail index $k = \lfloor (1-\alpha) \cdot N \rfloor$ depends only on the trial count and the level, so it does not move. [Value at Risk (VaR)](https://reinsurance.dev/glossary/#var-value-at-risk) is the $k$-th largest loss and [Tail Value at Risk (TVaR)](https://reinsurance.dev/glossary/#tvar-tail-value-at-risk) the mean of the worst $k$, so both scale by $f$. [Expected loss (EL)](https://reinsurance.dev/glossary/#el-expected-loss) is the mean over all trials, and scales for the same reason. The property has a name: [positive homogeneity](https://reinsurance.dev/glossary/#coherent-risk-measure).

Consecutive scalings fold into a single multiplication, and scaling distributes over the roll-up sum, which is why a participation can be applied once at roll-up rather than per contract.
:::

The [quota share](https://reinsurance.dev/financial-modelling/contracts/quota-share/) page shows the cession scaling inside a composition, and the [portfolio roll-up](https://reinsurance.dev/financial-modelling/portfolios/#the-roll-up-participation-then-sum) applies the participation scaling outside every composition. The next term, the [occurrence excess](https://reinsurance.dev/financial-modelling/terms/occurrence-excess/), is where a limit placed before or after the cession stops giving the same answer.
