@actuarial-ts/core 0.1.0

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.
Files changed (120) hide show
  1. package/LICENSE +202 -0
  2. package/NOTICE +5 -0
  3. package/README.md +133 -0
  4. package/dist/benktander.d.ts +45 -0
  5. package/dist/benktander.d.ts.map +1 -0
  6. package/dist/benktander.js +38 -0
  7. package/dist/benktander.js.map +1 -0
  8. package/dist/berquist.d.ts +14 -0
  9. package/dist/berquist.d.ts.map +1 -0
  10. package/dist/berquist.js +292 -0
  11. package/dist/berquist.js.map +1 -0
  12. package/dist/bf.d.ts +23 -0
  13. package/dist/bf.d.ts.map +1 -0
  14. package/dist/bf.js +83 -0
  15. package/dist/bf.js.map +1 -0
  16. package/dist/capping.d.ts +96 -0
  17. package/dist/capping.d.ts.map +1 -0
  18. package/dist/capping.js +207 -0
  19. package/dist/capping.js.map +1 -0
  20. package/dist/caseOutstanding.d.ts +80 -0
  21. package/dist/caseOutstanding.d.ts.map +1 -0
  22. package/dist/caseOutstanding.js +147 -0
  23. package/dist/caseOutstanding.js.map +1 -0
  24. package/dist/chainladder.d.ts +15 -0
  25. package/dist/chainladder.d.ts.map +1 -0
  26. package/dist/chainladder.js +81 -0
  27. package/dist/chainladder.js.map +1 -0
  28. package/dist/clark.d.ts +91 -0
  29. package/dist/clark.d.ts.map +1 -0
  30. package/dist/clark.js +490 -0
  31. package/dist/clark.js.map +1 -0
  32. package/dist/diagnostics.d.ts +80 -0
  33. package/dist/diagnostics.d.ts.map +1 -0
  34. package/dist/diagnostics.js +359 -0
  35. package/dist/diagnostics.js.map +1 -0
  36. package/dist/discounting.d.ts +166 -0
  37. package/dist/discounting.d.ts.map +1 -0
  38. package/dist/discounting.js +210 -0
  39. package/dist/discounting.js.map +1 -0
  40. package/dist/elrMethods.d.ts +104 -0
  41. package/dist/elrMethods.d.ts.map +1 -0
  42. package/dist/elrMethods.js +151 -0
  43. package/dist/elrMethods.js.map +1 -0
  44. package/dist/factors.d.ts +19 -0
  45. package/dist/factors.d.ts.map +1 -0
  46. package/dist/factors.js +136 -0
  47. package/dist/factors.js.map +1 -0
  48. package/dist/fisherLange.d.ts +92 -0
  49. package/dist/fisherLange.d.ts.map +1 -0
  50. package/dist/fisherLange.js +224 -0
  51. package/dist/fisherLange.js.map +1 -0
  52. package/dist/freqSev.d.ts +57 -0
  53. package/dist/freqSev.d.ts.map +1 -0
  54. package/dist/freqSev.js +82 -0
  55. package/dist/freqSev.js.map +1 -0
  56. package/dist/ilf.d.ts +111 -0
  57. package/dist/ilf.d.ts.map +1 -0
  58. package/dist/ilf.js +449 -0
  59. package/dist/ilf.js.map +1 -0
  60. package/dist/index.d.ts +29 -0
  61. package/dist/index.d.ts.map +1 -0
  62. package/dist/index.js +29 -0
  63. package/dist/index.js.map +1 -0
  64. package/dist/mack.d.ts +55 -0
  65. package/dist/mack.d.ts.map +1 -0
  66. package/dist/mack.js +244 -0
  67. package/dist/mack.js.map +1 -0
  68. package/dist/merzWuthrich.d.ts +29 -0
  69. package/dist/merzWuthrich.d.ts.map +1 -0
  70. package/dist/merzWuthrich.js +132 -0
  71. package/dist/merzWuthrich.js.map +1 -0
  72. package/dist/munichChainLadder.d.ts +101 -0
  73. package/dist/munichChainLadder.d.ts.map +1 -0
  74. package/dist/munichChainLadder.js +254 -0
  75. package/dist/munichChainLadder.js.map +1 -0
  76. package/dist/odpBootstrap.d.ts +65 -0
  77. package/dist/odpBootstrap.d.ts.map +1 -0
  78. package/dist/odpBootstrap.js +243 -0
  79. package/dist/odpBootstrap.js.map +1 -0
  80. package/dist/onlevel.d.ts +39 -0
  81. package/dist/onlevel.d.ts.map +1 -0
  82. package/dist/onlevel.js +104 -0
  83. package/dist/onlevel.js.map +1 -0
  84. package/dist/salvageSubro.d.ts +82 -0
  85. package/dist/salvageSubro.d.ts.map +1 -0
  86. package/dist/salvageSubro.js +100 -0
  87. package/dist/salvageSubro.js.map +1 -0
  88. package/dist/stochastic.d.ts +56 -0
  89. package/dist/stochastic.d.ts.map +1 -0
  90. package/dist/stochastic.js +99 -0
  91. package/dist/stochastic.js.map +1 -0
  92. package/dist/tail.d.ts +18 -0
  93. package/dist/tail.d.ts.map +1 -0
  94. package/dist/tail.js +121 -0
  95. package/dist/tail.js.map +1 -0
  96. package/dist/trend.d.ts +46 -0
  97. package/dist/trend.d.ts.map +1 -0
  98. package/dist/trend.js +99 -0
  99. package/dist/trend.js.map +1 -0
  100. package/dist/triangle.d.ts +19 -0
  101. package/dist/triangle.d.ts.map +1 -0
  102. package/dist/triangle.js +163 -0
  103. package/dist/triangle.js.map +1 -0
  104. package/dist/triangleAlgebra.d.ts +10 -0
  105. package/dist/triangleAlgebra.d.ts.map +1 -0
  106. package/dist/triangleAlgebra.js +97 -0
  107. package/dist/triangleAlgebra.js.map +1 -0
  108. package/dist/types.d.ts +280 -0
  109. package/dist/types.d.ts.map +1 -0
  110. package/dist/types.js +79 -0
  111. package/dist/types.js.map +1 -0
  112. package/dist/ulae.d.ts +172 -0
  113. package/dist/ulae.d.ts.map +1 -0
  114. package/dist/ulae.js +164 -0
  115. package/dist/ulae.js.map +1 -0
  116. package/dist/util.d.ts +24 -0
  117. package/dist/util.d.ts.map +1 -0
  118. package/dist/util.js +66 -0
  119. package/dist/util.js.map +1 -0
  120. package/package.json +66 -0
