Skip to content

Scenarios API

API reference for scenario plans, the bounded-memory loop, aggregators, and shock operations.

Scenario Plan

ScenarioRun

ScenarioResult

Scenario Loop

for_each_scenario

BatchSnapshot

The snapshot passed to an on_batch callback — by for_each_scenario and by ScenarioRun.run — after every batch folds: the running aggregate partials plus progress fields (elapsed_s, fraction_done, eta_s, throughput), for rendering a convergence trace. See Watching a run converge.

with_scenarios

Portfolio Aggregation

Memory-safe portfolio runs: fold each batch to per-period aggregates (Aggregating at Scale), or spill the full per-policy grid to disk (Streaming and Spill).

run_aggregated

AggregatedResult

run_to_parquet

SpillResult

SelectionDecision

How batch_size="auto" resolved — the chosen batch plus the measured ladder behind it. Audit output of the auto-batch search (see Aggregating at Scale).

ProbeResult

One measured rung of the auto-batch search — a probed batch size and its measured cost.

Aggregators

The 14 built-in aggregators implement the Aggregator Protocol with the .alias(), .over(), and .of() modifiers. See the Aggregators concept page for usage guidance.

Sum

Bases: _BaseAggregator

Count

Bases: _BaseAggregator

Min

Bases: _BaseAggregator

Max

Bases: _BaseAggregator

ArgMin

Bases: _BaseAggregator

ArgMax

Bases: _BaseAggregator

Mean

Bases: _BaseAggregator

Variance

Bases: _BaseAggregator

Std

Bases: _BaseAggregator

Quantile

Bases: _BaseAggregator

Median

Bases: _BaseAggregator

CTE

Bases: _BaseAggregator

QuantileRank

Bases: _BaseAggregator

Per-Period Aggregators

The Period* family folds a per-period list column across the portfolio at each projection period, returning one value per period (vs. the scalar aggregators above, which fold to a single number). PeriodMedian, PeriodQuantile, and PeriodCTE are DDSketch-backed for bounded-memory tail metrics. See the Aggregators concept page for usage.

PeriodSum

PeriodMean

PeriodMin

PeriodMax

PeriodCount

PeriodStd

PeriodVariance

PeriodMedian

PeriodQuantile

PeriodCTE

Custom Aggregators

See the Custom Aggregators concept page for full worked examples.

BaseAggregator

VectorAggregator

The base class for per-period (Period*) aggregators — those carrying per-period vector state.

Bases: _BaseAggregator

scenario_aggregator

register_aggregator

Config Parsing

parse_shock_config

parse_scenario_config

parse_aggregations

Basic Shock Classes

MultiplicativeShock

Bases: Shock

A shock that multiplies values by a factor.

Used for scenarios like "increase mortality by 20%" (factor=1.2) or "decrease lapse by 10%" (factor=0.9).

Parameters:

Name Type Description Default
factor float

The multiplicative factor to apply

required
table str | None

Optional table name this shock targets

None
column str | None

Optional column name this shock targets

None

When to use

  • Stress testing with percentage changes
  • Sensitivity analysis on rates
  • Regulatory capital scenarios (e.g., SCR shocks)

Examples:

20% increase in mortality:

```python no_output_check from gaspatchio_core.scenarios.shocks import MultiplicativeShock

shock = MultiplicativeShock(factor=1.2, table="mortality")

**10% decrease in lapse rates:**

```python no_output_check
shock = MultiplicativeShock(factor=0.9, table="lapse")

describe() -> str

Return description of this shock.

AdditiveShock

Bases: Shock

A shock that adds a constant delta to values.

Used for scenarios like "increase discount rate by 50bps" (delta=0.005) or "decrease expense loading by 1%" (delta=-0.01).

Parameters:

Name Type Description Default
delta float

The additive constant to apply

required
table str | None

Optional table name this shock targets

None
column str | None

Optional column name this shock targets

None

When to use

  • Interest rate shocks (parallel shifts)
  • Expense loading adjustments
  • Basis point changes to rates

Examples:

Add 50bps to discount rates:

```python no_output_check from gaspatchio_core.scenarios.shocks import AdditiveShock

shock = AdditiveShock(delta=0.005, table="discount_rates")

**Subtract 1% from expense loading:**

```python no_output_check
shock = AdditiveShock(delta=-0.01, table="expenses")

describe() -> str

Return description of this shock.

OverrideShock

Bases: Shock

A shock that replaces all values with a constant.

Used for scenarios like "set lapse to zero" (value=0.0) or "assume 100% mortality" (value=1.0).

Parameters:

Name Type Description Default
value Any

The constant value to set

required
table str | None

Optional table name this shock targets

None
column str | None

Optional column name this shock targets

