risksim 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
risksim-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Michael Bryant
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
risksim-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,275 @@
1
+ Metadata-Version: 2.4
2
+ Name: risksim
3
+ Version: 0.1.0
4
+ Summary: Portfolio-level loss simulation and aggregate treaty modeling in Python
5
+ Author: Michael Bryant
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/michaelabryant/risksim
8
+ Project-URL: Repository, https://github.com/michaelabryant/risksim
9
+ Project-URL: Issues, https://github.com/michaelabryant/risksim/issues
10
+ Keywords: actuarial,insurance,simulation,risk,reinsurance
11
+ Classifier: Development Status :: 3 - Alpha
12
+ Classifier: Intended Audience :: Science/Research
13
+ Classifier: Intended Audience :: Financial and Insurance Industry
14
+ Classifier: License :: OSI Approved :: MIT License
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.10
17
+ Classifier: Topic :: Scientific/Engineering :: Mathematics
18
+ Classifier: Topic :: Scientific/Engineering :: Information Analysis
19
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
20
+ Requires-Python: >=3.10
21
+ Description-Content-Type: text/markdown
22
+ License-File: LICENSE
23
+ Requires-Dist: numpy
24
+ Dynamic: license-file
25
+
26
+ # risksim
27
+
28
+ `risksim` is a Python package for portfolio-level loss simulation and aggregate treaty modeling.
29
+
30
+ It is designed to sit on top of stochastic loss models that expose a `.sample(size)` method. In particular, it pairs naturally with `lossmodels`, where `lossmodels` handles loss-model generation and `risksim` handles portfolio composition, aggregate contracts, and simulation summaries.
31
+
32
+ ## Features
33
+
34
+ - combine multiple simulated loss components into a portfolio
35
+ - apply aggregate annual layers
36
+ - build simple multi-layer aggregate contract programs
37
+ - summarize gross, ceded, and retained loss
38
+ - compute simulation-based risk measures such as mean, VaR, and TVaR
39
+
40
+ ## Installation
41
+
42
+ ### From PyPI
43
+
44
+ ```bash
45
+ pip install risksim
46
+ ```
47
+
48
+ ### From source
49
+
50
+ ```bash
51
+ git clone https://github.com/michaelabryant/risksim.git
52
+ cd risksim
53
+ pip install -e .
54
+ ```
55
+
56
+ ## Optional companion package
57
+
58
+ `risksim` works with any model that implements:
59
+
60
+ ```python
61
+ sample(size: int = 1) -> np.ndarray
62
+ ```
63
+
64
+ Many of the examples below use [`lossmodels`](https://github.com/michaelabryant/lossmodels), which provides aggregate actuarial loss models that integrate naturally with `risksim`.
65
+
66
+ If you want to run the `lossmodels` examples locally, install `lossmodels` as well.
67
+
68
+ ## Quick start
69
+
70
+ Any object with a `.sample(size)` method can be used inside a `Portfolio`.
71
+
72
+ ```python
73
+ import numpy as np
74
+
75
+ from risksim import AggregateLayer, Portfolio, PortfolioItem
76
+
77
+
78
+ class ConstantModel:
79
+ def __init__(self, value: float) -> None:
80
+ self.value = float(value)
81
+
82
+ def sample(self, size: int = 1) -> np.ndarray:
83
+ return np.full(size, self.value, dtype=float)
84
+
85
+ def mean(self) -> float:
86
+ return self.value
87
+
88
+ def variance(self) -> float:
89
+ return 0.0
90
+
91
+
92
+ medical = ConstantModel(200.0)
93
+ rx = ConstantModel(50.0)
94
+
95
+ portfolio = Portfolio(
96
+ [
97
+ PortfolioItem("medical", medical),
98
+ PortfolioItem("rx", rx),
99
+ ]
100
+ )
101
+
102
+ contract = AggregateLayer(
103
+ attachment=100.0,
104
+ limit=75.0,
105
+ share=1.0,
106
+ name="aggregate_xol",
107
+ )
108
+
109
+ result = portfolio.simulate(size=10_000, contract=contract)
110
+
111
+ print("net mean:", result.mean())
112
+ print("gross mean:", result.gross_mean())
113
+ print("ceded mean:", result.ceded_mean())
114
+ print("VaR 99%:", result.var(0.99))
115
+ print("TVaR 99%:", result.tvar(0.99))
116
+ print(result.summary())
117
+ ```
118
+
119
+ ## Using `lossmodels`
120
+
121
+ A common workflow is to build aggregate loss models with `lossmodels` and then combine them with `risksim`.
122
+
123
+ ```python
124
+ from lossmodels.aggregate import CollectiveRiskModel
125
+ from lossmodels.frequency import Poisson
126
+ from lossmodels.severity import Lognormal
127
+
128
+ from risksim import AggregateLayer, Portfolio, PortfolioItem
129
+
130
+ medical = CollectiveRiskModel(
131
+ Poisson(lam=2.0),
132
+ Lognormal(mu=2.0, sigma=0.3),
133
+ )
134
+
135
+ rx = CollectiveRiskModel(
136
+ Poisson(lam=1.0),
137
+ Lognormal(mu=1.5, sigma=0.2),
138
+ )
139
+
140
+ portfolio = Portfolio(
141
+ [
142
+ PortfolioItem("medical", medical),
143
+ PortfolioItem("rx", rx),
144
+ ]
145
+ )
146
+
147
+ contract = AggregateLayer(
148
+ attachment=50.0,
149
+ limit=100.0,
150
+ name="agg_xol",
151
+ )
152
+
153
+ result = portfolio.simulate(size=50_000, contract=contract)
154
+ print(result.summary())
155
+ ```
156
+
157
+ ## Contract programs
158
+
159
+ `risksim` also supports simple multi-layer aggregate contract programs.
160
+
161
+ ```python
162
+ from lossmodels.aggregate import CollectiveRiskModel
163
+ from lossmodels.frequency import Poisson
164
+ from lossmodels.severity import Lognormal
165
+
166
+ from risksim import AggregateLayer, ContractProgram, Portfolio, PortfolioItem
167
+
168
+ line = CollectiveRiskModel(
169
+ Poisson(lam=4.0),
170
+ Lognormal(mu=3.5, sigma=0.7),
171
+ )
172
+
173
+ portfolio = Portfolio([PortfolioItem("line", line)])
174
+
175
+ program = ContractProgram(
176
+ [
177
+ AggregateLayer(attachment=50.0, limit=50.0, name="layer_1"),
178
+ AggregateLayer(attachment=100.0, limit=100.0, name="layer_2"),
179
+ ],
180
+ name="two_layer_tower",
181
+ )
182
+
183
+ result = portfolio.simulate(size=20_000, contract=program)
184
+
185
+ print("gross mean:", result.gross_mean())
186
+ print("ceded mean:", result.ceded_mean())
187
+ print("retained mean:", result.retained_mean())
188
+ print("layer means:", result.layer_means())
189
+ ```
190
+
191
+ ## Public API
192
+
193
+ ```python
194
+ from risksim import AggregateLayer, ContractProgram, Portfolio, PortfolioItem, SimulationResult
195
+ ```
196
+
197
+ ## Core concepts
198
+
199
+ ### `PortfolioItem`
200
+ Wraps one simulated component with a name and optional weight.
201
+
202
+ ### `Portfolio`
203
+ Combines multiple simulated components into a total portfolio loss.
204
+
205
+ ### `AggregateLayer`
206
+ Applies a single aggregate annual contract to simulated gross losses.
207
+
208
+ For annual gross loss `S`, ceded loss is:
209
+
210
+ ```text
211
+ share * min(max(S - attachment, 0), limit)
212
+ ```
213
+
214
+ with no cap if `limit=None`.
215
+
216
+ ### `ContractProgram`
217
+ Combines multiple aggregate layers applied to the same gross loss.
218
+
219
+ ### `SimulationResult`
220
+ Stores simulation outputs and provides convenience methods such as:
221
+
222
+ - `mean()`
223
+ - `variance()`
224
+ - `std()`
225
+ - `var(q)`
226
+ - `tvar(q)`
227
+ - `prob_exceeding(threshold)`
228
+ - `summary()`
229
+
230
+ If retained losses are present, the primary `losses` view is net/retained loss. Otherwise it is gross loss.
231
+
232
+ ## Example scripts
233
+
234
+ The `examples/` directory contains runnable scripts:
235
+
236
+ - `examples/basic_portfolio.py`
237
+ - `examples/aggregate_layer.py`
238
+ - `examples/contract_program.py`
239
+
240
+ Run them with:
241
+
242
+ ```bash
243
+ python examples/basic_portfolio.py
244
+ python examples/aggregate_layer.py
245
+ python examples/contract_program.py
246
+ ```
247
+
248
+ ## Project scope
249
+
250
+ The current version focuses on:
251
+
252
+ - portfolio-level simulation from component loss models
253
+ - aggregate annual treaty application
254
+ - simple non-overlapping multi-layer programs
255
+ - simulation-based portfolio summaries
256
+
257
+ It does not yet model:
258
+
259
+ - dependence between components
260
+ - occurrence-based contracts requiring claim-level paths
261
+ - reinstatements
262
+ - capital allocation
263
+ - premium or pricing workflows beyond simulated summaries
264
+
265
+ ## Development
266
+
267
+ Run the test suite with:
268
+
269
+ ```bash
270
+ python -m pytest -q
271
+ ```
272
+
273
+ ## License
274
+
275
+ MIT
@@ -0,0 +1,250 @@
1
+ # risksim
2
+
3
+ `risksim` is a Python package for portfolio-level loss simulation and aggregate treaty modeling.
4
+
5
+ It is designed to sit on top of stochastic loss models that expose a `.sample(size)` method. In particular, it pairs naturally with `lossmodels`, where `lossmodels` handles loss-model generation and `risksim` handles portfolio composition, aggregate contracts, and simulation summaries.
6
+
7
+ ## Features
8
+
9
+ - combine multiple simulated loss components into a portfolio
10
+ - apply aggregate annual layers
11
+ - build simple multi-layer aggregate contract programs
12
+ - summarize gross, ceded, and retained loss
13
+ - compute simulation-based risk measures such as mean, VaR, and TVaR
14
+
15
+ ## Installation
16
+
17
+ ### From PyPI
18
+
19
+ ```bash
20
+ pip install risksim
21
+ ```
22
+
23
+ ### From source
24
+
25
+ ```bash
26
+ git clone https://github.com/michaelabryant/risksim.git
27
+ cd risksim
28
+ pip install -e .
29
+ ```
30
+
31
+ ## Optional companion package
32
+
33
+ `risksim` works with any model that implements:
34
+
35
+ ```python
36
+ sample(size: int = 1) -> np.ndarray
37
+ ```
38
+
39
+ Many of the examples below use [`lossmodels`](https://github.com/michaelabryant/lossmodels), which provides aggregate actuarial loss models that integrate naturally with `risksim`.
40
+
41
+ If you want to run the `lossmodels` examples locally, install `lossmodels` as well.
42
+
43
+ ## Quick start
44
+
45
+ Any object with a `.sample(size)` method can be used inside a `Portfolio`.
46
+
47
+ ```python
48
+ import numpy as np
49
+
50
+ from risksim import AggregateLayer, Portfolio, PortfolioItem
51
+
52
+
53
+ class ConstantModel:
54
+ def __init__(self, value: float) -> None:
55
+ self.value = float(value)
56
+
57
+ def sample(self, size: int = 1) -> np.ndarray:
58
+ return np.full(size, self.value, dtype=float)
59
+
60
+ def mean(self) -> float:
61
+ return self.value
62
+
63
+ def variance(self) -> float:
64
+ return 0.0
65
+
66
+
67
+ medical = ConstantModel(200.0)
68
+ rx = ConstantModel(50.0)
69
+
70
+ portfolio = Portfolio(
71
+ [
72
+ PortfolioItem("medical", medical),
73
+ PortfolioItem("rx", rx),
74
+ ]
75
+ )
76
+
77
+ contract = AggregateLayer(
78
+ attachment=100.0,
79
+ limit=75.0,
80
+ share=1.0,
81
+ name="aggregate_xol",
82
+ )
83
+
84
+ result = portfolio.simulate(size=10_000, contract=contract)
85
+
86
+ print("net mean:", result.mean())
87
+ print("gross mean:", result.gross_mean())
88
+ print("ceded mean:", result.ceded_mean())
89
+ print("VaR 99%:", result.var(0.99))
90
+ print("TVaR 99%:", result.tvar(0.99))
91
+ print(result.summary())
92
+ ```
93
+
94
+ ## Using `lossmodels`
95
+
96
+ A common workflow is to build aggregate loss models with `lossmodels` and then combine them with `risksim`.
97
+
98
+ ```python
99
+ from lossmodels.aggregate import CollectiveRiskModel
100
+ from lossmodels.frequency import Poisson
101
+ from lossmodels.severity import Lognormal
102
+
103
+ from risksim import AggregateLayer, Portfolio, PortfolioItem
104
+
105
+ medical = CollectiveRiskModel(
106
+ Poisson(lam=2.0),
107
+ Lognormal(mu=2.0, sigma=0.3),
108
+ )
109
+
110
+ rx = CollectiveRiskModel(
111
+ Poisson(lam=1.0),
112
+ Lognormal(mu=1.5, sigma=0.2),
113
+ )
114
+
115
+ portfolio = Portfolio(
116
+ [
117
+ PortfolioItem("medical", medical),
118
+ PortfolioItem("rx", rx),
119
+ ]
120
+ )
121
+
122
+ contract = AggregateLayer(
123
+ attachment=50.0,
124
+ limit=100.0,
125
+ name="agg_xol",
126
+ )
127
+
128
+ result = portfolio.simulate(size=50_000, contract=contract)
129
+ print(result.summary())
130
+ ```
131
+
132
+ ## Contract programs
133
+
134
+ `risksim` also supports simple multi-layer aggregate contract programs.
135
+
136
+ ```python
137
+ from lossmodels.aggregate import CollectiveRiskModel
138
+ from lossmodels.frequency import Poisson
139
+ from lossmodels.severity import Lognormal
140
+
141
+ from risksim import AggregateLayer, ContractProgram, Portfolio, PortfolioItem
142
+
143
+ line = CollectiveRiskModel(
144
+ Poisson(lam=4.0),
145
+ Lognormal(mu=3.5, sigma=0.7),
146
+ )
147
+
148
+ portfolio = Portfolio([PortfolioItem("line", line)])
149
+
150
+ program = ContractProgram(
151
+ [
152
+ AggregateLayer(attachment=50.0, limit=50.0, name="layer_1"),
153
+ AggregateLayer(attachment=100.0, limit=100.0, name="layer_2"),
154
+ ],
155
+ name="two_layer_tower",
156
+ )
157
+
158
+ result = portfolio.simulate(size=20_000, contract=program)
159
+
160
+ print("gross mean:", result.gross_mean())
161
+ print("ceded mean:", result.ceded_mean())
162
+ print("retained mean:", result.retained_mean())
163
+ print("layer means:", result.layer_means())
164
+ ```
165
+
166
+ ## Public API
167
+
168
+ ```python
169
+ from risksim import AggregateLayer, ContractProgram, Portfolio, PortfolioItem, SimulationResult
170
+ ```
171
+
172
+ ## Core concepts
173
+
174
+ ### `PortfolioItem`
175
+ Wraps one simulated component with a name and optional weight.
176
+
177
+ ### `Portfolio`
178
+ Combines multiple simulated components into a total portfolio loss.
179
+
180
+ ### `AggregateLayer`
181
+ Applies a single aggregate annual contract to simulated gross losses.
182
+
183
+ For annual gross loss `S`, ceded loss is:
184
+
185
+ ```text
186
+ share * min(max(S - attachment, 0), limit)
187
+ ```
188
+
189
+ with no cap if `limit=None`.
190
+
191
+ ### `ContractProgram`
192
+ Combines multiple aggregate layers applied to the same gross loss.
193
+
194
+ ### `SimulationResult`
195
+ Stores simulation outputs and provides convenience methods such as:
196
+
197
+ - `mean()`
198
+ - `variance()`
199
+ - `std()`
200
+ - `var(q)`
201
+ - `tvar(q)`
202
+ - `prob_exceeding(threshold)`
203
+ - `summary()`
204
+
205
+ If retained losses are present, the primary `losses` view is net/retained loss. Otherwise it is gross loss.
206
+
207
+ ## Example scripts
208
+
209
+ The `examples/` directory contains runnable scripts:
210
+
211
+ - `examples/basic_portfolio.py`
212
+ - `examples/aggregate_layer.py`
213
+ - `examples/contract_program.py`
214
+
215
+ Run them with:
216
+
217
+ ```bash
218
+ python examples/basic_portfolio.py
219
+ python examples/aggregate_layer.py
220
+ python examples/contract_program.py
221
+ ```
222
+
223
+ ## Project scope
224
+
225
+ The current version focuses on:
226
+
227
+ - portfolio-level simulation from component loss models
228
+ - aggregate annual treaty application
229
+ - simple non-overlapping multi-layer programs
230
+ - simulation-based portfolio summaries
231
+
232
+ It does not yet model:
233
+
234
+ - dependence between components
235
+ - occurrence-based contracts requiring claim-level paths
236
+ - reinstatements
237
+ - capital allocation
238
+ - premium or pricing workflows beyond simulated summaries
239
+
240
+ ## Development
241
+
242
+ Run the test suite with:
243
+
244
+ ```bash
245
+ python -m pytest -q
246
+ ```
247
+
248
+ ## License
249
+
250
+ MIT
@@ -0,0 +1,28 @@
1
+ [project]
2
+ name = "risksim"
3
+ version = "0.1.0"
4
+ description = "Portfolio-level loss simulation and aggregate treaty modeling in Python"
5
+ readme = "README.md"
6
+ requires-python = ">=3.10"
7
+ dependencies = ["numpy"]
8
+ keywords = ["actuarial", "insurance", "simulation", "risk", "reinsurance"]
9
+ authors = [
10
+ { name = "Michael Bryant" }
11
+ ]
12
+ license = { text = "MIT" }
13
+ classifiers = [
14
+ "Development Status :: 3 - Alpha",
15
+ "Intended Audience :: Science/Research",
16
+ "Intended Audience :: Financial and Insurance Industry",
17
+ "License :: OSI Approved :: MIT License",
18
+ "Programming Language :: Python :: 3",
19
+ "Programming Language :: Python :: 3.10",
20
+ "Topic :: Scientific/Engineering :: Mathematics",
21
+ "Topic :: Scientific/Engineering :: Information Analysis",
22
+ "Topic :: Software Development :: Libraries :: Python Modules",
23
+ ]
24
+
25
+ [project.urls]
26
+ Homepage = "https://github.com/michaelabryant/risksim"
27
+ Repository = "https://github.com/michaelabryant/risksim"
28
+ Issues = "https://github.com/michaelabryant/risksim/issues"
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,13 @@
1
+ from .contracts import AggregateLayer, ContractProgram
2
+ from .portfolio import Portfolio, PortfolioItem
3
+ from .results import SimulationResult
4
+
5
+ __all__ = [
6
+ "AggregateLayer",
7
+ "ContractProgram",
8
+ "Portfolio",
9
+ "PortfolioItem",
10
+ "SimulationResult",
11
+ ]
12
+
13
+ __version__ = "0.1.0"