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¶
Count¶
Min¶
Max¶
ArgMin¶
ArgMax¶
Mean¶
Variance¶
Std¶
Quantile¶
Median¶
CTE¶
QuantileRank¶
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¶
Bases: VectorAggregator
PeriodMean¶
Bases: VectorAggregator
PeriodMin¶
Bases: VectorAggregator
PeriodMax¶
Bases: VectorAggregator
PeriodCount¶
Bases: VectorAggregator
PeriodStd¶
Bases: VectorAggregator
PeriodVariance¶
Bases: VectorAggregator
PeriodMedian¶
Bases: VectorAggregator
PeriodQuantile¶
Bases: VectorAggregator
PeriodCTE¶
Bases: VectorAggregator
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.
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.
Related Table Methods¶
The following methods on the Table class work with scenarios:
Table.from_scenario_files()- Load separate assumption files per scenarioTable.from_scenario_template()- Load scenario files using a path templateTable.from_shocks()- Create multiple shocked tables from shock specificationsTable.with_shock()- Apply a single shock to create a modified table
See the Actuarial Frame API for details on these methods.
See Also¶
- Shock Operations - Conceptual guide with progressive examples
- What-If Analysis - Natural language to config translation
- Scenarios Overview - High-level scenario concepts