Skip to contents

The 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 OneYearFit pointer; 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; NULL for 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 in chain_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, variance scale * |mean|) or "none" for parameter error only. For mack_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 in mack().

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); FALSE resamples them uncentred, as England, Verrall and Wuthrich's Appendix 1 is written.

Value

A one_year_fit object.

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