Skip to content

Analytics Toolkit · Section 2

The trial worldview

What trials, events, and occurrences are, why trial-based simulation is the foundation of catastrophe risk analytics, and how data is structured.

Everything in property-cat reinsurance analytics begins with a question: what could happen? Not what will happen — catastrophes are too rare and too variable for prediction — but what is the full range of plausible outcomes?

The answer comes from trial-based simulation: generate thousands of possible futures of catastrophe activity, compute the losses for each, and use the resulting distribution to make decisions.

A trial is one complete picture of what might happen — a possible future of catastrophe activity. “In this future, a Category 4 hurricane hits Miami in August, and a magnitude 7.2 earthquake strikes Tokyo in March. Nothing else.” Another trial might have no hurricane season at all, but a devastating earthquake in California.

Most models simulate one year at a time, though some produce multi-year forecasts (e.g. for long-term capital planning or climate-adjusted views). Either way, each trial captures the full set of loss-producing events — including the possibility of none.

Where do trials come from? Catastrophe models — maintained by vendors like Moody’s RMS, Verisk, and CoreLogic — generate trials through Monte Carlo simulation. Each model maintains an event catalog: a database of tens of thousands of physically plausible catastrophes (specific hurricane tracks, earthquake ruptures, windstorm paths), each with an estimated annual frequency and a deterministic loss for a given exposure. The simulation engine samples from these catalogs — respecting physical constraints (no North Atlantic hurricanes in January) and frequency distributions (how often does a Category 4 hit South Florida?) — to produce thousands of synthetic futures.

The output is a set of trials, each containing zero or more loss-producing events. We identify a trial by its trial_id. A trial contains one or more occurrences — instances of catalog events that produce losses.

Trials are equiprobable and independent. In a simulation with NN trials, each represents a 1/N1/N probability of occurring. They are independent of each other — the outcome of one trial tells you nothing about another.

Two terms that the industry uses loosely but that are worth keeping apart:

An event is a specific physical catastrophe in a model’s event catalog — a particular hurricane track, earthquake rupture, or windstorm path. Events have catalog IDs, annual frequencies (rates), and physical metadata (wind speed, magnitude, geographic footprint).

An occurrence is a loss instance within a trial — one catalog event producing a loss in one simulated future. Each occurrence is identified by the composite key (trial_id, timestamp, event_id). A trial may contain zero, one, or many occurrences.

The distinction matters because different contract types operate at different levels:

  • Occurrence contracts (CatXoL) evaluate each occurrence independently
  • Aggregate contracts (AggXoL) accumulate losses across all occurrences in a trial

This is the same occurrence-vs-aggregate distinction from the Products and Contracts section. The Financial Modelling chapter formalizes the difference as two distinct terms — occurrence excess and aggregate excess — that differ in what they group by before applying the attachment and limit.

The Year Event Loss Table (YELT) is the canonical data structure for trial-based loss data.

At its smallest, a YELT is three columns — a trial identifier, an event reference, and the loss.2 That shape carries no explicit timing: the only within-trial ordering available is the event ids themselves, so aggregate analysis on a three-column YELT relies on a strict event-id ordering inside each trial — which requires event ids to be distinct per trial, and means one event cannot occur twice in the same trial. Production YELTs add the occurrence date instead, which gives temporal sequencing directly and lets an event recur. Those four columns are the core:

ColumnTypeDescription
trial_idintegerWhich simulated future
timestampdateWhen the occurrence happens within the trial
event_idintegerWhich catalog event produced this loss
lossfloatSubject loss amount

That core is what makes a YELT a YELT, and it is enough to drive the trial-loss metrics in this chapter — EP curves, EL, VaR, TVaR. (The damage ratio below is the exception: it needs the enrichment’s tiv.) The five remaining columns of this site’s schema are a house enrichment — a convention of this site, not an industry standard — that makes the worked examples self-contained without joins back to an event catalog or an exposure schedule:

