@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.
- package/LICENSE +202 -0
- package/NOTICE +5 -0
- package/README.md +133 -0
- package/dist/benktander.d.ts +45 -0
- package/dist/benktander.d.ts.map +1 -0
- package/dist/benktander.js +38 -0
- package/dist/benktander.js.map +1 -0
- package/dist/berquist.d.ts +14 -0
- package/dist/berquist.d.ts.map +1 -0
- package/dist/berquist.js +292 -0
- package/dist/berquist.js.map +1 -0
- package/dist/bf.d.ts +23 -0
- package/dist/bf.d.ts.map +1 -0
- package/dist/bf.js +83 -0
- package/dist/bf.js.map +1 -0
- package/dist/capping.d.ts +96 -0
- package/dist/capping.d.ts.map +1 -0
- package/dist/capping.js +207 -0
- package/dist/capping.js.map +1 -0
- package/dist/caseOutstanding.d.ts +80 -0
- package/dist/caseOutstanding.d.ts.map +1 -0
- package/dist/caseOutstanding.js +147 -0
- package/dist/caseOutstanding.js.map +1 -0
- package/dist/chainladder.d.ts +15 -0
- package/dist/chainladder.d.ts.map +1 -0
- package/dist/chainladder.js +81 -0
- package/dist/chainladder.js.map +1 -0
- package/dist/clark.d.ts +91 -0
- package/dist/clark.d.ts.map +1 -0
- package/dist/clark.js +490 -0
- package/dist/clark.js.map +1 -0
- package/dist/diagnostics.d.ts +80 -0
- package/dist/diagnostics.d.ts.map +1 -0
- package/dist/diagnostics.js +359 -0
- package/dist/diagnostics.js.map +1 -0
- package/dist/discounting.d.ts +166 -0
- package/dist/discounting.d.ts.map +1 -0
- package/dist/discounting.js +210 -0
- package/dist/discounting.js.map +1 -0
- package/dist/elrMethods.d.ts +104 -0
- package/dist/elrMethods.d.ts.map +1 -0
- package/dist/elrMethods.js +151 -0
- package/dist/elrMethods.js.map +1 -0
- package/dist/factors.d.ts +19 -0
- package/dist/factors.d.ts.map +1 -0
- package/dist/factors.js +136 -0
- package/dist/factors.js.map +1 -0
- package/dist/fisherLange.d.ts +92 -0
- package/dist/fisherLange.d.ts.map +1 -0
- package/dist/fisherLange.js +224 -0
- package/dist/fisherLange.js.map +1 -0
- package/dist/freqSev.d.ts +57 -0
- package/dist/freqSev.d.ts.map +1 -0
- package/dist/freqSev.js +82 -0
- package/dist/freqSev.js.map +1 -0
- package/dist/ilf.d.ts +111 -0
- package/dist/ilf.d.ts.map +1 -0
- package/dist/ilf.js +449 -0
- package/dist/ilf.js.map +1 -0
- package/dist/index.d.ts +29 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +29 -0
- package/dist/index.js.map +1 -0
- package/dist/mack.d.ts +55 -0
- package/dist/mack.d.ts.map +1 -0
- package/dist/mack.js +244 -0
- package/dist/mack.js.map +1 -0
- package/dist/merzWuthrich.d.ts +29 -0
- package/dist/merzWuthrich.d.ts.map +1 -0
- package/dist/merzWuthrich.js +132 -0
- package/dist/merzWuthrich.js.map +1 -0
- package/dist/munichChainLadder.d.ts +101 -0
- package/dist/munichChainLadder.d.ts.map +1 -0
- package/dist/munichChainLadder.js +254 -0
- package/dist/munichChainLadder.js.map +1 -0
- package/dist/odpBootstrap.d.ts +65 -0
- package/dist/odpBootstrap.d.ts.map +1 -0
- package/dist/odpBootstrap.js +243 -0
- package/dist/odpBootstrap.js.map +1 -0
- package/dist/onlevel.d.ts +39 -0
- package/dist/onlevel.d.ts.map +1 -0
- package/dist/onlevel.js +104 -0
- package/dist/onlevel.js.map +1 -0
- package/dist/salvageSubro.d.ts +82 -0
- package/dist/salvageSubro.d.ts.map +1 -0
- package/dist/salvageSubro.js +100 -0
- package/dist/salvageSubro.js.map +1 -0
- package/dist/stochastic.d.ts +56 -0
- package/dist/stochastic.d.ts.map +1 -0
- package/dist/stochastic.js +99 -0
- package/dist/stochastic.js.map +1 -0
- package/dist/tail.d.ts +18 -0
- package/dist/tail.d.ts.map +1 -0
- package/dist/tail.js +121 -0
- package/dist/tail.js.map +1 -0
- package/dist/trend.d.ts +46 -0
- package/dist/trend.d.ts.map +1 -0
- package/dist/trend.js +99 -0
- package/dist/trend.js.map +1 -0
- package/dist/triangle.d.ts +19 -0
- package/dist/triangle.d.ts.map +1 -0
- package/dist/triangle.js +163 -0
- package/dist/triangle.js.map +1 -0
- package/dist/triangleAlgebra.d.ts +10 -0
- package/dist/triangleAlgebra.d.ts.map +1 -0
- package/dist/triangleAlgebra.js +97 -0
- package/dist/triangleAlgebra.js.map +1 -0
- package/dist/types.d.ts +280 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +79 -0
- package/dist/types.js.map +1 -0
- package/dist/ulae.d.ts +172 -0
- package/dist/ulae.d.ts.map +1 -0
- package/dist/ulae.js +164 -0
- package/dist/ulae.js.map +1 -0
- package/dist/util.d.ts +24 -0
- package/dist/util.d.ts.map +1 -0
- package/dist/util.js +66 -0
- package/dist/util.js.map +1 -0
- package/package.json +66 -0
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import type { CalendarYearDiagnostic, DiagnosticsResult, Triangle } from "./types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Mack's calendar-year test: within each development column, factors above
|
|
4
|
+
* the column median are Large, below are Small (ties to the median drop out).
|
|
5
|
+
* Under the null of no diagonal effects, Large/Small mix randomly along each
|
|
6
|
+
* calendar diagonal; Z = sum over diagonals of min(#L, #S) has a known mean
|
|
7
|
+
* and variance. A total outside the 95% range flags calendar-year effects.
|
|
8
|
+
*/
|
|
9
|
+
export declare function calendarYearTest(tri: Triangle): CalendarYearDiagnostic | null;
|
|
10
|
+
export interface DiagnosticsInput {
|
|
11
|
+
paid: Triangle;
|
|
12
|
+
incurred: Triangle;
|
|
13
|
+
openCounts: Triangle;
|
|
14
|
+
reportedCounts: Triangle;
|
|
15
|
+
closedCounts: Triangle;
|
|
16
|
+
}
|
|
17
|
+
export declare function runDiagnostics(input: DiagnosticsInput): DiagnosticsResult;
|
|
18
|
+
export interface FactorCorrelationColumn {
|
|
19
|
+
/** Development year k in Mack's 1-indexed notation (subsequent factors F_k vs preceding F_{k-1}). */
|
|
20
|
+
k: number;
|
|
21
|
+
/** Number of (preceding, subsequent) factor pairs used. */
|
|
22
|
+
pairs: number;
|
|
23
|
+
/** Spearman rank correlation T_k. */
|
|
24
|
+
statistic: number;
|
|
25
|
+
}
|
|
26
|
+
export interface FactorCorrelationResult {
|
|
27
|
+
columns: FactorCorrelationColumn[];
|
|
28
|
+
/** T: the (pairs-1)-weighted average of the T_k. E[T] = 0 under the null. */
|
|
29
|
+
statistic: number;
|
|
30
|
+
/** Var(T) = 1 / sum of weights. */
|
|
31
|
+
variance: number;
|
|
32
|
+
/** Half-width of the 50% interval: 0.67 x sqrt(Var(T)). */
|
|
33
|
+
bound50: number;
|
|
34
|
+
/** True when |T| exceeds the 50% bound (be reluctant with chain ladder). */
|
|
35
|
+
correlated: boolean;
|
|
36
|
+
warnings: string[];
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Mack's Spearman test for correlation between subsequent development
|
|
40
|
+
* factors (Mack 1994, CAS Forum Spring 1994, Appendix G).
|
|
41
|
+
*
|
|
42
|
+
* For each development year k = 2..I-2: rank the subsequent factors F_k over
|
|
43
|
+
* the rows where the NEXT factor exists, rank the preceding factors F_{k-1}
|
|
44
|
+
* over those same rows (re-ranked after dropping the deeper rows), and take
|
|
45
|
+
* T_k = 1 - 6 sum(d^2) / (n(n^2-1)). Combine with weights (pairs - 1) —
|
|
46
|
+
* inverse to Var(T_k) = 1/(n_k - 1). Under the null E[T] = 0 and
|
|
47
|
+
* Var(T) = 1/sum(weights); the DELIBERATELY tight 50% interval
|
|
48
|
+
* (|T| <= 0.67 sqrt(Var)) screens for correlation in a substantial part of
|
|
49
|
+
* the triangle rather than formally testing at 5%.
|
|
50
|
+
*
|
|
51
|
+
* Returns null when no column pair has at least two factor pairs.
|
|
52
|
+
*/
|
|
53
|
+
export declare function factorCorrelationTest(tri: Triangle): FactorCorrelationResult | null;
|
|
54
|
+
export interface MackResidualCell {
|
|
55
|
+
origin: string;
|
|
56
|
+
fromAge: number;
|
|
57
|
+
toAge: number;
|
|
58
|
+
/** 1-based calendar diagonal of the factor's numerator cell. */
|
|
59
|
+
calendar: number;
|
|
60
|
+
factor: number;
|
|
61
|
+
/** (F - f_k) sqrt(C_ik) / sigma_k; null where sigma^2 is not data-estimable or zero. */
|
|
62
|
+
residual: number | null;
|
|
63
|
+
}
|
|
64
|
+
export interface MackResidualsResult {
|
|
65
|
+
cells: MackResidualCell[];
|
|
66
|
+
warnings: string[];
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Standardized Mack residuals r_ik = (F_ik - f_k) sqrt(C_ik) / sigma_k
|
|
70
|
+
* around the volume-weighted factors, with sigma^2_k estimated from the
|
|
71
|
+
* data (Mack 1994). Columns whose sigma^2 cannot be estimated from at least
|
|
72
|
+
* two factors — or where the factors show no dispersion at all — yield null
|
|
73
|
+
* residuals with a warning; extrapolated sigma^2 is deliberately NOT used
|
|
74
|
+
* here (a residual against an extrapolated scale is not a diagnostic).
|
|
75
|
+
*
|
|
76
|
+
* Structural property: within each column, sum_i residual_ik x sqrt(C_ik)
|
|
77
|
+
* = 0 exactly, because f_k is the volume-weighted average.
|
|
78
|
+
*/
|
|
79
|
+
export declare function mackResiduals(tri: Triangle): MackResidualsResult;
|
|
80
|
+
//# sourceMappingURL=diagnostics.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"diagnostics.d.ts","sourceRoot":"","sources":["../src/diagnostics.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,sBAAsB,EAEtB,iBAAiB,EACjB,QAAQ,EACT,MAAM,YAAY,CAAC;AAqBpB;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,QAAQ,GAAG,sBAAsB,GAAG,IAAI,CA8E7E;AAsED,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,QAAQ,CAAC;IACf,QAAQ,EAAE,QAAQ,CAAC;IACnB,UAAU,EAAE,QAAQ,CAAC;IACrB,cAAc,EAAE,QAAQ,CAAC;IACzB,YAAY,EAAE,QAAQ,CAAC;CACxB;AAED,wBAAgB,cAAc,CAAC,KAAK,EAAE,gBAAgB,GAAG,iBAAiB,CAgEzE;AAMD,MAAM,WAAW,uBAAuB;IACtC,qGAAqG;IACrG,CAAC,EAAE,MAAM,CAAC;IACV,2DAA2D;IAC3D,KAAK,EAAE,MAAM,CAAC;IACd,qCAAqC;IACrC,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,uBAAuB;IACtC,OAAO,EAAE,uBAAuB,EAAE,CAAC;IACnC,6EAA6E;IAC7E,SAAS,EAAE,MAAM,CAAC;IAClB,mCAAmC;IACnC,QAAQ,EAAE,MAAM,CAAC;IACjB,2DAA2D;IAC3D,OAAO,EAAE,MAAM,CAAC;IAChB,4EAA4E;IAC5E,UAAU,EAAE,OAAO,CAAC;IACpB,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAmBD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,QAAQ,GAAG,uBAAuB,GAAG,IAAI,CAyDnF;AAMD,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,gEAAgE;IAChE,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,wFAAwF;IACxF,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;CACzB;AAED,MAAM,WAAW,mBAAmB;IAClC,KAAK,EAAE,gBAAgB,EAAE,CAAC;IAC1B,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,QAAQ,GAAG,mBAAmB,CA+BhE"}
|
|
@@ -0,0 +1,359 @@
|
|
|
1
|
+
import { isNum, ols, safeRatio } from "./util.js";
|
|
2
|
+
import { mackEstimators } from "./mack.js";
|
|
3
|
+
/**
|
|
4
|
+
* Data diagnostics an actuary uses to see when the data violates method
|
|
5
|
+
* assumptions:
|
|
6
|
+
* - paid-to-incurred ratios (case adequacy drift distorts incurred methods)
|
|
7
|
+
* - average case reserves (severity/adequacy shifts)
|
|
8
|
+
* - closure rates (settlement-rate shifts distort paid development)
|
|
9
|
+
* - calendar-year effect detection (Mack's 1994 diagonal rank test)
|
|
10
|
+
*/
|
|
11
|
+
function ratioGrid(numTri, denTri) {
|
|
12
|
+
return numTri.origins.map((_, i) => numTri.ages.map((_, j) => safeRatio(numTri.values[i]?.[j] ?? null, denTri.values[i]?.[j] ?? null)));
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Mack's calendar-year test: within each development column, factors above
|
|
16
|
+
* the column median are Large, below are Small (ties to the median drop out).
|
|
17
|
+
* Under the null of no diagonal effects, Large/Small mix randomly along each
|
|
18
|
+
* calendar diagonal; Z = sum over diagonals of min(#L, #S) has a known mean
|
|
19
|
+
* and variance. A total outside the 95% range flags calendar-year effects.
|
|
20
|
+
*/
|
|
21
|
+
export function calendarYearTest(tri) {
|
|
22
|
+
const nOrigins = tri.origins.length;
|
|
23
|
+
const nCols = tri.ages.length - 1;
|
|
24
|
+
if (nCols < 1 || nOrigins < 3)
|
|
25
|
+
return null;
|
|
26
|
+
const marks = tri.origins.map(() => new Array(nCols).fill(null));
|
|
27
|
+
for (let j = 0; j < nCols; j++) {
|
|
28
|
+
const entries = [];
|
|
29
|
+
for (let i = 0; i < nOrigins; i++) {
|
|
30
|
+
const f = safeRatio(tri.values[i]?.[j + 1] ?? null, tri.values[i]?.[j] ?? null);
|
|
31
|
+
if (isNum(f))
|
|
32
|
+
entries.push({ i, f });
|
|
33
|
+
}
|
|
34
|
+
if (entries.length < 2)
|
|
35
|
+
continue;
|
|
36
|
+
const sorted = entries.map((e) => e.f).sort((a, b) => a - b);
|
|
37
|
+
const mid = sorted.length % 2 === 1
|
|
38
|
+
? sorted[(sorted.length - 1) / 2]
|
|
39
|
+
: (sorted[sorted.length / 2 - 1] + sorted[sorted.length / 2]) / 2;
|
|
40
|
+
for (const e of entries) {
|
|
41
|
+
if (e.f > mid)
|
|
42
|
+
marks[e.i][j] = "L";
|
|
43
|
+
else if (e.f < mid)
|
|
44
|
+
marks[e.i][j] = "S";
|
|
45
|
+
// equal to the median -> eliminated
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
// Group by calendar diagonal: factor cell (i, j) belongs to diagonal i + j + 1
|
|
49
|
+
// (the calendar period of the numerator age).
|
|
50
|
+
const byDiagonal = new Map();
|
|
51
|
+
for (let i = 0; i < nOrigins; i++) {
|
|
52
|
+
for (let j = 0; j < nCols; j++) {
|
|
53
|
+
const mark = marks[i][j];
|
|
54
|
+
if (!mark)
|
|
55
|
+
continue;
|
|
56
|
+
const d = i + j + 1;
|
|
57
|
+
const bucket = byDiagonal.get(d) ?? { L: 0, S: 0 };
|
|
58
|
+
bucket[mark]++;
|
|
59
|
+
byDiagonal.set(d, bucket);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
const binom = (n, k) => {
|
|
63
|
+
if (k < 0 || k > n)
|
|
64
|
+
return 0;
|
|
65
|
+
let result = 1;
|
|
66
|
+
for (let x = 1; x <= k; x++)
|
|
67
|
+
result = (result * (n - x + 1)) / x;
|
|
68
|
+
return result;
|
|
69
|
+
};
|
|
70
|
+
const diagonals = [];
|
|
71
|
+
let totalZ = 0;
|
|
72
|
+
let expectedTotalZ = 0;
|
|
73
|
+
let varianceTotalZ = 0;
|
|
74
|
+
const sortedDiagonals = [...byDiagonal.entries()].sort((a, b) => a[0] - b[0]);
|
|
75
|
+
for (const [d, { L, S }] of sortedDiagonals) {
|
|
76
|
+
const n = L + S;
|
|
77
|
+
if (n < 1)
|
|
78
|
+
continue;
|
|
79
|
+
const z = Math.min(L, S);
|
|
80
|
+
const m = Math.floor((n - 1) / 2);
|
|
81
|
+
const c = binom(n - 1, m);
|
|
82
|
+
const expectedZ = n / 2 - (c * n) / 2 ** n;
|
|
83
|
+
const varianceZ = (n * (n - 1)) / 4 - (c * n * (n - 1)) / 2 ** n + expectedZ - expectedZ ** 2;
|
|
84
|
+
diagonals.push({ label: `diagonal ${d}`, countLarge: L, countSmall: S, z, expectedZ, varianceZ });
|
|
85
|
+
totalZ += z;
|
|
86
|
+
expectedTotalZ += expectedZ;
|
|
87
|
+
varianceTotalZ += varianceZ;
|
|
88
|
+
}
|
|
89
|
+
if (diagonals.length === 0)
|
|
90
|
+
return null;
|
|
91
|
+
const half = 1.96 * Math.sqrt(Math.max(0, varianceTotalZ));
|
|
92
|
+
const confidenceInterval = [expectedTotalZ - half, expectedTotalZ + half];
|
|
93
|
+
return {
|
|
94
|
+
diagonals,
|
|
95
|
+
totalZ,
|
|
96
|
+
expectedTotalZ,
|
|
97
|
+
varianceTotalZ,
|
|
98
|
+
significant: totalZ < confidenceInterval[0] || totalZ > confidenceInterval[1],
|
|
99
|
+
confidenceInterval,
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Median relative shift of the most recent origin periods against the prior
|
|
104
|
+
* ones, per development column, restricted to columns that are still
|
|
105
|
+
* developing (median value below the maturity cap). This is how an actuary
|
|
106
|
+
* reads a closure-rate exhibit: a step change in the recent rows at immature
|
|
107
|
+
* ages, not a smooth trend across saturated columns.
|
|
108
|
+
*/
|
|
109
|
+
function recentVsPriorShift(grid, options = {}) {
|
|
110
|
+
const recentN = options.recent ?? 3;
|
|
111
|
+
const maturityCap = options.maturityCap ?? Infinity;
|
|
112
|
+
if (grid.length === 0)
|
|
113
|
+
return null;
|
|
114
|
+
const nCols = grid[0].length;
|
|
115
|
+
const shifts = [];
|
|
116
|
+
for (let j = 0; j < nCols; j++) {
|
|
117
|
+
const values = [];
|
|
118
|
+
for (let i = 0; i < grid.length; i++) {
|
|
119
|
+
const v = grid[i][j] ?? null;
|
|
120
|
+
if (isNum(v))
|
|
121
|
+
values.push(v);
|
|
122
|
+
}
|
|
123
|
+
if (values.length < recentN + 2)
|
|
124
|
+
continue;
|
|
125
|
+
const sorted = [...values].sort((a, b) => a - b);
|
|
126
|
+
const median = sorted[Math.floor(sorted.length / 2)];
|
|
127
|
+
if (median >= maturityCap)
|
|
128
|
+
continue; // column is saturated; no signal left
|
|
129
|
+
const recent = values.slice(-recentN);
|
|
130
|
+
const prior = values.slice(0, values.length - recentN);
|
|
131
|
+
const avg = (xs) => xs.reduce((a, b) => a + b, 0) / xs.length;
|
|
132
|
+
const priorAvg = avg(prior);
|
|
133
|
+
if (priorAvg === 0)
|
|
134
|
+
continue;
|
|
135
|
+
shifts.push(avg(recent) / priorAvg - 1);
|
|
136
|
+
}
|
|
137
|
+
if (shifts.length === 0)
|
|
138
|
+
return null;
|
|
139
|
+
shifts.sort((a, b) => a - b);
|
|
140
|
+
const mid = Math.floor(shifts.length / 2);
|
|
141
|
+
return shifts.length % 2 === 1 ? shifts[mid] : (shifts[mid - 1] + shifts[mid]) / 2;
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Median relative per-period trend of a metric across development columns,
|
|
145
|
+
* fitted down each column (same maturity across origin periods).
|
|
146
|
+
*/
|
|
147
|
+
function medianColumnTrend(grid) {
|
|
148
|
+
if (grid.length === 0)
|
|
149
|
+
return null;
|
|
150
|
+
const nCols = grid[0].length;
|
|
151
|
+
const trends = [];
|
|
152
|
+
for (let j = 0; j < nCols; j++) {
|
|
153
|
+
const xs = [];
|
|
154
|
+
const ys = [];
|
|
155
|
+
for (let i = 0; i < grid.length; i++) {
|
|
156
|
+
const v = grid[i][j] ?? null;
|
|
157
|
+
if (isNum(v) && v > 0) {
|
|
158
|
+
xs.push(i);
|
|
159
|
+
ys.push(Math.log(v));
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
if (xs.length >= 3) {
|
|
163
|
+
const fit = ols(xs, ys);
|
|
164
|
+
if (fit)
|
|
165
|
+
trends.push(Math.exp(fit.slope) - 1);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
if (trends.length === 0)
|
|
169
|
+
return null;
|
|
170
|
+
trends.sort((a, b) => a - b);
|
|
171
|
+
const mid = Math.floor(trends.length / 2);
|
|
172
|
+
return trends.length % 2 === 1 ? trends[mid] : (trends[mid - 1] + trends[mid]) / 2;
|
|
173
|
+
}
|
|
174
|
+
export function runDiagnostics(input) {
|
|
175
|
+
const { paid, incurred, openCounts, reportedCounts, closedCounts } = input;
|
|
176
|
+
const paidToIncurredRatios = ratioGrid(paid, incurred);
|
|
177
|
+
const caseGrid = paid.origins.map((_, i) => paid.ages.map((_, j) => {
|
|
178
|
+
const inc = incurred.values[i]?.[j] ?? null;
|
|
179
|
+
const pd = paid.values[i]?.[j] ?? null;
|
|
180
|
+
const open = openCounts.values[i]?.[j] ?? null;
|
|
181
|
+
const caseAmt = isNum(inc) && isNum(pd) ? inc - pd : null;
|
|
182
|
+
return safeRatio(caseAmt, open);
|
|
183
|
+
}));
|
|
184
|
+
const closureRates = ratioGrid(closedCounts, reportedCounts);
|
|
185
|
+
const cyTest = calendarYearTest(paid);
|
|
186
|
+
const findings = [];
|
|
187
|
+
const closureShift = recentVsPriorShift(closureRates, { recent: 3, maturityCap: 0.95 });
|
|
188
|
+
if (closureShift !== null && Math.abs(closureShift) > 0.05) {
|
|
189
|
+
findings.push({
|
|
190
|
+
severity: "warning",
|
|
191
|
+
code: "SETTLEMENT_RATE_SHIFT",
|
|
192
|
+
message: `Claim settlement is ${closureShift > 0 ? "speeding up" : "slowing down"}: at still-developing maturities, closure rates for the most recent origin periods run ${(Math.abs(closureShift) * 100).toFixed(0)}% ${closureShift > 0 ? "above" : "below"} the prior periods. Paid development factors are distorted; weigh the Berquist-Sherman settlement-rate adjustment.`,
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
const caseTrend = medianColumnTrend(caseGrid);
|
|
196
|
+
if (caseTrend !== null && Math.abs(caseTrend) > 0.08) {
|
|
197
|
+
findings.push({
|
|
198
|
+
severity: "warning",
|
|
199
|
+
code: "CASE_ADEQUACY_SHIFT",
|
|
200
|
+
message: `Average case reserves at the same maturity are trending ${caseTrend > 0 ? "up" : "down"} ${(caseTrend * 100).toFixed(1)}% per period, which suggests a change in case reserve adequacy (or severity). Incurred development is distorted; consider the Berquist-Sherman case-reserve adjustment and compare against a severity trend expectation.`,
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
const p2iTrend = medianColumnTrend(paidToIncurredRatios);
|
|
204
|
+
if (p2iTrend !== null && Math.abs(p2iTrend) > 0.03) {
|
|
205
|
+
findings.push({
|
|
206
|
+
severity: "info",
|
|
207
|
+
code: "PAID_TO_INCURRED_SHIFT",
|
|
208
|
+
message: `Paid-to-incurred ratios at the same maturity are drifting ${p2iTrend > 0 ? "up" : "down"} (median ${(p2iTrend * 100).toFixed(1)}% per period). Paid and incurred projections are likely to diverge; investigate before relying on either alone.`,
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
if (cyTest?.significant) {
|
|
212
|
+
findings.push({
|
|
213
|
+
severity: "warning",
|
|
214
|
+
code: "CALENDAR_YEAR_EFFECT",
|
|
215
|
+
message: `Mack's calendar-year test rejects the null of no diagonal effects (Z = ${cyTest.totalZ.toFixed(1)} vs expected ${cyTest.expectedTotalZ.toFixed(1)}, 95% range ${cyTest.confidenceInterval[0].toFixed(1)}-${cyTest.confidenceInterval[1].toFixed(1)}). Calendar-period influences (inflation spikes, process changes, reserve reviews) are present; development-based methods assume these away.`,
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
if (findings.length === 0) {
|
|
219
|
+
findings.push({
|
|
220
|
+
severity: "info",
|
|
221
|
+
code: "NO_MATERIAL_DISTORTIONS",
|
|
222
|
+
message: "No material settlement-rate, case-adequacy, or calendar-year distortions detected. Standard development assumptions look reasonable for this data.",
|
|
223
|
+
});
|
|
224
|
+
}
|
|
225
|
+
return {
|
|
226
|
+
paidToIncurredRatios,
|
|
227
|
+
averageCaseReserves: caseGrid,
|
|
228
|
+
closureRates,
|
|
229
|
+
calendarYearTest: cyTest,
|
|
230
|
+
findings,
|
|
231
|
+
};
|
|
232
|
+
}
|
|
233
|
+
/** Average ranks (ties averaged), 1-based. */
|
|
234
|
+
function averageRanks(values) {
|
|
235
|
+
const order = values
|
|
236
|
+
.map((v, idx) => ({ v, idx }))
|
|
237
|
+
.sort((a, b) => a.v - b.v);
|
|
238
|
+
const ranks = new Array(values.length).fill(0);
|
|
239
|
+
let pos = 0;
|
|
240
|
+
while (pos < order.length) {
|
|
241
|
+
let end = pos;
|
|
242
|
+
while (end + 1 < order.length && order[end + 1].v === order[pos].v)
|
|
243
|
+
end++;
|
|
244
|
+
const avg = (pos + end) / 2 + 1;
|
|
245
|
+
for (let x = pos; x <= end; x++)
|
|
246
|
+
ranks[order[x].idx] = avg;
|
|
247
|
+
pos = end + 1;
|
|
248
|
+
}
|
|
249
|
+
return ranks;
|
|
250
|
+
}
|
|
251
|
+
/**
|
|
252
|
+
* Mack's Spearman test for correlation between subsequent development
|
|
253
|
+
* factors (Mack 1994, CAS Forum Spring 1994, Appendix G).
|
|
254
|
+
*
|
|
255
|
+
* For each development year k = 2..I-2: rank the subsequent factors F_k over
|
|
256
|
+
* the rows where the NEXT factor exists, rank the preceding factors F_{k-1}
|
|
257
|
+
* over those same rows (re-ranked after dropping the deeper rows), and take
|
|
258
|
+
* T_k = 1 - 6 sum(d^2) / (n(n^2-1)). Combine with weights (pairs - 1) —
|
|
259
|
+
* inverse to Var(T_k) = 1/(n_k - 1). Under the null E[T] = 0 and
|
|
260
|
+
* Var(T) = 1/sum(weights); the DELIBERATELY tight 50% interval
|
|
261
|
+
* (|T| <= 0.67 sqrt(Var)) screens for correlation in a substantial part of
|
|
262
|
+
* the triangle rather than formally testing at 5%.
|
|
263
|
+
*
|
|
264
|
+
* Returns null when no column pair has at least two factor pairs.
|
|
265
|
+
*/
|
|
266
|
+
export function factorCorrelationTest(tri) {
|
|
267
|
+
const n = tri.origins.length;
|
|
268
|
+
const nCols = tri.ages.length - 1;
|
|
269
|
+
const warnings = [];
|
|
270
|
+
// F[i][c] = C[i][c+1] / C[i][c] (0-indexed column c holds Mack's F_{c+1}).
|
|
271
|
+
const F = tri.origins.map((_, i) => Array.from({ length: nCols }, (_, c) => safeRatio(tri.values[i]?.[c + 1] ?? null, tri.values[i]?.[c] ?? null)));
|
|
272
|
+
const columns = [];
|
|
273
|
+
for (let k = 2; k <= Math.min(n - 2, nCols); k++) {
|
|
274
|
+
const cs = k - 1; // 0-indexed subsequent column (F_k)
|
|
275
|
+
const cp = k - 2; // 0-indexed preceding column (F_{k-1})
|
|
276
|
+
const sub = [];
|
|
277
|
+
const pre = [];
|
|
278
|
+
for (let i = 0; i < n; i++) {
|
|
279
|
+
const a = F[i][cs] ?? null;
|
|
280
|
+
const b = F[i][cp] ?? null;
|
|
281
|
+
if (isNum(a) && isNum(b)) {
|
|
282
|
+
sub.push(a);
|
|
283
|
+
pre.push(b);
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
const m = sub.length;
|
|
287
|
+
if (m < 2)
|
|
288
|
+
continue;
|
|
289
|
+
const hasTies = new Set(sub).size !== sub.length || new Set(pre).size !== pre.length;
|
|
290
|
+
if (hasTies) {
|
|
291
|
+
warnings.push(`Development year ${k}: tied factors; the Spearman statistic is approximate under ties`);
|
|
292
|
+
}
|
|
293
|
+
const r = averageRanks(sub);
|
|
294
|
+
const s = averageRanks(pre);
|
|
295
|
+
let d2 = 0;
|
|
296
|
+
for (let x = 0; x < m; x++)
|
|
297
|
+
d2 += (r[x] - s[x]) ** 2;
|
|
298
|
+
const Tk = 1 - (6 * d2) / (m * (m * m - 1));
|
|
299
|
+
columns.push({ k, pairs: m, statistic: Tk });
|
|
300
|
+
}
|
|
301
|
+
if (columns.length === 0)
|
|
302
|
+
return null;
|
|
303
|
+
const weightSum = columns.reduce((a, c) => a + (c.pairs - 1), 0);
|
|
304
|
+
if (weightSum <= 0)
|
|
305
|
+
return null;
|
|
306
|
+
const statistic = columns.reduce((a, c) => a + (c.pairs - 1) * c.statistic, 0) / weightSum;
|
|
307
|
+
const variance = 1 / weightSum;
|
|
308
|
+
const bound50 = 0.67 * Math.sqrt(variance);
|
|
309
|
+
return {
|
|
310
|
+
columns,
|
|
311
|
+
statistic,
|
|
312
|
+
variance,
|
|
313
|
+
bound50,
|
|
314
|
+
correlated: Math.abs(statistic) > bound50,
|
|
315
|
+
warnings,
|
|
316
|
+
};
|
|
317
|
+
}
|
|
318
|
+
/**
|
|
319
|
+
* Standardized Mack residuals r_ik = (F_ik - f_k) sqrt(C_ik) / sigma_k
|
|
320
|
+
* around the volume-weighted factors, with sigma^2_k estimated from the
|
|
321
|
+
* data (Mack 1994). Columns whose sigma^2 cannot be estimated from at least
|
|
322
|
+
* two factors — or where the factors show no dispersion at all — yield null
|
|
323
|
+
* residuals with a warning; extrapolated sigma^2 is deliberately NOT used
|
|
324
|
+
* here (a residual against an extrapolated scale is not a diagnostic).
|
|
325
|
+
*
|
|
326
|
+
* Structural property: within each column, sum_i residual_ik x sqrt(C_ik)
|
|
327
|
+
* = 0 exactly, because f_k is the volume-weighted average.
|
|
328
|
+
*/
|
|
329
|
+
export function mackResiduals(tri) {
|
|
330
|
+
const warnings = [];
|
|
331
|
+
const { f, sigma2 } = mackEstimators(tri);
|
|
332
|
+
const cells = [];
|
|
333
|
+
const flaggedColumns = new Set();
|
|
334
|
+
for (let c = 0; c < tri.ages.length - 1; c++) {
|
|
335
|
+
const s2 = sigma2[c] ?? null;
|
|
336
|
+
const usable = isNum(s2) && s2 > 0;
|
|
337
|
+
if (!usable && !flaggedColumns.has(c)) {
|
|
338
|
+
flaggedColumns.add(c);
|
|
339
|
+
warnings.push(`Column ${tri.ages[c]}-${tri.ages[c + 1]}: sigma^2 is ${s2 === null ? "not estimable from the data" : "zero (no dispersion)"}; residuals are null there`);
|
|
340
|
+
}
|
|
341
|
+
for (let i = 0; i < tri.origins.length; i++) {
|
|
342
|
+
const c0 = tri.values[i]?.[c] ?? null;
|
|
343
|
+
const c1 = tri.values[i]?.[c + 1] ?? null;
|
|
344
|
+
if (!isNum(c0) || !isNum(c1) || c0 <= 0)
|
|
345
|
+
continue;
|
|
346
|
+
const factor = c1 / c0;
|
|
347
|
+
cells.push({
|
|
348
|
+
origin: tri.origins[i],
|
|
349
|
+
fromAge: tri.ages[c],
|
|
350
|
+
toAge: tri.ages[c + 1],
|
|
351
|
+
calendar: i + c + 1,
|
|
352
|
+
factor,
|
|
353
|
+
residual: usable ? ((factor - f[c]) * Math.sqrt(c0)) / Math.sqrt(s2) : null,
|
|
354
|
+
});
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
return { cells, warnings };
|
|
358
|
+
}
|
|
359
|
+
//# sourceMappingURL=diagnostics.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"diagnostics.js","sourceRoot":"","sources":["../src/diagnostics.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
import type { ChainLadderResult } from "./types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Discounting unpaid claim estimates per ASOP No. 20 ("Discounting of
|
|
4
|
+
* Property/Casualty Unpaid Claim Estimates", the revised standard effective
|
|
5
|
+
* June 1, 2026). The standard's discipline, encoded rather than footnoted:
|
|
6
|
+
*
|
|
7
|
+
* - Rate PROVENANCE is required input ({ source, asOfDate }): the standard
|
|
8
|
+
* requires the actuary to disclose the basis of the discount rates and the
|
|
9
|
+
* date as of which they were determined. This module refuses to discount
|
|
10
|
+
* without it.
|
|
11
|
+
* - Nominal and discounted amounts are reported SIDE BY SIDE, per origin and
|
|
12
|
+
* in total, with the effective discount factor between them. Neither
|
|
13
|
+
* replaces the other.
|
|
14
|
+
* - Risk margins are EXPLICIT ONLY: an optional `riskMargin` amount passes
|
|
15
|
+
* through the result untouched; no total in this module adds it in.
|
|
16
|
+
* Implicit margins (conservative rates, shaded patterns) are never
|
|
17
|
+
* manufactured here, and blending a margin into the discounted figure is
|
|
18
|
+
* left to the consumer to do visibly.
|
|
19
|
+
*
|
|
20
|
+
* Timing convention (payments assumed at period boundaries per the pattern):
|
|
21
|
+
* each expected payment occupies a development interval (fromMonths,
|
|
22
|
+
* toMonths] measured from the VALUATION DATE, i.e. the latest observed
|
|
23
|
+
* diagonal of the triangle behind the pattern. The `convention` option fixes
|
|
24
|
+
* the discount exponent for the interval's payment:
|
|
25
|
+
*
|
|
26
|
+
* - "end-period": t = toMonths / 12 years - the payment falls on the
|
|
27
|
+
* interval's closing boundary.
|
|
28
|
+
* - "mid-period": t = (fromMonths + toMonths) / 24 years - the standard
|
|
29
|
+
* uniform-payment approximation (cash spread evenly over the interval is
|
|
30
|
+
* discounted as if paid at its midpoint).
|
|
31
|
+
*
|
|
32
|
+
* Discount factors are (1 + rate)^(-t) with annual effective spot rates.
|
|
33
|
+
* Under a spot curve, a payment at time t uses the rate for the year
|
|
34
|
+
* containing t (t in (k-1, k] years uses spotByYear[k-1]); payments beyond
|
|
35
|
+
* the curve horizon use the LAST spot rate, with a warning.
|
|
36
|
+
*/
|
|
37
|
+
export type DiscountConvention = "mid-period" | "end-period";
|
|
38
|
+
/** One expected payment, located relative to the valuation date. */
|
|
39
|
+
export interface PayoutCashflow {
|
|
40
|
+
/** Months after the valuation date at which the payment interval opens. */
|
|
41
|
+
fromMonths: number;
|
|
42
|
+
/** Months after the valuation date at which the interval closes. */
|
|
43
|
+
toMonths: number;
|
|
44
|
+
/** Expected payment within the interval (negative = expected recovery). */
|
|
45
|
+
amount: number;
|
|
46
|
+
}
|
|
47
|
+
export interface PayoutPatternRow {
|
|
48
|
+
origin: string;
|
|
49
|
+
/** Age (months) of the latest observed diagonal cell (the valuation age). */
|
|
50
|
+
latestAge: number;
|
|
51
|
+
/** The chain ladder unpaid this row's cashflows tie to (sum of amounts). */
|
|
52
|
+
unpaid: number;
|
|
53
|
+
cashflows: PayoutCashflow[];
|
|
54
|
+
}
|
|
55
|
+
export interface PayoutPattern {
|
|
56
|
+
rows: PayoutPatternRow[];
|
|
57
|
+
warnings: string[];
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Expected future incremental payments per origin, derived from a chain
|
|
61
|
+
* ladder result: the increment for development interval (ages[j], ages[j+1]]
|
|
62
|
+
* is ultimate x (percentDeveloped[j+1] - percentDeveloped[j]), and the tail
|
|
63
|
+
* cash implied by a tail factor > 1 (ultimate x (1 - percentDeveloped at the
|
|
64
|
+
* last age)) is compressed into a single interval of the same width as the
|
|
65
|
+
* last observed development step, immediately after the last age (warned; a
|
|
66
|
+
* single-age triangle uses a 12-month tail interval). Each row's cashflow
|
|
67
|
+
* amounts sum to its unpaid by construction.
|
|
68
|
+
*
|
|
69
|
+
* `ages` must be the development ages the chain ladder ran on (the result
|
|
70
|
+
* does not carry them). Negative increments (percent developed not monotone,
|
|
71
|
+
* i.e. an LDF below 1) are kept and warned - never dropped or fabricated
|
|
72
|
+
* away.
|
|
73
|
+
*/
|
|
74
|
+
export declare function payoutPatternFromChainLadder(cl: ChainLadderResult, ages: number[]): PayoutPattern;
|
|
75
|
+
/**
|
|
76
|
+
* Discount rates, annual effective:
|
|
77
|
+
* - "flat": one rate for every maturity.
|
|
78
|
+
* - "curve": spotByYear[k] is the spot rate for payments in year k+1 (times
|
|
79
|
+
* t in (k, k+1] years). Payments beyond the horizon use the last rate.
|
|
80
|
+
*/
|
|
81
|
+
export type DiscountRates = {
|
|
82
|
+
kind: "flat";
|
|
83
|
+
annualRate: number;
|
|
84
|
+
} | {
|
|
85
|
+
kind: "curve";
|
|
86
|
+
spotByYear: number[];
|
|
87
|
+
};
|
|
88
|
+
/**
|
|
89
|
+
* Where the rates came from and when - REQUIRED, because ASOP 20 requires
|
|
90
|
+
* the actuary to disclose the basis of the discount rate(s) and the date as
|
|
91
|
+
* of which they were determined.
|
|
92
|
+
*/
|
|
93
|
+
export interface RateProvenance {
|
|
94
|
+
/** e.g. "US Treasury CMT curve", "company investment yield per ASOP 20 5.3". */
|
|
95
|
+
source: string;
|
|
96
|
+
/** ISO date (yyyy-mm-dd) the rates were determined as of. */
|
|
97
|
+
asOfDate: string;
|
|
98
|
+
}
|
|
99
|
+
/** Explicit cashflows for one origin (the non-pattern input path). */
|
|
100
|
+
export interface OriginCashflows {
|
|
101
|
+
origin: string;
|
|
102
|
+
cashflows: PayoutCashflow[];
|
|
103
|
+
}
|
|
104
|
+
export interface DiscountUnpaidInput {
|
|
105
|
+
/** Payout pattern from payoutPatternFromChainLadder. Exactly one of pattern/cashflows. */
|
|
106
|
+
pattern?: PayoutPattern;
|
|
107
|
+
/** Explicit per-origin cashflows. Exactly one of pattern/cashflows. */
|
|
108
|
+
cashflows?: OriginCashflows[];
|
|
109
|
+
rates: DiscountRates;
|
|
110
|
+
provenance: RateProvenance;
|
|
111
|
+
convention: DiscountConvention;
|
|
112
|
+
/**
|
|
113
|
+
* Explicit risk margin (a dollar amount, not a rate). Carried through the
|
|
114
|
+
* result UNCHANGED and kept out of every total - never blended.
|
|
115
|
+
*/
|
|
116
|
+
riskMargin?: number;
|
|
117
|
+
}
|
|
118
|
+
export interface DiscountedCashflowDetail {
|
|
119
|
+
/** Payment time in years from the valuation date under the chosen convention. */
|
|
120
|
+
timeYears: number;
|
|
121
|
+
amount: number;
|
|
122
|
+
/** Annual effective spot rate applied at timeYears. */
|
|
123
|
+
rate: number;
|
|
124
|
+
/** (1 + rate)^(-timeYears). */
|
|
125
|
+
discountFactor: number;
|
|
126
|
+
discounted: number;
|
|
127
|
+
}
|
|
128
|
+
export interface DiscountedUnpaidRow {
|
|
129
|
+
origin: string;
|
|
130
|
+
/** Undiscounted expected future payments (sum of cashflow amounts). */
|
|
131
|
+
nominal: number;
|
|
132
|
+
discounted: number;
|
|
133
|
+
/** nominal - discounted (the amount of discount taken). */
|
|
134
|
+
discount: number;
|
|
135
|
+
/** discounted / nominal; null when nominal is not positive. */
|
|
136
|
+
effectiveDiscountFactor: number | null;
|
|
137
|
+
cashflows: DiscountedCashflowDetail[];
|
|
138
|
+
}
|
|
139
|
+
export interface DiscountUnpaidResult {
|
|
140
|
+
method: "discountUnpaid";
|
|
141
|
+
convention: DiscountConvention;
|
|
142
|
+
rates: DiscountRates;
|
|
143
|
+
provenance: RateProvenance;
|
|
144
|
+
rows: DiscountedUnpaidRow[];
|
|
145
|
+
totals: {
|
|
146
|
+
nominal: number;
|
|
147
|
+
discounted: number;
|
|
148
|
+
discount: number;
|
|
149
|
+
effectiveDiscountFactor: number | null;
|
|
150
|
+
};
|
|
151
|
+
/**
|
|
152
|
+
* The caller's explicit risk margin, passed through untouched (null when
|
|
153
|
+
* none was supplied). NOT included in any total above: presenting it as a
|
|
154
|
+
* separate line is the consumer's job, per the explicit-only rule.
|
|
155
|
+
*/
|
|
156
|
+
riskMargin: number | null;
|
|
157
|
+
warnings: string[];
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Discounts expected future payments and reports nominal and discounted
|
|
161
|
+
* unpaid side by side, per origin and in total. See the module doc for the
|
|
162
|
+
* timing convention, curve lookup, and the ASOP 20 provenance/risk-margin
|
|
163
|
+
* rules this function enforces.
|
|
164
|
+
*/
|
|
165
|
+
export declare function discountUnpaid(input: DiscountUnpaidInput): DiscountUnpaidResult;
|
|
166
|
+
//# sourceMappingURL=discounting.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"discounting.d.ts","sourceRoot":"","sources":["../src/discounting.ts"],"names":[],"mappings":"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"}
|