Skip to main content

risksim

Portfolio-level loss simulation and aggregate reinsurance modeling.


Overview

risksim composes one or more stochastic loss models into a portfolio, simulates the portfolio's aggregate loss, applies aggregate reinsurance structures, and summarizes the gross, ceded, and retained results. It is intentionally model-agnostic: anything that exposes a .sample(size) method can be a portfolio component, so risksim handles composition, contracts, and simulation summaries while the loss generation lives wherever you like.

It pairs naturally with lossmodels — build a collective-risk model (or any severity/frequency-based model) there, drop it into a risksim portfolio here — but it has no hard dependency on it; its only runtime requirement is numpy.

Highlights

  • Portfolios — combine multiple simulated loss components, each with an optional weight, into a single portfolio.
  • Aggregate reinsurance — aggregate annual layers (attachment, limit, share) and multi-layer contract programs.
  • One simulation, every view — a single run yields gross, ceded, retained, per-component, and per-layer losses.
  • Risk measures — mean, variance / standard deviation, VaR, TVaR, exceedance probabilities, and a one-call summary, on any loss vector.
  • Model-agnostic — any object implementing .sample(size) works; components that also expose .mean() unlock closed-form portfolio moments.

Installation

pip install risksim

From source:

pip install -e .

Requires Python >=3.10; the only runtime dependency is numpy. The examples below use lossmodels for the component models — install it too if you want to run them as written.

Package structure

risksim/
├── portfolio.py    # Portfolio and PortfolioItem
├── contracts.py    # AggregateLayer, ContractProgram, apply_contract
├── results.py      # SimulationResult (gross / ceded / retained / component / layer views)
├── metrics.py      # mean, variance, std, var, tvar, prob_exceeding, summary
└── protocols.py    # SupportsSample, SupportsMoments

Quick start

from lossmodels import Poisson, Lognormal, CollectiveRiskModel
from risksim import Portfolio, PortfolioItem, AggregateLayer

# two lines of business, each a collective-risk model (any .sample object works)
line_a = CollectiveRiskModel(Poisson(3.0), Lognormal(8.0, 0.9))
line_b = CollectiveRiskModel(Poisson(1.5), Lognormal(9.0, 0.7))

portfolio = Portfolio([
    PortfolioItem("line_a", line_a),
    PortfolioItem("line_b", line_b, weight=1.25),   # optional exposure weight
])

# simulate the portfolio's aggregate annual loss, net of an aggregate layer
layer = AggregateLayer(attachment=250_000, limit=500_000, share=1.0)
result = portfolio.simulate(100_000, contract=layer)

print("gross mean   :", result.gross_mean)
print("ceded mean   :", result.ceded_mean)
print("retained mean:", result.retained_mean)
print("retained 99% VaR :", result.var(0.99))
print(result.summary())

Portfolios

