Computes the actuarial present value of a discrete life annuity using compact actuarial notation.
Arguments
- lt
A life table as produced by
lifetable, or atidyact_life_contractobject created bylife_contract. A life table must contain columnsxandlx.- x
Integer actuarial age, or a vector of scenario ages. Optional when
ltis a single-lifetidyact_life_contract.- i
Numeric annual interest-rate input, scalar or by scenario. Optional when
ltis a single-lifetidyact_life_contract.- i_type
Character string indicating the interest-rate type. Allowed values are
"effective","nominal_interest","nominal_discount", and"force".- m
Positive integer. Conversion frequency for nominal interest rates. Ignored for
i_type = "effective"andi_type = "force". Intidyactuarial,mis reserved for interest conversion frequency, not deferment.- n
Numeric term in years. Use
NULLorInffor a whole-life annuity. For exact k-thly valuation (woolhouse = "none"), fractional terms are allowed whenn * kis an integer. Woolhouse approximations require an integer number of years.- h
Integer deferment period in years.
- k
Positive integer. Number of annuity payments per year. For example, use
k = 12for monthly payments. The annuity is normalized to an annual payment rate of 1, so each individual payment has amount1 / k.- timing
Character string. Either
"immediate"for payments at the end of each payment period or"due"for payments at the beginning of each payment period.- woolhouse
Character string. For
k > 1, use"none"for exact fractional-age computation,"first"for the first-order Woolhouse approximation, or"second"for the second-order Woolhouse approximation.- frac
Character string. Fractional-age assumption used when
k > 1andwoolhouse = "none". Allowed values are"UDD","CF","CML", and"Balducci". IfNULL, thefracattribute ofltis used when available; otherwise"UDD"is used.- tidy
Logical. If
FALSE, returns a numeric APV. IfTRUE, returns one tibble row per scenario with intermediate quantities.
Value
If tidy = FALSE, a numeric vector of actuarial present values,
of length one for a single scenario.
If tidy = TRUE, a tibble with one row per scenario, the main input values,
equivalent interest rate, deferment factor, pure endowment factor, and APV.
Details
The function supports:
whole-life annuities,
temporary annuities,
integer deferment,
annual or k-thly payments,
exact fractional survival for k-thly payments,
first- and second-order Woolhouse approximations.
This function follows the compact actuarial notation used throughout
tidyactuarial:
lt: life table;x: actuarial age;i: interest rate;i_type: interest-rate type;m: interest conversion frequency;n: annuity term;h: deferment period;k: payment frequency.
For annual annuities-due, $$\ddot{a}_{x:\overline{n}|} = \sum_{j=0}^{n-1} v^j\,{}_jp_x.$$
For annual annuities-immediate, $$a_{x:\overline{n}|} = \sum_{j=1}^{n} v^j\,{}_jp_x.$$
Deferment is handled through $$v^h\,{}_hp_x,$$ where \(h\) is the deferment period.
For k-thly payments with woolhouse = "none", fractional survival is
computed under the selected fractional-age assumption. The payment stream
is normalized to an annual payment rate of 1:
$$\ddot{a}_{x:\overline{n}|}^{(k)} =
\frac{1}{k}\sum_{j=0}^{kn-1}
v^{j/k}\,{}_{j/k}p_x.$$
Consequently, each k-thly installment has amount \(1/k\). This
normalization is essential when the function is used as the premium
annuity in the equivalence principle: the resulting premium is annualized,
and the amount paid at each installment is the annualized premium divided
by \(k\).
Scenarios and tidy workflows. All arguments except lt and
tidy may have a common positive length; only length-one arguments
recycle. n = NULL and frac = NULL keep their scalar default
meanings. Scenarios are paired by position, not expanded to a Cartesian
product, and each describes one life under the shared table. Invalid or
missing inputs are rejected with the scenario number; no partial result is
returned. Use dplyr::mutate() with tidy = FALSE for portfolios,
or tidy = TRUE for an auditable scenario table. Different mortality
tables require separate calls, for example in a list-column workflow.
Model and numerical limits. Discounting retains the original log
accumulation rate; exact payments are valued from the issue age, avoiding
products of separately rounded deferment and conditional values. Intermediate
diagnostic values can be zero or infinite while the APV remains finite.
Tables must have an annual age grid and nonincreasing finite lx,
with a positive count at issue. For compatibility, a count of zero is assumed
at one year beyond the last recorded age, even for an open input table.
Known extinct tails contribute zero. Woolhouse is an approximation using
annual survival estimates of boundary forces, not an exact integral; its
second order requires positive survival where a boundary force is needed.
Negative approximations generate a warning and are not clamped. Prefer
woolhouse = "none" for exact payments under the chosen fractional
assumption. At n = 0, APV and the annuity value at start are zero,
while the zero-term pure endowment factor is one.
See also
insurance_x, premium_x,
reserve_x, t_px, t_Ex
Other life-contingencies:
add_insurance(),
add_premium_schedule(),
annuity_multi(),
annuity_xy(),
insurance_variable_k(),
insurance_x(),
insurance_xy(),
life_contract(),
premium_gross(),
premium_x(),
premium_xy(),
reserve_x(),
reserve_xy(),
simulate_annuity_x(),
simulate_insurance_x()
Examples
lt <- data.frame(
x = 60:65,
lx = c(100000, 99000, 97500, 95500, 93000, 90000)
)
# Annual annuity-immediate
annuity_x(
lt = lt,
x = 60,
i = 0.06,
timing = "immediate"
)
#> [1] 4.012725
# Annual annuity-due
annuity_x(
lt = lt,
x = 60,
i = 0.06,
timing = "due"
)
#> [1] 5.012725
# Temporary annuity
annuity_x(
lt = lt,
x = 60,
i = 0.06,
n = 3,
timing = "due"
)
#> [1] 2.801709
# Deferred annuity
annuity_x(
lt = lt,
x = 60,
i = 0.06,
h = 2,
timing = "due"
)
#> [1] 3.078762
# Tidy output
annuity_x(
lt = lt,
x = 60,
i = 0.06,
n = 3,
timing = "due",
tidy = TRUE
)
#> # A tibble: 1 × 17
#> x i i_type m i_effective n n_used h x_h k timing
#> <int> <dbl> <chr> <int> <dbl> <dbl> <dbl> <int> <int> <int> <chr>
#> 1 60 0.06 effective 1 0.06 3 3 0 60 1 due
#> # ℹ 6 more variables: woolhouse <chr>, frac <chr>, deferment_factor <dbl>,
#> # pure_endowment_factor <dbl>, annuity_value_at_start <dbl>, apv <dbl>
# Pipe workflow with a life contract
life_contract(lt = lt, lives = "single", x = 60, i = 0.06) |>
annuity_x(n = 3, timing = "due")
#> [1] 2.801709
# Parallel single-life scenarios, suitable for mutate()
policies <- tibble::tibble(age = c(60, 61, 62), rate = c(0.03, 0.04, 0.05))
dplyr::mutate(policies,
apv = annuity_x(lt, x = age, i = rate, n = 2, k = 12, timing = "due"))
#> # A tibble: 3 × 3
#> age rate apv
#> <dbl> <dbl> <dbl>
#> 1 60 0.03 1.92
#> 2 61 0.04 1.90
#> 3 62 0.05 1.87
annuity_x(lt, x = c(60, 61), i = 0.04, n = c(2, 3), tidy = TRUE)
#> # A tibble: 2 × 17
#> x i i_type m i_effective n n_used h x_h k timing
#> <int> <dbl> <chr> <int> <dbl> <dbl> <dbl> <int> <int> <int> <chr>
#> 1 60 0.04 effective 1 0.04 2 2 0 60 1 immedi…
#> 2 61 0.04 effective 1 0.04 3 3 0 61 1 immedi…
#> # ℹ 6 more variables: woolhouse <chr>, frac <chr>, deferment_factor <dbl>,
#> # pure_endowment_factor <dbl>, annuity_value_at_start <dbl>, apv <dbl>