Simulated one-year view
one_year_fit.RdThe claims development result (CDR) of the chain ladder or an
expected-loss method over the coming year, by re-reserving on the ODP
bootstrap ("actuary in the box": Ohlsson and Lauzeningks 2009; England,
Verrall and Wuthrich 2019). The coming year is every cell valued in the
twelve months after the segment's valuation: one per origin for an
annual development grain, four for a quarterly one (fewer for an origin
that reaches the last age). Each simulation resamples the residuals of
the volume-weighted chain ladder as odp_bootstrap() does, projects the
increments of those cells in turn from the origin's resampled latest
value with the bootstrap's process error, as odp_bootstrap() projects,
adds them to the observed latest value, appends the cells to the
triangle, refits method and records CDR = opening ultimate - closing ultimate, so a negative CDR is an adverse development. An origin whose
remaining cells all fall in the year thus has its lifetime bootstrap
reserve as its one-year view. An origin at the last age gets no new
cell, an origin short of the latest diagonal develops from its own
latest cell (only the year's cells are appended), and a new origin
written in the coming year is not simulated. Unlike
claims_development_result() (Merz and Wuthrich), any averaging, tail
and development grain are allowed.
Usage
one_year_fit(ptr)
odp_one_year(
triangle,
column = NULL,
method = c("chain_ladder", "expected_loss", "bornhuetter_ferguson", "benktander",
"cape_cod"),
exposure = NULL,
apriori = 1,
n_iters = 1,
trend = 0,
decay = 1,
average = "volume",
sigma_interpolation = "log-linear",
tail = 1,
n_sims = 10000,
seed = 0,
process = c("gamma", "none")
)
mack_one_year(
triangle,
column = NULL,
method = c("chain_ladder", "expected_loss", "bornhuetter_ferguson", "benktander",
"cape_cod"),
exposure = NULL,
apriori = 1,
n_iters = 1,
trend = 0,
decay = 1,
average = "volume",
sigma_interpolation = "log-linear",
tail = 1,
n_sims = 10000,
seed = 0,
process = c("gamma", "lognormal", "residuals", "normal", "none"),
mack_average = "volume",
mack_sigma_interpolation = "log-linear",
centre_residuals = TRUE
)Arguments
- ptr
A
OneYearFitpointer; used internally.- triangle
A cumulative triangle, with any number of segments, every origin observed from the first age up to its latest.
- column
Name of the loss column; by default the only one.
- method
The reserving method refitted at the start and at the end of the year:
"chain_ladder","expected_loss","bornhuetter_ferguson","benktander"or"cape_cod".- exposure
Name of the exposure column for the expected-loss methods;
NULLfor the chain ladder.- apriori, n_iters
As in
expected_loss_fit().- trend, decay
As in
cape_cod().- average, sigma_interpolation, tail
The chain ladder or development pattern of
method, as inchain_ladder().- n_sims
Number of simulations; positive.
- seed
Seed of the simulation streams, a non-negative whole number.
- process
Process error. For
odp_one_year(), on each simulated incremental value:"gamma"(mean the expected value, variancescale * |mean|) or"none"for parameter error only. Formack_one_year(), on each next cumulative value:"gamma"or"lognormal"(negated for a negative mean) or"normal", with Mack's mean and variance;"residuals"(the mean plus a resampled residual times the standard deviation, which carries the residuals' mean and variance); or"none".- mack_average, mack_sigma_interpolation
How Mack's model in
mack_one_year()averages the link ratios and fills in a sigma behind a single link ratio, as inmack().- centre_residuals
For
mack_one_year(), subtract the residuals' mean before resampling them, so that the pseudo factors are unbiased and the mean CDR is about zero (the default);FALSEresamples them uncentred, as England, Verrall and Wuthrich's Appendix 1 is written.
Details
method names one of chain_ladder(), expected_loss(),
bornhuetter_ferguson(), benktander() and cape_cod(), with the same
settings: average, sigma_interpolation and tail give the chain
ladder refitted (or the development pattern of the other methods),
apriori is read by the expected loss, Bornhuetter-Ferguson and
Benktander methods, n_iters by Benktander, trend and decay by Cape
Cod; giving a setting the method does not read is an error. The
expected-loss methods need exposure, the chain ladder takes none; each
origin's latest exposure is kept for the end of the year, and Cape Cod
trends to the valuation a year later.
The bootstrap only drives the simulation: its factors are always
volume-weighted without a tail, whatever method refits. On that same
chain ladder the standard deviation of the CDR is not Merz and
Wuthrich's: the ODP's process variance is the scale times the mean,
Mack's sigma^2 times the cumulative value. In total it is 0.62 times
Merz-Wuthrich on RAA, 1.37 on GenIns and 1.14 on ABC, and per origin
from 0.50 to 5.96 times
(knowledge/findings/one-year-bootstrap-vs-merz-wuthrich.md).
mack_one_year() re-reserves the same way under Mack's process instead,
England, Verrall and Wuthrich's (2019, Appendix 1) bootstrap of Mack's
model: each simulation resamples the scaled bias-adjusted residuals of
the link ratios into pseudo factors, averaged as mack_average, and
draws each cumulative value of the coming year from the one before C
(the observed latest value for the first) with mean f* C and variance
sigma^2 |C|^(2 - alpha), with the same pseudo factors all year. With the
volume-weighted chain ladder and no tail, its standard deviations are
Merz and Wuthrich's (claims_development_result()) within Monte Carlo
error, which reconciles the two, and its mean is Merz and Wuthrich's
zero, because by default (centre_residuals = TRUE) the pool of
residuals is centred first. Uncentred (centre_residuals = FALSE, EVW's
Appendix 1 as written), the pool's non-zero mean biases the pseudo
factors: the mean CDR is about -0.2 (RAA), -0.04 (GenIns) and +0.18
(ABC) times its standard deviation, and RAA's standard deviations up to
1.3% wide. Mack's model has no tail here: the
development past the oldest age moves only through method's refitted
tail. Its fit has model = "mack", no scale, and mack, the
mack_fit it simulates from; it needs no negative cumulative value.
Every segment of the triangle is bootstrapped on its own, with its own
residuals and scale, into one joint distribution of the CDR; simulation
i uses random stream i of seed for every segment in turn, so
results do not depend on the number of threads.
Properties of the fit: chain_ladder (the bootstrap's volume-weighted
chain_ladder_fit), keys, index, origins, development; per
origin (named as a chain_ladder_fit's) latest, opening_ultimate
(the method's ultimate on the observed triangle) and opening_reserve
(opening_ultimate - latest); scale (the bootstrap's phi, which
needs a single-segment fit: use totals_frame() or segment()); and
cdr, a predictive_distribution of the CDR with the triangle's keys
and origin as dimensions and one component per segment and origin, so
aggregate(fit@cdr, keep = "lob") keeps the dependence between
segments. mean(), quantile(), VaR() and TVaR() of cdr describe
the total, and -quantile(fit@cdr, 0.005) is the one-year loss at
99.5%. Columns of draw_matrix() follow origins.
as.data.frame() has one row per segment and origin: origin,
latest, opening_ultimate, opening_reserve, and the cdr_mean and
cdr_std_dev of the simulated CDR; totals_frame() one per segment,
with the ODP bootstrap's scale too. model is "odp" or "mack".
Errors: as odp_bootstrap() (or mack() for mack_one_year()) and the
method's own fit; a missing exposure for an expected-loss method or one
given for the chain ladder; or a refit that fails in any simulation (a
zero value under a simple average, say), counted in the message with one
of the failures.
These are Python's OdpBootstrap.one_year() and
MackBootstrap.one_year(), which return a OneYearFit.
See also
claims_development_result() for Merz and Wuthrich's formulas,
odp_bootstrap() and mack_bootstrap() for the lifetime view.
Examples
long <- data.frame(year = rep(2018:2021, 4:1),
age = c(12, 24, 36, 48, 12, 24, 36, 12, 24, 12),
paid = c(100, 150, 165, 170, 110, 170, 180, 120, 175, 130),
premium = rep(c(250, 260, 270, 280), 4:1))
tri <- triangle(long, "year", "age", c("paid", "premium"))
cl <- odp_one_year(tri, "paid", n_sims = 2000, seed = 42)
cl@opening_reserve
#> 2018 2019 2020 2021
#> 0.000000 5.454545 19.389205 86.605114
mean(cl@cdr)
#> [1] -0.3381156
# The one-year view is narrower than the lifetime view.
c(one_year = sqrt(variance(cl@cdr)),
lifetime = sqrt(variance(odp_bootstrap(tri, "paid", n_sims = 2000, seed = 42)@reserves)))
#> one_year lifetime
#> 13.93714 15.53053
bf <- odp_one_year(tri, "paid", "bornhuetter_ferguson", exposure = "premium", apriori = 0.7,
n_sims = 2000, seed = 42)
as.data.frame(bf)
#> origin latest opening_ultimate opening_reserve cdr_mean cdr_std_dev
#> 1 2018 170 170.0000 0.000000 0.0000000 0.000000
#> 2 2019 180 185.3529 5.352941 -0.2046123 3.023400
#> 3 2020 175 193.8517 18.851662 -0.5441021 4.470905
#> 4 2021 130 208.3666 78.366581 -6.1970037 9.982098
-quantile(bf@cdr, 0.005)
#> [1] 43.53641
# Under Mack's process the chain ladder's one-year view is Merz and
# Wuthrich's, up to Monte Carlo error.
mk <- mack_one_year(tri, "paid", n_sims = 2000, seed = 42)
mk@model
#> [1] "mack"
c(simulated = sqrt(variance(mk@cdr)),
merz_wuthrich = claims_development_result(mk@mack)@total_one_year_standard_error)
#> simulated merz_wuthrich
#> 16.34670 16.45603