@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
package/dist/ulae.js ADDED
@@ -0,0 +1,164 @@
1
+ import { ReservingError } from "./types.js";
2
+ import { isNum } from "./util.js";
3
+ /**
4
+ * Weight presets from the paper. The GENERALIZED method is any caller-chosen
5
+ * triple (there is no handbook of u-values; the paper develops them by
6
+ * interviewing claims personnel), so it deliberately has no preset entry.
7
+ */
8
+ export const ULAE_WEIGHT_PRESETS = {
9
+ /**
10
+ * Kittel's refined method: 50% opening / 50% closing, with the caller
11
+ * supplying R = reported losses and C = paid losses per Kittel's
12
+ * assumptions (no partial payments or reopenings, no future development).
13
+ * W = M / (50% x (paid + reported)).
14
+ */
15
+ kittel: { weights: { u1: 0.5, u2: 0, u3: 0.5 }, basis: "weighted" },
16
+ /**
17
+ * Classical paid-to-paid: the same 50/50 lifecycle assumption plus the
18
+ * steady-state identity R = P = C, which collapses the basis to paid
19
+ * losses: W = M / P. Reserve = W* x (IBNR + 50% x case reserves).
20
+ */
21
+ classicalPaidToPaid: { weights: { u1: 0.5, u2: 0, u3: 0.5 }, basis: "paid" },
22
+ };
23
+ const WEIGHT_SUM_TOLERANCE = 1e-6;
24
+ function validateWeights(weights) {
25
+ const { u1, u2, u3 } = weights;
26
+ for (const [name, value] of [
27
+ ["u1", u1],
28
+ ["u2", u2],
29
+ ["u3", u3],
30
+ ]) {
31
+ if (!isNum(value) || value < 0 || value > 1) {
32
+ throw new ReservingError("BAD_WEIGHTS", `ULAE weight ${name} must be a finite number within [0, 1], got ${value}`);
33
+ }
34
+ }
35
+ if (Math.abs(u1 + u2 + u3 - 1) > WEIGHT_SUM_TOLERANCE) {
36
+ throw new ReservingError("BAD_WEIGHTS", `ULAE weights must sum to 1 (u1 + u2 + u3 = ${u1 + u2 + u3})`);
37
+ }
38
+ }
39
+ function requireNonNegative(value, name) {
40
+ if (!isNum(value) || value < 0) {
41
+ throw new ReservingError("BAD_LOSSES", `${name} must be a finite, non-negative number, got ${value}`);
42
+ }
43
+ }
44
+ /**
45
+ * Calendar-period ULAE ratios W = M / B (the paper's Exhibits B-F machinery).
46
+ * Pass opts.basis = "paid" for the classical paid-to-paid collapse.
47
+ */
48
+ export function ulaeRatios(periods, weights, opts = {}) {
49
+ validateWeights(weights);
50
+ if (periods.length === 0) {
51
+ throw new ReservingError("NO_DATA", "ULAE ratios need at least one calendar period");
52
+ }
53
+ const basisKind = opts.basis ?? "weighted";
54
+ const warnings = [];
55
+ const rows = [];
56
+ let totalM = 0;
57
+ let totalB = 0;
58
+ for (const period of periods) {
59
+ requireNonNegative(period.ulaePaid, `Period ${period.label}: ulaePaid`);
60
+ requireNonNegative(period.reportedUltimate, `Period ${period.label}: reportedUltimate`);
61
+ requireNonNegative(period.paid, `Period ${period.label}: paid`);
62
+ requireNonNegative(period.closedUltimate, `Period ${period.label}: closedUltimate`);
63
+ const basis = basisKind === "paid"
64
+ ? period.paid
65
+ : weights.u1 * period.reportedUltimate +
66
+ weights.u2 * period.paid +
67
+ weights.u3 * period.closedUltimate;
68
+ const ratio = basis > 0 ? period.ulaePaid / basis : null;
69
+ if (ratio === null) {
70
+ warnings.push(`Period ${period.label} has a non-positive loss basis; its ULAE ratio is not computable`);
71
+ }
72
+ rows.push({ label: period.label, ulaePaid: period.ulaePaid, basis, ratio });
73
+ totalM += period.ulaePaid;
74
+ totalB += basis;
75
+ }
76
+ return {
77
+ weights,
78
+ basis: basisKind,
79
+ rows,
80
+ totals: { ulaePaid: totalM, basis: totalB, ratio: totalB > 0 ? totalM / totalB : null },
81
+ warnings,
82
+ };
83
+ }
84
+ /**
85
+ * The paper's three reserve forms (pp. 113-115), analogous to expected-loss /
86
+ * Bornhuetter-Ferguson / development loss reserving:
87
+ *
88
+ * - "expected": unpaid = W* L - M(t)
89
+ * - "bornhuetterFerguson": unpaid = W* [u1 (L - R(t)) + u2 (L - P(t)) + u3 (L - C(t))]
90
+ * = W* (L - B(t)) -- the paper's recommended default
91
+ * - "development": unpaid = M(t) (L / B(t) - 1)
92
+ *
93
+ * With Kittel's weights (50/0/50) and C(t) = P(t) the B-F form reduces to
94
+ * W* x (IBNR + 50% x case reserves) - the Kittel identity.
95
+ */
96
+ export function ulaeReserve(input) {
97
+ validateWeights(input.weights);
98
+ if (!isNum(input.selectedW) || input.selectedW < 0) {
99
+ throw new ReservingError("BAD_RATIO", `Selected ULAE ratio W* must be a finite, non-negative number, got ${input.selectedW}`);
100
+ }
101
+ requireNonNegative(input.ultimateLosses, "ultimateLosses");
102
+ const { u1, u2, u3 } = input.weights;
103
+ const warnings = [];
104
+ // A measure is needed when its weight is positive (B-F and development
105
+ // forms); an omitted-but-unweighted measure is treated as 0 in B(t).
106
+ const measure = (value, weight, name, needed) => {
107
+ if (value === undefined) {
108
+ if (needed && weight > 0) {
109
+ throw new ReservingError("NO_DATA", `${name} is required when its ULAE weight is positive (${input.form} form)`);
110
+ }
111
+ return 0;
112
+ }
113
+ requireNonNegative(value, name);
114
+ return value;
115
+ };
116
+ const needsBasis = input.form !== "expected";
117
+ const R = measure(input.reportedToDate, u1, "reportedToDate", needsBasis);
118
+ const P = measure(input.paidToDate, u2, "paidToDate", needsBasis);
119
+ const C = measure(input.closedToDate, u3, "closedToDate", needsBasis);
120
+ const haveBasis = (u1 === 0 || input.reportedToDate !== undefined) &&
121
+ (u2 === 0 || input.paidToDate !== undefined) &&
122
+ (u3 === 0 || input.closedToDate !== undefined);
123
+ const basisToDate = haveBasis ? u1 * R + u2 * P + u3 * C : null;
124
+ const requireM = () => {
125
+ if (input.ulaePaidToDate === undefined) {
126
+ throw new ReservingError("NO_DATA", `ulaePaidToDate is required for the ${input.form} ULAE reserve form`);
127
+ }
128
+ requireNonNegative(input.ulaePaidToDate, "ulaePaidToDate");
129
+ return input.ulaePaidToDate;
130
+ };
131
+ let unpaidUlae;
132
+ let components = null;
133
+ switch (input.form) {
134
+ case "expected": {
135
+ const M = requireM();
136
+ unpaidUlae = input.selectedW * input.ultimateLosses - M;
137
+ if (unpaidUlae < 0) {
138
+ warnings.push("ULAE paid to date exceeds W* x ultimate losses; the expected-form reserve is negative");
139
+ }
140
+ break;
141
+ }
142
+ case "bornhuetterFerguson": {
143
+ const L = input.ultimateLosses;
144
+ components = {
145
+ opening: input.selectedW * u1 * (L - R),
146
+ maintaining: input.selectedW * u2 * (L - P),
147
+ closing: input.selectedW * u3 * (L - C),
148
+ };
149
+ unpaidUlae = components.opening + components.maintaining + components.closing;
150
+ break;
151
+ }
152
+ case "development": {
153
+ const M = requireM();
154
+ if (basisToDate === null || basisToDate <= 0) {
155
+ throw new ReservingError("NO_DATA", "The development ULAE reserve form needs a positive loss basis to date (B = u1 R + u2 P + u3 C)");
156
+ }
157
+ unpaidUlae = M * (input.ultimateLosses / basisToDate - 1);
158
+ warnings.push("The development form is overly responsive to random ULAE emergence (Conger-Nolibos); the Bornhuetter-Ferguson form is the paper's recommended default");
159
+ break;
160
+ }
161
+ }
162
+ return { form: input.form, unpaidUlae, basisToDate, components, warnings };
163
+ }
164
+ //# sourceMappingURL=ulae.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ulae.js","sourceRoot":"","sources":["../src/ulae.ts"],"names":[],"mappings":"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"}
package/dist/util.d.ts ADDED
@@ -0,0 +1,24 @@
1
+ /** Shared numeric helpers. All null-safe by construction. */
2
+ /** True when v is a usable finite number. */
3
+ export declare function isNum(v: number | null | undefined): v is number;
4
+ /**
5
+ * Safe ratio: returns null when either side is missing or the denominator
6
+ * is missing, zero, or negative ("no factor", never an exception).
7
+ */
8
+ export declare function safeRatio(num: number | null, den: number | null): number | null;
9
+ /** Ordinary least squares of y on x. Returns null when fewer than 2 points. */
10
+ export declare function ols(x: number[], y: number[]): {
11
+ intercept: number;
12
+ slope: number;
13
+ rSquared: number;
14
+ n: number;
15
+ } | null;
16
+ /** Index of the last non-null cell in a row; -1 when the row is empty. */
17
+ export declare function lastObservedIndex(row: (number | null)[]): number;
18
+ /**
19
+ * Index of the last cell observed in BOTH rows (paired-triangle diagonals);
20
+ * -1 when no cell is jointly observed. Interior holes are respected: the
21
+ * search walks left until both sides are numbers.
22
+ */
23
+ export declare function lastJointObservedIndex(a: (number | null)[], b: (number | null)[]): number;
24
+ //# sourceMappingURL=util.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"util.d.ts","sourceRoot":"","sources":["../src/util.ts"],"names":[],"mappings":"AAAA,6DAA6D;AAE7D,6CAA6C;AAC7C,wBAAgB,KAAK,CAAC,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,CAAC,IAAI,MAAM,CAE/D;AAED;;;GAGG;AACH,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,GAAG,IAAI,CAG/E;AAED,+EAA+E;AAC/E,wBAAgB,GAAG,CACjB,CAAC,EAAE,MAAM,EAAE,EACX,CAAC,EAAE,MAAM,EAAE,GACV;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CA2B1E;AAED,0EAA0E;AAC1E,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,CAAC,MAAM,GAAG,IAAI,CAAC,EAAE,GAAG,MAAM,CAKhE;AAED;;;;GAIG;AACH,wBAAgB,sBAAsB,CAAC,CAAC,EAAE,CAAC,MAAM,GAAG,IAAI,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,MAAM,GAAG,IAAI,CAAC,EAAE,GAAG,MAAM,CAKzF"}
package/dist/util.js ADDED
@@ -0,0 +1,66 @@
1
+ /** Shared numeric helpers. All null-safe by construction. */
2
+ /** True when v is a usable finite number. */
3
+ export function isNum(v) {
4
+ return typeof v === "number" && Number.isFinite(v);
5
+ }
6
+ /**
7
+ * Safe ratio: returns null when either side is missing or the denominator
8
+ * is missing, zero, or negative ("no factor", never an exception).
9
+ */
10
+ export function safeRatio(num, den) {
11
+ if (!isNum(num) || !isNum(den) || den <= 0)
12
+ return null;
13
+ return num / den;
14
+ }
15
+ /** Ordinary least squares of y on x. Returns null when fewer than 2 points. */
16
+ export function ols(x, y) {
17
+ const n = Math.min(x.length, y.length);
18
+ if (n < 2)
19
+ return null;
20
+ let sx = 0;
21
+ let sy = 0;
22
+ for (let i = 0; i < n; i++) {
23
+ sx += x[i];
24
+ sy += y[i];
25
+ }
26
+ const mx = sx / n;
27
+ const my = sy / n;
28
+ let sxx = 0;
29
+ let sxy = 0;
30
+ let syy = 0;
31
+ for (let i = 0; i < n; i++) {
32
+ const dx = x[i] - mx;
33
+ const dy = y[i] - my;
34
+ sxx += dx * dx;
35
+ sxy += dx * dy;
36
+ syy += dy * dy;
37
+ }
38
+ if (sxx === 0)
39
+ return null;
40
+ const slope = sxy / sxx;
41
+ const intercept = my - slope * mx;
42
+ // R^2 = 1 - SSE/SST; when SST is 0 the fit is a perfect horizontal line.
43
+ const rSquared = syy === 0 ? 1 : 1 - (syy - (sxy * sxy) / sxx) / syy;
44
+ return { intercept, slope, rSquared, n };
45
+ }
46
+ /** Index of the last non-null cell in a row; -1 when the row is empty. */
47
+ export function lastObservedIndex(row) {
48
+ for (let j = row.length - 1; j >= 0; j--) {
49
+ if (isNum(row[j] ?? null))
50
+ return j;
51
+ }
52
+ return -1;
53
+ }
54
+ /**
55
+ * Index of the last cell observed in BOTH rows (paired-triangle diagonals);
56
+ * -1 when no cell is jointly observed. Interior holes are respected: the
57
+ * search walks left until both sides are numbers.
58
+ */
59
+ export function lastJointObservedIndex(a, b) {
60
+ for (let j = Math.min(a.length, b.length) - 1; j >= 0; j--) {
61
+ if (isNum(a[j] ?? null) && isNum(b[j] ?? null))
62
+ return j;
63
+ }
64
+ return -1;
65
+ }
66
+ //# sourceMappingURL=util.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"util.js","sourceRoot":"","sources":["../src/util.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,66 @@
1
+ {
2
+ "name": "@actuarial-ts/core",
3
+ "version": "0.1.0",
4
+ "description": "Pure, zero-dependency P&C loss reserving engine for TypeScript: triangles, chain ladder, Mack, Bornhuetter-Ferguson, Benktander, Cape Cod (Gluck decay), Munich chain ladder, Clark growth curves, frequency-severity, Berquist-Sherman, ULAE, discounting, tails, capping/ILF, trend/on-level, diagnostics, and a seeded stochastic layer (ODP bootstrap, Merz-Wuthrich one-year risk) \u2014 validated against published actuarial literature.",
5
+ "license": "Apache-2.0",
6
+ "type": "module",
7
+ "main": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "types": "./dist/index.d.ts",
12
+ "default": "./dist/index.js"
13
+ },
14
+ "./package.json": "./package.json"
15
+ },
16
+ "files": [
17
+ "dist",
18
+ "README.md",
19
+ "LICENSE",
20
+ "NOTICE"
21
+ ],
22
+ "sideEffects": false,
23
+ "engines": {
24
+ "node": ">=20"
25
+ },
26
+ "repository": {
27
+ "type": "git",
28
+ "url": "git+https://github.com/yerromnitsuj/actng.git",
29
+ "directory": "packages/core"
30
+ },
31
+ "keywords": [
32
+ "actuarial",
33
+ "reserving",
34
+ "chain-ladder",
35
+ "mack",
36
+ "bornhuetter-ferguson",
37
+ "cape-cod",
38
+ "berquist-sherman",
39
+ "loss-development",
40
+ "triangle",
41
+ "ibnr",
42
+ "insurance",
43
+ "property-casualty",
44
+ "odp-bootstrap",
45
+ "merz-wuthrich",
46
+ "munich-chain-ladder",
47
+ "clark",
48
+ "stochastic-reserving",
49
+ "ulae",
50
+ "discounting"
51
+ ],
52
+ "scripts": {
53
+ "build": "tsc -p tsconfig.build.json",
54
+ "test": "vitest run",
55
+ "test:watch": "vitest",
56
+ "typecheck": "tsc --noEmit",
57
+ "prepack": "tsc -p tsconfig.build.json"
58
+ },
59
+ "devDependencies": {
60
+ "typescript": "^5.7.3",
61
+ "vitest": "^3.0.5"
62
+ },
63
+ "publishConfig": {
64
+ "access": "public"
65
+ }
66
+ }