@@ -0,0 +1,292 @@
1
+ import { ReservingError } from "./types.js";
2
+ import { isNum, ols, safeRatio } from "./util.js";
3
+ /**
4
+ * Berquist-Sherman adjustments (Berquist & Sherman 1977; Friedland ch. 13).
5
+ *
6
+ * Case-reserve adequacy: restate historical average case reserves (case
7
+ * reserves / open counts, by cell) to the current adequacy level by
8
+ * de-trending the latest diagonal backwards at an annual severity trend,
9
+ * then rebuild adjusted incurred = paid + restated average case x open counts.
10
+ *
11
+ * Settlement-rate: compute disposal rates (closed counts / ultimate counts),
12
+ * take the current settlement pattern from the latest diagonal, and restate
13
+ * historical paid losses by interpolating paid at the disposal-rate-equivalent
14
+ * closed-count level -- the textbook interpolation on (closed count, paid)
15
+ * points within each origin row, not a scalar ratio shortcut.
16
+ */
17
+ function assertSameShape(a, b, what) {
18
+ if (a.origins.length !== b.origins.length ||
19
+ a.ages.length !== b.ages.length ||
20
+ a.origins.some((o, i) => o !== b.origins[i]) ||
21
+ a.ages.some((g, j) => g !== b.ages[j])) {
22
+ throw new ReservingError("SHAPE", `${what} triangles must share origins and ages`);
23
+ }
24
+ }
25
+ /** Last observed row index in a column; -1 when the column is empty. */
26
+ function lastObservedRowInColumn(tri, j) {
27
+ for (let i = tri.origins.length - 1; i >= 0; i--) {
28
+ if (isNum(tri.values[i][j] ?? null))
29
+ return i;
30
+ }
31
+ return -1;
32
+ }
33
+ export function berquistCaseAdequacy(paid, incurred, openCounts, options = {}) {
34
+ assertSameShape(paid, incurred, "Paid and incurred");
35
+ assertSameShape(paid, openCounts, "Paid and open-count");
36
+ const nOrigins = paid.origins.length;
37
+ const nAges = paid.ages.length;
38
+ const warnings = [];
39
+ const periodYears = (paid.ages[0] ?? 12) / 12;
40
+ // Average open case reserve per open claim, by cell.
41
+ const averageCaseReserves = [];
42
+ for (let i = 0; i < nOrigins; i++) {
43
+ const row = [];
44
+ for (let j = 0; j < nAges; j++) {
45
+ const inc = incurred.values[i][j] ?? null;
46
+ const pd = paid.values[i][j] ?? null;
47
+ const open = openCounts.values[i][j] ?? null;
48
+ const caseAmt = isNum(inc) && isNum(pd) ? inc - pd : null;
49
+ row.push(safeRatio(caseAmt, open));
50
+ }
51
+ averageCaseReserves.push(row);
52
+ }
53
+ // Severity trend: user override, else fitted from ln(average case) regressed
54
+ // on origin index within each column, combined as a point-weighted average.
55
+ let severityTrend;
56
+ let trendSource;
57
+ if (options.severityTrend !== undefined) {
58
+ severityTrend = options.severityTrend;
59
+ trendSource = "user";
60
+ }
61
+ else {
62
+ let weighted = 0;
63
+ let weight = 0;
64
+ for (let j = 0; j < nAges; j++) {
65
+ const xs = [];
66
+ const ys = [];
67
+ for (let i = 0; i < nOrigins; i++) {
68
+ const v = averageCaseReserves[i][j] ?? null;
69
+ if (isNum(v) && v > 0) {
70
+ xs.push(i);
71
+ ys.push(Math.log(v));
72
+ }
73
+ }
74
+ if (xs.length >= 3) {
75
+ const fit = ols(xs, ys);
76
+ if (fit) {
77
+ const annualTrend = Math.exp(fit.slope / periodYears) - 1;
78
+ weighted += annualTrend * fit.n;
79
+ weight += fit.n;
80
+ }
81
+ }
82
+ }
83
+ if (weight > 0) {
84
+ severityTrend = weighted / weight;
85
+ trendSource = "fitted";
86
+ }
87
+ else {
88
+ severityTrend = 0;
89
+ trendSource = "fitted";
90
+ warnings.push("Could not fit a severity trend from the data (too few open-claim cells); used 0% -- supply a trend explicitly");
91
+ }
92
+ }
93
+ if (severityTrend <= -1) {
94
+ throw new ReservingError("BAD_TREND", "Severity trend must be greater than -100%");
95
+ }
96
+ // Restate: de-trend each column's latest-diagonal average case backwards.
97
+ const restated = averageCaseReserves.map((r) => r.map(() => null));
98
+ for (let j = 0; j < nAges; j++) {
99
+ const diagRow = lastObservedRowInColumn(openCounts, j);
100
+ if (diagRow < 0)
101
+ continue;
102
+ const diagAvg = averageCaseReserves[diagRow][j] ?? null;
103
+ for (let i = 0; i <= diagRow; i++) {
104
+ if (!isNum(openCounts.values[i][j] ?? null))
105
+ continue;
106
+ if (!isNum(diagAvg)) {
107
+ // No open claims on the diagonal for this maturity; keep the actual value.
108
+ restated[i][j] = averageCaseReserves[i][j] ?? null;
109
+ continue;
110
+ }
111
+ const yearsBack = (diagRow - i) * periodYears;
112
+ restated[i][j] = diagAvg / Math.pow(1 + severityTrend, yearsBack);
113
+ }
114
+ }
115
+ // Adjusted incurred = paid + restated average case x open counts.
116
+ const adjustedValues = [];
117
+ let fallbackCells = 0;
118
+ for (let i = 0; i < nOrigins; i++) {
119
+ const row = [];
120
+ for (let j = 0; j < nAges; j++) {
121
+ const pd = paid.values[i][j] ?? null;
122
+ const open = openCounts.values[i][j] ?? null;
123
+ if (!isNum(pd) || !isNum(open)) {
124
+ row.push(null);
125
+ continue;
126
+ }
127
+ if (open === 0) {
128
+ row.push(pd);
129
+ continue;
130
+ }
131
+ const avg = restated[i][j] ?? null;
132
+ if (!isNum(avg)) {
133
+ row.push(incurred.values[i][j] ?? null);
134
+ fallbackCells++;
135
+ continue;
136
+ }
137
+ row.push(pd + avg * open);
138
+ }
139
+ adjustedValues.push(row);
140
+ }
141
+ if (fallbackCells > 0) {
142
+ warnings.push(`${fallbackCells} cell(s) kept their unadjusted incurred value because no diagonal average case reserve was available at that maturity`);
143
+ }
144
+ return {
145
+ averageCaseReserves,
146
+ severityTrend,
147
+ trendSource,
148
+ restatedAverageCaseReserves: restated,
149
+ adjustedIncurred: {
150
+ kind: "incurred",
151
+ origins: [...paid.origins],
152
+ ages: [...paid.ages],
153
+ values: adjustedValues,
154
+ },
155
+ warnings,
156
+ };
157
+ }
158
+ function interpolate(points, x, mode, warnings, cellLabel) {
159
+ if (points.length === 0)
160
+ return null;
161
+ // Exact hit keeps the actual value.
162
+ for (const p of points) {
163
+ if (Math.abs(p.x - x) < 1e-9)
164
+ return p.y;
165
+ }
166
+ let lower = null;
167
+ let upper = null;
168
+ for (const p of points) {
169
+ if (p.x < x && (!lower || p.x > lower.x))
170
+ lower = p;
171
+ if (p.x > x && (!upper || p.x < upper.x))
172
+ upper = p;
173
+ }
174
+ if (lower && upper) {
175
+ return interpolateSegment(lower, upper, x, mode);
176
+ }
177
+ if (!lower && upper) {
178
+ // Below every observed point: anchor at the origin (0 closed, 0 paid).
179
+ return interpolateSegment({ x: 0, y: 0 }, upper, x, mode);
180
+ }
181
+ if (lower && !upper) {
182
+ // Above every observed point: extrapolate from the last segment.
183
+ const below = points.filter((p) => p.x < lower.x);
184
+ const prev = below.length > 0 ? below[below.length - 1] : { x: 0, y: 0 };
185
+ warnings.push(`Adjusted closed counts at ${cellLabel} exceed every observed count in that origin row; paid was extrapolated beyond the data`);
186
+ return interpolateSegment(prev, lower, x, mode);
187
+ }
188
+ return null;
189
+ }
190
+ function interpolateSegment(p1, p2, x, mode) {
191
+ if (p2.x === p1.x)
192
+ return p1.y;
193
+ if (mode === "exponential" && p1.y > 0 && p2.y > 0) {
194
+ // y = a * e^(b x) through both points (log-linear in paid).
195
+ const b = Math.log(p2.y / p1.y) / (p2.x - p1.x);
196
+ const a = p1.y * Math.exp(-b * p1.x);
197
+ return a * Math.exp(b * x);
198
+ }
199
+ // Linear (also the fallback when a zero paid value makes exponential undefined).
200
+ return p1.y + ((p2.y - p1.y) * (x - p1.x)) / (p2.x - p1.x);
201
+ }
202
+ export function berquistSettlement(paid, closedCounts, options) {
203
+ assertSameShape(paid, closedCounts, "Paid and closed-count");
204
+ const { ultimateCounts } = options;
205
+ const interpolation = options.interpolation ?? "exponential";
206
+ const nOrigins = paid.origins.length;
207
+ const nAges = paid.ages.length;
208
+ if (ultimateCounts.length !== nOrigins) {
209
+ throw new ReservingError("SHAPE", `Expected ${nOrigins} ultimate claim counts (one per origin), got ${ultimateCounts.length}`);
210
+ }
211
+ const warnings = [];
212
+ // Disposal rates = closed counts / ultimate counts.
213
+ const disposalRates = [];
214
+ for (let i = 0; i < nOrigins; i++) {
215
+ const ult = ultimateCounts[i];
216
+ const row = [];
217
+ for (let j = 0; j < nAges; j++) {
218
+ row.push(safeRatio(closedCounts.values[i][j] ?? null, ult > 0 ? ult : null));
219
+ }
220
+ disposalRates.push(row);
221
+ }
222
+ // Current settlement pattern: disposal rates along the latest diagonal.
223
+ const selectedDisposalRates = [];
224
+ for (let j = 0; j < nAges; j++) {
225
+ const diagRow = lastObservedRowInColumn(closedCounts, j);
226
+ selectedDisposalRates.push(diagRow >= 0 ? (disposalRates[diagRow][j] ?? null) : null);
227
+ }
228
+ // Restated closed counts at the current settlement pattern.
229
+ const adjustedClosedCounts = [];
230
+ for (let i = 0; i < nOrigins; i++) {
231
+ const ult = ultimateCounts[i];
232
+ const row = [];
233
+ for (let j = 0; j < nAges; j++) {
234
+ const observed = isNum(closedCounts.values[i][j] ?? null);
235
+ const sel = selectedDisposalRates[j] ?? null;
236
+ row.push(observed && isNum(sel) && ult > 0 ? sel * ult : null);
237
+ }
238
+ adjustedClosedCounts.push(row);
239
+ }
240
+ // Interpolate adjusted paid within each origin row on (closed, paid) points.
241
+ const adjustedValues = [];
242
+ for (let i = 0; i < nOrigins; i++) {
243
+ const points = [];
244
+ for (let j = 0; j < nAges; j++) {
245
+ const c = closedCounts.values[i][j] ?? null;
246
+ const p = paid.values[i][j] ?? null;
247
+ if (isNum(c) && isNum(p))
248
+ points.push({ x: c, y: p });
249
+ }
250
+ points.sort((a, b) => a.x - b.x);
251
+ // Collapse duplicate closed counts, keeping the latest evaluation's paid
252
+ // (points sort stably by closed count, so for equal counts the later
253
+ // development age comes last; taking its value also handles the rare
254
+ // decreasing-paid case, e.g. recoveries).
255
+ const dedup = [];
256
+ for (const p of points) {
257
+ const last = dedup[dedup.length - 1];
258
+ if (last && Math.abs(last.x - p.x) < 1e-9)
259
+ last.y = p.y;
260
+ else
261
+ dedup.push({ ...p });
262
+ }
263
+ const row = [];
264
+ for (let j = 0; j < nAges; j++) {
265
+ const target = adjustedClosedCounts[i][j] ?? null;
266
+ const actualPaid = paid.values[i][j] ?? null;
267
+ if (!isNum(target) || !isNum(actualPaid)) {
268
+ row.push(actualPaid);
269
+ continue;
270
+ }
271
+ const label = `${paid.origins[i]} @ ${paid.ages[j]}mo`;
272
+ const y = interpolate(dedup, target, interpolation, warnings, label);
273
+ row.push(isNum(y) ? Math.max(0, y) : actualPaid);
274
+ }
275
+ adjustedValues.push(row);
276
+ }
277
+ return {
278
+ disposalRates,
279
+ selectedDisposalRates,
280
+ ultimateCounts: [...ultimateCounts],
281
+ adjustedClosedCounts,
282
+ interpolation,
283
+ adjustedPaid: {
284
+ kind: "paid",
285
+ origins: [...paid.origins],
286
+ ages: [...paid.ages],
287
+ values: adjustedValues,
288
+ },
289
+ warnings,
290
+ };
291
+ }
292
+ //# sourceMappingURL=berquist.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"berquist.js","sourceRoot":"","sources":["../src/berquist.ts"],"names":[],"mappings":"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"}
package/dist/bf.d.ts ADDED
@@ -0,0 +1,23 @@
1
+ import type { BornhuetterFergusonResult, ChainLadderResult, ExposureRecord, Triangle } from "./types.js";
2
+ /**
3
+ * Bornhuetter-Ferguson method.
4
+ *
5
+ * Ground truth:
6
+ * - Expected ultimate = a-priori loss ratio x earned premium.
7
+ * - BF ultimate = actual to date + expected ultimate x (1 - 1/CDF).
8
+ *
9
+ * A-priori selection: by default, derived from the chain ladder ultimates of
10
+ * mature origin periods (percent developed >= maturityThreshold), as the
11
+ * premium-weighted loss ratio across those periods. The user (or the advisor)
12
+ * can override with an explicit loss ratio, globally or per origin.
13
+ */
14
+ export interface BfOptions {
15
+ /** Global a-priori loss ratio override. */
16
+ aprioriLossRatio?: number;
17
+ /** Per-origin a-priori overrides (take precedence over the global value). */
18
+ aprioriByOrigin?: Record<string, number>;
19
+ /** Percent-developed cutoff for "mature" periods used to derive the default a-priori. */
20
+ maturityThreshold?: number;
21
+ }
22
+ export declare function runBornhuetterFerguson(tri: Triangle, chainLadder: ChainLadderResult, exposures: ExposureRecord[], options?: BfOptions): BornhuetterFergusonResult;
23
+ //# sourceMappingURL=bf.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bf.d.ts","sourceRoot":"","sources":["../src/bf.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,yBAAyB,EAEzB,iBAAiB,EACjB,cAAc,EACd,QAAQ,EACT,MAAM,YAAY,CAAC;AAIpB;;;;;;;;;;;GAWG;AACH,MAAM,WAAW,SAAS;IACxB,2CAA2C;IAC3C,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,6EAA6E;IAC7E,eAAe,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACzC,yFAAyF;IACzF,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED,wBAAgB,sBAAsB,CACpC,GAAG,EAAE,QAAQ,EACb,WAAW,EAAE,iBAAiB,EAC9B,SAAS,EAAE,cAAc,EAAE,EAC3B,OAAO,GAAE,SAAc,GACtB,yBAAyB,CA4F3B"}
package/dist/bf.js ADDED
@@ -0,0 +1,83 @@
1
+ import { ReservingError } from "./types.js";
2
+ import { isNum, lastObservedIndex } from "./util.js";
3
+ export function runBornhuetterFerguson(tri, chainLadder, exposures, options = {}) {
4
+ const warnings = [];
5
+ const maturityThreshold = options.maturityThreshold ?? 0.9;
6
+ const premiumByOrigin = new Map(exposures.map((e) => [e.origin, e.earnedPremium]));
7
+ // Default a-priori: premium-weighted CL loss ratio across mature periods.
8
+ let derivedApriori = null;
9
+ {
10
+ let lossSum = 0;
11
+ let premSum = 0;
12
+ for (const row of chainLadder.rows) {
13
+ const prem = premiumByOrigin.get(row.origin);
14
+ if (!isNum(prem ?? null) || prem <= 0)
15
+ continue;
16
+ if (row.percentDeveloped >= maturityThreshold) {
17
+ lossSum += row.ultimate;
18
+ premSum += prem;
19
+ }
20
+ }
21
+ if (premSum > 0)
22
+ derivedApriori = lossSum / premSum;
23
+ }
24
+ if (derivedApriori === null && options.aprioriLossRatio === undefined) {
25
+ // Fall back to all periods when nothing is mature enough.
26
+ let lossSum = 0;
27
+ let premSum = 0;
28
+ for (const row of chainLadder.rows) {
29
+ const prem = premiumByOrigin.get(row.origin);
30
+ if (!isNum(prem ?? null) || prem <= 0)
31
+ continue;
32
+ lossSum += row.ultimate;
33
+ premSum += prem;
34
+ }
35
+ if (premSum > 0) {
36
+ derivedApriori = lossSum / premSum;
37
+ warnings.push("No origin period is mature enough to anchor the a-priori; derived it from all periods' chain ladder ultimates instead");
38
+ }
39
+ }
40
+ const clByOrigin = new Map(chainLadder.rows.map((r) => [r.origin, r]));
41
+ const rows = [];
42
+ for (let i = 0; i < tri.origins.length; i++) {
43
+ const origin = tri.origins[i];
44
+ const cl = clByOrigin.get(origin);
45
+ if (!cl)
46
+ continue;
47
+ const latestIdx = lastObservedIndex(tri.values[i]);
48
+ const latestValue = latestIdx >= 0 ? tri.values[i][latestIdx] : 0;
49
+ const prem = premiumByOrigin.get(origin) ?? null;
50
+ if (!isNum(prem) || prem <= 0) {
51
+ warnings.push(`Origin ${origin} has no usable earned premium; excluded from BF`);
52
+ continue;
53
+ }
54
+ const apriori = options.aprioriByOrigin?.[origin] ?? options.aprioriLossRatio ?? derivedApriori;
55
+ if (!isNum(apriori ?? null)) {
56
+ throw new ReservingError("NO_APRIORI", "Cannot derive an a-priori loss ratio (no exposure data matched the triangle origins) and no override was supplied");
57
+ }
58
+ const expectedUltimate = apriori * prem;
59
+ const expectedUnreported = expectedUltimate * (1 - 1 / cl.cdf);
60
+ const ultimate = latestValue + expectedUnreported;
61
+ rows.push({
62
+ origin,
63
+ latestValue,
64
+ cdf: cl.cdf,
65
+ aprioriLossRatio: apriori,
66
+ earnedPremium: prem,
67
+ expectedUltimate,
68
+ expectedUnreported,
69
+ ultimate,
70
+ unpaid: ultimate - latestValue,
71
+ });
72
+ }
73
+ if (rows.length === 0) {
74
+ throw new ReservingError("NO_BF_ROWS", "Bornhuetter-Ferguson produced no rows; check that exposure origins match the triangle origins");
75
+ }
76
+ const totals = rows.reduce((acc, r) => ({
77
+ latest: acc.latest + r.latestValue,
78
+ ultimate: acc.ultimate + r.ultimate,
79
+ unpaid: acc.unpaid + r.unpaid,
80
+ }), { latest: 0, ultimate: 0, unpaid: 0 });
81
+ return { method: "bornhuetterFerguson", basis: tri.kind, rows, totals, warnings };
82
+ }
83
+ //# sourceMappingURL=bf.js.map
package/dist/bf.js.map ADDED
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bf.js","sourceRoot":"","sources":["../src/bf.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAC5C,OAAO,EAAE,KAAK,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAC;AAuBrD,MAAM,UAAU,sBAAsB,CACpC,GAAa,EACb,WAA8B,EAC9B,SAA2B,EAC3B,UAAqB,EAAE;IAEvB,MAAM,QAAQ,GAAa,EAAE,CAAC;IAC9B,MAAM,iBAAiB,GAAG,OAAO,CAAC,iBAAiB,IAAI,GAAG,CAAC;IAC3D,MAAM,eAAe,GAAG,IAAI,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC;IAEnF,0EAA0E;IAC1E,IAAI,cAAc,GAAkB,IAAI,CAAC;IACzC,CAAC;QACC,IAAI,OAAO,GAAG,CAAC,CAAC;QAChB,IAAI,OAAO,GAAG,CAAC,CAAC;QAChB,KAAK,MAAM,GAAG,IAAI,WAAW,CAAC,IAAI,EAAE,CAAC;YACnC,MAAM,IAAI,GAAG,eAAe,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;YAC7C,IAAI,CAAC,KAAK,CAAC,IAAI,IAAI,IAAI,CAAC,IAAI,IAAK,IAAI,CAAC;gBAAE,SAAS;YACjD,IAAI,GAAG,CAAC,gBAAgB,IAAI,iBAAiB,EAAE,CAAC;gBAC9C,OAAO,IAAI,GAAG,CAAC,QAAQ,CAAC;gBACxB,OAAO,IAAI,IAAK,CAAC;YACnB,CAAC;QACH,CAAC;QACD,IAAI,OAAO,GAAG,CAAC;YAAE,cAAc,GAAG,OAAO,GAAG,OAAO,CAAC;IACtD,CAAC;IACD,IAAI,cAAc,KAAK,IAAI,IAAI,OAAO,CAAC,gBAAgB,KAAK,SAAS,EAAE,CAAC;QACtE,0DAA0D;QAC1D,IAAI,OAAO,GAAG,CAAC,CAAC;QAChB,IAAI,OAAO,GAAG,CAAC,CAAC;QAChB,KAAK,MAAM,GAAG,IAAI,WAAW,CAAC,IAAI,EAAE,CAAC;YACnC,MAAM,IAAI,GAAG,eAAe,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;YAC7C,IAAI,CAAC,KAAK,CAAC,IAAI,IAAI,IAAI,CAAC,IAAI,IAAK,IAAI,CAAC;gBAAE,SAAS;YACjD,OAAO,IAAI,GAAG,CAAC,QAAQ,CAAC;YACxB,OAAO,IAAI,IAAK,CAAC;QACnB,CAAC;QACD,IAAI,OAAO,GAAG,CAAC,EAAE,CAAC;YAChB,cAAc,GAAG,OAAO,GAAG,OAAO,CAAC;YACnC,QAAQ,CAAC,IAAI,CACX,uHAAuH,CACxH,CAAC;QACJ,CAAC;IACH,CAAC;IAED,MAAM,UAAU,GAAG,IAAI,GAAG,CAAC,WAAW,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;IACvE,MAAM,IAAI,GAA6B,EAAE,CAAC;IAC1C,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QAC5C,MAAM,MAAM,GAAG,GAAG,CAAC,OAAO,CAAC,CAAC,CAAE,CAAC;QAC/B,MAAM,EAAE,GAAG,UAAU,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QAClC,IAAI,CAAC,EAAE;YAAE,SAAS;QAClB,MAAM,SAAS,GAAG,iBAAiB,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAE,CAAC,CAAC;QACpD,MAAM,WAAW,GAAG,SAAS,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAE,CAAC,SAAS,CAAE,CAAC,CAAC,CAAC,CAAC,CAAC;QACpE,MAAM,IAAI,GAAG,eAAe,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,IAAI,CAAC;QACjD,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,EAAE,CAAC;YAC9B,QAAQ,CAAC,IAAI,CAAC,UAAU,MAAM,iDAAiD,CAAC,CAAC;YACjF,SAAS;QACX,CAAC;QACD,MAAM,OAAO,GACX,OAAO,CAAC,eAAe,EAAE,CAAC,MAAM,CAAC,IAAI,OAAO,CAAC,gBAAgB,IAAI,cAAc,CAAC;QAClF,IAAI,CAAC,KAAK,CAAC,OAAO,IAAI,IAAI,CAAC,EAAE,CAAC;YAC5B,MAAM,IAAI,cAAc,CACtB,YAAY,EACZ,mHAAmH,CACpH,CAAC;QACJ,CAAC;QACD,MAAM,gBAAgB,GAAG,OAAQ,GAAG,IAAI,CAAC;QACzC,MAAM,kBAAkB,GAAG,gBAAgB,GAAG,CAAC,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC;QAC/D,MAAM,QAAQ,GAAG,WAAW,GAAG,kBAAkB,CAAC;QAClD,IAAI,CAAC,IAAI,CAAC;YACR,MAAM;YACN,WAAW;YACX,GAAG,EAAE,EAAE,CAAC,GAAG;YACX,gBAAgB,EAAE,OAAQ;YAC1B,aAAa,EAAE,IAAI;YACnB,gBAAgB;YAChB,kBAAkB;YAClB,QAAQ;YACR,MAAM,EAAE,QAAQ,GAAG,WAAW;SAC/B,CAAC,CAAC;IACL,CAAC;IAED,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACtB,MAAM,IAAI,cAAc,CACtB,YAAY,EACZ,+FAA+F,CAChG,CAAC;IACJ,CAAC;IAED,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CACxB,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC;QACX,MAAM,EAAE,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC,WAAW;QAClC,QAAQ,EAAE,GAAG,CAAC,QAAQ,GAAG,CAAC,CAAC,QAAQ;QACnC,MAAM,EAAE,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC,MAAM;KAC9B,CAAC,EACF,EAAE,MAAM,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,CACtC,CAAC;IAEF,OAAO,EAAE,MAAM,EAAE,qBAAqB,EAAE,KAAK,EAAE,GAAG,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC;AACpF,CAAC"}
@@ -0,0 +1,96 @@
1
+ import type { ClaimSnapshot } from "./types.js";
2
+ /**
3
+ * Claim-level loss capping: the foundation of developing a reliable layer.
4
+ *
5
+ * Large losses are volatile and distort development patterns; capping every
6
+ * claim at a per-occurrence limit and developing the capped ("limited")
7
+ * triangles gives stable factors. The excess layer is restored later via
8
+ * increased-limits factors, applied to the developed capped ultimates.
9
+ *
10
+ * The cap can be INDEXED: stated at a base-year cost level and moved by an
11
+ * annual rate so the layer stays constant in real terms across origin years
12
+ * (a flat $250k cap in 2016 is a deeper real layer than in 2025). indexRate 0
13
+ * reproduces the flat-cap convention.
14
+ */
15
+ export interface CapOptions {
16
+ /** Per-occurrence cap, stated at the baseYear cost level. */
17
+ cap: number;
18
+ /** Annual index rate moving the cap across accident years (0 = flat cap). */
19
+ indexRate?: number;
20
+ /**
21
+ * Accident year at whose cost level `cap` is stated. Defaults to the latest
22
+ * accident year present in the data.
23
+ */
24
+ baseYear?: number;
25
+ }
26
+ /**
27
+ * The default base year for a cap index: the latest accident year with a
28
+ * snapshot evaluated on or before asOfDate. capClaims and
29
+ * claimSizeDiagnostics MUST resolve this identically, or the applied caps
30
+ * diverge from what the exhibits report; services should resolve it once via
31
+ * this helper and pass baseYear explicitly to both.
32
+ */
33
+ export declare function latestAccidentYear(claims: ClaimSnapshot[], asOfDate?: string): number;
34
+ /** The effective cap for one accident year under the index. */
35
+ export declare function effectiveCap(options: Required<CapOptions>, year: number): number;
36
+ /**
37
+ * Caps every snapshot at the (indexed) per-occurrence limit for its accident
38
+ * year: capped incurred = min(reported incurred, cap_y); capped paid =
39
+ * min(paid, cap_y); capped case = capped incurred - capped paid (never
40
+ * negative by construction). Claim counts and statuses are untouched - the
41
+ * cap limits dollars, not claims.
42
+ */
43
+ export declare function capClaims(claims: ClaimSnapshot[], options: CapOptions): ClaimSnapshot[];
44
+ export interface ClaimSizeYearRow {
45
+ year: number;
46
+ claimCount: number;
47
+ /** Reported incurred at each claim's latest evaluation. */
48
+ totalIncurred: number;
49
+ maxClaim: number;
50
+ percentiles: {
51
+ p: number;
52
+ value: number;
53
+ }[];
54
+ }
55
+ export interface CapCandidateYearCell {
56
+ year: number;
57
+ /** The candidate cap at this year's cost level (indexed). */
58
+ effectiveCap: number;
59
+ /** Claims whose reported incurred pierces the effective cap. */
60
+ pierceCount: number;
61
+ pierceShare: number;
62
+ /** Dollars above the cap as a share of total reported incurred. */
63
+ excessShare: number;
64
+ }
65
+ export interface CapCandidate {
66
+ /** Candidate cap stated at the base-year cost level. */
67
+ cap: number;
68
+ byYear: CapCandidateYearCell[];
69
+ totalPierceCount: number;
70
+ totalPierceShare: number;
71
+ totalExcessShare: number;
72
+ }
73
+ export interface ClaimSizeDiagnostics {
74
+ years: ClaimSizeYearRow[];
75
+ candidates: CapCandidate[];
76
+ baseYear: number;
77
+ indexRate: number;
78
+ /** Claims with a positive reported incurred at their latest evaluation. */
79
+ nonZeroClaimCount: number;
80
+ }
81
+ export interface ClaimSizeDiagnosticsOptions {
82
+ /** Only snapshots evaluated on or before this ISO date are considered. */
83
+ asOfDate?: string;
84
+ /** Candidate caps stated at the base-year level; sensible defaults derived if omitted. */
85
+ candidateCaps?: number[];
86
+ /** Caps merged into the derived defaults (e.g. the currently-set cap). */
87
+ extraCaps?: number[];
88
+ indexRate?: number;
89
+ baseYear?: number;
90
+ }
91
+ /**
92
+ * Latest-evaluation claim-size distribution by accident year plus pierce and
93
+ * excess-share statistics for a set of candidate caps (indexed to each year).
94
+ */
95
+ export declare function claimSizeDiagnostics(claims: ClaimSnapshot[], options?: ClaimSizeDiagnosticsOptions): ClaimSizeDiagnostics;
96
+ //# sourceMappingURL=capping.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"capping.d.ts","sourceRoot":"","sources":["../src/capping.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAIhD;;;;;;;;;;;;GAYG;AAEH,MAAM,WAAW,UAAU;IACzB,6DAA6D;IAC7D,GAAG,EAAE,MAAM,CAAC;IACZ,6EAA6E;IAC7E,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAMD;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,aAAa,EAAE,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,CAcrF;AAED,+DAA+D;AAC/D,wBAAgB,YAAY,CAAC,OAAO,EAAE,QAAQ,CAAC,UAAU,CAAC,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAEhF;AAqBD;;;;;;GAMG;AACH,wBAAgB,SAAS,CAAC,MAAM,EAAE,aAAa,EAAE,EAAE,OAAO,EAAE,UAAU,GAAG,aAAa,EAAE,CAcvF;AAKD,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;IACnB,2DAA2D;IAC3D,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE;QAAE,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;CAC7C;AAED,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,MAAM,CAAC;IACb,6DAA6D;IAC7D,YAAY,EAAE,MAAM,CAAC;IACrB,gEAAgE;IAChE,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,mEAAmE;IACnE,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,YAAY;IAC3B,wDAAwD;IACxD,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,oBAAoB,EAAE,CAAC;IAC/B,gBAAgB,EAAE,MAAM,CAAC;IACzB,gBAAgB,EAAE,MAAM,CAAC;IACzB,gBAAgB,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,oBAAoB;IACnC,KAAK,EAAE,gBAAgB,EAAE,CAAC;IAC1B,UAAU,EAAE,YAAY,EAAE,CAAC;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,2EAA2E;IAC3E,iBAAiB,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,2BAA2B;IAC1C,0EAA0E;IAC1E,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,0FAA0F;IAC1F,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;IACzB,0EAA0E;IAC1E,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAsBD;;;GAGG;AACH,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,aAAa,EAAE,EACvB,OAAO,GAAE,2BAAgC,GACxC,oBAAoB,CA+GtB"}