ColumnTypeDescription
perilstringPeril type (HU, EQ, WS)
geography_idstringGeographic region of the loss
lob_idstringLine of business
cedent_idstringWhich cedent’s book the loss belongs to
tivfloatTotal insured value of the exposed risk

Real schemas vary: vendors and in-house platforms differ in which of these columns they carry, what they call them, and whether the information lives in the loss table at all or in tables it joins to. Treat the nine-column table as one concrete, workable design — the four-column core is the part you can rely on meeting everywhere.

The primary key of the enriched YELT is (trial_id, timestamp, event_id, cedent_id, geography_id, lob_id) — the occurrence key plus the resolution columns and the cedent. timestamp is part of the key because event_id names a prototypical catalog event, not an instance: the same event can occur more than once within a trial, at different timestamps. And a single occurrence — identified by (trial_id, timestamp, event_id) — can produce multiple rows if it affects more than one geography or line of business: a major hurricane might generate separate loss records for Florida and Texas, or for property and casualty lines.

The geography_id and lob_id columns define the resolution of the loss data. They determine how finely losses are broken down, and they matter because different contracts may cover different geographies or lines of business. A contract covering only Florida property would filter to geography_id = 'FL' and lob_id = 'Property' before applying its terms.

The last column, tiv, records the total insured value (TIV) — the sum of insured values of the exposure this occurrence touched, at the row’s geography and LOB resolution. Where loss says how much damage the event caused, tiv says how much insured value stood in its path.

TIV gives losses a denominator. The damage ratio of a set of YELT rows SS is the modelled loss per unit of exposed insured value:

DR(S)=rSlossrrStivr\text{DR}(S) = \frac{\sum_{r \in S} \text{loss}_r}{\sum_{r \in S} \text{tiv}_r}

In English: add up the losses, add up the exposed TIV, divide. In code, it is one line per slice — df.groupby(dim).apply(lambda g: g['loss'].sum() / g['tiv'].sum()). A damage ratio of 12% means the events that struck this slice destroyed, on average, 12% of the insured value they touched — weighted toward the larger exposures. For a single occurrence — the largest in the SunCoast YELT, a $174.1M Texas hurricane loss against $700.9M of exposed TIV — the damage ratio is 24.8%: a quarter of the insured value in the storm’s path was lost.

The YELT is both the input to and the output from every financial computation. Contract terms consume a YELT and produce a new YELT with transformed loss values. This symmetry — YELT in, YELT out — is a core design principle that enables composability, as we will see in the Financial Modelling chapter.

The loss column stores losses as positive numbers: a $46.9M loss is recorded as 46.9, and both loss and tiv are strictly greater than zero in a valid base YELT — model output entering the pipeline. (Transformed YELTs — the outputs of contract terms — may legitimately contain zero losses, but never negative ones.) This is the site’s sign convention, and it deserves a moment of attention before any metric is computed on this data — because the industry has two conventions, and they disagree.

Accounting and finance systems often represent losses as negative values. A loss is money flowing out, a premium is money flowing in, and the net position is a plain sum — no special-case arithmetic. Catastrophe model vendors and loss analytics platforms overwhelmingly do the opposite: a loss is a positive magnitude, because risk analytics asks “how big?” far more often than “which direction?”.

The choice looks cosmetic. It is not. It silently determines the orientation of every computation downstream:

ConsequenceLoss-positive (this site)Loss-negative
The “worst” trialLargest valueSmallest (most negative) value
EP-curve sort orderDescendingAscending
The tailTop of the sorted tableBottom of the sorted table
1-in-100 loss99th percentile1st percentile
Net of premiumExplicit subtraction: premiumloss\text{premium} - \text{loss}Plain sum: premium+loss\text{premium} + \text{loss}

We use loss-positive throughout, for two reasons. First, it matches how the domain speaks and how the data arrives: “a $100M loss” and “the 1-in-20 loss is $616.2M” state positive magnitudes, and vendor catastrophe model output ships losses as positive values. Second, it keeps the tail machinery in the next two sections — distribution semantics and metrics — direct rather than mirrored: sort descending, the worst trials sit at the top, rank rr maps to exceedance probability r/Nr/N with no negation anywhere.