None

When to use

  • Extreme stress scenarios
  • Disabling a decrement entirely
  • Testing boundary conditions

Examples:

Set lapse rates to zero:

```python no_output_check from gaspatchio_core.scenarios.shocks import OverrideShock

shock = OverrideShock(value=0.0, table="lapse")

**Override discount rate to flat 5%:**

```python no_output_check
shock = OverrideShock(value=0.05, table="discount_rates")

describe() -> str

Return description of this shock.

Value Constraint Shocks

ClipShock

Bases: Shock

A shock that clips (caps/floors) values to a range.

Used for scenarios like "lapse rate cannot exceed 100%" (max=1.0) or "mortality floor of 0.1%" (min=0.001). Can also combine both.

This is essential for regulatory scenarios like Solvency II SCR lapse up, where shocked values must be capped at actuarial limits.

Parameters:

Name Type Description Default
min_value float | None

Optional floor value (values below are set to this)

None
max_value float | None

Optional ceiling value (values above are set to this)

None
table str | None

Optional table name this shock targets

None
column str | None

Optional column name this shock targets

None

When to use

  • Post-shock value constraints (e.g., lapse ≤ 100%)
  • Regulatory scenarios with actuarial limits
  • Preventing unrealistic shocked values
  • Combining with other shocks in a pipeline

Examples:

Cap lapse rates at 100%:

```python no_output_check from gaspatchio_core.scenarios.shocks import ClipShock

shock = ClipShock(max_value=1.0, table="lapse")

**Floor mortality at 0.1%:**

```python no_output_check
shock = ClipShock(min_value=0.001, table="mortality")

Clip to a range:

python no_output_check shock = ClipShock(min_value=0.0, max_value=1.0, table="rates")

describe() -> str

Return description of this shock.

Composable Shocks

PipelineShock

Bases: Shock

A shock that chains multiple operations in sequence.

Used for complex scenarios like "multiply by 1.5 then cap at 100%" which requires composing multiple shock operations.

The operations are applied left-to-right: the output of each shock becomes the input to the next.

Parameters:

Name Type Description Default
shocks tuple[Shock, ...]

Sequence of shocks to apply in order

tuple()
table str | None

Optional table name this shock targets

None
column str | None

Optional column name this shock targets

None

When to use

  • Solvency II lapse up: multiply then cap
  • Complex stress scenarios with multiple transformations
  • Building reusable shock combinations

Examples:

Solvency II lapse up (multiply by 1.5, cap at 100%):

```python no_output_check from gaspatchio_core.scenarios.shocks import ( PipelineShock, MultiplicativeShock, ClipShock, )

shock = PipelineShock( shocks=[ MultiplicativeShock(factor=1.5), ClipShock(max_value=1.0), ], table="lapse", ) ```

Lapse down with floor (multiply by 0.5, floor at original - 0.2):

This would need a custom approach for relative floors.

describe() -> str

Return description of this shock.

MaxShock

Bases: Shock

A shock that takes the maximum of two shock expressions.

Used for scenarios like Solvency II lapse down: "max(lapse × 0.5, lapse - 0.2)" where the result is the larger of two transformations.

Parameters:

Name Type Description Default
shock_a Shock

First shock option

required
shock_b Shock

Second shock option

required
table str | None

Optional table name this shock targets

None
column str | None

Optional column name this shock targets

None

When to use

  • Solvency II lapse down: max(×0.5, -0.2)
  • Taking the less severe of two shocks
  • Complex regulatory scenarios

Examples:

Solvency II lapse down:

```python no_output_check from gaspatchio_core.scenarios.shocks import ( MaxShock, MultiplicativeShock, AdditiveShock, )

shock = MaxShock( shock_a=MultiplicativeShock(factor=0.5), shock_b=AdditiveShock(delta=-0.2), table="lapse", )

Result: max(lapse × 0.5, lapse - 0.2)

```

describe() -> str

Return description of this shock.

MinShock

Bases: Shock

A shock that takes the minimum of two shock expressions.

Used for scenarios where the result should be the smaller of two transformations.

Parameters:

Name Type Description Default
shock_a Shock

First shock option

required
shock_b Shock

Second shock option

required
table str | None

Optional table name this shock targets

None
column str | None

Optional column name this shock targets

None

When to use

  • Taking the more severe of two shocks
  • Cap scenarios (similar to ClipShock but based on transformations)
  • Complex regulatory scenarios

Examples:

Take the lower of two mortality assumptions:

```python no_output_check from gaspatchio_core.scenarios.shocks import ( MinShock, MultiplicativeShock, OverrideShock, )

shock = MinShock( shock_a=MultiplicativeShock(factor=1.5), shock_b=OverrideShock(value=0.1), # Cap at 10% mortality table="mortality", ) ```