A PortfolioItem wraps a sampleable loss model with a name and an optional weight (a multiplier applied to that component's sampled losses). A Portfolio is a sequence of items.

from risksim import Portfolio, PortfolioItem

port = Portfolio([PortfolioItem("a", model_a), PortfolioItem("b", model_b, weight=0.5)])

gross = port.sample(50_000)              # total portfolio loss per simulation
by_component = port.sample_components(50_000)  # per-component loss matrix
print(port.component_names())

When every component also exposes .mean() / .variance() (the SupportsMoments protocol — which lossmodels models satisfy), the portfolio reports closed-form moments without simulating:

port.mean()       # sum of component means (times weights)
port.std()
port.variance()

simulate(size, contract=None) runs the portfolio and returns a SimulationResult; sample(size) returns just the gross loss vector.

Aggregate reinsurance

An AggregateLayer is an aggregate annual structure defined by three numbers:

  • attachment — the aggregate retention; losses below it are not ceded.
  • limit — the width of the layer above the attachment (None = unlimited).
  • share — the ceded proportion of the layer (e.g. 0.8 for an 80% placement).

For a gross annual loss L, the ceded amount is share × min(max(L − attachment, 0), limit).

from risksim import AggregateLayer, ContractProgram, apply_contract

# a single layer: 80% of the 500k aggregate layer above a 250k retention
layer = AggregateLayer(attachment=250_000, limit=500_000, share=0.8)

# stack layers into a program (e.g. a working layer plus a higher layer)
program = ContractProgram([
    AggregateLayer(attachment=250_000, limit=500_000, share=1.0, name="working"),
    AggregateLayer(attachment=750_000, limit=1_000_000, share=0.5, name="higher"),
])

# apply either to a loss vector directly
ceded, retained = apply_contract(gross_losses, program)

apply_contract(losses, contract) returns (ceded, retained) arrays aligned with the input, where ceded + retained == losses. Passing a contract to Portfolio.simulate(..., contract=program) does the same inside the simulation and records the per-layer detail.

The simulation result

SimulationResult holds every view from a single run and computes risk measures on demand:

Attribute / method Meaning
gross_losses, ceded_losses, retained_losses aligned loss vectors
component_losses, component_names per-component loss matrix
layer_losses, layer_names per-layer ceded amounts (with a contract)
gross_mean, ceded_mean, retained_mean mean of each view
component_means, layer_means per-component / per-layer means
losses the retained vector (the portfolio's net position)
mean(), std(), variance() moments of the net loss
var(q), tvar(q) Value-at-Risk and Tail-VaR of the net loss
prob_exceeding(threshold) P(net loss > threshold)
summary() a dict of headline statistics
n_sims the number of simulations

Risk measures

The metrics module operates on any loss vector (a NumPy array or list), so you can use it independently of the portfolio machinery:

from risksim import metrics

metrics.mean(losses)
metrics.std(losses)            # metrics.variance(...) also available
metrics.var(losses, 0.99)      # 99% VaR
metrics.tvar(losses, 0.99)     # 99% TVaR
metrics.prob_exceeding(losses, 1_000_000)
metrics.summary(losses, quantiles=(0.95, 0.99, 0.995))

The SupportsSample protocol

Any object implementing sample(size: int) -> np.ndarray can be a portfolio component — a lossmodels collective-risk model or severity, a custom class, or a thin wrapper around a sampler. Components that additionally implement mean() / variance() (SupportsMoments) enable the closed-form Portfolio.mean() / .std() / .variance() shortcuts.

Testing

pytest -q

License

MIT License

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

risksim-0.3.0.tar.gz (16.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

risksim-0.3.0-py3-none-any.whl (12.2 kB view details)

Uploaded Python 3

File details

Details for the file risksim-0.3.0.tar.gz.

File metadata

  • Download URL: risksim-0.3.0.tar.gz
  • Upload date:
  • Size: 16.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.10.12

File hashes

Hashes for risksim-0.3.0.tar.gz
Algorithm Hash digest
SHA256 2dfd8b81724dd7ee93b8c1c5d73b1bba20cb26fbcdec2c7a9ab69e62f2abd91b
MD5 d8d38f9043f098961f20dfa28346724b
BLAKE2b-256 34ca9196b0e6af70134d8e99f6e51c15ed0322407a046a55525e76137319fafc

See more details on using hashes here.

File details

Details for the file risksim-0.3.0-py3-none-any.whl.

File metadata

  • Download URL: risksim-0.3.0-py3-none-any.whl
  • Upload date:
  • Size: 12.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.10.12

File hashes

Hashes for risksim-0.3.0-py3-none-any.whl
Algorithm Hash digest
SHA256 943c8b2bbb7339acb8144da207a26899a6e328de854c760d7ac70dcc87990e6e
MD5 151756382db5625826cb8a94623ab135
BLAKE2b-256 6b4a7488fbf200935dd48361bef39c400a06469476171f2e3b0e5a5d5f846ac5

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page