@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 @@
1
+ {"version":3,"file":"factors.js","sourceRoot":"","sources":["../src/factors.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,92 @@
1
+ import type { Triangle } from "./types.js";
2
+ /**
3
+ * Fisher-Lange disposal-rate (average-cost-per-claim-settled) method: the
4
+ * reserve is future settlements x trended severity, cell by cell.
5
+ *
6
+ * Ground truth:
7
+ * - Disposal rates d[i][j] = incremental CLOSED counts / SUPPLIED ultimate
8
+ * counts (the ultimates are the caller's independent estimate - e.g. a
9
+ * count chain ladder - never derived here). The rate used per age is the
10
+ * caller's `disposalSelections[j]` or, by default, the latest observed
11
+ * diagonal rate for that age.
12
+ * - Future closed counts for origin i at a future age j = ultimateCounts[i]
13
+ * x selected d[j].
14
+ * - Severities by settlement age: incremental paid / incremental closed per
15
+ * cell. The selected severity for age j is the closed-count-weighted
16
+ * average of the observed cell severities, each trended FROM its cell's
17
+ * calendar period TO the latest observed diagonal (the internal
18
+ * reference).
19
+ * - Reserve = sum over future cells of counts x severity trended to that
20
+ * cell's calendar period.
21
+ *
22
+ * Severity trend convention (compounds by CALENDAR distance): a cell's
23
+ * calendar position is originIndex x ageStep + age (months), where the
24
+ * origin cadence is inferred from the (required equal) development-age
25
+ * spacing. A severity moved y calendar years is multiplied by
26
+ * (1 + severityTrend)^y, fractional years allowed (quarterly triangles
27
+ * compound by quarter-year fractions). Because every observed severity is
28
+ * trended to one reference and then forward to each future cell, the
29
+ * projection is invariant to the reference choice; `targetYear` only shifts
30
+ * the calendar year the DISPLAYED selectedSeverities are stated at.
31
+ *
32
+ * Projection zeros are loud, never silent: an age with no selectable
33
+ * disposal rate projects zero closures with a warning, and a needed age
34
+ * with no observable severity projects zero payment with a warning (the
35
+ * "sparse cell" warnings).
36
+ */
37
+ export interface FisherLangeOptions {
38
+ /**
39
+ * Selected disposal rate per development age (length = ages.length);
40
+ * null falls back to the latest observed diagonal rate for that age.
41
+ */
42
+ disposalSelections?: (number | null)[];
43
+ /** Annual severity trend (e.g. 0.05 = +5%/calendar year). */
44
+ severityTrend: number;
45
+ /**
46
+ * Calendar year the displayed selectedSeverities are stated at (default:
47
+ * the latest diagonal's year). Display only - the reserve is invariant.
48
+ * Requires an annual triangle (12-month spacing, first age 12) with
49
+ * numeric origin labels; otherwise ignored with a warning.
50
+ */
51
+ targetYear?: number;
52
+ }
53
+ export interface FisherLangeRow {
54
+ origin: string;
55
+ /** Age (months) of the latest cell observed in BOTH triangles. */
56
+ latestAge: number;
57
+ paidToDate: number;
58
+ closedToDate: number;
59
+ ultimateCounts: number;
60
+ /** Future closed counts per remaining age column (after latestAge). */
61
+ futureClosedCounts: number[];
62
+ /**
63
+ * Trended severity applied per remaining age column; null where no
64
+ * severity was observable (that cell projected zero payment, warned).
65
+ */
66
+ futureSeverities: (number | null)[];
67
+ unpaid: number;
68
+ ultimate: number;
69
+ }
70
+ export interface FisherLangeResult {
71
+ method: "fisherLange";
72
+ /** Historical incremental severities (paid / closed) per cell. */
73
+ severities: (number | null)[][];
74
+ /** Historical disposal rates (incremental closed / ultimate counts). */
75
+ disposalRates: (number | null)[][];
76
+ /** Disposal rate used per age (caller's selection or diagonal default). */
77
+ selectedDisposalRates: (number | null)[];
78
+ /** Selected severity per age, stated at referenceYear (display only). */
79
+ selectedSeverities: (number | null)[];
80
+ /** Calendar year selectedSeverities are stated at; null when origin labels don't parse. */
81
+ referenceYear: number | null;
82
+ ultimateCounts: number[];
83
+ rows: FisherLangeRow[];
84
+ totals: {
85
+ paidToDate: number;
86
+ unpaid: number;
87
+ ultimate: number;
88
+ };
89
+ warnings: string[];
90
+ }
91
+ export declare function runFisherLange(paid: Triangle, closedCounts: Triangle, ultimateCounts: number[], options: FisherLangeOptions): FisherLangeResult;
92
+ //# sourceMappingURL=fisherLange.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fisherLange.d.ts","sourceRoot":"","sources":["../src/fisherLange.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAK3C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AAEH,MAAM,WAAW,kBAAkB;IACjC;;;OAGG;IACH,kBAAkB,CAAC,EAAE,CAAC,MAAM,GAAG,IAAI,CAAC,EAAE,CAAC;IACvC,6DAA6D;IAC7D,aAAa,EAAE,MAAM,CAAC;IACtB;;;;;OAKG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,kEAAkE;IAClE,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,cAAc,EAAE,MAAM,CAAC;IACvB,uEAAuE;IACvE,kBAAkB,EAAE,MAAM,EAAE,CAAC;IAC7B;;;OAGG;IACH,gBAAgB,EAAE,CAAC,MAAM,GAAG,IAAI,CAAC,EAAE,CAAC;IACpC,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,aAAa,CAAC;IACtB,kEAAkE;IAClE,UAAU,EAAE,CAAC,MAAM,GAAG,IAAI,CAAC,EAAE,EAAE,CAAC;IAChC,wEAAwE;IACxE,aAAa,EAAE,CAAC,MAAM,GAAG,IAAI,CAAC,EAAE,EAAE,CAAC;IACnC,2EAA2E;IAC3E,qBAAqB,EAAE,CAAC,MAAM,GAAG,IAAI,CAAC,EAAE,CAAC;IACzC,yEAAyE;IACzE,kBAAkB,EAAE,CAAC,MAAM,GAAG,IAAI,CAAC,EAAE,CAAC;IACtC,2FAA2F;IAC3F,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,IAAI,EAAE,cAAc,EAAE,CAAC;IACvB,MAAM,EAAE;QAAE,UAAU,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC;IACjE,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAcD,wBAAgB,cAAc,CAC5B,IAAI,EAAE,QAAQ,EACd,YAAY,EAAE,QAAQ,EACtB,cAAc,EAAE,MAAM,EAAE,EACxB,OAAO,EAAE,kBAAkB,GAC1B,iBAAiB,CAsQnB"}
@@ -0,0 +1,224 @@
1
+ import { ReservingError } from "./types.js";
2
+ import { cumulativeToIncremental } from "./triangleAlgebra.js";
3
+ import { isNum, lastJointObservedIndex, lastObservedIndex, safeRatio } from "./util.js";
4
+ function assertSameShape(a, b) {
5
+ const sameOrigins = a.origins.length === b.origins.length && a.origins.every((o, i) => o === b.origins[i]);
6
+ const sameAges = a.ages.length === b.ages.length && a.ages.every((v, j) => v === b.ages[j]);
7
+ if (!sameOrigins || !sameAges) {
8
+ throw new ReservingError("SHAPE", "The paid and closed-count triangles must share identical origins and development ages");
9
+ }
10
+ }
11
+ export function runFisherLange(paid, closedCounts, ultimateCounts, options) {
12
+ assertSameShape(paid, closedCounts);
13
+ const nOrigins = paid.origins.length;
14
+ const nAges = paid.ages.length;
15
+ if (nAges < 2) {
16
+ throw new ReservingError("TOO_SMALL", "Fisher-Lange requires at least two development ages");
17
+ }
18
+ const step = paid.ages[1] - paid.ages[0];
19
+ for (let j = 1; j < nAges; j++) {
20
+ if (paid.ages[j] - paid.ages[j - 1] !== step) {
21
+ throw new ReservingError("SHAPE", "Fisher-Lange infers calendar distance from the age step, which requires equally spaced development ages");
22
+ }
23
+ }
24
+ if (ultimateCounts.length !== nOrigins) {
25
+ throw new ReservingError("SHAPE", `Expected ${nOrigins} ultimate claim counts (one per origin), got ${ultimateCounts.length}`);
26
+ }
27
+ ultimateCounts.forEach((u, i) => {
28
+ if (!isNum(u) || u < 0) {
29
+ throw new ReservingError("BAD_COUNTS", `Ultimate counts must be finite and non-negative; origin ${paid.origins[i]} has ${u}`);
30
+ }
31
+ });
32
+ if (!isNum(options.severityTrend) || options.severityTrend <= -1) {
33
+ throw new ReservingError("BAD_TREND", "Severity trend must be greater than -100%");
34
+ }
35
+ if (options.disposalSelections !== undefined && options.disposalSelections.length !== nAges) {
36
+ throw new ReservingError("SELECTION_SHAPE", `Expected ${nAges} disposal-rate selections (one per age), got ${options.disposalSelections.length}`);
37
+ }
38
+ if (options.targetYear !== undefined && !Number.isInteger(options.targetYear)) {
39
+ throw new ReservingError("BAD_DATE", `targetYear must be an integer calendar year, got ${options.targetYear}`);
40
+ }
41
+ const warnings = [];
42
+ const growth = 1 + options.severityTrend;
43
+ const incPaid = cumulativeToIncremental(paid).values;
44
+ const incClosed = cumulativeToIncremental(closedCounts).values;
45
+ const calMonths = (i, j) => i * step + paid.ages[j];
46
+ // Calendar guard: calMonths places origins by array index, which assumes
47
+ // consecutive origin periods. For annual triangles with numeric year
48
+ // labels the assumption is checkable for free - a gap (e.g. 2020, 2023,
49
+ // 2024) silently compresses severity-trend distances, so warn loudly.
50
+ // Quarterly/non-numeric labels stay unchecked (integer label spacing can
51
+ // never equal a quarterly step; the cadence inference is documented above).
52
+ if (step === 12 && paid.origins.every((o) => /^\d+$/.test(o))) {
53
+ for (let i = 1; i < nOrigins; i++) {
54
+ const gap = Number(paid.origins[i]) - Number(paid.origins[i - 1]);
55
+ if (gap !== 1) {
56
+ warnings.push(`Origins ${paid.origins[i - 1]} and ${paid.origins[i]} are ${gap} years apart but are trended as consecutive; with a nonzero severity trend the reserve is misstated - insert explicit null rows for the missing years`);
57
+ }
58
+ }
59
+ }
60
+ // Historical severity and disposal-rate triangles (null-safe by safeRatio).
61
+ const severities = [];
62
+ const disposalRates = [];
63
+ for (let i = 0; i < nOrigins; i++) {
64
+ const ult = ultimateCounts[i];
65
+ severities.push(paid.ages.map((_, j) => safeRatio(incPaid[i][j] ?? null, incClosed[i][j] ?? null)));
66
+ disposalRates.push(paid.ages.map((_, j) => safeRatio(incClosed[i][j] ?? null, ult > 0 ? ult : null)));
67
+ }
68
+ // Reference: the latest observed calendar position across both incremental
69
+ // triangles. All severity statements below are internally at REF.
70
+ let refMonths = -1;
71
+ let refI = -1;
72
+ let refJ = -1;
73
+ for (let i = 0; i < nOrigins; i++) {
74
+ for (let j = 0; j < nAges; j++) {
75
+ if (!isNum(incPaid[i][j] ?? null) && !isNum(incClosed[i][j] ?? null))
76
+ continue;
77
+ const cal = calMonths(i, j);
78
+ if (cal > refMonths) {
79
+ refMonths = cal;
80
+ refI = i;
81
+ refJ = j;
82
+ }
83
+ }
84
+ }
85
+ if (refMonths < 0) {
86
+ throw new ReservingError("NO_DATA", "No observed cells in the paid or closed-count triangles");
87
+ }
88
+ // Selected disposal rate per age: caller's, else latest diagonal.
89
+ const diagonalDisposal = (j) => {
90
+ for (let i = nOrigins - 1; i >= 0; i--) {
91
+ const d = disposalRates[i][j] ?? null;
92
+ if (isNum(d))
93
+ return d;
94
+ }
95
+ return null;
96
+ };
97
+ const selectedDisposalRates = paid.ages.map((age, j) => {
98
+ const caller = options.disposalSelections?.[j] ?? null;
99
+ if (isNum(caller)) {
100
+ if (caller >= 0)
101
+ return caller;
102
+ warnings.push(`Negative disposal-rate selection for age ${age} months; ignored in favor of the latest diagonal rate`);
103
+ }
104
+ return diagonalDisposal(j);
105
+ });
106
+ const disposalSum = selectedDisposalRates.reduce((a, d) => a + (isNum(d) ? d : 0), 0);
107
+ if (Math.abs(disposalSum - 1) > 0.01) {
108
+ warnings.push(`Selected disposal rates sum to ${disposalSum.toFixed(4)} across all ages; ` +
109
+ (disposalSum < 1
110
+ ? "claims closing beyond the last development age are NOT projected"
111
+ : "more closures than ultimate counts are projected - review the pattern"));
112
+ }
113
+ // Selected severity per age at REF: closed-count-weighted average of the
114
+ // observed cell severities, each trended to REF.
115
+ const selectedSevAtRef = paid.ages.map((_, j) => {
116
+ let trendedPaid = 0;
117
+ let closed = 0;
118
+ for (let i = 0; i < nOrigins; i++) {
119
+ if (!isNum(severities[i][j] ?? null))
120
+ continue;
121
+ trendedPaid += incPaid[i][j] * growth ** ((refMonths - calMonths(i, j)) / 12);
122
+ closed += incClosed[i][j];
123
+ }
124
+ return safeRatio(trendedPaid, closed);
125
+ });
126
+ // Projection.
127
+ const warnedNoDisposal = new Set();
128
+ const warnedNoSeverity = new Set();
129
+ const rows = [];
130
+ for (let i = 0; i < nOrigins; i++) {
131
+ const paidRow = paid.values[i];
132
+ const closedRow = closedCounts.values[i];
133
+ const lastPaid = lastObservedIndex(paidRow);
134
+ const lastClosed = lastObservedIndex(closedRow);
135
+ const k = lastJointObservedIndex(paidRow, closedRow);
136
+ if (k < 0) {
137
+ warnings.push(`Origin ${paid.origins[i]} has no age with both paid and closed counts observed; excluded from results`);
138
+ continue;
139
+ }
140
+ if (lastPaid !== lastClosed) {
141
+ warnings.push(`Origin ${paid.origins[i]}: paid and closed-count diagonals end at different ages (${paid.ages[lastPaid]} vs ${paid.ages[lastClosed]}); projected from the latest jointly observed age ${paid.ages[k]}`);
142
+ }
143
+ const futureClosedCounts = [];
144
+ const futureSeverities = [];
145
+ let unpaid = 0;
146
+ for (let j = k + 1; j < nAges; j++) {
147
+ const d = selectedDisposalRates[j];
148
+ if (!isNum(d)) {
149
+ if (!warnedNoDisposal.has(j)) {
150
+ warnedNoDisposal.add(j);
151
+ warnings.push(`No disposal rate is selectable for age ${paid.ages[j]} months (sparse column); future closures there are projected as zero`);
152
+ }
153
+ futureClosedCounts.push(0);
154
+ futureSeverities.push(null);
155
+ continue;
156
+ }
157
+ const counts = ultimateCounts[i] * d;
158
+ futureClosedCounts.push(counts);
159
+ const sevRef = selectedSevAtRef[j];
160
+ if (!isNum(sevRef)) {
161
+ if (counts > 0 && !warnedNoSeverity.has(j)) {
162
+ warnedNoSeverity.add(j);
163
+ warnings.push(`No severity is observable for age ${paid.ages[j]} months (sparse column); payments there are projected as zero`);
164
+ }
165
+ futureSeverities.push(null);
166
+ continue;
167
+ }
168
+ const sev = sevRef * growth ** ((calMonths(i, j) - refMonths) / 12);
169
+ futureSeverities.push(sev);
170
+ unpaid += counts * sev;
171
+ }
172
+ const paidToDate = paidRow[k];
173
+ rows.push({
174
+ origin: paid.origins[i],
175
+ latestAge: paid.ages[k],
176
+ paidToDate,
177
+ closedToDate: closedRow[k],
178
+ ultimateCounts: ultimateCounts[i],
179
+ futureClosedCounts,
180
+ futureSeverities,
181
+ unpaid,
182
+ ultimate: paidToDate + unpaid,
183
+ });
184
+ }
185
+ if (rows.length === 0) {
186
+ throw new ReservingError("NO_DATA", "No origin period has both paid and closed counts observed at any age");
187
+ }
188
+ // Display statement year for the selected severities. Derivable only for
189
+ // annual triangles whose first age is 12 months and whose origin labels
190
+ // are numeric years; the projection above never depends on it.
191
+ let referenceYear = null;
192
+ if (step === 12 && paid.ages[0] === 12 && /^\d+$/.test(paid.origins[refI] ?? "")) {
193
+ referenceYear = Number(paid.origins[refI]) + refJ;
194
+ }
195
+ let displayShiftYears = 0;
196
+ if (options.targetYear !== undefined) {
197
+ if (referenceYear === null) {
198
+ warnings.push("targetYear ignored: stating severities at a calendar year needs an annual triangle (12-month spacing, first age 12) with numeric origin labels");
199
+ }
200
+ else {
201
+ displayShiftYears = options.targetYear - referenceYear;
202
+ referenceYear = options.targetYear;
203
+ }
204
+ }
205
+ const selectedSeverities = selectedSevAtRef.map((s) => isNum(s) ? s * growth ** displayShiftYears : null);
206
+ const totals = rows.reduce((acc, r) => ({
207
+ paidToDate: acc.paidToDate + r.paidToDate,
208
+ unpaid: acc.unpaid + r.unpaid,
209
+ ultimate: acc.ultimate + r.ultimate,
210
+ }), { paidToDate: 0, unpaid: 0, ultimate: 0 });
211
+ return {
212
+ method: "fisherLange",
213
+ severities,
214
+ disposalRates,
215
+ selectedDisposalRates,
216
+ selectedSeverities,
217
+ referenceYear,
218
+ ultimateCounts: [...ultimateCounts],
219
+ rows,
220
+ totals,
221
+ warnings,
222
+ };
223
+ }
224
+ //# sourceMappingURL=fisherLange.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fisherLange.js","sourceRoot":"","sources":["../src/fisherLange.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,57 @@
1
+ import type { TriangleKind, LdfSelections, Triangle } from "./types.js";
2
+ /**
3
+ * Frequency-severity ultimate method (Friedland, "Estimating Unpaid Claims
4
+ * Using Basic Techniques", ch. 11, the development technique applied to
5
+ * claim counts and average values).
6
+ *
7
+ * Ground truth:
8
+ * - Ultimate claims_i = ultimate counts_i x ultimate severity_i.
9
+ * - Ultimate counts: chain ladder on the (reported) count triangle with the
10
+ * caller's selected count LDFs and tail.
11
+ * - Ultimate severity: chain ladder on the average-severity triangle
12
+ * (losses / counts, cell-wise and null-safe) with the caller's selected
13
+ * severity LDFs and tail — developing average values is the standard
14
+ * Friedland treatment.
15
+ * - Selections are the CALLER's judgment on both bases, per the engine-wide
16
+ * rule; this module never picks factors.
17
+ *
18
+ * Caveat the caller must own (doc, not warning): severity here is per
19
+ * REPORTED claim including closed-without-payment; a drifting CWP share
20
+ * masquerades as severity development. Check closure diagnostics before
21
+ * leaning on this method.
22
+ */
23
+ export interface FrequencySeverityOptions {
24
+ /** Selected count LDFs, one per development interval (null = unselected -> 1.000 with a warning). */
25
+ countSelected: LdfSelections["selected"];
26
+ countTailFactor?: number;
27
+ /** Selected severity LDFs on the average-severity triangle. */
28
+ severitySelected: LdfSelections["selected"];
29
+ severityTailFactor?: number;
30
+ }
31
+ export interface FrequencySeverityRow {
32
+ origin: string;
33
+ /** Latest observed value on the LOSS triangle (the dollars basis). */
34
+ latestValue: number;
35
+ ultimateCounts: number;
36
+ ultimateSeverity: number;
37
+ ultimate: number;
38
+ unpaid: number;
39
+ }
40
+ export interface FrequencySeverityResult {
41
+ method: "frequencySeverity";
42
+ basis: TriangleKind;
43
+ rows: FrequencySeverityRow[];
44
+ totals: {
45
+ latest: number;
46
+ ultimate: number;
47
+ unpaid: number;
48
+ };
49
+ warnings: string[];
50
+ }
51
+ /**
52
+ * Average-severity triangle: cell-wise losses / counts. Null-safe: a
53
+ * missing, zero, or negative count yields a null severity cell.
54
+ */
55
+ export declare function severityTriangle(lossTri: Triangle, countTri: Triangle): Triangle;
56
+ export declare function runFrequencySeverity(lossTri: Triangle, countTri: Triangle, options: FrequencySeverityOptions): FrequencySeverityResult;
57
+ //# sourceMappingURL=freqSev.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"freqSev.d.ts","sourceRoot":"","sources":["../src/freqSev.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAKxE;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,MAAM,WAAW,wBAAwB;IACvC,qGAAqG;IACrG,aAAa,EAAE,aAAa,CAAC,UAAU,CAAC,CAAC;IACzC,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,+DAA+D;IAC/D,gBAAgB,EAAE,aAAa,CAAC,UAAU,CAAC,CAAC;IAC5C,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED,MAAM,WAAW,oBAAoB;IACnC,MAAM,EAAE,MAAM,CAAC;IACf,sEAAsE;IACtE,WAAW,EAAE,MAAM,CAAC;IACpB,cAAc,EAAE,MAAM,CAAC;IACvB,gBAAgB,EAAE,MAAM,CAAC;IACzB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,uBAAuB;IACtC,MAAM,EAAE,mBAAmB,CAAC;IAC5B,KAAK,EAAE,YAAY,CAAC;IACpB,IAAI,EAAE,oBAAoB,EAAE,CAAC;IAC7B,MAAM,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;IAC7D,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,GAAG,QAAQ,CAUhF;AAcD,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,QAAQ,EACjB,QAAQ,EAAE,QAAQ,EAClB,OAAO,EAAE,wBAAwB,GAChC,uBAAuB,CAiEzB"}
@@ -0,0 +1,82 @@
1
+ import { ReservingError } from "./types.js";
2
+ import { isNum, lastObservedIndex, safeRatio } from "./util.js";
3
+ import { runChainLadder } from "./chainladder.js";
4
+ /**
5
+ * Average-severity triangle: cell-wise losses / counts. Null-safe: a
6
+ * missing, zero, or negative count yields a null severity cell.
7
+ */
8
+ export function severityTriangle(lossTri, countTri) {
9
+ assertSameShape(lossTri, countTri);
10
+ return {
11
+ kind: lossTri.kind,
12
+ origins: [...lossTri.origins],
13
+ ages: [...lossTri.ages],
14
+ values: lossTri.values.map((row, i) => row.map((loss, j) => safeRatio(loss ?? null, countTri.values[i][j] ?? null))),
15
+ };
16
+ }
17
+ function assertSameShape(a, b) {
18
+ const sameOrigins = a.origins.length === b.origins.length && a.origins.every((o, i) => o === b.origins[i]);
19
+ const sameAges = a.ages.length === b.ages.length && a.ages.every((v, i) => v === b.ages[i]);
20
+ if (!sameOrigins || !sameAges) {
21
+ throw new ReservingError("SHAPE", "The loss and count triangles must share identical origins and development ages");
22
+ }
23
+ }
24
+ export function runFrequencySeverity(lossTri, countTri, options) {
25
+ assertSameShape(lossTri, countTri);
26
+ const warnings = [];
27
+ const countCl = runChainLadder(countTri, {
28
+ selected: options.countSelected,
29
+ tailFactor: options.countTailFactor ?? 1,
30
+ });
31
+ for (const w of countCl.warnings)
32
+ warnings.push(`counts: ${w}`);
33
+ const sevTri = severityTriangle(lossTri, countTri);
34
+ const sevCl = runChainLadder(sevTri, {
35
+ selected: options.severitySelected,
36
+ tailFactor: options.severityTailFactor ?? 1,
37
+ });
38
+ for (const w of sevCl.warnings)
39
+ warnings.push(`severity: ${w}`);
40
+ const countByOrigin = new Map(countCl.rows.map((r) => [r.origin, r]));
41
+ const sevByOrigin = new Map(sevCl.rows.map((r) => [r.origin, r]));
42
+ const rows = [];
43
+ for (let i = 0; i < lossTri.origins.length; i++) {
44
+ const origin = lossTri.origins[i];
45
+ const counts = countByOrigin.get(origin);
46
+ const sev = sevByOrigin.get(origin);
47
+ if (!counts || !sev) {
48
+ warnings.push(`Origin ${origin} has no observed counts or severities; excluded from frequency-severity`);
49
+ continue;
50
+ }
51
+ const latestIdx = lastObservedIndex(lossTri.values[i]);
52
+ const latestValue = latestIdx >= 0 ? lossTri.values[i][latestIdx] : 0;
53
+ const ultimate = counts.ultimate * sev.ultimate;
54
+ if (!isNum(ultimate)) {
55
+ warnings.push(`Origin ${origin}: the frequency-severity ultimate is not computable`);
56
+ continue;
57
+ }
58
+ rows.push({
59
+ origin,
60
+ latestValue,
61
+ ultimateCounts: counts.ultimate,
62
+ ultimateSeverity: sev.ultimate,
63
+ ultimate,
64
+ unpaid: ultimate - latestValue,
65
+ });
66
+ }
67
+ if (rows.length === 0) {
68
+ throw new ReservingError("NO_DATA", "No origin period has both observed counts and observed severities");
69
+ }
70
+ return {
71
+ method: "frequencySeverity",
72
+ basis: lossTri.kind,
73
+ rows,
74
+ totals: {
75
+ latest: rows.reduce((a, r) => a + r.latestValue, 0),
76
+ ultimate: rows.reduce((a, r) => a + r.ultimate, 0),
77
+ unpaid: rows.reduce((a, r) => a + r.unpaid, 0),
78
+ },
79
+ warnings,
80
+ };
81
+ }
82
+ //# sourceMappingURL=freqSev.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"freqSev.js","sourceRoot":"","sources":["../src/freqSev.ts"],"names":[],"mappings":"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"}
package/dist/ilf.d.ts ADDED
@@ -0,0 +1,111 @@
1
+ import type { ClaimSnapshot } from "./types.js";
2
+ export declare function normalCdf(z: number): number;
3
+ export type SeverityDistribution = {
4
+ kind: "lognormal";
5
+ mu: number;
6
+ sigma: number;
7
+ } | {
8
+ kind: "pareto";
9
+ theta: number;
10
+ alpha: number;
11
+ };
12
+ /** Mean E[X]; null when infinite (Pareto alpha <= 1). */
13
+ export declare function severityMean(dist: SeverityDistribution): number | null;
14
+ /** Limited expected value E[X ∧ c]. */
15
+ export declare function limitedExpectedValue(dist: SeverityDistribution, c: number): number;
16
+ /**
17
+ * The uncap factor to a target limit: E[X ∧ target] / E[X ∧ cap], with
18
+ * target null meaning unlimited (E[X] / E[X ∧ cap]). Throws when the
19
+ * distribution has no finite mean and target is unlimited.
20
+ */
21
+ export declare function uncapFactor(dist: SeverityDistribution, cap: number, target: number | null): number;
22
+ export interface SeverityObservation {
23
+ /** Severity at the claim's latest evaluation, at base-year cost level. */
24
+ value: number;
25
+ /**
26
+ * True when the claim is still open. Its reported incurred is then treated
27
+ * as a right-censoring floor on ultimate severity - a CASE-ADEQUACY
28
+ * ASSUMPTION, not a fact: redundant case reserves overstate the fitted
29
+ * tail, deficient ones understate it. Fits must carry this caveat.
30
+ */
31
+ censored: boolean;
32
+ }
33
+ export interface SeverityFit {
34
+ distribution: SeverityDistribution;
35
+ logLikelihood: number;
36
+ nExact: number;
37
+ nCensored: number;
38
+ nExcludedNonPositive: number;
39
+ valid: boolean;
40
+ warnings: string[];
41
+ /**
42
+ * Kaplan-Meier (censoring-adjusted) empirical quantiles vs fitted
43
+ * unconditional quantiles. Closed-claims-only quantiles are biased small
44
+ * (large claims stay open), so the empirical side uses the product-limit
45
+ * estimator; null where censoring exhausts the observable range.
46
+ */
47
+ quantileCheck: {
48
+ p: number;
49
+ empirical: number | null;
50
+ fitted: number;
51
+ }[];
52
+ }
53
+ /**
54
+ * Fits a severity distribution by maximum likelihood with right-censoring:
55
+ * closed claims contribute the density, open claims the survival at their
56
+ * reported incurred. Treating reported incurred as a floor on ultimate
57
+ * severity is a CASE-ADEQUACY assumption - on books with redundant reserves
58
+ * the fitted tail (and any uncap factor from it) is overstated. Fits are
59
+ * additionally gated on censored share and parameter sanity: a likelihood
60
+ * dominated by open claims can push the tail arbitrarily heavy while looking
61
+ * converged.
62
+ */
63
+ export declare function fitSeverity(observations: SeverityObservation[], kind: SeverityDistribution["kind"]): SeverityFit;
64
+ /**
65
+ * Kaplan-Meier product-limit quantiles over exact + right-censored values:
66
+ * the censoring-adjusted empirical benchmark (closed-only quantiles are
67
+ * biased small because large claims stay open). Returns null for probes the
68
+ * survival curve cannot reach (censoring exhausts the observable range).
69
+ * Ties convention: events precede censorings at the same value.
70
+ */
71
+ export declare function kaplanMeierQuantiles(exact: number[], censored: number[], probes: number[]): (number | null)[];
72
+ /**
73
+ * Structural validation shared by every ILF-table write path (import route,
74
+ * workspace patch) and by interpolation: >= 2 rows, positive limits and
75
+ * factors, unique limits, factors non-decreasing in the limit. Throws
76
+ * ReservingError so garbage is rejected at the door, identically everywhere.
77
+ */
78
+ export declare function validateIlfTable(table: IlfTableRow[]): IlfTableRow[];
79
+ /**
80
+ * Base-year-level severity observations from a loss run: each claim's latest
81
+ * evaluation on or before asOfDate, deflated by the cap index, open claims
82
+ * censored at reported incurred.
83
+ */
84
+ export declare function severityObservations(claims: ClaimSnapshot[], options: {
85
+ asOfDate?: string;
86
+ indexRate?: number;
87
+ baseYear: number;
88
+ }): SeverityObservation[];
89
+ export interface IlfTableRow {
90
+ limit: number;
91
+ factor: number;
92
+ }
93
+ /**
94
+ * Log-log interpolated ILF at a limit. Exact at knots; throws when the
95
+ * table does not bracket the requested limit (extrapolating an ILF table is
96
+ * how excess layers get silently mispriced).
97
+ */
98
+ export declare function interpolateIlf(table: IlfTableRow[], limit: number): number;
99
+ /** Table-based uncap factor: ILF(target)/ILF(cap). */
100
+ export declare function tableUncapFactor(table: IlfTableRow[], cap: number, target: number): number;
101
+ /**
102
+ * Illustrative severity curves for when no licensed table and no credible
103
+ * own-data fit exist. Parameters are textbook-plausible shapes, NOT ISO or
104
+ * NCCI factors - the UI must say so loudly.
105
+ */
106
+ export declare const ILLUSTRATIVE_CURVES: {
107
+ id: string;
108
+ label: string;
109
+ distribution: SeverityDistribution;
110
+ }[];
111
+ //# sourceMappingURL=ilf.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ilf.d.ts","sourceRoot":"","sources":["../src/ilf.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAgChD,wBAAgB,SAAS,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAE3C;AAKD,MAAM,MAAM,oBAAoB,GAC5B;IAAE,IAAI,EAAE,WAAW,CAAC;IAAC,EAAE,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAChD;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAErD,yDAAyD;AACzD,wBAAgB,YAAY,CAAC,IAAI,EAAE,oBAAoB,GAAG,MAAM,GAAG,IAAI,CAMtE;AAED,uCAAuC;AACvC,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,oBAAoB,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAgBlF;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CACzB,IAAI,EAAE,oBAAoB,EAC1B,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,MAAM,GAAG,IAAI,GACpB,MAAM,CA0BR;AAKD,MAAM,WAAW,mBAAmB;IAClC,0EAA0E;IAC1E,KAAK,EAAE,MAAM,CAAC;IACd;;;;;OAKG;IACH,QAAQ,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,WAAW,WAAW;IAC1B,YAAY,EAAE,oBAAoB,CAAC;IACnC,aAAa,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,oBAAoB,EAAE,MAAM,CAAC;IAC7B,KAAK,EAAE,OAAO,CAAC;IACf,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB;;;;;OAKG;IACH,aAAa,EAAE;QAAE,CAAC,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;CAC1E;AAoGD;;;;;;;;;GASG;AACH,wBAAgB,WAAW,CACzB,YAAY,EAAE,mBAAmB,EAAE,EACnC,IAAI,EAAE,oBAAoB,CAAC,MAAM,CAAC,GACjC,WAAW,CAmJb;AAED;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,MAAM,EAAE,EACf,QAAQ,EAAE,MAAM,EAAE,EAClB,MAAM,EAAE,MAAM,EAAE,GACf,CAAC,MAAM,GAAG,IAAI,CAAC,EAAE,CA4BnB;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,WAAW,EAAE,GAAG,WAAW,EAAE,CAsBpE;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,aAAa,EAAE,EACvB,OAAO,EAAE;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,GACnE,mBAAmB,EAAE,CAiBvB;AAKD,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,WAAW,EAAE,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAoB1E;AAED,sDAAsD;AACtD,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,WAAW,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAK1F;AAED;;;;GAIG;AACH,eAAO,MAAM,mBAAmB,EAAE;IAChC,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,YAAY,EAAE,oBAAoB,CAAC;CACpC,EAgBA,CAAC"}