The price is that losses and premiums no longer net by simple addition — combining them requires explicit subtraction. We consider that a feature. When financial record types beyond loss enter the schema (premiums, reinstatement premiums, expenses), each should be an explicit record type with explicit aggregation semantics — not a sign trick. Accordingly, a negative loss in a YELT is a validation error: not a recovery, not a premium, not a correction. Validate it at every ingestion boundary — one line buys a lot of safety:

assert (yelt['loss'] > 0).all(), "negative loss: sign-convention violation"

If your organization uses the loss-negative convention, everything on this site still applies — the metrics section shows exactly what to flip.

Each of Helios Re’s cedents has its own YELT with 20 trials. The number of occurrences varies by cedent and trial — some trials contain a single event, while others contain a dozen. Here is SunCoast Insurance’s YELT, the one we will use most throughout this chapter.

helios_re/show_yelt.py Python

Another common data structure produced by vendor catastrophe models is the Event Loss Table (ELT). Understanding what it is, where it comes from, and why YELTs supersede it for most analytics is worth the detour.

An ELT is the most common output format from catastrophe model vendors. Each row represents a single event from the model’s catalog, paired with a loss estimate and an annual frequency:

ColumnTypeDescription
event_idintegerCatalog event identifier
ratefloatAnnual frequency of occurrence
lossfloatExpected loss if the event occurs

A model’s event catalog might contain 50,000+ physically plausible hurricanes, earthquakes, and windstorms, each with its own rate. A rate of 0.002 means this event occurs on average 0.002 times per year — equivalently, once every 500 years. Note that rate is a frequency, not a probability: a rate of 2.0 means two expected occurrences per year, while the probability of at least one occurrence is 1eλ0.8651 - e^{-\lambda} \approx 0.865. For rare events (rate ≪ 1), the distinction is negligible; for frequent perils, it matters.

What you can do with an ELT:

  • Compute expected annual loss directly: iratei×lossi\sum_i \text{rate}_i \times \text{loss}_i
  • Evaluate per-occurrence contracts (like CatXoL) on individual events
  • Build occurrence exceedance probability (OEP) curves by treating events independently
  • Assess contracts quickly — an ELT is compact and fast to process

What you cannot do with an ELT:

  • Analyze aggregate contracts — there is no concept of which events happen together in a given year
  • Capture temporal sequencing — events have no timestamps, so you cannot model how losses erode coverage over time
  • Preserve co-occurrence patterns — a hurricane season with three landfalls looks the same as three independent hurricanes

This is where YELTs come in. A YELT groups events into trials, preserving which events co-occur and in what order.

From ELT to YELT: Converting an ELT to a YELT means running a Monte Carlo simulation. For each trial, sample events from the catalog according to their rates, assign timestamps based on each peril’s seasonality distribution, and record which events occurred together. Some vendors expose the YELT directly; others provide the ELT and expect the user (or their platform) to perform the simulation step.

The reverse — collapsing a YELT back to an ELT — is simple but destructive. You aggregate across trials and discard the grouping. Information is lost.

PropertyYELTELT
Temporal sequencingPreserved (timestamps within trials)Absent
Co-occurrencePreserved (events grouped into trials)Lost (events are independent)
Aggregate analysisNatural (sum within trial, respecting order)Requires simulation
Data sizeLarger (NN trials × occurrences)Smaller (unique events × rate)
Primary use caseFull financial modellingQuick screening, single-event analysis

Every worked example on this site runs on the same dataset: the 20-trial demo tier of the Helios Re YELT. The size is a deliberate choice. Twenty trials fit on one screen, every sort can be checked by hand, and any number in prose can be recomputed from the table it came from. It is also two to five orders of magnitude below the 10,000 to 1,000,000+ trials of production practice, and that gap deserves precision about what it does and does not change.

