Skip to content

Scenarios API

API reference for scenario expansion, shock operations, and stress testing.

Core Functions

with_scenarios

batch_scenarios

describe_scenarios

Generate human-readable descriptions of scenario configurations.

Creates audit-trail-ready documentation of what shocks are applied in each scenario. Useful for governance, compliance, and model documentation requirements.

When to use

  • Generating audit trails for regulatory compliance
  • Documenting scenario configurations in model reports
  • Creating change logs for assumption modifications
  • Building scenario comparison reports

Parameters:

Name Type Description Default
scenarios dict[str, list[Shock]]

Mapping of scenario ID to list of shocks

required
output_format Literal['text', 'markdown', 'dict']

Output format - "markdown" (default), "text", or "dict"

'markdown'

Returns:

Type Description
str | dict[str, list[str]]

Formatted description string, or dict for programmatic access

Examples:

Generate markdown documentation:

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

scenarios = { "BASE": [], "STRESSED": [MultiplicativeShock(factor=1.2, table="mortality")], }

print(describe_scenarios(scenarios))

**Get as dictionary for programmatic access:**

```python no_output_check
result = describe_scenarios(scenarios, output_format="dict")
for scenario_id, shocks in result.items():
    print(f"{scenario_id}: {len(shocks)} shocks")

sensitivity_analysis

Config Parsing

parse_shock_config

parse_scenario_config

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