describe() -> str

Return description of this shock.

Filter Shocks

FilteredShock

Bases: Shock

A shock that applies only to rows matching a filter condition (WHERE clause).

Used for dimension-filtered shocks like "increase early-duration lapse by 25%" where only rows matching the filter are modified.

This implements GSP-65: Dimension-filtered shocks.

Parameters:

Name Type Description Default
shock Shock

The shock to apply to matching rows

required
where FilterCondition

Filter condition dictionary

required
table str | None

Optional table name this shock targets

None
column str | None

Optional column name this shock targets

None

When to use

  • Apply shocks to specific segments (e.g., early durations)
  • Age-specific mortality adjustments
  • Product-specific lapse stress
  • Regulatory scenarios with conditional shocks

Examples:

Increase early-duration lapse by 25%:

```python no_output_check from gaspatchio_core.scenarios.shocks import FilteredShock, MultiplicativeShock

shock = FilteredShock( shock=MultiplicativeShock(factor=1.25), where={"duration": {"lte": 3}}, table="lapse", )

**Mortality shock for elderly lives:**

```python no_output_check
shock = FilteredShock(
    shock=MultiplicativeShock(factor=1.15),
    where={"attained_age": {"gte": 65}},
    table="mortality",
)

Complex filter with multiple conditions:

python no_output_check shock = FilteredShock( shock=AdditiveShock(delta=0.02), where={"sex": "F", "smoker_status": "S"}, table="mortality", )

describe() -> str

Return description of this shock.

TimeConditionalShock

Bases: Shock

A shock that applies only at specific projection times (WHEN clause).

Used for time-conditional shocks like "40% mass lapse at t=0 only" where the shock is applied based on projection period.

This implements GSP-74: Time-conditional shocks.

Parameters:

Name Type Description Default
shock Shock

The shock to apply at matching times

required
when FilterCondition

Time condition dictionary (uses 't' column by default)

required
table str | None

Optional table name this shock targets

None
column str | None

Optional column name this shock targets

None
time_column str

Column name for time (default: "t")

't'

When to use

  • Mass lapse at policy inception (t=0)
  • First-year expense shocks
  • Time-limited stress scenarios
  • Shock only during specific periods

Examples:

Mass lapse at t=0:

```python no_output_check from gaspatchio_core.scenarios.shocks import TimeConditionalShock, AdditiveShock

shock = TimeConditionalShock( shock=AdditiveShock(delta=0.40), # Add 40% lapse when={"t": {"eq": 0}}, table="lapse", )

**Expense shock for first 5 years:**

```python no_output_check
shock = TimeConditionalShock(
    shock=MultiplicativeShock(factor=1.10),
    when={"t": {"lte": 5}},
    table="expenses",
)

describe() -> str

Return description of this shock.

Parameter Shocks

ParameterShock

A shock specification for scalar model parameters (not table values).

Used for scenarios like "increase expense inflation by 1%" where the target is a scalar model input rather than an assumption table.

Unlike table shocks, parameter shocks store the transformation specification and are applied at model setup time by the model code.

Parameters:

Name Type Description Default
param str

Name of the parameter to shock

required
operation str

Type of operation ("multiply", "add", or "set")

required
value float

Value for the operation (factor, delta, or constant)

required

When to use

  • Shocking scalar model inputs (expense inflation, discount rate spread)
  • Parameters that aren't stored in assumption tables
  • Model-level sensitivity analysis

Not a Shock subclass

ParameterShock is NOT a Shock subclass because it doesn't operate on Polars expressions. It stores the shock specification for the model code to apply.

Examples:

Add 1% to expense inflation:

```python no_output_check from gaspatchio_core.scenarios.shocks import ParameterShock

shock = ParameterShock(param="expense_inflation", operation="add", value=0.01)

Apply in model code:

base_inflation = 0.02 shocked_inflation = shock.apply(base_inflation) # 0.03

**Multiply discount spread:**

```python no_output_check
shock = ParameterShock(param="discount_spread", operation="multiply", value=1.5)

apply(base_value: float) -> float

Apply this shock to a base parameter value.

Parameters:

Name Type Description Default
base_value float

The original parameter value

required

Returns:

Type Description
float

The shocked parameter value

describe() -> str

Return a human-readable description of this shock.

The following methods on the Table class work with scenarios:

  • Table.from_scenario_files() - Load separate assumption files per scenario
  • Table.from_scenario_template() - Load scenario files using a path template
  • Table.from_shocks() - Create multiple shocked tables from shock specifications
  • Table.with_shock() - Apply a single shock to create a modified table

See the Actuarial Frame API for details on these methods.

See Also