The method changes nothing. Every operation in this chapter — group, sum, sort, rank — is identical at N=20N = 20 and N=1,000,000N = 1{,}000{,}000; no step in the machinery knows how many trials flow through it. What changes is resolution: the finest exceedance probability a trial set can express is 1/N1/N. At 20 trials that is 5% — the worst trial is the 1-in-20 loss, and no rarer quote exists in the data. At 100,000 trials it is 0.001%, and the 1-in-200 and 1-in-500 quotes that capital decisions run on rest on hundreds of trials each. Extra trials buy depth and stability in the tail metrics: quotes at deeper return periods exist at all, and each rests on enough trials that one simulated storm cannot move it.

For exactly this contrast, the demo data ships a second tier: a 1,000-trial YELT per cedent, same schema, same event catalog — suncoast_1000.csv beside suncoast_20.csv. Any runnable example on the site switches tiers by replacing cedents.suncoast with load_cedent("suncoast", 1000). (The 1,000-trial CSV is a few megabytes; the first run fetches it.)

helios_re/demo_scale.py Python

Read the two reports against each other. At 20 trials the 1-in-20 quote rests on a single trial and the 1-in-100 quote does not exist. At 1,000 trials the 1-in-100 quote rests on ten trials and the 1-in-200 on five.

The levels do not reconcile across tiers, and they are not supposed to. Both tiers are subsets of the same underlying 10,000-trial simulation, sampled with dense tail coverage and a sparse body — the 20-trial tier far more aggressively, so that hand-sized examples still exercise limits and reinstatements. The demo tier’s expected loss for SunCoast is $275.6M; the 1,000-trial tier’s is $205.6M; neither is a market-calibrated estimate of anything. Read demo-tier numbers as mechanics, never as levels.

The same calibration inflates the economics, and this deserves stating as plainly as the resolution gap. A dataset in which limits, reinstatements, and inuring all visibly fire within 20 trials is one where losses run far more frequent and severe, relative to the limits, than in any realistic book — C1’s expected loss is $17.39M against a $30M layer, a loss cost far beyond what a real catastrophe layer carries. And since a premium must clear its expected loss for any pricing story to cohere, the premiums are inflated with the losses: Helios Re’s rates on line run at multiples of market levels. Switching tiers does not repair this — both subsample the same simulation — and no choice of premiums against the same losses could. The mechanisms and the arithmetic transfer to a production run unchanged; the levels — expected losses, premiums, and every ratio built from them — do not.

When another page quotes a number computed from this dataset, it carries a link back to this section — the phrase “20-trial demo tier” is the site’s standing marker that the mechanics are exact and the resolution is not.

With a YELT, you have everything needed to build an empirical probability distribution over any quantity you can compute from losses. Sum all occurrence losses within each trial, and you have a distribution of annual aggregate loss. Take the maximum occurrence loss per trial, and you have a distribution of peak single-event loss.

For equiprobable trials, each trial contributes equal probability mass. With the Helios Re YELT — 20 trials — each trial represents a 5% probability.

The next section shows how to construct and read exceedance probability (EP) curves from this data — the chart property-cat analytics is organized around.


  1. Kirsten Mitchell-Wallace, Matthew Jones, John Hillier, and Matthew Foote (eds.), Natural Catastrophe Risk Management and Modelling: A Practitioner’s Guide, Wiley, 2017 — the standard practitioner reference for catastrophe-model output structures, including ELTs and YLTs.

  2. David Homer and Ming Li, “Notes on Using Property Catastrophe Model Results”, Casualty Actuarial Society E-Forum, 2017 — describes the event loss table (ELT) and year event loss table (YELT) formats and how analytics consume them; its minimal YELT is the (year, event, loss) triple. 2

  3. Moody’s RMS, “Introduction to Metrics”, Risk Modeler documentation — defines the period loss table (PLT): simulated event losses per period, each row a dated event within a simulation period.