risksim¶
Portfolio Monte Carlo simulation and risk measures: simulate aggregate outcomes across a portfolio of contracts and summarize the distribution with standard risk measures.
The package builds a portfolio from contract definitions, simulates aggregate outcomes, and reports risk measures (such as value-at-risk and tail value-at-risk) over the simulated distribution — the capital view that sits at the end of the experience → pricing → loss → tail → capital pipeline.
var and tvar follow the ecosystem-wide empirical estimators (inverted-CDF
order statistic; Acerbi–Tasche), so a portfolio’s risk measures here match the
same quantities computed in lossmodels or extremeloss byte for byte, and
every simulation accepts the shared rng argument (None, seed, or
Generator) for bit-reproducible runs — see Conventions.
See the API reference below for the full surface; each object’s docstring carries its own usage.
Portfolio simulation¶
A portfolio is a list of named items, each wrapping anything with a .sample
method — a fitted lossmodels.CollectiveRiskModel drops straight in:
import risksim as rs
port = rs.Portfolio([
rs.PortfolioItem("commercial", crm),
rs.PortfolioItem("specialty", other_model, weight=0.4),
])
res = port.simulate(100_000, rng=7)
res.gross_losses, res.component_losses, res.component_names
simulate returns a SimulationResult carrying the gross, ceded, and
retained loss vectors, the per-component draws, and — when a contract is
applied — the per-layer recoveries. The rng argument (None, seed, or
Generator) resolves to one generator threaded through the components, so the
same seed reproduces every array bit for bit.
Contracts¶
AggregateLayer(attachment, limit, share) follows the ecosystem coverage
semantics: limit is the layer width, so the layer exhausts at
attachment + limit (see
Conventions). ContractProgram stacks
layers, and apply_contract applies either to any loss vector, returning
(ceded, retained):
treaty = rs.AggregateLayer(attachment=3_200_000, limit=1_500_000,
name="agg_stop_loss")
res = port.simulate(100_000, contract=treaty, rng=7)
res.ceded_losses, res.retained_losses, res.layer_losses
ceded, retained = rs.apply_contract([50.0, 150.0, 400.0],
rs.AggregateLayer(attachment=100.0, limit=200.0))
# ceded -> [ 0., 50., 200.]
# retained -> [ 50., 100., 200.]
Risk measures¶
rs.metrics.var(res.gross_losses, 0.99)
rs.metrics.tvar(res.retained_losses, 0.99)
These are the ecosystem-wide empirical estimators — see the intro above and Conventions.
API reference¶
- class AggregateLayer(attachment: float = 0.0, limit: float | None = None, share: float = 1.0, name: str | None = None)[source]¶
Bases:
objectAggregate annual layer applied to simulated aggregate losses.
For aggregate annual loss S, ceded loss is:
C = share * min((S - attachment)+, limit)
with no cap if limit is None.
- apply_contract(losses: ndarray | list[float], contract: AggregateLayer | ContractProgram) tuple[ndarray, ndarray][source]¶
Return (ceded, retained) arrays for a single aggregate layer or a multi-layer contract program.
- class ContractProgram(layers: Sequence[AggregateLayer], name: str = 'contract_program')[source]¶
Bases:
objectCollection of aggregate layers applied to the same gross loss.
This first version assumes the layers are intended to work together without overlap. For a standard non-overlapping tower, total ceded loss is the row-wise sum of ceded loss by layer.
- class Portfolio(items: Sequence[PortfolioItem], name: str = 'portfolio')[source]¶
Bases:
objectPortfolio of aggregate-loss components.
This first version assumes components are sampled independently.
- class PortfolioItem(name: 'str', model: 'SupportsSample', weight: 'float' = 1.0)[source]¶
Bases:
object
- class SimulationResult(gross_losses: ndarray, ceded_losses: ndarray | None = None, retained_losses: ndarray | None = None, component_losses: ndarray | None = None, component_names: Sequence[str] | None = None, layer_losses: ndarray | None = None, layer_names: Sequence[str] | None = None, contract_name: str | None = None)[source]¶
Bases:
objectContainer for portfolio simulation outputs.
If retained_losses is present, the primary losses view is retained/net loss. Otherwise, the primary losses view is gross loss.