| Title: | Tidy Tools for Actuarial Mathematics and Life Contingencies |
|---|---|
| Description: | Provides tidyverse-aligned tools for actuarial mathematics and life contingencies, including life tables, survival probabilities, actuarial present values of cash flows, life annuities, life insurance, premiums, reserves, multiple-life calculations, Monte Carlo simulation, and deterministic cash-flow diagrams. The package emphasizes clear actuarial notation, reproducible workflows, and pipe-friendly tools for actuarial education and applied actuarial analysis. |
| Authors: | Julian Fajardo [aut, cre] |
| Maintainer: | Julian Fajardo <[email protected]> |
| License: | MIT + file LICENSE |
| Version: | 0.1.5 |
| Built: | 2026-06-04 11:09:09 UTC |
| Source: | https://github.com/julianfajardo1908/tidyactuarial |
Computes the actuarial present value factor for a level annuity using compact actuarial notation.
a_angle( n = NULL, k = 1L, i, i_type = "effective", m = 1L, h = 0, timing = "immediate", perpetuity = FALSE, payment = 1, tidy = FALSE )a_angle( n = NULL, k = 1L, i, i_type = "effective", m = 1L, h = 0, timing = "immediate", perpetuity = FALSE, payment = 1, tidy = FALSE )
n |
Numeric vector of payment durations in years. Ignored when
|
k |
Positive integer vector giving the number of discrete payments per year. Ignored for continuous annuities. |
i |
Numeric vector of interest-rate values. |
i_type |
Character vector indicating the interest-rate type. Allowed
values are |
m |
Positive integer vector giving the conversion frequency for nominal
rates. Ignored for |
h |
Numeric vector of deferment times in years. Must be greater than or equal to 0. |
timing |
Character vector. One of |
perpetuity |
Logical vector. If |
payment |
Numeric vector of level payment amounts. Used only when
|
tidy |
Logical scalar. If |
Supported timing conventions:
"immediate": annuity-immediate with discrete payments.
"due": annuity-due with discrete payments.
"continuous": continuous annuity.
For discrete annuities, k is the number of payments per year, so
payments are made every year. The function returns the annuity
factor, assuming a unit payment at each payment time.
Deferment is supported through h. For discrete annuities, the
deferment must align with the payment grid, that is, must be an
integer.
If perpetuity = TRUE, the infinite-term annuity factor is returned.
This function follows the compact actuarial notation used throughout
tidyactuarial:
n: annuity term;
k: payment frequency;
i: interest rate;
i_type: interest-rate type;
m: conversion frequency for nominal rates;
h: deferment period.
The function first converts the supplied rate to the equivalent annual
effective interest rate using standardize_interest.
For finite discrete annuities:
For due annuities:
For continuous annuities:
Input vectors must have length 1 or a common length. Missing values are propagated.
If tidy = FALSE, a numeric vector of annuity factors.
If tidy = TRUE, a tibble with input values, equivalent rates, annuity
factors, payment amounts, and present values.
s_angle, standardize_interest,
present_value
Other annuities:
annuity_arith(),
annuity_geom(),
s_angle()
# Numeric annuity factor a_angle(n = 10, i = 0.05) # Nominal interest converted monthly, with monthly payments a_angle( n = 10, i = 0.06, i_type = "nominal_interest", m = 12, k = 12 ) # Continuous annuity a_angle( n = 15, i = 0.04, i_type = "force", timing = "continuous" ) # Tibble output for teaching or auditing a_angle( n = 10, i = 0.05, payment = 1000, tidy = TRUE ) # Vectorized example a_angle( n = c(5, 10, 20), k = c(1, 12, 1), i = c(0.05, 0.06, 0.04), i_type = c("effective", "nominal_interest", "force"), m = c(1, 12, 1), h = c(0, 0, 2), timing = c("immediate", "immediate", "continuous"), perpetuity = c(FALSE, FALSE, FALSE) )# Numeric annuity factor a_angle(n = 10, i = 0.05) # Nominal interest converted monthly, with monthly payments a_angle( n = 10, i = 0.06, i_type = "nominal_interest", m = 12, k = 12 ) # Continuous annuity a_angle( n = 15, i = 0.04, i_type = "force", timing = "continuous" ) # Tibble output for teaching or auditing a_angle( n = 10, i = 0.05, payment = 1000, tidy = TRUE ) # Vectorized example a_angle( n = c(5, 10, 20), k = c(1, 12, 1), i = c(0.05, 0.06, 0.04), i_type = c("effective", "nominal_interest", "force"), m = c(1, 12, 1), h = c(0, 0, 2), timing = c("immediate", "immediate", "continuous"), perpetuity = c(FALSE, FALSE, FALSE) )
Builds an amortization schedule under a fixed annual interest-rate specification, allowing extra principal payments and optional adjustment of either the remaining term or the remaining payment amount.
amort_schedule( principal, n, i, i_type = "effective", m = 1L, k = 1L, timing = c("immediate", "due"), payment = NULL, extra_principal = NULL, adjust = c("none", "term", "payment"), tol = 1e-08 )amort_schedule( principal, n, i, i_type = "effective", m = 1L, k = 1L, timing = c("immediate", "due"), payment = NULL, extra_principal = NULL, adjust = c("none", "term", "payment"), tol = 1e-08 )
principal |
Numeric scalar. Initial outstanding balance. |
n |
Positive integer. Number of contractual periods. |
i |
Numeric scalar. Annual interest-rate input. |
i_type |
Character string indicating the annual interest-rate type:
|
m |
Positive integer. Conversion frequency for nominal annual rates. |
k |
Positive integer. Number of amortization periods per year. |
timing |
Character string. One of |
payment |
Optional numeric scalar. Initial regular payment per period.
If |
extra_principal |
Optional extra principal payments. Can be:
|
adjust |
Character string. One of |
tol |
Numeric tolerance for zero-balance detection. |
The annual rate is converted internally to an effective rate per schedule
period using k.
Adjustment policies after extra principal payments:
"none": keep the original payment and contractual term,
unless the loan is fully repaid early.
"term": keep the regular payment and shorten the term.
No special logic is needed: the loop exits naturally when the
outstanding balance reaches zero.
"payment": keep the remaining contractual term and
recalculate the regular payment after each period.
This function follows the compact actuarial notation used throughout
tidyactuarial: i is the interest rate, i_type is the
interest-rate type, m is the conversion frequency for nominal annual
rates, and k is the number of amortization periods per year.
For timing = "immediate" (annuity-immediate), interest accrues on the
outstanding balance during the period, and the payment is made at the end.
For timing = "due" (annuity-due), the payment is made at the start of
the period and interest accrues on the balance after the payment.
If the user supplies a custom payment that is smaller than the
periodic interest, principal repayment will be negative (negative
amortization). This is permitted but the user should be aware.
A tibble with one row per realized period and columns:
Period index.
Outstanding balance at the start of the period.
Interest charged during the period.
Regular payment in the period.
Extra principal paid in the period.
Principal repaid through the regular payment.
Total principal repaid in the period.
Total payment made in the period.
Outstanding balance at the end of the period.
Equivalent annual effective rate.
Equivalent effective rate per schedule period.
Schedule frequency.
Payment timing convention.
Adjustment rule used.
a_angle, present_value,
pv_flow, standardize_interest
Other amortization:
sinking_fund_schedule()
amort_schedule( principal = 100000, n = 12, i = 0.12, i_type = "nominal_interest", m = 12, k = 12 ) amort_schedule( principal = 100000, n = 24, i = 0.12, i_type = "nominal_interest", m = 12, k = 12, extra_principal = c("6" = 5000, "12" = 3000), adjust = "term" ) amort_schedule( principal = 100000, n = 24, i = 0.12, i_type = "nominal_interest", m = 12, k = 12, extra_principal = c("6" = 5000, "12" = 3000), adjust = "payment" )amort_schedule( principal = 100000, n = 12, i = 0.12, i_type = "nominal_interest", m = 12, k = 12 ) amort_schedule( principal = 100000, n = 24, i = 0.12, i_type = "nominal_interest", m = 12, k = 12, extra_principal = c("6" = 5000, "12" = 3000), adjust = "term" ) amort_schedule( principal = 100000, n = 24, i = 0.12, i_type = "nominal_interest", m = 12, k = 12, extra_principal = c("6" = 5000, "12" = 3000), adjust = "payment" )
Computes the actuarial present value or accumulated value factor for an arithmetic annuity, using compact actuarial notation.
annuity_arith( n, k = 1L, i, i_type = "effective", m = 1L, h = 0, timing = "immediate", pattern = "increasing", P1 = 1, g = 1, valuation = c("present", "accumulated"), tidy = FALSE )annuity_arith( n, k = 1L, i, i_type = "effective", m = 1L, h = 0, timing = "immediate", pattern = "increasing", P1 = 1, g = 1, valuation = c("present", "accumulated"), tidy = FALSE )
n |
Numeric vector of payment durations in years. Each value must be positive and finite. |
k |
Positive integer vector giving the number of payments per year. |
i |
Numeric vector of interest-rate values. |
i_type |
Character vector indicating the interest-rate type. Allowed
values are |
m |
Positive integer vector giving the conversion frequency for nominal
rates. Ignored for |
h |
Numeric vector of deferment times in years. Must be greater than or equal to 0. |
timing |
Character vector. One of |
pattern |
Character vector. One of |
P1 |
Numeric vector. First payment for |
g |
Numeric vector. Arithmetic increment for
|
valuation |
Character string. Use |
tidy |
Logical scalar. If |
This function covers increasing, decreasing, and custom arithmetic payment patterns. It replaces the more specific increasing and decreasing annuity functions.
Supported payment patterns:
"increasing": payments .
"decreasing": payments .
"custom": payments following
.
Supported timing conventions:
"immediate": payments at the end of each period.
"due": payments at the beginning of each period.
This function follows the compact actuarial notation used throughout
tidyactuarial: n is the term, k is the payment
frequency, i is the interest-rate input, i_type is the
interest-rate type, m is the conversion frequency for nominal rates,
and h is the deferment period.
The function first converts the supplied rate to the equivalent annual
effective interest rate using standardize_interest.
For each scenario, the total number of payments is
The present value is computed by summing the discounted payment stream. The
accumulated value is computed at the end of the annuity term. Under this
convention, h affects the present value factor but not the
accumulated value factor.
If tidy = FALSE, a numeric vector of arithmetic annuity factors.
If tidy = TRUE, a tibble with input values, equivalent rates, period
quantities, and both present and accumulated value factors.
a_angle, s_angle,
standardize_interest
Other annuities:
a_angle(),
annuity_geom(),
s_angle()
# Increasing arithmetic annuity annuity_arith(n = 10, i = 0.05, pattern = "increasing") # Decreasing arithmetic annuity annuity_arith(n = 10, i = 0.05, pattern = "decreasing") # Custom arithmetic annuity annuity_arith( n = 10, i = 0.05, pattern = "custom", P1 = 100, g = 25 ) # Accumulated value factor annuity_arith( n = 10, i = 0.05, pattern = "increasing", valuation = "accumulated" ) # Tibble output annuity_arith( n = 10, i = 0.05, pattern = "decreasing", tidy = TRUE )# Increasing arithmetic annuity annuity_arith(n = 10, i = 0.05, pattern = "increasing") # Decreasing arithmetic annuity annuity_arith(n = 10, i = 0.05, pattern = "decreasing") # Custom arithmetic annuity annuity_arith( n = 10, i = 0.05, pattern = "custom", P1 = 100, g = 25 ) # Accumulated value factor annuity_arith( n = 10, i = 0.05, pattern = "increasing", valuation = "accumulated" ) # Tibble output annuity_arith( n = 10, i = 0.05, pattern = "decreasing", tidy = TRUE )
Computes the actuarial present value or accumulated value factor for a geometric annuity, using compact actuarial notation.
annuity_geom( n = NULL, k = 1L, i, i_type = "effective", m = 1L, g = 0, g_type = "effective", g_m = 1L, h = 0, timing = "immediate", P1 = 1, perpetuity = FALSE, valuation = c("present", "accumulated"), tidy = FALSE )annuity_geom( n = NULL, k = 1L, i, i_type = "effective", m = 1L, g = 0, g_type = "effective", g_m = 1L, h = 0, timing = "immediate", P1 = 1, perpetuity = FALSE, valuation = c("present", "accumulated"), tidy = FALSE )
n |
Numeric vector of payment durations in years. Ignored only when
|
k |
Positive integer vector giving the number of payments per year. |
i |
Numeric vector of interest-rate values. |
i_type |
Character vector indicating the interest-rate type. Allowed
values are |
m |
Positive integer vector giving the conversion frequency for nominal
interest-rate inputs. Ignored for |
g |
Numeric vector of annual growth-rate values for the payments. |
g_type |
Character vector indicating the growth-rate type. Allowed
values are |
g_m |
Positive integer vector giving the conversion frequency for
nominal growth-rate inputs. Ignored for |
h |
Numeric vector of deferment times in years. Must be greater than or equal to 0. For present values, the deferment discounts the payment block. For accumulated values, it is recorded but does not change the factor under the adopted terminal-horizon convention. |
timing |
Character vector. One of |
P1 |
Numeric vector giving the first payment of the geometric sequence. |
perpetuity |
Logical vector. If |
valuation |
Character string. Use |
tidy |
Logical scalar. If |
This function covers finite geometric annuities and geometric perpetuities.
Supported timing conventions:
"immediate": payments at the end of each period.
"due": payments at the beginning of each period.
This function follows the compact actuarial notation used throughout
tidyactuarial: n is the term, k is the payment
frequency, i is the interest-rate input, i_type is the
interest-rate type, m is the conversion frequency for nominal
interest rates, g is the growth-rate input, g_type is the
growth-rate type, g_m is the conversion frequency for nominal growth
rates, h is the deferment period, and P1 is the first payment.
Let be the effective interest rate per payment period,
the effective growth rate per payment period, and
.
For a finite geometric annuity-immediate with payment periods:
If , then
The accumulated value factor is computed at the standard terminal horizon:
For annuities-due, the corresponding immediate factor is multiplied by
.
If tidy = FALSE, a numeric vector.
If tidy = TRUE, a tibble with input values, equivalent rates, period
quantities, and both present and accumulated value factors.
a_angle, s_angle,
annuity_arith, standardize_interest
Other annuities:
a_angle(),
annuity_arith(),
s_angle()
# Present value of a geometric annuity annuity_geom( n = 10, i = 0.05, g = 0.02, valuation = "present" ) # Accumulated value of a geometric annuity annuity_geom( n = 10, i = 0.05, g = 0.02, valuation = "accumulated" ) # Nominal interest and nominal growth annuity_geom( n = 10, k = 12, i = 0.06, i_type = "nominal_interest", m = 12, g = 0.024, g_type = "nominal_interest", g_m = 12 ) # Tibble output annuity_geom( n = 10, i = 0.05, g = 0.02, tidy = TRUE )# Present value of a geometric annuity annuity_geom( n = 10, i = 0.05, g = 0.02, valuation = "present" ) # Accumulated value of a geometric annuity annuity_geom( n = 10, i = 0.05, g = 0.02, valuation = "accumulated" ) # Nominal interest and nominal growth annuity_geom( n = 10, k = 12, i = 0.06, i_type = "nominal_interest", m = 12, g = 0.024, g_type = "nominal_interest", g_m = 12 ) # Tibble output annuity_geom( n = 10, i = 0.05, g = 0.02, tidy = TRUE )
Computes the APV of a discrete annuity contingent on multiple independent lives using compact actuarial notation.
annuity_multi( lt, ages, i, i_type = "effective", m = 1L, n = NULL, h = 0L, k = 1L, annuity = c("cohort", "reversionary"), cohort = c("first", "last"), alpha = NULL, timing = c("immediate", "due"), woolhouse = c("none", "first", "second") )annuity_multi( lt, ages, i, i_type = "effective", m = 1L, n = NULL, h = 0L, k = 1L, annuity = c("cohort", "reversionary"), cohort = c("first", "last"), alpha = NULL, timing = c("immediate", "due"), woolhouse = c("none", "first", "second") )
lt |
A life table object (data frame or tibble) with column |
ages |
Integer vector of actuarial ages for the lives at issue. Must have length 1, 2, or 3. |
i |
Numeric scalar. Annual interest-rate input. |
i_type |
Character string indicating the interest-rate type. Allowed
values are |
m |
Positive integer. Conversion frequency for nominal rates. Ignored
for |
n |
Integer term in years after deferment. If |
h |
Integer deferment period in years. |
k |
Integer payments per year. If |
annuity |
Type of annuity logic: |
cohort |
Survival status: |
alpha |
Reversionary fraction, typically |
timing |
|
woolhouse |
|
This implementation supports up to three lives, which covers the most common practical multi-life arrangements.
Supports status-based annuities (joint-life / last-survivor) and a
joint-and-survivor style annuity ("reversionary") that pays 1 while all
lives are alive and then pays a fraction while at least one life
remains alive.
This function follows the compact actuarial notation used throughout
tidyactuarial: i is the interest rate, i_type is the
interest-rate type, m is the conversion frequency for nominal rates,
n is the term, h is the deferment period, and k is the
payment frequency.
Under the assumption of independent future lifetimes, the survival probability for the status is calculated as:
Joint-life (first-death):
Last-survivor:
For annuity = "reversionary", the APV is a weighted combination of
the two statuses:
A single numeric value representing the APV.
annuity_x for single-life annuities,
t_px for survival probabilities.
Other life-contingencies:
annuity_x(),
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()
lt <- data.frame( x = 60:90, lx = seq(100000, 0, length.out = 31) ) annuity_multi( lt = lt, ages = c(60, 62), i = 0.05, n = 5, cohort = "first", timing = "due" ) annuity_multi( lt = lt, ages = c(60, 62), i = 0.05, n = 5, cohort = "last", timing = "due" )lt <- data.frame( x = 60:90, lx = seq(100000, 0, length.out = 31) ) annuity_multi( lt = lt, ages = c(60, 62), i = 0.05, n = 5, cohort = "first", timing = "due" ) annuity_multi( lt = lt, ages = c(60, 62), i = 0.05, n = 5, cohort = "last", timing = "due" )
Computes the actuarial present value of a discrete life annuity using compact actuarial notation.
annuity_x( lt, x, i, i_type = "effective", m = 1L, n = NULL, h = 0L, k = 1L, timing = c("immediate", "due"), woolhouse = c("none", "first", "second"), frac = NULL, tidy = FALSE )annuity_x( lt, x, i, i_type = "effective", m = 1L, n = NULL, h = 0L, k = 1L, timing = c("immediate", "due"), woolhouse = c("none", "first", "second"), frac = NULL, tidy = FALSE )
lt |
A life table as produced by |
x |
Integer actuarial age. Optional when |
i |
Numeric scalar. Annual interest-rate input. Optional when |
i_type |
Character string indicating the interest-rate type. Allowed
values are |
m |
Positive integer. Conversion frequency for nominal interest rates.
Ignored for |
n |
Integer term in years. Use |
h |
Integer deferment period in years. |
k |
Positive integer. Number of annuity payments per year. For example,
use |
timing |
Character string. Either |
woolhouse |
Character string. For |
frac |
Character string. Fractional-age assumption used when
|
tidy |
Logical. If |
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,
For annual annuities-immediate,
Deferment is handled through
where is the deferment period.
For k-thly payments with woolhouse = "none", fractional survival is
computed under the selected fractional-age assumption.
If tidy = FALSE, a numeric scalar containing the actuarial present
value.
If tidy = TRUE, a one-row tibble with the main input values,
equivalent interest rate, deferment factor, pure endowment factor, and APV.
insurance_x, premium_x,
reserve_x, t_px, t_Ex
Other life-contingencies:
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()
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" ) # Annual annuity-due annuity_x( lt = lt, x = 60, i = 0.06, timing = "due" ) # Temporary annuity annuity_x( lt = lt, x = 60, i = 0.06, n = 3, timing = "due" ) # Deferred annuity annuity_x( lt = lt, x = 60, i = 0.06, h = 2, timing = "due" ) # Tidy output annuity_x( lt = lt, x = 60, i = 0.06, n = 3, timing = "due", tidy = TRUE ) # Pipe workflow with a life contract life_contract(lt = lt, lives = "single", x = 60, i = 0.06) |> annuity_x(n = 3, timing = "due")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" ) # Annual annuity-due annuity_x( lt = lt, x = 60, i = 0.06, timing = "due" ) # Temporary annuity annuity_x( lt = lt, x = 60, i = 0.06, n = 3, timing = "due" ) # Deferred annuity annuity_x( lt = lt, x = 60, i = 0.06, h = 2, timing = "due" ) # Tidy output annuity_x( lt = lt, x = 60, i = 0.06, n = 3, timing = "due", tidy = TRUE ) # Pipe workflow with a life contract life_contract(lt = lt, lives = "single", x = 60, i = 0.06) |> annuity_x(n = 3, timing = "due")
Computes the actuarial present value of a discrete annuity contingent on two independent lives, using compact actuarial notation.
annuity_xy( lt, x = NULL, y = NULL, i = NULL, i_type = "effective", m = 1L, status = c("joint", "last"), benefit = NULL, n = Inf, h = 0L, k = 1L, timing = c("immediate", "due"), woolhouse = c("none", "first", "second"), frac, tidy = FALSE, ... )annuity_xy( lt, x = NULL, y = NULL, i = NULL, i_type = "effective", m = 1L, status = c("joint", "last"), benefit = NULL, n = Inf, h = 0L, k = 1L, timing = c("immediate", "due"), woolhouse = c("none", "first", "second"), frac, tidy = FALSE, ... )
lt |
A life table, a list of two life tables |
x |
Integer actuarial age for the first life. |
y |
Integer actuarial age for the second life. |
i |
Numeric scalar. Annual interest-rate input. |
i_type |
Character string indicating the interest-rate type. Allowed
values are |
m |
Positive integer. Conversion frequency for nominal rates. Ignored
for |
status |
Character string. Use |
benefit |
Optional list with numeric scalar weights |
n |
Term in years. Use |
h |
Nonnegative integer deferment period in years. |
k |
Positive integer. Number of payments per year. |
timing |
Payment timing. Use |
woolhouse |
Woolhouse approximation for |
frac |
Fractional-age assumption for exact k-thly computation:
|
tidy |
Logical scalar. If |
... |
Transitional compatibility for older calls using
|
The function supports joint-life, last-survivor, and state-based reversionary-style payments. The life table input may be either one common table for both lives or a list of two life tables, one for each life.
This function follows the compact actuarial notation used throughout
tidyactuarial: lt is the life table input, x and
y are the two actuarial ages, i is the interest-rate input,
i_type is the interest-rate type, m is the conversion
frequency for nominal rates, n is the term, h is the
deferment period, and k is the payment frequency.
The function assumes independent future lifetimes. For state-based benefits,
the expected payment at time is
When benefit = NULL, status = "joint" uses
benefit = list(both = 1, x_only = 0, y_only = 0), while
status = "last" uses
benefit = list(both = 1, x_only = 1, y_only = 1).
For k-thly payments, the function values a payment rate of 1 per year,
so each payment has size .
If tidy = FALSE, a numeric scalar.
If tidy = TRUE, a one-row tibble with input values, standardized
interest rate, term used, and APV.
annuity_x, insurance_xy,
premium_xy, t_pxy, t_px
Other life-contingencies:
annuity_multi(),
annuity_x(),
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()
lt <- data.frame( x = 60:66, lx = c(100000, 99000, 97500, 95500, 93000, 90000, 86000) ) # Joint-life annuity-due annuity_xy( lt = lt, x = 60, y = 62, i = 0.05, status = "joint", timing = "due" ) # Last-survivor annuity-due annuity_xy( lt = lt, x = 60, y = 62, i = 0.05, status = "last", timing = "due" ) # Different life tables for the two lives lt_m <- lt lt_f <- data.frame( x = 60:66, lx = c(100000, 99200, 98100, 96500, 94500, 92000, 89000) ) annuity_xy( lt = list(lt_m, lt_f), x = 60, y = 62, i = 0.05, status = "joint", timing = "due" ) # State-based reversionary-style payments annuity_xy( lt = list(lt_m, lt_f), x = 60, y = 62, i = 0.05, benefit = list(both = 0, x_only = 1, y_only = 0), timing = "due" )lt <- data.frame( x = 60:66, lx = c(100000, 99000, 97500, 95500, 93000, 90000, 86000) ) # Joint-life annuity-due annuity_xy( lt = lt, x = 60, y = 62, i = 0.05, status = "joint", timing = "due" ) # Last-survivor annuity-due annuity_xy( lt = lt, x = 60, y = 62, i = 0.05, status = "last", timing = "due" ) # Different life tables for the two lives lt_m <- lt lt_f <- data.frame( x = 60:66, lx = c(100000, 99200, 98100, 96500, 94500, 92000, 89000) ) annuity_xy( lt = list(lt_m, lt_f), x = 60, y = 62, i = 0.05, status = "joint", timing = "due" ) # State-based reversionary-style payments annuity_xy( lt = list(lt_m, lt_f), x = 60, y = 62, i = 0.05, benefit = list(both = 0, x_only = 1, y_only = 0), timing = "due" )
Computes the actuarial present value (APV) of a cash-flow stream contingent on survival. The life table is supplied as the first argument (pipe-friendly). Payments may be specified by numeric times or by calendar dates.
apv_life_flow( lt, ages, t = NULL, date = NULL, date0 = NULL, cf, i, i_type = "effective", m = 1L, status = c("single", "first", "last", "reversionary"), alpha = NULL, plot = FALSE )apv_life_flow( lt, ages, t = NULL, date = NULL, date0 = NULL, cf, i, i_type = "effective", m = 1L, status = c("single", "first", "last", "reversionary"), alpha = NULL, plot = FALSE )
lt |
A life table data frame with column |
ages |
Integer vector of actuarial ages. Use length 1 for a single life and length 2 or more for multiple lives. |
t |
Numeric vector of payment times in years, measured from time 0.
Provide either |
date |
Optional vector of |
date0 |
Optional |
cf |
Numeric vector of cash flows. Must have the same length as
|
i |
Numeric scalar. Annual interest-rate input. |
i_type |
Character string indicating the interest-rate type. Allowed
values are |
m |
Positive integer. Conversion frequency for nominal rates. Ignored
for |
status |
Survival status: |
alpha |
Reversionary fraction for |
plot |
Logical. If |
Multiple lives are supported under an independence assumption, through
common statuses: single-life, first-death (all alive), last-survivor
(any alive), and reversionary (joint-and-survivor) with fraction
alpha.
This function follows the compact actuarial notation used throughout
tidyactuarial: t denotes payment time, cf denotes cash
flows, i denotes the interest rate, i_type denotes the
interest-rate type, and m denotes the conversion frequency for nominal
rates.
For each payment at time , the APV contribution is
The survival probability depends on the status:
"single": for a single life.
"first": ,
so all lives must be alive.
"last": ,
so at least one life must be alive.
"reversionary": full benefit while all lives are alive, and
fraction while at least one but not all lives are alive.
Fractional-year survival is computed under UDD within each year.
A tibble with one row per payment and columns:
t, cf, surv_prob, discount,
expected_cf, pv, and pv_cum. If date was
provided, a date column is included. The total APV is stored as
attr(result, "apv").
lt <- data.frame( x = 40:100, lx = seq(100000, 0, length.out = 61) ) apv_life_flow( lt = lt, ages = 40, t = c(1, 2, 3), cf = c(100, 100, 100), i = 0.05 ) apv_life_flow( lt = lt, ages = c(60, 58), t = c(1, 2, 3), cf = c(100, 100, 100), i = 0.05, status = "first" )lt <- data.frame( x = 40:100, lx = seq(100000, 0, length.out = 61) ) apv_life_flow( lt = lt, ages = 40, t = c(1, 2, 3), cf = c(100, 100, 100), i = 0.05 ) apv_life_flow( lt = lt, ages = c(60, 58), t = c(1, 2, 3), cf = c(100, 100, 100), i = 0.05, status = "first" )
Computes the book value of a level coupon bond at one or more coupon dates, under a specified yield basis, using compact actuarial notation.
bond_book_value( face, c, n, t, k = 1L, y_effective_per_period = NULL, y = NULL, y_type = "effective", y_m = 1L, R = NULL, tol = 1e-10, check = TRUE, tidy = FALSE )bond_book_value( face, c, n, t, k = 1L, y_effective_per_period = NULL, y = NULL, y_type = "effective", y_m = 1L, R = NULL, tol = 1e-10, check = TRUE, tidy = FALSE )
face |
Numeric scalar. Face or par value of the bond. |
c |
Numeric scalar. Annual coupon rate as a proportion. |
n |
Numeric scalar. Final maturity in years. |
t |
Numeric vector. Valuation time(s) in years, measured from issue.
Each value must lie between |
k |
Positive integer. Number of coupon payments per year. |
y_effective_per_period |
Optional numeric scalar. Effective yield per coupon period. If supplied, it is used directly. |
y |
Optional numeric scalar. Annual yield rate value. |
y_type |
Character string indicating the annual yield type:
|
y_m |
Positive integer. Conversion frequency for nominal annual yields. |
R |
Numeric scalar. Redemption value at final maturity. If |
tol |
Numeric scalar. Tolerance used in alignment checks. |
check |
Logical scalar. If |
tidy |
Logical scalar. If |
The book value is interpreted prospectively: at a valuation time that lies on the coupon grid, it equals the present value at that time of all remaining future coupons and the final redemption amount, discounted at the bond's yield basis.
This function interprets t as a time immediately after any coupon due
at that date has been paid. Therefore:
at t = 0, the book value equals the bond price,
at t = n, the book value is 0.
Assumptions:
Coupons are paid in arrears at regular intervals.
n * k must be an integer.
Each t * k must be an integer.
Stub periods are not supported.
Valuation is performed at coupon dates; no accrued interest is included.
Yield input conventions:
If y_effective_per_period is supplied, it takes precedence over
y, y_type, and y_m, and is interpreted as the
effective yield per coupon period.
Otherwise, y, y_type, and y_m define an annual
yield specification, which is converted first to annual effective
yield and then to effective yield per coupon period.
This function follows the compact bond notation used in
tidyactuarial: P is price, face is the face value,
c is the annual coupon rate, n is maturity, k is coupon
frequency, y is the yield, R is redemption value, and t
is valuation time.
Let the valuation time correspond to coupon period , with total
maturity period count . If the remaining future cash flows are
, and is the effective yield per coupon
period, then the book value at time is
This is the prospective book value on the bond's yield basis.
If tidy = FALSE, a numeric vector of book values, one for each
t.
If tidy = TRUE, a tibble with valuation times, valuation periods, book
values, yield information, and bond inputs.
bond_price, bond_cash_flows,
bond_duration, bond_convexity
Other bonds:
bond_callable_price(),
bond_convexity(),
bond_duration(),
bond_price(),
bond_ytm(),
portfolio_convexity(),
portfolio_duration()
# Book value at time 0 equals price bond_book_value( face = 100, c = 0.08, n = 5, t = 0, k = 2, y = 0.06, y_type = "effective" ) # Book value at several coupon dates bond_book_value( face = 100, c = 0.08, n = 5, t = c(0, 1, 2, 3, 4, 5), k = 1, y = 0.06, y_type = "effective" ) # Tidy output bond_book_value( face = 100, c = 0.08, n = 5, t = c(0, 1, 2, 3, 4, 5), k = 1, y = 0.06, y_type = "effective", tidy = TRUE ) # Yield given directly per coupon period bond_book_value( face = 1000, c = 0.05, n = 10, t = c(0, 2, 4, 6), k = 2, y_effective_per_period = 0.03 )# Book value at time 0 equals price bond_book_value( face = 100, c = 0.08, n = 5, t = 0, k = 2, y = 0.06, y_type = "effective" ) # Book value at several coupon dates bond_book_value( face = 100, c = 0.08, n = 5, t = c(0, 1, 2, 3, 4, 5), k = 1, y = 0.06, y_type = "effective" ) # Tidy output bond_book_value( face = 100, c = 0.08, n = 5, t = c(0, 1, 2, 3, 4, 5), k = 1, y = 0.06, y_type = "effective", tidy = TRUE ) # Yield given directly per coupon period bond_book_value( face = 1000, c = 0.05, n = 10, t = c(0, 2, 4, 6), k = 2, y_effective_per_period = 0.03 )
Computes the maximum price an investor should pay for a callable bond in order to guarantee a specified minimum yield, using compact actuarial notation.
bond_callable_price( face, c, n, k = 1L, call_t, call_R, y_effective_per_period = NULL, y = NULL, y_type = "effective", y_m = 1L, R = NULL, tol = 1e-10, check = TRUE, tidy = FALSE )bond_callable_price( face, c, n, k = 1L, call_t, call_R, y_effective_per_period = NULL, y = NULL, y_type = "effective", y_m = 1L, R = NULL, tol = 1e-10, check = TRUE, tidy = FALSE )
face |
Numeric scalar. Face or par value of the bond. |
c |
Numeric scalar. Annual coupon rate as a proportion. |
n |
Numeric scalar. Final maturity in years. Must be strictly positive. |
k |
Positive integer. Number of coupon payments per year. |
call_t |
Numeric vector of callable times in years. Each value must be
strictly between |
call_R |
Numeric vector of call prices corresponding to |
y_effective_per_period |
Optional numeric scalar. Effective yield per coupon period. If supplied, it is used directly. |
y |
Optional numeric scalar. Annual yield rate value. |
y_type |
Character string indicating the annual yield type:
|
y_m |
Positive integer. Conversion frequency for nominal annual yields. |
R |
Numeric scalar. Redemption value at final maturity. If |
tol |
Numeric scalar. Tolerance used in alignment checks. |
check |
Logical scalar. If |
tidy |
Logical scalar. If |
The bond is evaluated under each possible redemption scenario:
each callable date with its associated call price, and
final maturity with its final redemption value.
For each scenario, the bond price is computed using the target yield. The callable-bond price returned by this function is the smallest of those scenario prices, that is, the maximum price consistent with the target yield under the least favorable redemption scenario for the investor.
This follows the standard actuarial/financial interpretation used in introductory fixed-income mathematics: when a bond is callable at the issuer's option, the investor must protect against the redemption scenario that is least favorable to the investor at the required yield.
Assumptions:
Coupons are paid in arrears at regular intervals.
n * k must be an integer.
Each call_t * k must be an integer.
Stub periods are not supported.
Pricing is performed at a coupon date; no accrued interest is included.
Yield input conventions:
If y_effective_per_period is supplied, it takes precedence over
y, y_type, and y_m, and is interpreted as the
effective yield per coupon period.
Otherwise, y, y_type, and y_m define an annual
yield specification, which is converted first to annual effective
yield and then to effective yield per coupon period.
This function follows the compact bond notation used in
tidyactuarial: face is the face value, c is the annual
coupon rate, n is maturity, k is coupon frequency, y is
the target yield, R is the final redemption value, call_t is
the vector of call times, and call_R is the vector of call prices.
Let the callable bond have possible redemption scenarios indexed by
, where each scenario corresponds either to a call date
or to final maturity. For scenario , let denote the bond
price computed at the target yield assuming redemption occurs at that
scenario time and value.
Then this function returns
when tidy = FALSE.
This is the maximum price an investor can pay while still guaranteeing at least the target yield under the least favorable redemption scenario.
If tidy = FALSE, a numeric scalar: the worst-case callable-bond price
consistent with the target yield.
If tidy = TRUE, a tibble with one row per redemption scenario,
including scenario prices and the worst-case indicator.
bond_price, bond_cash_flows,
bond_book_value, bond_ytm
Other bonds:
bond_book_value(),
bond_convexity(),
bond_duration(),
bond_price(),
bond_ytm(),
portfolio_convexity(),
portfolio_duration()
# Callable bond with two possible call dates bond_callable_price( face = 100, c = 0.08, n = 10, k = 2, call_t = c(5, 7), call_R = c(105, 102), y = 0.06, y_type = "effective" ) # Tidy output with all redemption scenarios bond_callable_price( face = 100, c = 0.08, n = 10, k = 2, call_t = c(5, 7), call_R = c(105, 102), y = 0.06, y_type = "effective", tidy = TRUE ) # Target yield given directly per coupon period bond_callable_price( face = 1000, c = 0.05, n = 12, k = 2, call_t = c(4, 8), call_R = c(1030, 1015), y_effective_per_period = 0.028 )# Callable bond with two possible call dates bond_callable_price( face = 100, c = 0.08, n = 10, k = 2, call_t = c(5, 7), call_R = c(105, 102), y = 0.06, y_type = "effective" ) # Tidy output with all redemption scenarios bond_callable_price( face = 100, c = 0.08, n = 10, k = 2, call_t = c(5, 7), call_R = c(105, 102), y = 0.06, y_type = "effective", tidy = TRUE ) # Target yield given directly per coupon period bond_callable_price( face = 1000, c = 0.05, n = 12, k = 2, call_t = c(4, 8), call_R = c(1030, 1015), y_effective_per_period = 0.028 )
Builds the cash-flow schedule of a level coupon bond with constant coupon rate and a single redemption payment at maturity, using compact actuarial notation.
bond_cash_flows(face, c, n, k = 1L, R = NULL, tol = 1e-10, check = TRUE)bond_cash_flows(face, c, n, k = 1L, R = NULL, tol = 1e-10, check = TRUE)
face |
Numeric scalar. Face value of the bond. |
c |
Numeric scalar. Annual coupon rate. |
n |
Numeric scalar. Years to maturity. |
k |
Positive integer. Number of coupon payments per year. |
R |
Numeric scalar. Redemption value. If |
tol |
Numeric scalar. Tolerance. |
check |
Logical scalar. Input validation. |
This function follows the compact bond notation used in
tidyactuarial: face is the face value, c is the annual
coupon rate, n is the term to maturity, k is the number of
coupon payments per year, and R is the redemption value.
Stub periods are not supported; therefore, n * k must be an integer.
A tibble with the bond cash-flow schedule. The main actuarial
columns are t for payment time and cf for cash flow.
bond_cash_flows( face = 1000, c = 0.05, n = 10, k = 2, R = 1000 )bond_cash_flows( face = 1000, c = 0.05, n = 10, k = 2, R = 1000 )
Computes discrete convexity measures for a level coupon bond valued under a flat yield-to-maturity assumption, using compact actuarial notation.
bond_convexity( face, c, n, k = 1L, y_effective_per_period = NULL, y = NULL, y_type = "effective", y_m = 1L, R = NULL, tol = 1e-10, check = TRUE )bond_convexity( face, c, n, k = 1L, y_effective_per_period = NULL, y = NULL, y_type = "effective", y_m = 1L, R = NULL, tol = 1e-10, check = TRUE )
face |
Numeric scalar. Face value of the bond. |
c |
Numeric scalar. Annual coupon rate as a proportion. |
n |
Numeric scalar. Time to maturity in years. |
k |
Positive integer. Number of coupon payments per year. |
y_effective_per_period |
Optional numeric scalar. Effective yield per coupon period. |
y |
Optional numeric scalar. Annual yield rate value. |
y_type |
Character string indicating the annual yield type:
|
y_m |
Positive integer. Conversion frequency for nominal annual yields. |
R |
Numeric scalar. Redemption value at maturity. If |
tol |
Numeric scalar. Tolerance used to check maturity alignment. |
check |
Logical scalar. If |
Assumptions:
Coupons are paid in arrears at regular intervals.
n * k must be an integer.
Stub periods are not supported.
Valuation is at a coupon date with no accrued interest.
A single flat yield is used to discount all cash flows.
Yield input conventions:
If y_effective_per_period is supplied, it is interpreted as the
effective yield per coupon period.
Otherwise, y, y_type, and y_m define an annual
yield specification, which is converted first to annual effective
yield and then to effective yield per coupon period.
This function follows the compact bond notation used in
tidyactuarial: face is the face value, c is the annual
coupon rate, n is the time to maturity, k is the coupon
frequency, y is the annual yield input, and R is the redemption
value.
Let be the effective yield per coupon period, the number of
coupon payments per year, and let cash flows occur at coupon
periods . With and
, the discrete convexity in coupon periods is
Discrete convexity in years is .
This is the second-order sensitivity of the bond price to changes in the
yield per period. Together with bond_duration, it is used in
the second-order Taylor approximation of price changes.
A one-row tibble with:
Dirty price at the given yield.
Discrete convexity in coupon periods.
Discrete convexity in years.
Effective yield per coupon period.
Annual effective yield.
Coupon frequency.
Total number of coupon periods.
bond_duration, bond_price,
bond_cash_flows, bond_book_value,
bond_ytm
Other bonds:
bond_book_value(),
bond_callable_price(),
bond_duration(),
bond_price(),
bond_ytm(),
portfolio_convexity(),
portfolio_duration()
bond_convexity( face = 100, c = 0.08, n = 5, k = 2, y = 0.06, y_type = "effective" ) bond_convexity( face = 1000, c = 0.05, n = 10, k = 2, y_effective_per_period = 0.03 )bond_convexity( face = 100, c = 0.08, n = 5, k = 2, y = 0.06, y_type = "effective" ) bond_convexity( face = 1000, c = 0.05, n = 10, k = 2, y_effective_per_period = 0.03 )
Computes Macaulay duration and modified-duration measures for a level coupon bond valued under a flat yield-to-maturity assumption, using compact actuarial notation.
bond_duration( face, c, n, k = 1L, y_effective_per_period = NULL, y = NULL, y_type = "effective", y_m = 1L, R = NULL, tol = 1e-10, check = TRUE )bond_duration( face, c, n, k = 1L, y_effective_per_period = NULL, y = NULL, y_type = "effective", y_m = 1L, R = NULL, tol = 1e-10, check = TRUE )
face |
Numeric scalar. Face value of the bond. |
c |
Numeric scalar. Annual coupon rate as a proportion. |
n |
Numeric scalar. Time to maturity in years. |
k |
Positive integer. Number of coupon payments per year. |
y_effective_per_period |
Optional numeric scalar. Effective yield per coupon period. |
y |
Optional numeric scalar. Annual yield rate value. |
y_type |
Character string indicating the annual yield type:
|
y_m |
Positive integer. Conversion frequency for nominal annual yields. |
R |
Numeric scalar. Redemption value at maturity. If |
tol |
Numeric scalar. Tolerance used to check maturity alignment. |
check |
Logical scalar. If |
Assumptions:
Coupons are paid in arrears at regular intervals.
n * k must be an integer.
Stub periods are not supported.
Valuation is at a coupon date with no accrued interest.
A single flat yield is used to discount all cash flows.
Yield input conventions:
If y_effective_per_period is supplied, it is interpreted as the
effective yield per coupon period.
Otherwise, y, y_type, and y_m define an annual
yield specification, which is converted first to annual effective
yield and then to effective yield per coupon period.
This function follows the compact bond notation used in
tidyactuarial: face is the face value, c is the annual
coupon rate, n is the time to maturity, k is the coupon
frequency, y is the annual yield input, and R is the redemption
value.
Let be the effective yield per coupon period, the number of
coupon payments per year, and let cash flows occur at coupon
periods . With and
:
Macaulay duration in coupon periods:
Macaulay duration in years is .
Modified duration with respect to , in coupon periods, is
.
Modified duration with respect to the annual effective rate , in
years, is , where
.
Modified duration measures the first-order sensitivity of the bond price to
yield changes. Together with bond_convexity, it forms the
second-order Taylor approximation of price changes.
A one-row tibble with:
Dirty price at the given yield.
Macaulay duration in coupon periods.
Macaulay duration in years.
Modified duration with respect to the effective yield per coupon period, expressed in coupon periods.
Modified duration with respect to the annual effective yield, expressed in years.
Effective yield per coupon period.
Annual effective yield.
Coupon frequency.
Total number of coupon periods.
bond_convexity, bond_price,
bond_cash_flows, bond_book_value,
bond_ytm
Other bonds:
bond_book_value(),
bond_callable_price(),
bond_convexity(),
bond_price(),
bond_ytm(),
portfolio_convexity(),
portfolio_duration()
bond_duration( face = 100, c = 0.08, n = 5, k = 2, y = 0.06, y_type = "effective" ) bond_duration( face = 1000, c = 0.05, n = 10, k = 2, y_effective_per_period = 0.03 )bond_duration( face = 100, c = 0.08, n = 5, k = 2, y = 0.06, y_type = "effective" ) bond_duration( face = 1000, c = 0.05, n = 10, k = 2, y_effective_per_period = 0.03 )
Computes the dirty price of a level coupon bond at time 0 from its yield, using compact actuarial notation.
bond_price( face, c, n, k = 1L, y_effective_per_period = NULL, y = NULL, y_type = "effective", y_m = 1L, R = NULL, tol = 1e-10, check = TRUE )bond_price( face, c, n, k = 1L, y_effective_per_period = NULL, y = NULL, y_type = "effective", y_m = 1L, R = NULL, tol = 1e-10, check = TRUE )
face |
Numeric scalar. Face value of the bond. |
c |
Numeric scalar. Annual coupon rate as a proportion. |
n |
Numeric scalar. Time to maturity in years. |
k |
Positive integer. Number of coupon payments per year. |
y_effective_per_period |
Optional numeric scalar. Effective yield per coupon period. If supplied, it is used directly. |
y |
Optional numeric scalar. Annual yield rate value. |
y_type |
Character string indicating the annual yield type:
|
y_m |
Positive integer. Conversion frequency for nominal annual yields. |
R |
Numeric scalar. Redemption value at maturity. If |
tol |
Numeric scalar. Tolerance used when checking alignment of maturity with coupon periods. |
check |
Logical scalar. If |
Assumptions:
Coupons are paid in arrears at regular intervals.
n * k must be an integer.
Stub periods are not supported.
No accrued interest is considered; the price is evaluated at a coupon date.
The yield may be supplied in either of two ways:
directly as an effective yield per coupon period through
y_effective_per_period, or
as an annual rate specification through y, y_type, and
y_m.
If an annual rate specification is supplied, it is first converted to the equivalent annual effective yield and then to the effective yield per coupon period.
This function follows the compact bond notation used in
tidyactuarial: face is the face value, c is the annual
coupon rate, n is the time to maturity, k is the coupon
frequency, y is the annual yield input, and R is the redemption
value.
Let be the effective yield per coupon period, the number of
coupon payments per year, and let be the total number of coupon
periods. With coupon per period and discount factor
, the price is:
where the sum runs over all coupon and redemption cash flows indexed by
coupon period .
Numeric scalar: dirty price of the bond at time 0.
bond_ytm, bond_cash_flows,
bond_duration, bond_convexity,
bond_book_value, bond_callable_price
Other bonds:
bond_book_value(),
bond_callable_price(),
bond_convexity(),
bond_duration(),
bond_ytm(),
portfolio_convexity(),
portfolio_duration()
# 5-year annual coupon bond, yield given as annual effective bond_price( face = 100, c = 0.08, n = 5, k = 1, y = 0.06, y_type = "effective" ) # 10-year semiannual bond, yield given directly per coupon period bond_price( face = 1000, c = 0.05, n = 10, k = 2, y_effective_per_period = 0.03 ) # Semiannual coupons, nominal annual yield convertible quarterly bond_price( face = 100, c = 0.08, n = 5, k = 2, y = 0.06, y_type = "nominal_interest", y_m = 4 )# 5-year annual coupon bond, yield given as annual effective bond_price( face = 100, c = 0.08, n = 5, k = 1, y = 0.06, y_type = "effective" ) # 10-year semiannual bond, yield given directly per coupon period bond_price( face = 1000, c = 0.05, n = 10, k = 2, y_effective_per_period = 0.03 ) # Semiannual coupons, nominal annual yield convertible quarterly bond_price( face = 100, c = 0.08, n = 5, k = 2, y = 0.06, y_type = "nominal_interest", y_m = 4 )
Computes the yield to maturity (YTM) of a level coupon bond given its observed dirty price at time 0, using compact actuarial notation.
bond_ytm( P, face, c, n, k = 1L, R = NULL, interval = NULL, tol = 1e-12, maxiter = 1000, check = TRUE )bond_ytm( P, face, c, n, k = 1L, R = NULL, interval = NULL, tol = 1e-12, maxiter = 1000, check = TRUE )
P |
Numeric scalar. Observed dirty price of the bond at time 0. |
face |
Numeric scalar. Face value of the bond. |
c |
Numeric scalar. Annual coupon rate as a proportion. |
n |
Numeric scalar. Time to maturity in years. Must be strictly positive. |
k |
Positive integer. Number of coupon payments per year. |
R |
Numeric scalar. Redemption value at maturity. If |
interval |
Optional numeric vector of length 2 giving a bracket for the effective yield per coupon period. |
tol |
Numeric scalar. Tolerance passed to |
maxiter |
Positive integer. Maximum number of iterations passed to
|
check |
Logical scalar. If |
The YTM is solved first as the effective yield per coupon period and then reported together with common annual equivalents.
Assumptions:
Coupons are paid in arrears at regular intervals.
Price is observed at a coupon date (no accrued interest).
n * k must be an integer.
Stub periods are not supported.
This function follows the compact bond notation used in
tidyactuarial: P is the observed dirty price, face is
the face value, c is the annual coupon rate, n is the time to
maturity, k is the coupon frequency, and R is the redemption
value.
The effective yield per coupon period is the solution to
The root is found numerically using uniroot. If no
interval is supplied, the function automatically brackets the root
starting from and progressively widens the upper
bound until a sign change is detected.
From the per-period yield, the annual equivalents are:
A one-row tibble with columns:
Input dirty price.
Effective yield per coupon period.
Nominal annual yield convertible k times per year
(= k * i_period). When k = 2, this is the bond-equivalent
yield.
Annual effective yield.
Coupon frequency.
bond_price, bond_cash_flows,
bond_duration, bond_convexity,
bond_callable_price
Other bonds:
bond_book_value(),
bond_callable_price(),
bond_convexity(),
bond_duration(),
bond_price(),
portfolio_convexity(),
portfolio_duration()
bond_ytm( P = 100, face = 100, c = 0.06, n = 5, k = 1 ) bond_ytm( P = 950, face = 1000, c = 0.05, n = 10, k = 2 )bond_ytm( P = 100, face = 100, c = 0.06, n = 5, k = 1 ) bond_ytm( P = 950, face = 1000, c = 0.05, n = 10, k = 2 )
A small pedagogical dataset containing bond contracts for pricing, yield-to-maturity, duration, and convexity examples.
A small pedagogical dataset containing bond contracts for pricing, yield-to-maturity, duration, and convexity examples.
bonds_sample bonds_samplebonds_sample bonds_sample
A tibble with 5 rows and 8 variables:
Bond identifier.
Face value of the bond.
Annual coupon rate.
Number of coupon payments per year.
Maturity in years.
Annual nominal yield rate consistent with coupon frequency.
Short bond type label.
Theoretical bond price computed from the listed yield rate.
A tibble with 5 rows and 8 variables:
Bond identifier.
Face value of the bond.
Annual coupon rate.
Number of coupon payments per year.
Maturity in years.
Annual nominal yield rate consistent with coupon frequency.
Short bond type label.
Theoretical bond price computed from the listed yield rate.
This dataset uses the compact bond notation adopted in tidyactuarial:
face is the face value, c is the annual coupon rate,
k is the coupon frequency, n is the maturity, y is the
yield input, and P is the bond price.
This dataset uses the compact bond notation adopted in tidyactuarial:
face is the face value, c is the annual coupon rate,
k is the coupon frequency, n is the maturity, y is the
yield input, and P is the bond price.
Synthetic pedagogical data created for tidyactuarial examples.
Synthetic pedagogical data created for tidyactuarial examples.
data(bonds_sample) bonds_sample |> dplyr::select(bond_id, face, c, k, n, y, P) data(bonds_sample) bonds_sample |> dplyr::select(bond_id, face, c, k, n, y, P)data(bonds_sample) bonds_sample |> dplyr::select(bond_id, face, c, k, n, y, P) data(bonds_sample) bonds_sample |> dplyr::select(bond_id, face, c, k, n, y, P)
A small pedagogical dataset containing cash-flow scenarios for present value, future value, net present value, internal rate of return, equations of value, and cash-flow diagrams.
A small pedagogical dataset containing cash-flow scenarios for present value, future value, net present value, internal rate of return, equations of value, and cash-flow diagrams.
cash_flows_sample cash_flows_samplecash_flows_sample cash_flows_sample
A tibble with 19 rows and 5 variables:
Scenario identifier.
Payment time.
Cash-flow amount. Negative values represent outflows and positive values represent inflows.
Type of cash flow.
Short description of the cash flow.
A tibble with 19 rows and 5 variables:
Scenario identifier.
Payment time.
Cash-flow amount. Negative values represent outflows and positive values represent inflows.
Type of cash flow.
Short description of the cash flow.
This dataset uses the compact financial-actuarial notation used throughout
tidyactuarial: t denotes time and C denotes the cash-flow
amount at that time.
This dataset uses the compact financial-actuarial notation used throughout
tidyactuarial: t denotes time and C denotes the cash-flow
amount at that time.
Synthetic pedagogical data created for tidyactuarial examples.
Synthetic pedagogical data created for tidyactuarial examples.
data(cash_flows_sample) cash_flows_sample |> dplyr::filter(scenario_id == "investment_project") |> dplyr::select(scenario_id, t, C, cashflow_type) data(cash_flows_sample) cash_flows_sample |> dplyr::filter(scenario_id == "investment_project") |> dplyr::select(scenario_id, t, C, cashflow_type)data(cash_flows_sample) cash_flows_sample |> dplyr::filter(scenario_id == "investment_project") |> dplyr::select(scenario_id, t, C, cashflow_type) data(cash_flows_sample) cash_flows_sample |> dplyr::filter(scenario_id == "investment_project") |> dplyr::select(scenario_id, t, C, cashflow_type)
The function builds annual commutation columns from x, lx, and
an interest-rate specification. The interest rate is converted internally to
an annual effective rate before constructing the discount factor.
commutation_table(lt, i, i_type = "effective", m = 1L, check = TRUE)commutation_table(lt, i, i_type = "effective", m = 1L, check = TRUE)
lt |
A life table object as produced by |
i |
Numeric scalar. Annual interest-rate input. |
i_type |
Character string indicating the interest-rate type. Allowed
values are |
m |
Positive integer. Conversion frequency for nominal rates. Ignored
for |
check |
Logical. If |
Constructs classical annual commutation functions , ,
, , , and from a life table defined
at integer ages, using compact actuarial notation.
This function follows the compact actuarial notation used throughout
tidyactuarial: lt is the life table, i is the
interest-rate input, i_type is the interest-rate type, and m
is the conversion frequency for nominal rates.
The annual effective rate is obtained through standardize_interest.
If denotes the annual effective rate, then
The annual deaths are computed as
closing the table with . The main commutation functions
are then computed as
with reverse cumulative sums used to obtain , ,
, and .
A tibble with columns x, lx, dx, v,
Dx, Nx, Sx, Cx, Mx, and Rx.
lt <- data.frame( x = 60:65, lx = c(100000, 99000, 97500, 95500, 93000, 90000) ) commutation_table( lt = lt, i = 0.05 ) commutation_table( lt = lt, i = 0.06, i_type = "nominal_interest", m = 12 )lt <- data.frame( x = 60:65, lx = c(100000, 99000, 97500, 95500, 93000, 90000) ) commutation_table( lt = lt, i = 0.05 ) commutation_table( lt = lt, i = 0.06, i_type = "nominal_interest", m = 12 )
Computes the discount factor implied by a spot rate for a given time, using compact actuarial notation.
discount_factor_spot(t, i, i_type = "effective", m = 1L, tidy = FALSE)discount_factor_spot(t, i, i_type = "effective", m = 1L, tidy = FALSE)
t |
Numeric vector of times in years. Each value must be greater than or equal to 0. |
i |
Numeric vector of spot-rate values. |
i_type |
Character vector indicating the spot-rate type. Allowed values
are |
m |
Positive integer vector giving the conversion frequency for nominal spot-rate inputs. |
tidy |
Logical scalar. If |
The spot rate may be supplied in FM-style notation:
annual effective rate,
nominal annual interest rate,
nominal annual discount rate,
force of interest.
Internally, the supplied spot rate is first converted to the equivalent
annual effective rate using standardize_interest. The discount
factor is then computed as
This function follows the compact actuarial notation used throughout
tidyactuarial: t denotes time, i denotes the spot-rate
input, i_type denotes the interest-rate type, and m denotes the
conversion frequency for nominal rates.
If , the discount factor is 1.
Input vectors must have length 1 or a common length. Missing values are propagated.
If tidy = FALSE, a numeric vector of discount factors.
If tidy = TRUE, a tibble with input values, standardized rates, and
discount factors.
standardize_interest, present_value,
pv_flow
Other interest:
forward_rate(),
interest_equivalents(),
standardize_interest(),
yield_curve()
# Numeric discount factor discount_factor_spot( t = 3, i = 0.05 ) # Vectorized example discount_factor_spot( t = c(1, 2, 3), i = c(0.05, 0.055, 0.06) ) # FM-style input with nominal annual interest discount_factor_spot( t = 2, i = 0.08, i_type = "nominal_interest", m = 2 ) # Tibble output for teaching or auditing discount_factor_spot( t = c(1, 2, 3), i = c(0.05, 0.055, 0.06), tidy = TRUE )# Numeric discount factor discount_factor_spot( t = 3, i = 0.05 ) # Vectorized example discount_factor_spot( t = c(1, 2, 3), i = c(0.05, 0.055, 0.06) ) # FM-style input with nominal annual interest discount_factor_spot( t = 2, i = 0.08, i_type = "nominal_interest", m = 2 ) # Tibble output for teaching or auditing discount_factor_spot( t = c(1, 2, 3), i = c(0.05, 0.055, 0.06), tidy = TRUE )
Computes the curtate or complete expected future lifetime at integer age
, optionally restricted to a temporary horizon of years.
e_x( lt, x, t = NULL, type = c("curtate", "complete"), frac, tidy = FALSE, check = TRUE, tol = 1e-10 )e_x( lt, x, t = NULL, type = c("curtate", "complete"), frac, tidy = FALSE, check = TRUE, tol = 1e-10 )
lt |
A life table object as produced by |
x |
Integer age(s). |
t |
Optional nonnegative numeric duration(s). If |
type |
Character: |
frac |
Fractional-age assumption for |
tidy |
Logical. If |
check |
Logical. If |
tol |
Numeric tolerance for integer checks. |
Curtate life expectancy (Finan, Section 23.7):
The -year temporary curtate expectancy is (Finan, Sec. 23.7):
Complete life expectancy (Finan, Section 23.3):
The integral is decomposed year-by-year. Within each year, the
within-year survival integral is evaluated
in closed form under the selected fractional-age assumption
(Finan, Section 24):
UDD (Sec. 24.1):
CF (Sec. 24.2):
Balducci (Sec. 24.3):
Under UDD, the complete expectancy satisfies the well-known approximation (Finan, Example 20.24):
A numeric vector of expected future lifetimes, or a tibble if
tidy = TRUE with columns x, t, type,
frac, ex.
Computes the expected future lifetime for two independent lives aged
x and y, for either joint-life (first death) or
last-survivor (second death).
e_xy( lt, x, y, t = NULL, type = c("curtate", "complete"), frac, cohort = c("first", "last"), tidy = FALSE, check = TRUE, tol = 1e-10 )e_xy( lt, x, y, t = NULL, type = c("curtate", "complete"), frac, cohort = c("first", "last"), tidy = FALSE, check = TRUE, tol = 1e-10 )
lt |
A life table data frame with columns |
x |
Integer actuarial age for life 1. |
y |
Integer actuarial age for life 2. |
t |
Optional nonnegative numeric duration(s). If |
type |
Character: |
frac |
Fractional-age assumption for |
cohort |
Two-life cohort: |
tidy |
Logical. If |
check |
Logical. If |
tol |
Numeric tolerance for integer checks. |
Curtate expectation (Finan, Section 56.4 / Section 57):
Complete expectation (Finan, Section 56.4):
The integral is decomposed year-by-year. Within each year, the survival integral for the two-life status is computed numerically via composite trapezoid (80-point grid), since closed-form expressions for joint/last survivor under fractional-age assumptions are complex.
Key identity (Finan, Example 57.4):
This can be used to cross-validate results.
Numeric vector, or tibble if tidy = TRUE.
e_x for single-life expectancy,
t_pxy for two-life survival probabilities,
annuity_xy for two-life annuity APVs.
lt <- data.frame( x = 60:66, lx = c(100000, 99000, 97500, 95500, 93000, 90000, 86000) ) # Curtate joint-life expectancy (Finan, Sec. 56.4) e_xy(lt, x = 60, y = 62, type = "curtate", cohort = "first") # Curtate last-survivor expectancy (Finan, Sec. 57) e_xy(lt, x = 60, y = 62, type = "curtate", cohort = "last") # Verify identity (Finan, Example 57.4): # e_{xy-bar} = e_x + e_y - e_xy e_joint <- e_xy(lt, x = 60, y = 62, type = "curtate", cohort = "first") e_last <- e_xy(lt, x = 60, y = 62, type = "curtate", cohort = "last") e_x_val <- e_x(lt, x = 60, type = "curtate") e_y_val <- e_x(lt, x = 62, type = "curtate") c(last_surv = e_last, sum_minus_joint = e_x_val + e_y_val - e_joint) # Complete joint-life expectancy under UDD e_xy(lt, x = 60, y = 62, type = "complete", frac = "UDD", cohort = "first") # Temporary: 3-year curtate joint-life e_xy(lt, x = 60, y = 62, t = 3, type = "curtate", cohort = "first") # Tidy output e_xy(lt, x = 60, y = 62, type = "curtate", cohort = "first", tidy = TRUE)lt <- data.frame( x = 60:66, lx = c(100000, 99000, 97500, 95500, 93000, 90000, 86000) ) # Curtate joint-life expectancy (Finan, Sec. 56.4) e_xy(lt, x = 60, y = 62, type = "curtate", cohort = "first") # Curtate last-survivor expectancy (Finan, Sec. 57) e_xy(lt, x = 60, y = 62, type = "curtate", cohort = "last") # Verify identity (Finan, Example 57.4): # e_{xy-bar} = e_x + e_y - e_xy e_joint <- e_xy(lt, x = 60, y = 62, type = "curtate", cohort = "first") e_last <- e_xy(lt, x = 60, y = 62, type = "curtate", cohort = "last") e_x_val <- e_x(lt, x = 60, type = "curtate") e_y_val <- e_x(lt, x = 62, type = "curtate") c(last_surv = e_last, sum_minus_joint = e_x_val + e_y_val - e_joint) # Complete joint-life expectancy under UDD e_xy(lt, x = 60, y = 62, type = "complete", frac = "UDD", cohort = "first") # Temporary: 3-year curtate joint-life e_xy(lt, x = 60, y = 62, t = 3, type = "curtate", cohort = "first") # Tidy output e_xy(lt, x = 60, y = 62, type = "curtate", cohort = "first", tidy = TRUE)
Returns the annual effective forward rate implied between two maturities from a discrete yield curve stored in tibble-first format, using compact actuarial notation.
forward_rate( .data = NULL, t = NULL, i = NULL, t_start = NULL, t_end = NULL, col_t = "t", col_i = "i", col_t_start = "t_start", col_t_end = "t_end", i_type = "effective", m = 1L, method = c("exact", "linear"), plot = FALSE, .out = "f", .out_plot = "forward_rate_plot", .keep = c("all", "used", "none"), .na = c("propagate", "error", "drop") )forward_rate( .data = NULL, t = NULL, i = NULL, t_start = NULL, t_end = NULL, col_t = "t", col_i = "i", col_t_start = "t_start", col_t_end = "t_end", i_type = "effective", m = 1L, method = c("exact", "linear"), plot = FALSE, .out = "f", .out_plot = "forward_rate_plot", .keep = c("all", "used", "none"), .na = c("propagate", "error", "drop") )
.data |
A data.frame or tibble. If |
t |
Numeric vector of maturities in years when |
i |
Numeric vector of spot-rate values when |
t_start |
Numeric scalar giving the start maturity when
|
t_end |
Numeric scalar giving the end maturity when
|
col_t |
Name of the list-column containing maturities. |
col_i |
Name of the list-column containing spot rates. |
col_t_start |
Name of the numeric column containing the start maturity. |
col_t_end |
Name of the numeric column containing the end maturity. |
i_type |
Character vector indicating the spot-rate type. Allowed values
are |
m |
Positive integer vector giving the conversion frequency for nominal spot rates. May have length 1 or the same length as each curve. |
method |
Spot extraction method: |
plot |
Logical; if |
.out |
Name of the output column containing the forward rate. |
.out_plot |
Name of the output list-column containing |
.keep |
One of |
.na |
NA handling policy: |
Each row is treated as one curve. For tibble input, col_t and
col_i must be list-columns of equal-length numeric vectors, and
col_t_start and col_t_end must be numeric columns giving the
forward interval for each row.
The implied forward rate is computed from the standardized annual effective spot curve through:
so that
Two extraction methods are supported for the spot rates:
"exact": requires that t_start and t_end
match curve nodes.
"linear": uses linear interpolation between adjacent nodes.
No extrapolation is performed outside the observed maturity range.
This function follows the compact actuarial notation used throughout
tidyactuarial: t denotes maturity, i denotes the spot
rate, i_type denotes the interest-rate type, and m denotes the
conversion frequency for nominal spot rates. The output column f
denotes the implied annual effective forward rate.
Spot-rate inputs are converted to annual effective form using
standardize_interest before interpolation and forward-rate
calculation.
A tibble. By default it returns the original columns plus a new
numeric column named by .out. If plot = TRUE, it also adds
a list-column named by .out_plot containing ggplot2 objects.
Marcel B. Finan, A Basic Course in the Theory of Interest and Derivatives Markets: A Preparation for the Actuarial Exam FM/2, Section 53: The Term Structure of Interest Rates and Yield Curves.
Kellison, S. G. The Theory of Interest, Chapter 10: The Term Structure of Interest Rates.
yield_curve, discount_factor_spot,
standardize_interest
Other interest:
discount_factor_spot(),
interest_equivalents(),
standardize_interest(),
yield_curve()
# Simple example: exact forward rate forward_rate( t = c(1, 2, 3, 4, 5), i = c(0.040, 0.045, 0.048, 0.050, 0.051), t_start = 2, t_end = 5 ) # Interpolated forward rates for multiple curves curves <- tibble::tibble( curve_id = c("A", "B"), t = list(c(1, 2, 3, 5), c(1, 3, 5, 7)), i = list(c(0.04, 0.05, 0.055, 0.06), c(0.03, 0.035, 0.04, 0.045)), t_start = c(2, 2), t_end = c(4, 6) ) forward_rate( curves, method = "linear", plot = TRUE ) # Nominal annual spot rates convertible semiannually forward_rate( t = c(1, 2, 3), i = c(0.05, 0.055, 0.06), i_type = "nominal_interest", m = 2, t_start = 1, t_end = 3 )# Simple example: exact forward rate forward_rate( t = c(1, 2, 3, 4, 5), i = c(0.040, 0.045, 0.048, 0.050, 0.051), t_start = 2, t_end = 5 ) # Interpolated forward rates for multiple curves curves <- tibble::tibble( curve_id = c("A", "B"), t = list(c(1, 2, 3, 5), c(1, 3, 5, 7)), i = list(c(0.04, 0.05, 0.055, 0.06), c(0.03, 0.035, 0.04, 0.045)), t_start = c(2, 2), t_end = c(4, 6) ) forward_rate( curves, method = "linear", plot = TRUE ) # Nominal annual spot rates convertible semiannually forward_rate( t = c(1, 2, 3), i = c(0.05, 0.055, 0.06), i_type = "nominal_interest", m = 2, t_start = 1, t_end = 3 )
Computes the future value of a payment invested at time 0 and accumulated to a given time, using the annual effective interest rate implied by the supplied interest-rate specification and compact actuarial notation.
future_value(C, i, i_type = "effective", m = 1, t, tidy = FALSE)future_value(C, i, i_type = "effective", m = 1, t, tidy = FALSE)
C |
Numeric vector of initial payment amounts or capitals. |
i |
Numeric vector of interest-rate values. |
i_type |
Character vector indicating the interest-rate type.
Allowed values are |
m |
Positive integer vector giving the conversion frequency for nominal
rates. Ignored for |
t |
Numeric vector of times in years from valuation to accumulation. |
tidy |
Logical scalar. If |
The future value is computed as
where is the annual effective interest rate.
The input interest rate may be supplied as:
annual effective interest rate,
nominal annual interest rate,
nominal annual discount rate,
force of interest.
Internally, all rate specifications are first converted to the equivalent
annual effective interest rate using standardize_interest.
This function follows the compact actuarial notation used throughout
tidyactuarial: C denotes the initial payment amount or capital,
t denotes time, i denotes the interest-rate input,
i_type denotes the interest-rate type, and m denotes the
conversion frequency for nominal rates.
Input vectors must have length 1 or a common length. Missing values are
propagated. This function does not accept dates; use fv_flow
for dated cash flows.
If tidy = FALSE, a numeric vector of future values.
If tidy = TRUE, a tibble with input values, equivalent rates,
accumulation factors, and future values.
standardize_interest, present_value,
fv_flow
Other time-value:
fv_flow(),
irr_flow(),
irr_flow_multi(),
plot_cash_flow(),
present_value(),
pv_flow()
# Numeric future value future_value(C = 1000, i = 0.08, t = 3) # Nominal interest converted monthly future_value( C = 1000, i = 0.12, i_type = "nominal_interest", m = 12, t = 5 ) # Tibble output for teaching or auditing future_value( C = 1000, i = 0.08, t = 3, tidy = TRUE ) # Vectorized example future_value( C = c(1000, 2500, 4000), i = c(0.08, 0.10, 0.12), i_type = c("effective", "nominal_interest", "force"), m = c(1, 12, 1), t = c(3, 5, 2) )# Numeric future value future_value(C = 1000, i = 0.08, t = 3) # Nominal interest converted monthly future_value( C = 1000, i = 0.12, i_type = "nominal_interest", m = 12, t = 5 ) # Tibble output for teaching or auditing future_value( C = 1000, i = 0.08, t = 3, tidy = TRUE ) # Vectorized example future_value( C = c(1000, 2500, 4000), i = c(0.08, 0.10, 0.12), i_type = c("effective", "nominal_interest", "force"), m = c(1, 12, 1), t = c(3, 5, 2) )
Computes the future value of a cash-flow vector under either:
a constant interest-rate specification, or
a term structure of spot rates, one rate per cash flow.
fv_flow( cf, i, i_type = "effective", m = 1L, t = NULL, date = NULL, day_count = c("act/365", "act/360"), tol = 1e-10 )fv_flow( cf, i, i_type = "effective", m = 1L, t = NULL, date = NULL, day_count = c("act/365", "act/360"), tol = 1e-10 )
cf |
Numeric vector of cash flows. |
i |
Numeric scalar or numeric vector of interest-rate values. |
i_type |
Character vector indicating the interest-rate type:
|
m |
Positive integer vector giving the conversion frequency for nominal
rates. May have length 1 or the same length as |
t |
Optional numeric vector of cash-flow times in years. |
date |
Optional vector of cash-flow dates. If supplied, the earliest date is treated as time 0. |
day_count |
Day-count convention used to convert dates to year
fractions. One of |
tol |
Numeric tolerance used in internal checks. |
The cash flow is supplied explicitly through cf. Its timing is
supplied either through t (in years) or date (calendar dates).
If date is supplied, the earliest date is taken as time 0.
The future value is accumulated to the latest payment time or latest date.
Interest-rate input:
If i has length 1, the same rate is used for all cash flows.
If i has the same length as cf, each rate is
interpreted as the annual effective spot rate associated with the
corresponding cash-flow time.
Rate types may be supplied in FM-style notation:
annual effective rate ,
nominal annual interest rate ,
nominal annual discount rate ,
force of interest .
Internally, all supplied rates are converted to annual effective rates using
standardize_interest. When i is a vector, the
accumulation uses the implied discount-factor ratio under the spot-rate
interpretation.
This function follows the compact actuarial notation used throughout
tidyactuarial: cf denotes cash flows, t denotes time,
i denotes the interest rate, i_type denotes the interest-rate
type, and m denotes the conversion frequency for nominal rates.
Let be the latest cash-flow time, the accumulation horizon. For each
cash flow at time with annual effective spot rate
, the future value contribution is
The total future value is . When a single constant rate
is supplied, for all , and the formula simplifies
to
Numeric scalar: the future value of the cash flow accumulated to the latest cash-flow time.
pv_flow, future_value,
standardize_interest
Other time-value:
future_value(),
irr_flow(),
irr_flow_multi(),
plot_cash_flow(),
present_value(),
pv_flow()
# Constant annual effective rate fv_flow( cf = c(100, 150, 200), i = 0.08, i_type = "effective", t = c(0, 1, 2) ) # Spot rates, one per cash flow fv_flow( cf = c(100, 150, 200), i = c(0.05, 0.055, 0.06), i_type = "effective", t = c(1, 2, 3) ) # Using dates; earliest date is taken as t = 0 fv_flow( cf = c(100, 150, 200), i = c(0.05, 0.055, 0.06), i_type = "effective", date = as.Date(c("2026-01-10", "2027-01-10", "2028-01-10")) ) # Nominal rates by cash flow fv_flow( cf = c(100, 100, 100), i = c(0.12, 0.12, 0.12), i_type = "nominal_interest", m = c(12, 12, 12), t = c(1, 2, 3) )# Constant annual effective rate fv_flow( cf = c(100, 150, 200), i = 0.08, i_type = "effective", t = c(0, 1, 2) ) # Spot rates, one per cash flow fv_flow( cf = c(100, 150, 200), i = c(0.05, 0.055, 0.06), i_type = "effective", t = c(1, 2, 3) ) # Using dates; earliest date is taken as t = 0 fv_flow( cf = c(100, 150, 200), i = c(0.05, 0.055, 0.06), i_type = "effective", date = as.Date(c("2026-01-10", "2027-01-10", "2028-01-10")) ) # Nominal rates by cash flow fv_flow( cf = c(100, 100, 100), i = c(0.12, 0.12, 0.12), i_type = "nominal_interest", m = c(12, 12, 12), t = c(1, 2, 3) )
Computes asset weights that duration-immunize a stream of liabilities using two or more assets, using compact actuarial notation.
immunize_duration(L, t, P, D, i, i_type = "effective", m = 1L)immunize_duration(L, t, P, D, i, i_type = "effective", m = 1L)
L |
Numeric vector with liability payments. |
t |
Numeric vector of the same length as |
P |
Numeric vector with present values or prices of the immunizing assets, evaluated on the same yield basis. |
D |
Numeric vector with the Macaulay duration of each asset, expressed
in the same time units as |
i |
Numeric scalar. Interest-rate input used to discount the liabilities. |
i_type |
Character string indicating the interest-rate type. Allowed
values are |
m |
Positive integer. Conversion frequency for nominal rates. Ignored
for |
The method enforces:
present value of assets = present value of liabilities;
Macaulay duration of assets = Macaulay duration of liabilities.
For exactly two assets, a closed-form solution is used. For three or more assets, a minimum-norm solution is computed by linear algebra.
This function follows the compact actuarial notation used throughout
tidyactuarial: L denotes liabilities, t denotes payment
times, P denotes asset prices or present values, D denotes
asset durations, i denotes the interest rate, i_type denotes
the interest-rate type, and m denotes the conversion frequency for
nominal rates.
Let and be the present value and Macaulay duration of
the liability stream at yield . Let and be the
price and duration of asset . The weights are chosen so
that:
and
For two assets, the closed-form solution is:
For three or more assets, the minimum-norm solution of the linear system
is computed, where is a matrix with
rows
and
and
A tibble with:
Numeric vector of asset weights or units.
Present value of the liabilities.
Macaulay duration of the liabilities.
Present value of the immunized asset portfolio.
Macaulay duration of the asset portfolio.
Number of assets used.
immunize_duration_convexity,
bond_duration, bond_convexity
Other immunization:
immunize_duration_convexity(),
plot_immunization_gap()
# Two-asset immunization immunize_duration( L = c(5000, 8000), t = c(3, 7), P = c(100, 200), D = c(3, 7), i = 0.05 ) # Three-asset immunization: minimum-norm solution immunize_duration( L = c(5000, 8000), t = c(3, 7), P = c(100, 150, 200), D = c(2, 5, 8), i = 0.05 ) # Nominal annual interest rate convertible monthly immunize_duration( L = c(5000, 8000), t = c(3, 7), P = c(100, 200), D = c(3, 7), i = 0.06, i_type = "nominal_interest", m = 12 )# Two-asset immunization immunize_duration( L = c(5000, 8000), t = c(3, 7), P = c(100, 200), D = c(3, 7), i = 0.05 ) # Three-asset immunization: minimum-norm solution immunize_duration( L = c(5000, 8000), t = c(3, 7), P = c(100, 150, 200), D = c(2, 5, 8), i = 0.05 ) # Nominal annual interest rate convertible monthly immunize_duration( L = c(5000, 8000), t = c(3, 7), P = c(100, 200), D = c(3, 7), i = 0.06, i_type = "nominal_interest", m = 12 )
Computes asset weights that immunize a stream of liabilities using three or more assets, enforcing:
present value of assets = present value of liabilities;
Macaulay duration of assets = Macaulay duration of liabilities;
convexity of assets = convexity of liabilities.
immunize_duration_convexity(L, t, P, D, C, i, i_type = "effective", m = 1L)immunize_duration_convexity(L, t, P, D, C, i, i_type = "effective", m = 1L)
L |
Numeric vector with liability payments. |
t |
Numeric vector of the same length as |
P |
Numeric vector with present values or prices of the immunizing assets, evaluated on the same yield basis. |
D |
Numeric vector with the Macaulay duration of each asset, expressed
in the same time units as |
C |
Numeric vector with the discrete convexity of each asset, expressed
in the same time units as |
i |
Numeric scalar. Interest-rate input used to discount the liabilities. |
i_type |
Character string indicating the interest-rate type. Allowed
values are |
m |
Positive integer. Conversion frequency for nominal rates. Ignored
for |
For exactly three assets, the system is solved directly. For four or more assets, a minimum-norm solution is computed by linear algebra.
This function follows the compact actuarial notation used throughout
tidyactuarial: L denotes liabilities, t denotes payment
times, P denotes asset prices or present values, D denotes
asset durations, C denotes asset convexities, i denotes the
interest rate, i_type denotes the interest-rate type, and m
denotes the conversion frequency for nominal rates.
Let , , and be the present value, Macaulay
duration, and discrete convexity of the liability stream at yield .
The discrete convexity of the liabilities is computed as:
where after converting i to the equivalent
effective rate.
The weights satisfy the system ,
where the rows of are
and
and
For three assets, the system is square and solved directly. For four or more assets, the minimum-norm solution
is computed.
A tibble with:
Numeric vector of asset weights or units.
Present value of the liabilities.
Macaulay duration of the liabilities.
Discrete convexity of the liabilities.
Present value of the asset portfolio.
Macaulay duration of the asset portfolio.
Discrete convexity of the asset portfolio.
Number of assets used.
immunize_duration, bond_duration,
bond_convexity
Other immunization:
immunize_duration(),
plot_immunization_gap()
# Three-asset immunization immunize_duration_convexity( L = c(5000, 8000, 10000), t = c(3, 5, 7), P = c(100, 150, 200), D = c(2, 5, 8), C = c(6, 30, 72), i = 0.05 ) # Four-asset immunization: minimum-norm solution immunize_duration_convexity( L = c(5000, 8000, 10000), t = c(3, 5, 7), P = c(100, 120, 150, 200), D = c(2, 4, 6, 8), C = c(6, 20, 42, 72), i = 0.05 ) # Nominal annual interest rate convertible monthly immunize_duration_convexity( L = c(5000, 8000, 10000), t = c(3, 5, 7), P = c(100, 150, 200), D = c(2, 5, 8), C = c(6, 30, 72), i = 0.06, i_type = "nominal_interest", m = 12 )# Three-asset immunization immunize_duration_convexity( L = c(5000, 8000, 10000), t = c(3, 5, 7), P = c(100, 150, 200), D = c(2, 5, 8), C = c(6, 30, 72), i = 0.05 ) # Four-asset immunization: minimum-norm solution immunize_duration_convexity( L = c(5000, 8000, 10000), t = c(3, 5, 7), P = c(100, 120, 150, 200), D = c(2, 4, 6, 8), C = c(6, 20, 42, 72), i = 0.05 ) # Nominal annual interest rate convertible monthly immunize_duration_convexity( L = c(5000, 8000, 10000), t = c(3, 5, 7), P = c(100, 150, 200), D = c(2, 5, 8), C = c(6, 30, 72), i = 0.06, i_type = "nominal_interest", m = 12 )
Computes the actuarial present value of a life insurance where the death benefit may vary by subperiod and is payable at the end of the subperiod of death, using compact actuarial notation.
insurance_variable_k( lt, x, i, benefit, n = NULL, h = 0, k = 12, i_type = "effective", m = 1L, frac, tidy = FALSE, check = TRUE, tol = 1e-10 )insurance_variable_k( lt, x, i, benefit, n = NULL, h = 0, k = 12, i_type = "effective", m = 1L, frac, tidy = FALSE, check = TRUE, tol = 1e-10 )
lt |
A life table object or data frame containing at least columns
|
x |
Integer actuarial age at issue. |
i |
Annual interest-rate input. |
benefit |
Numeric vector of benefits by subperiod, or a function of
time returning the benefit at time |
n |
Optional term in years. If |
h |
Nonnegative deferment period in years. Default is |
k |
Positive integer. Number of subperiods per year. Default is
|
i_type |
Character vector indicating the interest-rate type. Allowed
values are |
m |
Positive integer vector giving the conversion frequency for nominal
interest-rate inputs. Ignored for |
frac |
Fractional-age assumption used in survival probabilities:
|
tidy |
Logical. If |
check |
Logical. If |
tol |
Numeric tolerance used for integer-grid checks. |
This function is useful for level, increasing, decreasing, and credit-style life insurance benefits when benefits are specified at a subannual frequency.
This function follows the compact actuarial notation used throughout
tidyactuarial: lt is the life table, x is the age at
issue, i is the interest-rate input, i_type is the
interest-rate type, m is the conversion frequency for nominal rates,
n is the term, h is the deferment period, and k is the
number of subperiods per year.
Let be the number of subperiods per year and the total
number of subperiods in the insurance term. With deferment , the
actuarial present value at age is:
Here is the benefit payable if death occurs in subperiod
, and , where is the annual
effective interest rate equivalent to the input i, i_type, and
m.
If benefit is numeric of length 1, it is recycled to all subperiods.
If it is numeric with length greater than 1, its length must equal
. If benefit is a function, it is evaluated at the end of
each subperiod, at times .
Fractional survival probabilities are computed via t_px under
the selected fractional-age assumption.
A numeric actuarial present value, or a one-row tibble if
tidy = TRUE.
insurance_x for level-benefit life insurance,
annuity_x for life annuity APVs,
t_px for survival probabilities.
Other life-contingencies:
annuity_multi(),
annuity_x(),
annuity_xy(),
insurance_x(),
insurance_xy(),
life_contract(),
premium_gross(),
premium_x(),
premium_xy(),
reserve_x(),
reserve_xy(),
simulate_annuity_x(),
simulate_insurance_x()
lt <- data.frame( x = 60:66, lx = c(100000, 99000, 97500, 95500, 93000, 90000, 86000) ) # Monthly insurance with increasing benefits insurance_variable_k( lt = lt, x = 60, i = 0.05, benefit = seq(100, 1200, length.out = 12), n = 1, k = 12 ) # Credit-style insurance with declining outstanding balance balance <- function(t) 2000 * exp(-0.3 * t) insurance_variable_k( lt = lt, x = 60, i = 0.05, benefit = balance, n = 1, k = 12 ) # Level benefit with annual payments insurance_variable_k( lt = lt, x = 60, i = 0.05, benefit = 1, n = 5, k = 1 ) # 2-year deferred, 3-year term with monthly varying benefits insurance_variable_k( lt = lt, x = 60, i = 0.05, benefit = rep(1000, 36), n = 3, h = 2, k = 12 ) # Nominal annual interest convertible monthly insurance_variable_k( lt = lt, x = 60, i = 0.06, i_type = "nominal_interest", m = 12, benefit = rep(1000, 12), n = 1, k = 12 ) # Tidy output insurance_variable_k( lt = lt, x = 60, i = 0.05, benefit = rep(1000, 12), n = 1, k = 12, tidy = TRUE )lt <- data.frame( x = 60:66, lx = c(100000, 99000, 97500, 95500, 93000, 90000, 86000) ) # Monthly insurance with increasing benefits insurance_variable_k( lt = lt, x = 60, i = 0.05, benefit = seq(100, 1200, length.out = 12), n = 1, k = 12 ) # Credit-style insurance with declining outstanding balance balance <- function(t) 2000 * exp(-0.3 * t) insurance_variable_k( lt = lt, x = 60, i = 0.05, benefit = balance, n = 1, k = 12 ) # Level benefit with annual payments insurance_variable_k( lt = lt, x = 60, i = 0.05, benefit = 1, n = 5, k = 1 ) # 2-year deferred, 3-year term with monthly varying benefits insurance_variable_k( lt = lt, x = 60, i = 0.05, benefit = rep(1000, 36), n = 3, h = 2, k = 12 ) # Nominal annual interest convertible monthly insurance_variable_k( lt = lt, x = 60, i = 0.06, i_type = "nominal_interest", m = 12, benefit = rep(1000, 12), n = 1, k = 12 ) # Tidy output insurance_variable_k( lt = lt, x = 60, i = 0.05, benefit = rep(1000, 12), n = 1, k = 12, tidy = TRUE )
Computes the actuarial present value of a discrete single-life insurance using a life table and compact actuarial notation.
insurance_x( lt, x, i, i_type = "effective", m = 1L, n = Inf, h = 0L, type = c("whole", "term", "endowment"), benefit = 1, tidy = FALSE, ... )insurance_x( lt, x, i, i_type = "effective", m = 1L, n = Inf, h = 0L, type = c("whole", "term", "endowment"), benefit = 1, tidy = FALSE, ... )
lt |
A life table as produced by |
x |
Integer actuarial age at issue. |
i |
Numeric scalar. Annual interest-rate input. |
i_type |
Character string indicating the interest-rate type. Allowed
values are |
m |
Positive integer. Conversion frequency for nominal rates. Ignored
for |
n |
Integer insurance term in years. Required for
|
h |
Integer deferment period in years. |
type |
Character string. One of |
benefit |
Numeric scalar. Benefit amount. |
tidy |
Logical scalar. If |
... |
Transitional compatibility for older calls using
|
The benefit is paid at the end of the year of death for whole-life and term insurance. For endowment insurance, the same benefit is paid either at death within the term or at the end of the term if the life survives.
Supported contracts:
"whole": whole-life insurance.
"term": n-year term insurance.
"endowment": n-year endowment insurance.
This function follows the compact actuarial notation used throughout
tidyactuarial: lt is the life table, x is the age at
issue, i is the interest-rate input, i_type is the
interest-rate type, m is the conversion frequency for nominal rates,
n is the insurance term, and h is the deferment period.
The function computes APVs directly from lx. For a deferred
insurance, the value at age x + h is multiplied by
For whole-life insurance, the death benefit APV at the deferred starting age
is computed over the available life-table horizon. For term and endowment
insurance, the death benefit is computed over the first n years.
Endowment insurance additionally includes the pure endowment component
If tidy = FALSE, a numeric scalar containing the actuarial present
value.
If tidy = TRUE, a one-row tibble with the main input values,
equivalent interest rate, deferral factor, pure endowment factor,
annuity-due value used in the standard identities, and APV.
annuity_x, premium_x,
reserve_x, t_Ex, insurance_xy
Other life-contingencies:
annuity_multi(),
annuity_x(),
annuity_xy(),
insurance_variable_k(),
insurance_xy(),
life_contract(),
premium_gross(),
premium_x(),
premium_xy(),
reserve_x(),
reserve_xy(),
simulate_annuity_x(),
simulate_insurance_x()
lt <- data.frame( x = 60:65, lx = c(100000, 99000, 97500, 95500, 93000, 90000) ) # Whole-life insurance insurance_x( lt = lt, x = 60, i = 0.06, type = "whole" ) # 5-year term insurance insurance_x( lt = lt, x = 60, i = 0.06, n = 5, type = "term" ) # 5-year endowment insurance insurance_x( lt = lt, x = 60, i = 0.06, n = 5, type = "endowment" ) # Deferred whole-life insurance insurance_x( lt = lt, x = 60, i = 0.06, h = 2, type = "whole" ) # Tidy output insurance_x( lt = lt, x = 60, i = 0.06, n = 5, type = "term", tidy = TRUE )lt <- data.frame( x = 60:65, lx = c(100000, 99000, 97500, 95500, 93000, 90000) ) # Whole-life insurance insurance_x( lt = lt, x = 60, i = 0.06, type = "whole" ) # 5-year term insurance insurance_x( lt = lt, x = 60, i = 0.06, n = 5, type = "term" ) # 5-year endowment insurance insurance_x( lt = lt, x = 60, i = 0.06, n = 5, type = "endowment" ) # Deferred whole-life insurance insurance_x( lt = lt, x = 60, i = 0.06, h = 2, type = "whole" ) # Tidy output insurance_x( lt = lt, x = 60, i = 0.06, n = 5, type = "term", tidy = TRUE )
This function evaluates cause-specific insurance benefits under a multiple decrement model. It supports whole-life and term insurance, integer deferment, vectorized issue ages and interest-rate assumptions, and compact actuarial notation.
insurance_xj( md, x, i, cause, type = c("whole", "term"), benefit = 1, n = NULL, h = 0L, i_type = "effective", m = 1L, tidy = FALSE, check = TRUE, tol = 1e-10 ) A_xj( md, x, i, cause, type = c("whole", "term"), benefit = 1, n = NULL, h = 0L, i_type = "effective", m = 1L, tidy = FALSE, check = TRUE, tol = 1e-10 )insurance_xj( md, x, i, cause, type = c("whole", "term"), benefit = 1, n = NULL, h = 0L, i_type = "effective", m = 1L, tidy = FALSE, check = TRUE, tol = 1e-10 ) A_xj( md, x, i, cause, type = c("whole", "term"), benefit = 1, n = NULL, h = 0L, i_type = "effective", m = 1L, tidy = FALSE, check = TRUE, tol = 1e-10 )
md |
A multiple decrement table produced by |
x |
Integer age(s) at issue. |
i |
Annual interest-rate input. Must produce an annual effective rate
greater than |
cause |
Character scalar. Name of the cause column in |
type |
Character scalar. Insurance type: |
benefit |
Numeric benefit amount payable at the end of the year of
decrement by the specified cause. Default is |
n |
Integer term length in years. Required when |
h |
Integer deferment period in years. Default is |
i_type |
Character vector indicating the interest-rate type. Allowed
values are |
m |
Positive integer vector giving the conversion frequency for nominal
rates. Ignored for |
tidy |
Logical. If |
check |
Logical. If |
tol |
Numeric tolerance for integer checks. |
Computes the actuarial present value (APV) of an annual discrete insurance
that pays benefit at the end of the year of decrement by a specified
cause j, using a multiple decrement table produced by
md_table.
Let be the one-year decrement probability for cause
at age , and let be the one-year
total survival probability against all decrements at age .
For a product with deferment and term , with benefit payable
at the end of the year of decrement by cause , the APV is:
Here , where is the annual effective
interest rate obtained from i, i_type, and m.
If type = "whole", the function sets n to the remaining length
of the table after deferment, that is, whole life over the available ages.
This function follows the compact actuarial notation used throughout
tidyactuarial: md is a multiple decrement table, x is
age at issue, i is the interest rate, i_type is the
interest-rate type, m is the conversion frequency for nominal rates,
n is the term, and h is the deferment period.
Numeric vector of APVs, or a tibble if tidy = TRUE.
t_qxj for cause-specific decrement probabilities,
lt_tau to build a single-decrement life table for the total
decrement.
qx_df <- tibble::tibble( x = 30:35, q_death = c(0.001, 0.0012, 0.0014, 0.0017, 0.0020, 1.0000), q_disability = c(0.002, 0.0021, 0.0022, 0.0023, 0.0024, 0.0000) ) md <- md_table(qx_df, radix = 1e5, close = TRUE) # 5-year term cause-specific insurance for death, i = 5% insurance_xj( md = md, x = 30, i = 0.05, cause = "q_death", type = "term", n = 5 ) # Whole-life over available ages, 2-year deferred insurance_xj( md = md, x = 30, i = 0.05, cause = "q_death", type = "whole", h = 2, tidy = TRUE )qx_df <- tibble::tibble( x = 30:35, q_death = c(0.001, 0.0012, 0.0014, 0.0017, 0.0020, 1.0000), q_disability = c(0.002, 0.0021, 0.0022, 0.0023, 0.0024, 0.0000) ) md <- md_table(qx_df, radix = 1e5, close = TRUE) # 5-year term cause-specific insurance for death, i = 5% insurance_xj( md = md, x = 30, i = 0.05, cause = "q_death", type = "term", n = 5 ) # Whole-life over available ages, 2-year deferred insurance_xj( md = md, x = 30, i = 0.05, cause = "q_death", type = "whole", h = 2, tidy = TRUE )
Computes the actuarial present value of a discrete two-life insurance with benefit payable at the end of the year of the triggering death, assuming independent future lifetimes and using compact actuarial notation.
insurance_xy( lt, x = NULL, y = NULL, i = NULL, i_type = "effective", m = 1L, type = c("whole", "term", "endowment"), status = c("joint", "last"), n = Inf, h = 0L, benefit = 1, frac, tidy = FALSE, ... )insurance_xy( lt, x = NULL, y = NULL, i = NULL, i_type = "effective", m = 1L, type = c("whole", "term", "endowment"), status = c("joint", "last"), n = Inf, h = 0L, benefit = 1, frac, tidy = FALSE, ... )
lt |
A life table, a list of two life tables |
x |
Integer actuarial age for the first life. |
y |
Integer actuarial age for the second life. |
i |
Numeric scalar. Annual interest-rate input. |
i_type |
Character string indicating the interest-rate type. Allowed
values are |
m |
Positive integer. Conversion frequency for nominal rates. Ignored
for |
type |
Character string. One of |
status |
Character string. Use |
n |
Term in years. Required as finite for term and endowment insurance.
Use |
h |
Nonnegative integer deferment period in years. |
benefit |
Numeric scalar. Insurance benefit. |
frac |
Fractional-age assumption used in two-life survival
probabilities. One of |
tidy |
Logical scalar. If |
... |
Transitional compatibility for older calls using
|
Supported contracts:
"whole": whole-life two-life insurance.
"term": n-year two-life term insurance.
"endowment": n-year two-life endowment insurance.
The status argument determines the two-life status:
status = "joint": first-death insurance, based on the
joint-life status.
status = "last": second-death insurance, based on the
last-survivor status.
This function follows the compact actuarial notation used throughout
tidyactuarial: lt is the life table input, x and
y are the two actuarial ages, i is the interest-rate input,
i_type is the interest-rate type, m is the conversion
frequency for nominal rates, n is the insurance term, and h is
the deferment period.
The function uses the standard fully discrete identities that express insurance values through two-life annuity-due values.
For a whole-life contract:
For an n-year term insurance:
For an n-year endowment insurance:
A deferred insurance is valued by multiplying the value at deferred ages
x + h and y + h by the deferment factor
for the selected two-life status.
If tidy = FALSE, a numeric scalar.
If tidy = TRUE, a one-row tibble with input values, standardized
interest rate, deferment factor, unit APV, and APV.
annuity_xy, premium_xy,
insurance_x, t_pxy
Other life-contingencies:
annuity_multi(),
annuity_x(),
annuity_xy(),
insurance_variable_k(),
insurance_x(),
life_contract(),
premium_gross(),
premium_x(),
premium_xy(),
reserve_x(),
reserve_xy(),
simulate_annuity_x(),
simulate_insurance_x()
lt <- data.frame( x = 60:110, lx = seq(100000, 0, length.out = 51) ) insurance_xy( lt = lt, x = 60, y = 62, i = 0.06, type = "whole", status = "joint" ) insurance_xy( lt = lt, x = 60, y = 62, i = 0.06, type = "term", status = "last", n = 10, tidy = TRUE ) lt |> life_contract(lives = "joint", x = 60, y = 62, i = 0.06) |> insurance_xy( type = "term", n = 4, status = "joint" )lt <- data.frame( x = 60:110, lx = seq(100000, 0, length.out = 51) ) insurance_xy( lt = lt, x = 60, y = 62, i = 0.06, type = "whole", status = "joint" ) insurance_xy( lt = lt, x = 60, y = 62, i = 0.06, type = "term", status = "last", n = 10, tidy = TRUE ) lt |> life_contract(lives = "joint", x = 60, y = 62, i = 0.06) |> insurance_xy( type = "term", n = 4, status = "joint" )
Converts a single interest-rate specification into equivalent actuarial
rates for the same conversion frequency m.
interest_equivalents( i_type = c("effective", "nominal_interest", "nominal_discount", "force"), i, m = 1L )interest_equivalents( i_type = c("effective", "nominal_interest", "nominal_discount", "force"), i, m = 1L )
i_type |
Character string indicating the input interest-rate type.
Must be one of |
i |
Numeric scalar giving the interest-rate value. |
m |
Positive integer scalar giving the conversion frequency for nominal rates. |
Internally, the supplied rate is first converted to the annual effective
interest rate using standardize_interest.
This function follows the compact actuarial notation used throughout
tidyactuarial: i denotes the interest-rate value,
i_type denotes the type of interest rate, and m denotes the
conversion frequency for nominal rates.
Given the annual effective interest rate , the equivalents are:
A tibble with columns:
Rate family: "effective", "discount",
"force", "nominal_interest", or
"nominal_discount".
Actuarial notation for the equivalent rate.
Conversion frequency used for nominal rates.
Human-readable description.
Equivalent rate value.
standardize_interest,
discount_factor_spot
Other interest:
discount_factor_spot(),
forward_rate(),
standardize_interest(),
yield_curve()
interest_equivalents(i_type = "nominal_interest", i = 0.18, m = 4) interest_equivalents(i_type = "nominal_discount", i = 0.10, m = 12) interest_equivalents(i_type = "force", i = 0.12) interest_equivalents(i_type = "effective", i = 0.08) # Batch use with purrr if (requireNamespace("purrr", quietly = TRUE) && requireNamespace("tibble", quietly = TRUE)) { cases <- tibble::tibble( i_type = c("effective", "force"), i = c(0.08, 0.12), m = c(1, 1) ) purrr::pmap(cases, interest_equivalents) }interest_equivalents(i_type = "nominal_interest", i = 0.18, m = 4) interest_equivalents(i_type = "nominal_discount", i = 0.10, m = 12) interest_equivalents(i_type = "force", i = 0.12) interest_equivalents(i_type = "effective", i = 0.08) # Batch use with purrr if (requireNamespace("purrr", quietly = TRUE) && requireNamespace("tibble", quietly = TRUE)) { cases <- tibble::tibble( i_type = c("effective", "force"), i = c(0.08, 0.12), m = c(1, 1) ) purrr::pmap(cases, interest_equivalents) }
Computes the internal rate of return (IRR) of a cash flow by finding the annual effective rate that makes its present value equal to zero, using compact actuarial notation.
irr_flow( cf, t = NULL, date = NULL, m = 1L, interval = c(-0.99, 10), tol = 1e-10, maxiter = 1000, day_count = c("act/365", "act/360") )irr_flow( cf, t = NULL, date = NULL, m = 1L, interval = c(-0.99, 10), tol = 1e-10, maxiter = 1000, day_count = c("act/365", "act/360") )
cf |
Numeric vector of cash flows. |
t |
Optional numeric vector of cash-flow times in years. |
date |
Optional vector of cash-flow dates. If supplied, the earliest date is treated as time 0. |
m |
Positive integer used only to report an equivalent nominal annual
interest rate convertible |
interval |
Numeric vector of length 2 giving the search interval for the
annual effective IRR. Default is |
tol |
Numeric tolerance passed to |
maxiter |
Maximum number of iterations passed to
|
day_count |
Day-count convention used when |
The cash flow is supplied explicitly through cf. Its timing is given
either through t (in years) or date (calendar dates). If
date is supplied, the earliest date is treated as time 0.
The IRR returned is interpreted as an annual effective rate.
This function follows the compact actuarial notation used throughout
tidyactuarial: cf denotes cash flows, t denotes time,
and m denotes the conversion frequency used to report the equivalent
nominal annual interest rate.
The IRR is defined as the rate satisfying
where are the cash flows and the corresponding times
in years.
The root is found using uniroot over the specified
interval. If the NPV does not change sign over the interval, no root
can be bracketed and the function returns gracefully with
converged = FALSE.
The number of sign changes in the nonzero cash-flow sequence is reported as a diagnostic. If there is exactly one sign change, the IRR is usually unique under the usual ordered cash-flow setting.
A one-row tibble with:
Estimated IRR as an annual effective rate.
Same as irr, reported explicitly.
Equivalent nominal annual interest rate
convertible m times.
Equivalent force of interest.
Present value at the estimated IRR, close to zero.
Left endpoint of the search interval.
Right endpoint of the search interval.
Logical flag indicating whether a root was found.
Number of iterations used by uniroot.
Length of cf.
Whether the cash flow has at least one positive and one negative value.
Number of sign changes in the nonzero cash-flow sequence.
If no sign change is present in the cash flow, or if the NPV does not change
sign over interval, the function returns converged = FALSE and
irr = NA_real_.
pv_flow, irr_flow_multi,
bond_ytm
Other time-value:
future_value(),
fv_flow(),
irr_flow_multi(),
plot_cash_flow(),
present_value(),
pv_flow()
irr_flow( cf = c(-1000, 300, 400, 500), t = c(0, 1, 2, 3) ) irr_flow( cf = c(-1000, 300, 400, 500), date = as.Date(c("2026-01-01", "2027-01-01", "2028-01-01", "2029-01-01")) )irr_flow( cf = c(-1000, 300, 400, 500), t = c(0, 1, 2, 3) ) irr_flow( cf = c(-1000, 300, 400, 500), date = as.Date(c("2026-01-01", "2027-01-01", "2028-01-01", "2029-01-01")) )
Searches for multiple internal rates of return (IRRs) of a cash flow by scanning a search interval and solving for all detectable roots of the net present value (NPV) function, using compact actuarial notation.
irr_flow_multi( cf, t = NULL, date = NULL, m = 1L, search_interval = c(-0.99, 10), grid_points = 2000L, tol = 1e-10, maxiter = 1000L, day_count = c("act/365", "act/360") )irr_flow_multi( cf, t = NULL, date = NULL, m = 1L, search_interval = c(-0.99, 10), grid_points = 2000L, tol = 1e-10, maxiter = 1000L, day_count = c("act/365", "act/360") )
cf |
Numeric vector of cash flows. |
t |
Optional numeric vector of cash-flow times in years. |
date |
Optional vector of cash-flow dates. If supplied, the earliest date is treated as time 0. |
m |
Positive integer used only to report an equivalent nominal annual
interest rate convertible |
search_interval |
Numeric vector of length 2 giving the search interval
for annual effective IRRs. Default is |
grid_points |
Positive integer giving the number of grid points used to scan the interval. Larger values improve detection at the cost of speed. |
tol |
Numeric tolerance passed to |
maxiter |
Positive integer passed to |
day_count |
Day-count convention used when |
This function is intended for cash flows with multiple sign changes, where
more than one IRR may exist. It evaluates the NPV on a fine grid over the
search interval, identifies subintervals with sign changes (and grid points
where the NPV is approximately zero), and applies
uniroot to each candidate interval.
The IRRs returned are interpreted as annual effective rates.
Timing can be supplied either through t (in years) or date
(calendar dates). If date is supplied, the earliest date is treated
as time 0.
This function follows the compact actuarial notation used throughout
tidyactuarial: cf denotes cash flows, t denotes time,
and m denotes the conversion frequency used to report the equivalent
nominal annual interest rate.
This function detects roots numerically over a finite search interval. It may miss roots if:
the grid is too coarse,
two roots are extremely close,
the NPV touches zero without changing sign,
or the root lies outside the search interval.
For a single-IRR workflow, use irr_flow.
A tibble with one row per detected IRR and columns:
Root index.
Detected IRR as an annual effective rate.
Same as irr, reported explicitly.
Equivalent nominal annual interest rate
convertible m times.
Equivalent force of interest.
NPV evaluated at the detected root, approximately zero.
Left endpoint of the local search bracket.
Right endpoint of the local search bracket.
Length of cf.
Whether the cash flow has at least one positive and one negative value.
Number of sign changes in the nonzero cash-flow sequence.
If no roots are detected, the function returns a tibble with zero rows.
Other time-value:
future_value(),
fv_flow(),
irr_flow(),
plot_cash_flow(),
present_value(),
pv_flow()
# A standard single-IRR cash flow irr_flow_multi( cf = c(-1000, 300, 400, 500), t = c(0, 1, 2, 3) ) # A cash flow with multiple sign changes irr_flow_multi( cf = c(-1000, 5000, -4500, 200), t = c(0, 1, 2, 3), search_interval = c(-0.99, 5), grid_points = 5000 ) # Date-based version irr_flow_multi( cf = c(-1000, 300, 400, 500), date = as.Date(c("2026-01-01", "2027-01-01", "2028-01-01", "2029-01-01")) )# A standard single-IRR cash flow irr_flow_multi( cf = c(-1000, 300, 400, 500), t = c(0, 1, 2, 3) ) # A cash flow with multiple sign changes irr_flow_multi( cf = c(-1000, 5000, -4500, 200), t = c(0, 1, 2, 3), search_interval = c(-0.99, 5), grid_points = 5000 ) # Date-based version irr_flow_multi( cf = c(-1000, 300, 400, 500), date = as.Date(c("2026-01-01", "2027-01-01", "2028-01-01", "2029-01-01")) )
Fits the nonparametric Kaplan–Meier estimator for
right-censored time-to-event data, computes Greenwood's variance estimator
for , and constructs a discrete life table by evaluating
at user-provided cut points (breaks).
km_lifetable( time, status, entry = NULL, breaks = NULL, radix = 1e+05, conf_level = 0.95, assumption = c("UDD", "CF", "Balducci") )km_lifetable( time, status, entry = NULL, breaks = NULL, radix = 1e+05, conf_level = 0.95, assumption = c("UDD", "CF", "Balducci") )
time |
Numeric vector. Observed times (event or censoring times). |
status |
Integer/numeric vector of the same length as |
entry |
Optional numeric vector of entry times (left truncation /
delayed entry). If provided, must have the same length as |
breaks |
Optional numeric vector of increasing cut points used to build
the discrete life table (e.g., |
radix |
Numeric. Life table radix used to scale |
conf_level |
Numeric in |
assumption |
Character. Fractional-age assumption used to compute
|
The resulting life table is intended for experience-based (empirical) life tables in actuarial/demographic contexts (e.g., cohort studies, population indicators). It is not a replacement for graduated/regulatory tables when smoothing, extrapolation, or product-specific selection effects are required.
Kaplan–Meier estimator. At each observed event time :
where is the risk set size and is the number of events.
Greenwood's variance:
Pointwise confidence intervals use the log(-log) transformation.
Life table mapping. For each interval :
Exposure is computed using the
selected fractional-age assumption (Finan, Section 24):
UDD (Finan, Sec. 24.1):
CF (constant force, Finan, Sec. 24.2):
Balducci (Finan, Sec. 24.3):
Additional columns follow Finan, Sections 23.3, 23.8–23.9:
: total expected years lived after
age (Finan, Sec. 23.3).
: complete life expectancy
(Finan, Sec. 23.3).
: central death rate (Finan, Sec. 23.9).
: average fraction of the
interval lived by those who die.
A list with two tibbles:
km: tibble with columns time, n_risk,
d, censored, S, varS, seS,
ci_low, ci_high.
lifetable: tibble with columns x, x_next,
width, lx, dx, qx, px, mx,
ax, Lx, Tx, ex. Carries class
"lifetable" and standard attributes for compatibility with
downstream functions.
lifetable for building tables from known mortality
inputs, plot_km for plotting the KM curve.
set.seed(1) n <- 200 trueT <- rexp(n, rate = 0.08) censT <- rexp(n, rate = 0.04) time <- pmin(trueT, censT) status <- as.integer(trueT <= censT) out <- km_lifetable(time, status, breaks = 0:25, radix = 100000) head(out$km) head(out$lifetable) # Tidy pipeline: filter high-mortality intervals out$lifetable |> dplyr::filter(qx > 0.05) # Compare UDD vs CF assumptions udd <- km_lifetable(time, status, breaks = 0:20, assumption = "UDD") cfm <- km_lifetable(time, status, breaks = 0:20, assumption = "CF") c(ex_udd = udd$lifetable$ex[1], ex_cf = cfm$lifetable$ex[1]) # Plot the KM curve with plot_km plot_km(out$km, time_col = "time", surv_col = "S", lower_col = "ci_low", upper_col = "ci_high")set.seed(1) n <- 200 trueT <- rexp(n, rate = 0.08) censT <- rexp(n, rate = 0.04) time <- pmin(trueT, censT) status <- as.integer(trueT <= censT) out <- km_lifetable(time, status, breaks = 0:25, radix = 100000) head(out$km) head(out$lifetable) # Tidy pipeline: filter high-mortality intervals out$lifetable |> dplyr::filter(qx > 0.05) # Compare UDD vs CF assumptions udd <- km_lifetable(time, status, breaks = 0:20, assumption = "UDD") cfm <- km_lifetable(time, status, breaks = 0:20, assumption = "CF") c(ex_udd = udd$lifetable$ex[1], ex_cf = cfm$lifetable$ex[1]) # Plot the KM curve with plot_km plot_km(out$km, time_col = "time", surv_col = "S", lower_col = "ci_low", upper_col = "ci_high")
Creates a lightweight actuarial contract object that stores common life-contingency inputs for use in pipe workflows.
life_contract( lt, lives = c("single", "joint", "last_survivor"), x = NULL, y = NULL, i, i_type = "effective", m = 1L, ... )life_contract( lt, lives = c("single", "joint", "last_survivor"), x = NULL, y = NULL, i, i_type = "effective", m = 1L, ... )
lt |
A life table or a list of two life tables. For single-life
contracts, provide one data frame or tibble. For two-life contracts,
provide either one data frame used for both lives, or |
lives |
Character string. Use |
x |
Numeric scalar. Age of the single life, or age of the first life in a two-life contract. |
y |
Numeric scalar. Age of the second life in a two-life contract.
Required when |
i |
Numeric scalar. Annual interest-rate input. |
i_type |
Character string indicating the interest-rate type. Allowed
values are |
m |
Positive integer. Conversion frequency for nominal rates. Ignored
for |
... |
Reserved for future extensions. Deprecated argument names such as
|
This function does not compute actuarial values. It validates and stores
common actuarial inputs such as the life table, life status, ages, and
interest-rate specification. Calculation functions such as annuity_x(),
insurance_x(), premium_x(), reserve_x(), annuity_xy(),
insurance_xy(), premium_xy(), reserve_xy(), and simulation functions
can then consume this object.
life_contract() follows the compact actuarial notation used throughout
tidyactuarial:
lt: life table;
x: age of the first or single life;
y: age of the second life;
i: interest rate;
i_type: type of interest rate;
m: conversion frequency for nominal rates.
The object stores actuarial fields using the compact names above. During the 0.1.4 API transition, it also stores internal compatibility fields so that functions not yet migrated can continue to read the contract. These internal fields are not part of the preferred user-facing notation.
An object of class "tidyact_life_contract".
Other life-contingencies:
annuity_multi(),
annuity_x(),
annuity_xy(),
insurance_variable_k(),
insurance_x(),
insurance_xy(),
premium_gross(),
premium_x(),
premium_xy(),
reserve_x(),
reserve_xy(),
simulate_annuity_x(),
simulate_insurance_x()
lt <- data.frame( x = 40:90, lx = round(100000 * exp(-0.018 * (0:50)^1.35)) ) lt$lx[nrow(lt)] <- 0 life_contract( lt = lt, lives = "single", x = 40, i = 0.05 ) life_contract( lt = lt, lives = "joint", x = 60, y = 58, i = 0.05 )lt <- data.frame( x = 40:90, lx = round(100000 * exp(-0.018 * (0:50)^1.35)) ) lt$lx[nrow(lt)] <- 0 life_contract( lt = lt, lives = "single", x = 40, i = 0.05 ) life_contract( lt = lt, lives = "joint", x = 60, y = 58, i = 0.05 )
Creates an annual life table with integer, consecutive ages and returns a
tibble (tidyverse-friendly) with class "lifetable".
lifetable( x, lx = NULL, qx = NULL, px = NULL, mx = NULL, radix = NULL, omega = NULL, close = TRUE, ax = 0.5, type = c("ultimate", "select"), frac = c("UDD", "CF", "Balducci"), check = TRUE, tol = 1e-10 )lifetable( x, lx = NULL, qx = NULL, px = NULL, mx = NULL, radix = NULL, omega = NULL, close = TRUE, ax = 0.5, type = c("ultimate", "select"), frac = c("UDD", "CF", "Balducci"), check = TRUE, tol = 1e-10 )
x |
Numeric vector of ages. Must be integer and consecutive
(annual table), e.g. |
lx |
Optional numeric vector of survivors |
qx |
Optional numeric vector of one-year death probabilities |
px |
Optional numeric vector of one-year survival probabilities |
mx |
Optional numeric vector of central death rates |
radix |
Optional positive scalar. Required if building |
omega |
Optional integer limiting age. If |
close |
Logical. If |
ax |
Scalar in |
type |
Character. |
frac |
Character. |
check |
Logical. If |
tol |
Numeric tolerance for integer checks and consistency checks. |
The table can be built from exactly one of:
lx (survivors), or
qx (one-year death probabilities), or
px (one-year survival probabilities), or
mx (central death rates),
and the function will compute the remaining columns consistently: dx,
qx, px, and mx.
When multiple inputs are provided, priority is:
lx > qx > px > mx.
If lx is provided together with qx, cross-consistency is
validated (both must agree via ).
By default, the table is actuarially closed at omega:
The life table follows the standard actuarial construction described in Finan, Sections 22–24 (Exam MLC preparation).
The basic identities are (Finan, Section 22):
The central death rate mx is computed via the discrete approximation
(Finan, Section 23.9):
which under UDD (ax = 0.5) reduces to the classical formula
(Finan, Section 24.1). This arises
because under UDD, , and therefore
.
At the terminal age with close = TRUE, closure forces
, , and .
The corresponding equals , which is 2
under UDD (ax = 0.5). If ax = 1, .
A tibble with class
c("lifetable","tbl_df","tbl","data.frame") and columns:
x: integer ages
lx: survivors at exact age x
dx: deaths in
qx: probability of death in
px: probability of survival to
mx: central death rate (derived using ax). At the
terminal age with close = TRUE, mx equals
and may be Inf if ax = 1.
Attributes include: radix, omega, type, frac,
closed, ax.
km_lifetable for Kaplan–Meier construction,
t_px and t_qx for survival and death
probabilities (including fractional ages),
e_x for curtate and complete life expectancy,
annuity_x and insurance_x for life
contingency valuations that consume a life table.
# Example 1: build from lx (Finan, Section 22 style) x <- 0:5 lx <- c(100000, 99500, 99000, 98200, 97000, 95000) lt1 <- lifetable(x = x, lx = lx, omega = 5, close = TRUE) lt1 # Example 2: build from qx (radix required) qx <- c(0.005, 0.005, 0.008, 0.012, 0.020, 1) lt2 <- lifetable(x = x, qx = qx, radix = 100000, omega = 5, close = TRUE) lt2 # Example 3: build from px px <- 1 - c(0.005, 0.005, 0.008, 0.012, 0.020, 1) lt3 <- lifetable(x = x, px = px, radix = 100000, omega = 5, close = TRUE) lt3 # Example 4: build from mx mx <- c(0.005, 0.006, 0.008, 0.012, 0.020, 0.030) lt4 <- lifetable(x = x, mx = mx, radix = 100000, omega = 5, close = TRUE, ax = 0.5) lt4 # Example 5: truncate to a smaller omega lt5 <- lifetable(x = 0:10, lx = 100000 * exp(-0.01 * (0:10)), omega = 7, close = TRUE) lt5 # Example 6: Finan Example 22.1 - exponential survival s(x) = exp(-0.005x) lt_exp <- lifetable( x = 0:7, lx = 1000 * exp(-0.005 * (0:7)), close = TRUE ) lt_exp # Example 7: verify survival identity (Finan, Section 22) # 2_p_2 = l_4 / l_2 = 97000 / 99000 lt1$lx[lt1$x == 4] / lt1$lx[lt1$x == 2] # Example 8: without closure - qx at omega is not forced to 1 lt_open <- lifetable(x = 0:3, lx = c(1000, 900, 750, 500), close = FALSE) lt_open$qx # last element is NA # Example 9: access table metadata attr(lt1, "omega") # 5 attr(lt1, "closed") # TRUE attr(lt1, "frac") # "UDD" attr(lt1, "ax") # 0.5# Example 1: build from lx (Finan, Section 22 style) x <- 0:5 lx <- c(100000, 99500, 99000, 98200, 97000, 95000) lt1 <- lifetable(x = x, lx = lx, omega = 5, close = TRUE) lt1 # Example 2: build from qx (radix required) qx <- c(0.005, 0.005, 0.008, 0.012, 0.020, 1) lt2 <- lifetable(x = x, qx = qx, radix = 100000, omega = 5, close = TRUE) lt2 # Example 3: build from px px <- 1 - c(0.005, 0.005, 0.008, 0.012, 0.020, 1) lt3 <- lifetable(x = x, px = px, radix = 100000, omega = 5, close = TRUE) lt3 # Example 4: build from mx mx <- c(0.005, 0.006, 0.008, 0.012, 0.020, 0.030) lt4 <- lifetable(x = x, mx = mx, radix = 100000, omega = 5, close = TRUE, ax = 0.5) lt4 # Example 5: truncate to a smaller omega lt5 <- lifetable(x = 0:10, lx = 100000 * exp(-0.01 * (0:10)), omega = 7, close = TRUE) lt5 # Example 6: Finan Example 22.1 - exponential survival s(x) = exp(-0.005x) lt_exp <- lifetable( x = 0:7, lx = 1000 * exp(-0.005 * (0:7)), close = TRUE ) lt_exp # Example 7: verify survival identity (Finan, Section 22) # 2_p_2 = l_4 / l_2 = 97000 / 99000 lt1$lx[lt1$x == 4] / lt1$lx[lt1$x == 2] # Example 8: without closure - qx at omega is not forced to 1 lt_open <- lifetable(x = 0:3, lx = c(1000, 900, 750, 500), close = FALSE) lt_open$qx # last element is NA # Example 9: access table metadata attr(lt1, "omega") # 5 attr(lt1, "closed") # TRUE attr(lt1, "frac") # "UDD" attr(lt1, "ax") # 0.5
A small pedagogical dataset containing level-payment loan contracts for amortization schedule and outstanding balance examples.
A small pedagogical dataset containing level-payment loan contracts for amortization schedule and outstanding balance examples.
loans_sample loans_sampleloans_sample loans_sample
A tibble with 4 rows and 7 variables:
Loan identifier.
Initial loan principal.
Annual effective interest rate.
Loan term in months.
Number of payments per year.
Short loan type label.
Level payment amount per payment period.
A tibble with 4 rows and 7 variables:
Loan identifier.
Initial loan principal.
Annual effective interest rate.
Loan term in months.
Number of payments per year.
Short loan type label.
Level payment amount per payment period.
This dataset uses compact loan notation: L is the initial loan
principal, i is the annual effective interest rate, n_months
is the loan term in months, k is the payment frequency, and R
is the level payment.
This dataset uses compact loan notation: L is the initial loan
principal, i is the annual effective interest rate, n_months
is the loan term in months, k is the payment frequency, and R
is the level payment.
Synthetic pedagogical data created for tidyactuarial examples.
Synthetic pedagogical data created for tidyactuarial examples.
data(loans_sample) loans_sample |> dplyr::select(loan_id, L, i, n_months, k, R) data(loans_sample) loans_sample |> dplyr::select(loan_id, L, i, n_months, k, R)data(loans_sample) loans_sample |> dplyr::select(loan_id, L, i, n_months, k, R) data(loans_sample) loans_sample |> dplyr::select(loan_id, L, i, n_months, k, R)
Builds a single-decrement lifetable for the total decrement (any cause),
using from a multiple decrement table produced by
md_table. This enables direct re-use of single-life functions
(e.g., t_px, t_qx, t_Ex, annuities, insurances) under the
total decrement model.
lt_tau(md, ...)lt_tau(md, ...)
md |
A multiple decrement table (typically the output of |
... |
Additional arguments passed to |
Given cause-specific decrement probabilities , the total decrement
is . This function simply passes
x = md$x and qx = md$q_total to lifetable.
A lifetable object as produced by lifetable.
qx_df <- tibble::tibble( x = 30:35, q_death = c(0.001, 0.0012, 0.0014, 0.0017, 0.0020, 1.0000), q_disability = c(0.002, 0.0021, 0.0022, 0.0023, 0.0024, 0.0000) ) md <- md_table(qx_df, radix = 1e5, close = TRUE) lt <- lt_tau(md, radix = 1e5, close = TRUE, frac = "UDD") t_px(lt, x = 30, t = 5)qx_df <- tibble::tibble( x = 30:35, q_death = c(0.001, 0.0012, 0.0014, 0.0017, 0.0020, 1.0000), q_disability = c(0.002, 0.0021, 0.0022, 0.0023, 0.0024, 0.0000) ) md <- md_table(qx_df, radix = 1e5, close = TRUE) lt <- lt_tau(md, radix = 1e5, close = TRUE, frac = "UDD") t_px(lt, x = 30, t = 5)
Computes Monte Carlo simulated present values of life annuity payments from simulated future lifetimes, using compact actuarial notation.
mc_annuity( .data = NULL, i, payment = 1, k = 1L, type = c("whole", "temporary", "deferred", "deferred_temporary", "certain", "guaranteed", "whole_life"), n = NULL, h = 0, n_guar = NULL, timing = c("immediate", "due"), i_type = c("effective", "nominal_interest", "nominal_discount", "force", "nominal"), m = 1, col_K = "Kx", col_T = "Tx", col_pv = "pv_annuity", ... )mc_annuity( .data = NULL, i, payment = 1, k = 1L, type = c("whole", "temporary", "deferred", "deferred_temporary", "certain", "guaranteed", "whole_life"), n = NULL, h = 0, n_guar = NULL, timing = c("immediate", "due"), i_type = c("effective", "nominal_interest", "nominal_discount", "force", "nominal"), m = 1, col_K = "Kx", col_T = "Tx", col_pv = "pv_annuity", ... )
.data |
A data frame or tibble containing simulated future lifetimes,
typically returned by |
i |
Numeric scalar. Interest-rate input used for discounting. |
payment |
Numeric scalar. Amount of each annuity payment. Default is
|
k |
Positive integer. Number of annuity payments per year. Default is
|
type |
Character string specifying the annuity type. Canonical options
are |
n |
Numeric scalar. Term of the annuity in years. Required for
|
h |
Numeric scalar. Deferral period in years. Default is |
n_guar |
Numeric scalar. Guaranteed payment period in years. Required
for |
timing |
Character string specifying the annuity payment timing.
Available options are |
i_type |
Character string specifying the interest-rate convention.
Allowed values are |
m |
Positive integer. Number of interest conversion periods per year
for nominal annual rates. Default is |
col_K |
Character string. Name of the column containing simulated
curtate future lifetimes. Default is |
col_T |
Character string. Name of the column containing simulated
complete future lifetimes. Default is |
col_pv |
Character string. Name of the output column containing
simulated present values of annuity payments. Default is
|
... |
Transitional compatibility for older calls using |
This function is designed to be used after simulate_lifetime,
simulate_lifetimes, or mc_multilife_status. It
takes simulated values of the curtate future lifetime , and when
needed the complete future lifetime , and evaluates the present
value random variable associated with classical annuity benefits.
This function follows the compact actuarial notation used throughout
tidyactuarial: i is the interest-rate input, i_type
is the interest-rate convention, m is the nominal conversion
frequency, k is the annuity payment frequency, n is the
annuity term, and h is the deferral period.
The arguments m and k have different meanings:
m is used only for nominal interest-rate conversion.
k controls how frequently annuity payments are made.
The argument payment represents the amount of each annuity payment.
Thus, for a monthly annuity with total annual payment equal to 1, use
payment = 1 / 12 and k = 12.
For annual payments, k = 1, the function works directly with
. For fractional payments, such as monthly, quarterly, or
semiannual payments, the function uses to determine whether the
life is alive at each fractional payment time.
For annual whole-life annuity-immediate, the simulated present value is
where is the amount of each payment.
For annual whole-life annuity-due, the simulated present value is
The function returns simulated present values, not only their expected value.
Therefore the resulting column can be summarized with summary_mc,
plotted with ggplot2, or used to construct premiums, losses, and
reserves.
A tibble with the original simulation columns and additional columns:
Original interest-rate input.
Interest-rate convention.
Interest conversion frequency.
Equivalent annual effective interest rate.
Annual discount factor.
Canonical annuity type.
Amount of each annuity payment.
Annuity payment frequency.
Annuity term, if applicable.
Deferral period.
Guaranteed period, if applicable.
Annuity payment timing.
Number of payments made in the simulated scenario.
First payment time in the simulated scenario.
Last payment time in the simulated scenario.
Simulated present value of annuity payments, or another
name supplied through col_pv.
For transition, the output also includes legacy columns such as
rate, interest_type, effective_rate,
discount_factor, annuity, payments_per_year,
term, deferral_years, and guarantee_years.
Bowers, N. L., Gerber, H. U., Hickman, J. C., Jones, D. A., and Nesbitt, C. J. (1997). Actuarial Mathematics. Second Edition. Society of Actuaries.
simulate_lifetime, simulate_lifetimes,
mc_multilife_status, mc_insurance,
mc_premium, mc_loss, mc_reserve,
summary_mc
Other monte-carlo:
mc_insurance(),
mc_loss(),
mc_premium(),
mc_reserve(),
simulate_lifetime(),
summary_mc()
lt <- tibble::tibble( x = 40:100, qx = seq(0.002, 1, length.out = 61) ) # Annual whole-life annuity-due lt |> simulate_lifetime( x = 40, n_sim = 25, seed = 123 ) |> mc_annuity( i = 0.05, type = "whole", payment = 1, k = 1, timing = "due" ) # Monthly whole-life annuity-due with total annual payment equal to 1 lt |> simulate_lifetime( x = 40, n_sim = 25, frac = "udd", seed = 123 ) |> mc_annuity( i = 0.05, type = "whole", payment = 1 / 12, k = 12, timing = "due" ) # Quarterly temporary life annuity-immediate lt |> simulate_lifetime( x = 40, n_sim = 25, frac = "udd", seed = 123 ) |> mc_annuity( i = 0.05, type = "temporary", n = 20, payment = 1 / 4, k = 4, timing = "immediate" ) # Nominal interest convertible monthly, with quarterly payments lt |> simulate_lifetime( x = 40, n_sim = 25, frac = "udd", seed = 123 ) |> mc_annuity( i = 0.06, i_type = "nominal_interest", m = 12, type = "whole", payment = 1 / 4, k = 4, timing = "due" ) # Multiple-life status workflow lt |> simulate_lifetimes( x = c(60, 58), n_sim = 25, frac = "udd", seed = 123 ) |> mc_multilife_status(status = "joint") |> mc_annuity( i = 0.04, type = "whole", payment = 1, k = 1, timing = "due", col_K = "K_status", col_T = "T_status" )lt <- tibble::tibble( x = 40:100, qx = seq(0.002, 1, length.out = 61) ) # Annual whole-life annuity-due lt |> simulate_lifetime( x = 40, n_sim = 25, seed = 123 ) |> mc_annuity( i = 0.05, type = "whole", payment = 1, k = 1, timing = "due" ) # Monthly whole-life annuity-due with total annual payment equal to 1 lt |> simulate_lifetime( x = 40, n_sim = 25, frac = "udd", seed = 123 ) |> mc_annuity( i = 0.05, type = "whole", payment = 1 / 12, k = 12, timing = "due" ) # Quarterly temporary life annuity-immediate lt |> simulate_lifetime( x = 40, n_sim = 25, frac = "udd", seed = 123 ) |> mc_annuity( i = 0.05, type = "temporary", n = 20, payment = 1 / 4, k = 4, timing = "immediate" ) # Nominal interest convertible monthly, with quarterly payments lt |> simulate_lifetime( x = 40, n_sim = 25, frac = "udd", seed = 123 ) |> mc_annuity( i = 0.06, i_type = "nominal_interest", m = 12, type = "whole", payment = 1 / 4, k = 4, timing = "due" ) # Multiple-life status workflow lt |> simulate_lifetimes( x = c(60, 58), n_sim = 25, frac = "udd", seed = 123 ) |> mc_multilife_status(status = "joint") |> mc_annuity( i = 0.04, type = "whole", payment = 1, k = 1, timing = "due", col_K = "K_status", col_T = "T_status" )
Computes Monte Carlo simulated present values of life insurance benefits from simulated future lifetimes, using compact actuarial notation.
mc_insurance( .data = NULL, i = NULL, benefit = 1, type = c("whole", "term", "deferred", "deferred_term", "pure_endowment", "endowment", "whole_life", "deferred_temporary"), n = NULL, h = 0, timing = c("end_of_year", "moment_of_death"), i_type = c("effective", "nominal_interest", "nominal_discount", "force", "nominal"), m = 1, col_K = "Kx", col_T = "Tx", col_pv = "pv_benefit", ... )mc_insurance( .data = NULL, i = NULL, benefit = 1, type = c("whole", "term", "deferred", "deferred_term", "pure_endowment", "endowment", "whole_life", "deferred_temporary"), n = NULL, h = 0, timing = c("end_of_year", "moment_of_death"), i_type = c("effective", "nominal_interest", "nominal_discount", "force", "nominal"), m = 1, col_K = "Kx", col_T = "Tx", col_pv = "pv_benefit", ... )
.data |
A data frame or tibble containing simulated future lifetimes,
typically returned by |
i |
Numeric scalar. Interest-rate input used for discounting. |
benefit |
Numeric scalar. Benefit amount payable under the insurance.
Default is |
type |
Character string specifying the insurance type. Canonical
options are |
n |
Numeric scalar. Insurance term in years. Required for
|
h |
Numeric scalar. Deferral period in years. Default is |
timing |
Character string specifying when death benefits are paid.
Available options are |
i_type |
Character string specifying the interest-rate convention.
Allowed values are |
m |
Positive integer. Number of interest conversion periods per year
for nominal annual rates. Default is |
col_K |
Character string. Name of the column containing simulated
curtate future lifetimes. Default is |
col_T |
Character string. Name of the column containing simulated
complete future lifetimes. Required when
|
col_pv |
Character string. Name of the output column containing
simulated present values of benefits. Default is |
... |
Transitional compatibility for older calls using |
This function is designed to be used after simulate_lifetime,
simulate_lifetimes, or mc_multilife_status. It
takes simulated values of the curtate future lifetime , and when
needed the complete future lifetime , and evaluates the present
value random variable associated with classical life insurance benefits.
This function follows the compact actuarial notation used throughout
tidyactuarial: i is the interest-rate input, i_type
is the interest-rate convention, m is the nominal conversion
frequency, n is the insurance term, and h is the deferral
period.
The arguments m and col_K have deliberately different roles:
m is used only for nominal interest-rate conversion.
col_K identifies the simulated curtate future lifetime column.
If timing = "end_of_year", death benefits are discounted using
. If timing = "moment_of_death", death benefits are
discounted using .
The following insurance types are supported:
"whole": benefit is paid whenever death occurs.
"term": benefit is paid if death occurs within n
years.
"deferred": benefit is paid if death occurs after the
deferral period h.
"deferred_term": benefit is paid if death occurs after
h and within the following n years.
"pure_endowment": benefit is paid at time n if the
life survives to that time.
"endowment": death benefit is paid if death occurs within
n years; otherwise, a survival benefit is paid at time n.
The function returns simulated present values, not only their expected value.
Therefore the resulting column can be summarized with
summary_mc, plotted with ggplot2, or used to construct
premiums, losses, and reserves.
A tibble with the original simulation columns and additional columns:
Original interest-rate input.
Interest-rate convention.
Interest conversion frequency.
Equivalent annual effective interest rate.
Annual discount factor.
Canonical insurance type.
Benefit amount.
Insurance term, if applicable.
Deferral period.
Timing used for death benefits.
Simulated payment time of the benefit.
Indicator that the benefit is paid.
Simulated present value of the benefit, or another name
supplied through col_pv.
For transition, the output also includes legacy columns such as
rate, interest_type, effective_rate,
discount_factor, insurance, term,
deferral_years, and payment_timing.
Bowers, N. L., Gerber, H. U., Hickman, J. C., Jones, D. A., and Nesbitt, C. J. (1997). Actuarial Mathematics. Second Edition. Society of Actuaries.
simulate_lifetime, simulate_lifetimes,
mc_multilife_status, mc_annuity,
mc_premium, mc_loss, mc_reserve,
summary_mc
Other monte-carlo:
mc_annuity(),
mc_loss(),
mc_premium(),
mc_reserve(),
simulate_lifetime(),
summary_mc()
lt <- tibble::tibble( x = 40:100, qx = seq(0.002, 1, length.out = 61) ) # Whole-life insurance payable at the end of the year of death lt |> simulate_lifetime( x = 40, n_sim = 25, seed = 123 ) |> mc_insurance( i = 0.05, type = "whole", benefit = 1 ) # 20-year term insurance lt |> simulate_lifetime( x = 40, n_sim = 25, seed = 123 ) |> mc_insurance( i = 0.05, type = "term", n = 20, benefit = 100000 ) # 10-year deferred whole-life insurance lt |> simulate_lifetime( x = 40, n_sim = 25, seed = 123 ) |> mc_insurance( i = 0.05, type = "deferred", h = 10, benefit = 1 ) # Endowment insurance payable at the moment of death if death occurs lt |> simulate_lifetime( x = 40, n_sim = 25, frac = "udd", seed = 123 ) |> mc_insurance( i = 0.05, type = "endowment", n = 20, timing = "moment_of_death", benefit = 1 ) # Nominal interest rate convertible monthly lt |> simulate_lifetime( x = 40, n_sim = 25, seed = 123 ) |> mc_insurance( i = 0.06, i_type = "nominal_interest", m = 12, type = "whole", benefit = 1 ) # First-death insurance using a multiple-life status lt |> simulate_lifetimes( x = c(60, 58), n_sim = 25, frac = "udd", seed = 123 ) |> mc_multilife_status(status = "joint") |> mc_insurance( i = 0.04, type = "whole", benefit = 100000, col_K = "K_status", col_T = "T_status" )lt <- tibble::tibble( x = 40:100, qx = seq(0.002, 1, length.out = 61) ) # Whole-life insurance payable at the end of the year of death lt |> simulate_lifetime( x = 40, n_sim = 25, seed = 123 ) |> mc_insurance( i = 0.05, type = "whole", benefit = 1 ) # 20-year term insurance lt |> simulate_lifetime( x = 40, n_sim = 25, seed = 123 ) |> mc_insurance( i = 0.05, type = "term", n = 20, benefit = 100000 ) # 10-year deferred whole-life insurance lt |> simulate_lifetime( x = 40, n_sim = 25, seed = 123 ) |> mc_insurance( i = 0.05, type = "deferred", h = 10, benefit = 1 ) # Endowment insurance payable at the moment of death if death occurs lt |> simulate_lifetime( x = 40, n_sim = 25, frac = "udd", seed = 123 ) |> mc_insurance( i = 0.05, type = "endowment", n = 20, timing = "moment_of_death", benefit = 1 ) # Nominal interest rate convertible monthly lt |> simulate_lifetime( x = 40, n_sim = 25, seed = 123 ) |> mc_insurance( i = 0.06, i_type = "nominal_interest", m = 12, type = "whole", benefit = 1 ) # First-death insurance using a multiple-life status lt |> simulate_lifetimes( x = c(60, 58), n_sim = 25, frac = "udd", seed = 123 ) |> mc_multilife_status(status = "joint") |> mc_insurance( i = 0.04, type = "whole", benefit = 100000, col_K = "K_status", col_T = "T_status" )
Computes simulated actuarial loss random variables from Monte Carlo present values of benefits, premium annuities, and premiums, using compact actuarial notation.
mc_loss( .data = NULL, col_Z = "pv_benefit", col_Y = "pv_annuity", col_P = "P", col_L = "L", P = NULL, ... )mc_loss( .data = NULL, col_Z = "pv_benefit", col_Y = "pv_annuity", col_P = "P", col_L = "L", P = NULL, ... )
.data |
A data frame or tibble containing simulated present values of benefits and premium annuities. |
col_Z |
Character string. Name of the column containing the simulated
present value of benefits. Default is |
col_Y |
Character string. Name of the column containing the simulated
present value of premium annuities. Default is |
col_P |
Character string. Name of the column containing the premium.
Default is |
col_L |
Character string. Name of the output column containing the
simulated loss random variable. Default is |
P |
Optional numeric scalar. If supplied, this value is used as the
premium instead of reading the premium from |
... |
Transitional compatibility for older calls using |
This function constructs the simulated loss random variable
where is the present value random variable of insurance benefits,
is the present value random variable of the premium annuity, and
is the premium per payment.
This function follows the compact actuarial notation used throughout
tidyactuarial: Z denotes the present value random variable of
benefits, Y denotes the present value random variable of the premium
annuity, P denotes the premium per payment, and L denotes the
actuarial loss random variable at issue.
The function does not estimate the premium. It only constructs the simulated
loss random variable. The premium may come from a column previously created
by mc_premium, or it may be supplied directly through the
P argument.
The interpretation of P depends on how the premium annuity present
value was constructed. If pv_annuity was generated with annual
payments, then P corresponds to that annual premium structure. If
pv_annuity was generated using fractional payments in
mc_annuity, such as payment = 1 / 12 and
k = 12, then P is applied to that same fractional payment
pattern.
Thus, mc_loss() can be used without modification for annual premiums,
monthly premiums, quarterly premiums, semiannual premiums, and multiple-life
premium structures, provided that col_Y contains the appropriate
simulated premium annuity present value.
The resulting loss column can be used to estimate quantities such as expected loss, variance, standard deviation, probability of positive loss, loss quantiles, empirical value-at-risk measures, and sensitivities across actuarial assumptions.
A tibble with the original columns and one additional column
containing the simulated loss random variable. The name of this column is
controlled by col_L. For transition, if col_L != "loss" and
the input does not already contain a column named loss, a legacy
column loss is also added with the same value.
Bowers, N. L., Gerber, H. U., Hickman, J. C., Jones, D. A., and Nesbitt, C. J. (1997). Actuarial Mathematics. Second Edition. Society of Actuaries.
simulate_lifetime, simulate_lifetimes,
mc_multilife_status, mc_insurance,
mc_annuity, mc_premium,
mc_reserve, summary_mc
Other monte-carlo:
mc_annuity(),
mc_insurance(),
mc_premium(),
mc_reserve(),
simulate_lifetime(),
summary_mc()
# Example 1: direct use with simulated present values sim_values <- tibble::tibble( sim_id = 1:5, pv_benefit = c(0.80, 0.75, 0.95, 0.60, 0.70), pv_annuity = c(8.0, 7.5, 9.0, 6.0, 7.0), P = 0.10 ) sim_values |> mc_loss() # Example 2: using a premium supplied directly sim_values |> mc_loss(P = 0.12) # Example 3: annual whole life loss lt <- tibble::tibble( x = 40:100, qx = seq(0.002, 1, length.out = 61) ) lt |> simulate_lifetime( x = 40, n_sim = 25, seed = 123 ) |> mc_insurance( i = 0.05, type = "whole", benefit = 1 ) |> mc_annuity( i = 0.05, type = "whole", payment = 1, k = 1, timing = "due" ) |> mc_premium() |> mc_loss() # Example 4: monthly whole life loss lt |> simulate_lifetime( x = 40, n_sim = 25, frac = "udd", seed = 123 ) |> mc_insurance( i = 0.05, type = "whole", benefit = 1 ) |> mc_annuity( i = 0.05, type = "whole", payment = 1 / 12, k = 12, timing = "due" ) |> mc_premium() |> mc_loss() # Example 5: summarising simulated losses lt |> simulate_lifetime( x = 45, n_sim = 25, frac = "udd", seed = 123 ) |> mc_insurance( i = 0.04, type = "term", n = 20, benefit = 100000 ) |> mc_annuity( i = 0.04, type = "temporary", n = 20, payment = 1 / 12, k = 12, timing = "due" ) |> mc_premium() |> mc_loss() |> summary_mc(value_col = "L") # Example 6: joint-life annual loss lt |> simulate_lifetimes( x = c(60, 58), n_sim = 25, seed = 123 ) |> mc_multilife_status(status = "joint") |> mc_insurance( i = 0.04, type = "whole", benefit = 100000, col_K = "K_status", col_T = "T_status" ) |> mc_annuity( i = 0.04, type = "whole", payment = 1, k = 1, timing = "due", col_K = "K_status", col_T = "T_status" ) |> mc_premium() |> mc_loss() # Transitional compatibility with old column arguments sim_values |> mc_loss( benefit_col = "pv_benefit", annuity_col = "pv_annuity", premium_col = "P", loss_col = "loss" )# Example 1: direct use with simulated present values sim_values <- tibble::tibble( sim_id = 1:5, pv_benefit = c(0.80, 0.75, 0.95, 0.60, 0.70), pv_annuity = c(8.0, 7.5, 9.0, 6.0, 7.0), P = 0.10 ) sim_values |> mc_loss() # Example 2: using a premium supplied directly sim_values |> mc_loss(P = 0.12) # Example 3: annual whole life loss lt <- tibble::tibble( x = 40:100, qx = seq(0.002, 1, length.out = 61) ) lt |> simulate_lifetime( x = 40, n_sim = 25, seed = 123 ) |> mc_insurance( i = 0.05, type = "whole", benefit = 1 ) |> mc_annuity( i = 0.05, type = "whole", payment = 1, k = 1, timing = "due" ) |> mc_premium() |> mc_loss() # Example 4: monthly whole life loss lt |> simulate_lifetime( x = 40, n_sim = 25, frac = "udd", seed = 123 ) |> mc_insurance( i = 0.05, type = "whole", benefit = 1 ) |> mc_annuity( i = 0.05, type = "whole", payment = 1 / 12, k = 12, timing = "due" ) |> mc_premium() |> mc_loss() # Example 5: summarising simulated losses lt |> simulate_lifetime( x = 45, n_sim = 25, frac = "udd", seed = 123 ) |> mc_insurance( i = 0.04, type = "term", n = 20, benefit = 100000 ) |> mc_annuity( i = 0.04, type = "temporary", n = 20, payment = 1 / 12, k = 12, timing = "due" ) |> mc_premium() |> mc_loss() |> summary_mc(value_col = "L") # Example 6: joint-life annual loss lt |> simulate_lifetimes( x = c(60, 58), n_sim = 25, seed = 123 ) |> mc_multilife_status(status = "joint") |> mc_insurance( i = 0.04, type = "whole", benefit = 100000, col_K = "K_status", col_T = "T_status" ) |> mc_annuity( i = 0.04, type = "whole", payment = 1, k = 1, timing = "due", col_K = "K_status", col_T = "T_status" ) |> mc_premium() |> mc_loss() # Transitional compatibility with old column arguments sim_values |> mc_loss( benefit_col = "pv_benefit", annuity_col = "pv_annuity", premium_col = "P", loss_col = "loss" )
Combines simulated future lifetimes from multiple lives into a single multiple-life status. For a joint-life status, the status fails at the first death. For a last-survivor status, the status fails at the last death.
mc_multilife_status( data, status = c("joint", "last_survivor"), col_sim = "sim_id", col_life = "life_id", col_K = "Kx", col_T = "Tx" )mc_multilife_status( data, status = c("joint", "last_survivor"), col_sim = "sim_id", col_life = "life_id", col_K = "Kx", col_T = "Tx" )
data |
A data frame or tibble produced by |
status |
Multiple-life status. One of |
col_sim |
Name of the simulation identifier column. |
col_life |
Name of the life identifier column. |
col_K |
Name of the curtate future lifetime column. |
col_T |
Name of the complete future lifetime column. |
A tibble with one row per simulation and the columns K_status
and T_status.
lt <- tibble::tibble( x = 40:100, qx = seq(0.002, 1, length.out = 61) ) lt |> simulate_lifetimes( x = c(60, 58), n_sim = 25, frac = "udd", seed = 123 ) |> mc_multilife_status(status = "joint")lt <- tibble::tibble( x = 40:100, qx = seq(0.002, 1, length.out = 61) ) lt |> simulate_lifetimes( x = c(60, 58), n_sim = 25, frac = "udd", seed = 123 ) |> mc_multilife_status(status = "joint")
Computes simulated prospective reserve losses at one or more policy durations from simulated future lifetimes, using compact actuarial notation.
mc_reserve( .data = NULL, t = 0, i = NULL, P = NULL, col_P = "P", benefit = 1, payment = 1, k = 1L, type = c("whole", "term", "deferred", "deferred_term", "pure_endowment", "endowment", "whole_life", "deferred_temporary"), annuity_type = c("whole", "temporary", "deferred", "deferred_temporary", "certain", "guaranteed", "whole_life"), n = NULL, h = 0, n_guar = NULL, timing = c("end_of_year", "moment_of_death"), premium_timing = c("due", "immediate"), reserve_timing = c("before_payment", "after_payment"), i_type = c("effective", "nominal_interest", "nominal_discount", "force", "nominal"), m = 1, col_K = "Kx", col_T = "Tx", in_force_basis = c("auto", "complete", "curtate"), not_in_force = c("na", "zero"), col_L = "L_t", ... )mc_reserve( .data = NULL, t = 0, i = NULL, P = NULL, col_P = "P", benefit = 1, payment = 1, k = 1L, type = c("whole", "term", "deferred", "deferred_term", "pure_endowment", "endowment", "whole_life", "deferred_temporary"), annuity_type = c("whole", "temporary", "deferred", "deferred_temporary", "certain", "guaranteed", "whole_life"), n = NULL, h = 0, n_guar = NULL, timing = c("end_of_year", "moment_of_death"), premium_timing = c("due", "immediate"), reserve_timing = c("before_payment", "after_payment"), i_type = c("effective", "nominal_interest", "nominal_discount", "force", "nominal"), m = 1, col_K = "Kx", col_T = "Tx", in_force_basis = c("auto", "complete", "curtate"), not_in_force = c("na", "zero"), col_L = "L_t", ... )
.data |
A data frame or tibble containing simulated future lifetimes,
typically returned by |
t |
Numeric vector. Policy duration or durations at which the reserve
is evaluated. Default is |
i |
Numeric scalar. Interest-rate input used for discounting. |
P |
Optional numeric scalar. Premium used in the reserve loss. If
|
col_P |
Character string. Name of the premium column in |
benefit |
Numeric scalar. Benefit amount payable under the insurance.
Default is |
payment |
Numeric scalar. Amount of each premium annuity payment.
Default is |
k |
Positive integer. Number of premium payments per year. Default is
|
type |
Character string specifying the insurance type. Canonical
options are |
annuity_type |
Character string specifying the premium annuity type.
Canonical options are |
n |
Numeric scalar. Contract term in years. Required for insurance
types |
h |
Numeric scalar. Deferral period in years. Default is |
n_guar |
Numeric scalar. Guaranteed payment period in years. Required
when |
timing |
Character string specifying when death benefits are paid.
Available options are |
premium_timing |
Character string specifying the premium payment timing.
Available options are |
reserve_timing |
Character string specifying whether payments due
exactly at the valuation duration are included. Available options are
|
i_type |
Character string specifying the interest-rate convention.
Allowed values are |
m |
Positive integer. Number of interest conversion periods per year
for nominal annual rates. Default is |
col_K |
Character string. Name of the column containing simulated
curtate future lifetimes. Default is |
col_T |
Character string. Name of the column containing simulated
complete future lifetimes. Default is |
in_force_basis |
Character string specifying how the in-force indicator
is evaluated. Available options are |
not_in_force |
Character string specifying what to return for scenarios
that are not in force at the valuation duration. Available options are
|
col_L |
Character string. Name of the output reserve loss column.
Default is |
... |
Transitional compatibility for older calls using |
This function recalculates future benefit and future premium present values
from each valuation duration. It is not a wrapper around
mc_loss, because reserves require valuing only the cash flows
that remain after the valuation time.
For a policy in force at duration , the simulated prospective loss is
where is the present value at duration of future benefits,
is the present value at duration of future premium
payments, and is the premium per payment.
This function follows the compact actuarial notation used throughout
tidyactuarial: t is the valuation duration, i is the
interest-rate input, i_type is the interest-rate convention, m
is the nominal conversion frequency, k is the premium payment
frequency, n is the contract term, h is the deferral period,
P is the premium per payment, and L_t is the simulated
prospective loss at duration t.
The arguments m and k have deliberately different meanings:
m is used only for nominal interest-rate conversion.
k controls how frequently future premium payments are made.
The argument payment represents the amount of each premium annuity
payment used to construct . Thus, for monthly premiums with total
annual premium equal to 1, use payment = 1 / 12 and k = 12.
If k = 1, future premiums are annual. If k > 1, future
premiums are made at fractional times, and a valid complete future lifetime
column supplied through col_T is required for life-contingent premium
annuities.
Durations may be integer or fractional. Fractional reserve durations require
complete future lifetimes. For example, monthly reserve calculations may use
t = seq(0, 20, by = 1 / 12).
If reserve_timing = "before_payment", cash flows occurring exactly at
the valuation duration are included. If
reserve_timing = "after_payment", cash flows occurring exactly at the
valuation duration are excluded.
If not_in_force = "na", scenarios that are not in force at a given
duration receive NA values for future present values and reserve
losses. This is useful for estimating reserves conditional on the policy
still being in force. If not_in_force = "zero", those scenarios
receive zero values, which may be useful for portfolio run-off summaries.
This function computes prospective reserves under the simulated model. It does not include expenses, surrender values, taxes, profit loadings, or statutory reserving adjustments.
A tibble with one row per original simulation and per requested
duration. It contains the original simulation columns and additional columns
including t, in_force, i, i_type, m,
i_effective, v, type, annuity_type,
benefit, payment, k, Z_t, Y_t,
P, and L_t or another name supplied through col_L.
For transition, the output also includes legacy columns such as
duration, rate, interest_type, effective_rate,
discount_factor, insurance, annuity,
payments_per_year, term, deferral_years,
guarantee_years, future_pv_benefit,
future_pv_premiums, premium, and reserve_loss.
Bowers, N. L., Gerber, H. U., Hickman, J. C., Jones, D. A., and Nesbitt, C. J. (1997). Actuarial Mathematics. Second Edition. Society of Actuaries.
simulate_lifetime, simulate_lifetimes,
mc_multilife_status, mc_insurance,
mc_annuity, mc_premium, mc_loss,
summary_mc
Other monte-carlo:
mc_annuity(),
mc_insurance(),
mc_loss(),
mc_premium(),
simulate_lifetime(),
summary_mc()
lt <- tibble::tibble( x = 40:100, qx = seq(0.002, 1, length.out = 61) ) # Annual prospective reserves for whole-life insurance lt |> simulate_lifetime( x = 40, n_sim = 25, seed = 123 ) |> mc_reserve( t = c(0, 5, 10), i = 0.05, type = "whole", annuity_type = "whole", benefit = 1, payment = 1, k = 1, premium_timing = "due" ) # Monthly premium reserve curve at annual valuation durations lt |> simulate_lifetime( x = 40, n_sim = 25, frac = "udd", seed = 123 ) |> mc_reserve( t = c(0, 1, 2, 3), i = 0.05, type = "whole", annuity_type = "whole", benefit = 1, payment = 1 / 12, k = 12, premium_timing = "due" ) # Fractional reserve durations lt |> simulate_lifetime( x = 40, n_sim = 25, frac = "udd", seed = 123 ) |> mc_reserve( t = seq(0, 1, by = 1 / 4), i = 0.05, type = "whole", annuity_type = "whole", benefit = 1, payment = 1 / 12, k = 12, premium_timing = "due" ) |> summary_mc(value_col = "L_t", by = "t") # Joint-life reserve using a multiple-life status lt |> simulate_lifetimes( x = c(60, 58), n_sim = 25, seed = 123 ) |> mc_multilife_status(status = "joint") |> mc_reserve( t = c(0, 5), i = 0.04, type = "whole", annuity_type = "whole", benefit = 1, payment = 1, k = 1, col_K = "K_status", col_T = "T_status" )lt <- tibble::tibble( x = 40:100, qx = seq(0.002, 1, length.out = 61) ) # Annual prospective reserves for whole-life insurance lt |> simulate_lifetime( x = 40, n_sim = 25, seed = 123 ) |> mc_reserve( t = c(0, 5, 10), i = 0.05, type = "whole", annuity_type = "whole", benefit = 1, payment = 1, k = 1, premium_timing = "due" ) # Monthly premium reserve curve at annual valuation durations lt |> simulate_lifetime( x = 40, n_sim = 25, frac = "udd", seed = 123 ) |> mc_reserve( t = c(0, 1, 2, 3), i = 0.05, type = "whole", annuity_type = "whole", benefit = 1, payment = 1 / 12, k = 12, premium_timing = "due" ) # Fractional reserve durations lt |> simulate_lifetime( x = 40, n_sim = 25, frac = "udd", seed = 123 ) |> mc_reserve( t = seq(0, 1, by = 1 / 4), i = 0.05, type = "whole", annuity_type = "whole", benefit = 1, payment = 1 / 12, k = 12, premium_timing = "due" ) |> summary_mc(value_col = "L_t", by = "t") # Joint-life reserve using a multiple-life status lt |> simulate_lifetimes( x = c(60, 58), n_sim = 25, seed = 123 ) |> mc_multilife_status(status = "joint") |> mc_reserve( t = c(0, 5), i = 0.04, type = "whole", annuity_type = "whole", benefit = 1, payment = 1, k = 1, col_K = "K_status", col_T = "T_status" )
Builds a multiple decrement table from cause-specific annual decrement
probabilities . This function is annual/discrete: ages must be
integer-valued and the input probabilities are interpreted as one-year
decrement probabilities for each cause.
md_table( qx_df, age_col = "x", cause_cols = NULL, radix = 1e+05, close = TRUE, check = TRUE, tol = 1e-10 )md_table( qx_df, age_col = "x", cause_cols = NULL, radix = 1e+05, close = TRUE, check = TRUE, tol = 1e-10 )
qx_df |
A data.frame/tibble with an age column (default |
age_col |
Character. Name of the age column (default |
cause_cols |
Character vector. Names of the cause columns. If |
radix |
Numeric. Starting cohort size at the first age (default |
close |
Logical. If |
check |
Logical. If |
tol |
Numeric tolerance used in checks (default |
Let the cause columns be . The total decrement
probability is and the total survival
probability is . The cohort is generated
recursively by with starting radix
.
If close = TRUE, the last age (omega) must satisfy
(within tolerance), so that the table closes
naturally.
A tibble with columns:
x: integer ages.
lx: cohort .
q_total: total decrement probability .
p_total: total survival probability .
d_total: total decrements .
cause columns (as provided).
cause-specific decrements d_* with .
qx_df <- tibble::tibble( x = 30:35, q_death = c(0.001, 0.0012, 0.0014, 0.0017, 0.0020, 1.0000), q_disability = c(0.002, 0.0021, 0.0022, 0.0023, 0.0024, 0.0000) ) md <- md_table(qx_df, radix = 1e5, close = TRUE) mdqx_df <- tibble::tibble( x = 30:35, q_death = c(0.001, 0.0012, 0.0014, 0.0017, 0.0020, 1.0000), q_disability = c(0.002, 0.0021, 0.0022, 0.0023, 0.0024, 0.0000) ) md <- md_table(qx_df, radix = 1e5, close = TRUE) md
A tidy collection of Colombian mortality tables for life-contingency examples. The dataset includes regulatory and pedagogical mortality tables used in Colombian actuarial applications.
mortality_colombia_tablesmortality_colombia_tables
A tibble with 12 variables:
Mortality table identifier.
Sex category, typically "male" or "female".
Integer actuarial age.
Number of survivors at exact age x.
Expected number of deaths between ages x and
x + 1.
One-year death probability between ages x and
x + 1.
One-year survival probability between ages x and
x + 1.
Force of mortality at age x, when available.
Complete life expectancy at age x, when available.
Source identifier or reference.
Death probability recalculated from lx and
dx, when available.
Difference between reported qx and recalculated
qx, when available.
The dataset is intended for actuarial examples involving Colombian mortality tables, survival probabilities, life annuities, life insurance present values, and validation of life-table calculations.
The variable names follow the compact actuarial notation used throughout
tidyactuarial: x denotes age, lx the number of lives,
dx the number of deaths, qx the one-year death probability,
px the one-year survival probability, mu_x the force of
mortality, and ex the life expectancy at age x.
The variables qx_calc and qx_diff are included as validation
aids. They allow users to compare reported death probabilities against
probabilities reconstructed from lx and dx.
Some tables may start at different initial ages, use different terminal ages, or use different radix values. Users should filter the desired table and sex before passing the data to life-contingency functions.
Colombian mortality tables cleaned for tidyactuarial examples. Source
identifiers are provided in the source column.
data(mortality_colombia_tables) head(mortality_colombia_tables) mortality_colombia_tables |> dplyr::count(table_id, sex) rv08_male <- mortality_colombia_tables |> dplyr::filter(table_id == "RV08_Rentistas_2005_2008", sex == "male") |> dplyr::select(x, lx, dx, qx, px, mu_x, ex) head(rv08_male)data(mortality_colombia_tables) head(mortality_colombia_tables) mortality_colombia_tables |> dplyr::count(table_id, sex) rv08_male <- mortality_colombia_tables |> dplyr::filter(table_id == "RV08_Rentistas_2005_2008", sex == "male") |> dplyr::select(x, lx, dx, qx, px, mu_x, ex) head(rv08_male)
Creates a tidy life table with one row per integer age from a parametric mortality law, using compact actuarial notation.
mortality_law_table( law = c("Exponential", "Gompertz", "Makeham", "Weibull", "Logistic", "DeMoivre", "Beta", "HeligmanPollard"), x_min, x_max, ..., params = NULL, frac = c("CF", "UDD", "Balducci", "CML"), l0 = 1e+05, close = TRUE, a_x = 0.5, check = TRUE, tol = 1e-10, radix = NULL, ax = NULL )mortality_law_table( law = c("Exponential", "Gompertz", "Makeham", "Weibull", "Logistic", "DeMoivre", "Beta", "HeligmanPollard"), x_min, x_max, ..., params = NULL, frac = c("CF", "UDD", "Balducci", "CML"), l0 = 1e+05, close = TRUE, a_x = 0.5, check = TRUE, tol = 1e-10, radix = NULL, ax = NULL )
law |
Character. Mortality law. One of |
x_min |
Integer. Minimum age, inclusive. |
x_max |
Integer. Maximum age, inclusive. Must satisfy
|
... |
Named law parameters. These values override |
params |
Named list of law parameters, or |
frac |
Character. Within-year assumption used to convert |
l0 |
Numeric scalar. Initial radix, that is, the starting value
|
close |
Logical. If |
a_x |
Numeric scalar. Average fraction of the year lived by those dying
between age |
check |
Logical. If |
tol |
Numeric tolerance used in checks. |
radix |
Deprecated. Use |
ax |
Deprecated. Use |
The output follows tidyactuarial conventions and includes columns such as
x, qx, px, lx, dx, Lx,
Tx, ex, and mx.
This function follows the compact actuarial notation used throughout
tidyactuarial: x denotes age, l0 denotes the starting
radix, a_x denotes the average fraction of the year lived by those
dying during the age interval, qx denotes the one-year death
probability, and px = 1 - qx.
The parameter F_hp is used for the Heligman-Pollard law instead of
F, because F is historically associated with FALSE in
R and should not be promoted in a CRAN-facing API. The old name F is
still accepted as a transitional alias.
A tibble with columns x, law, frac,
mu_x, qx, px, lx, dx, Lx,
Tx, ex, and mx.
Exponential: .
Gompertz: .
Makeham: .
Weibull: .
Logistic: .
DeMoivre: finite lifetime law with
for .
Beta: scaled lifetime model
.
HeligmanPollard: odds model returning directly.
Parameters for the selected law are supplied either through ... or
through the named list params. Direct parameters supplied through
... override values in params.
Required parameters:
"Exponential": lambda.
"Gompertz": B, c.
"Makeham": A, B, c.
"Weibull": shape, scale. Transitional aliases
k and lambda are accepted.
"Logistic": A, B, c, C.
"DeMoivre": omega.
"Beta": alpha, beta, omega.
"HeligmanPollard": A, B, C,
D, E, F_hp, and G. Transitional alias
F is accepted and mapped to F_hp.
For laws defined by a force of mortality , the one-year death
probability is obtained using frac:
"CF" or "CML": .
"UDD": .
"Balducci": .
"DeMoivre", "Beta", and "HeligmanPollard" define
qx directly. For these laws, frac is not used to derive
qx.
If close = TRUE, the last age is forced to close the table by setting
qx[x_max] = 1 and px[x_max] = 0.
mortality_law_table("Exponential", 0, 110, lambda = 0.01) mortality_law_table("Gompertz", 0, 110, B = 1e-5, c = 1.08) mortality_law_table("Makeham", 0, 110, A = 5e-4, B = 1e-6, c = 1.10) mortality_law_table("Weibull", 1, 110, shape = 2.5, scale = 90) mortality_law_table( "Logistic", 0, 110, A = 1e-4, B = 1e-6, c = 1.10, C = 1e-3 ) mortality_law_table("DeMoivre", 0, 100, omega = 100) mortality_law_table("Beta", 0, 100, alpha = 2, beta = 5, omega = 101) mortality_law_table( "HeligmanPollard", 1, 110, A = 0.0002, B = 0.1, C = 0.03, D = 10, E = 20, F_hp = 0.00005, G = 1.08 ) # Transitional compatibility with older names mortality_law_table("Weibull", 1, 110, k = 2.5, lambda = 90) mortality_law_table( "HeligmanPollard", 1, 110, A = 0.0002, B = 0.1, C = 0.03, D = 10, E = 20, F = 0.00005, G = 1.08 )mortality_law_table("Exponential", 0, 110, lambda = 0.01) mortality_law_table("Gompertz", 0, 110, B = 1e-5, c = 1.08) mortality_law_table("Makeham", 0, 110, A = 5e-4, B = 1e-6, c = 1.10) mortality_law_table("Weibull", 1, 110, shape = 2.5, scale = 90) mortality_law_table( "Logistic", 0, 110, A = 1e-4, B = 1e-6, c = 1.10, C = 1e-3 ) mortality_law_table("DeMoivre", 0, 100, omega = 100) mortality_law_table("Beta", 0, 100, alpha = 2, beta = 5, omega = 101) mortality_law_table( "HeligmanPollard", 1, 110, A = 0.0002, B = 0.1, C = 0.03, D = 10, E = 20, F_hp = 0.00005, G = 1.08 ) # Transitional compatibility with older names mortality_law_table("Weibull", 1, 110, k = 2.5, lambda = 90) mortality_law_table( "HeligmanPollard", 1, 110, A = 0.0002, B = 0.1, C = 0.03, D = 10, E = 20, F = 0.00005, G = 1.08 )
A compact international panel of period life tables for selected countries from 2015 to 2023. The dataset is intended for comparative mortality examples, especially before, during, and after the COVID-19 pandemic period.
mortality_world_sample_2015_2023mortality_world_sample_2015_2023
A tibble with 35,451 rows and 14 variables:
Country name.
Numeric ISO country code.
Continent.
Geographic region.
Calendar year, from 2015 to 2023.
Period label: "pre_pandemic",
"pre_pandemic_reference", "pandemic", "transition",
or "post_pandemic".
Sex category: "male", "female", or "both".
Integer actuarial age, from 0 to 100.
Central death rate at age x.
One-year death probability between ages x and x + 1.
One-year survival probability between ages x and x + 1.
Number of survivors at exact age x, based on l0 = 100000.
Expected number of deaths between ages x and x + 1.
Data source.
The dataset is derived from central death rates mx. Death probabilities
qx were computed using the annual approximation
with . The last available age is closed by setting
qx = 1. Survivors lx and expected deaths dx are then
reconstructed recursively from l0 = 100000.
This dataset is a selected-country panel, not a complete world mortality database.
United Nations, World Population Prospects 2024.
data(mortality_world_sample_2015_2023) mortality_world_sample_2015_2023 |> dplyr::filter(country == "Colombia", sex == "both", x == 70) |> dplyr::select(year, pandemic_period, qx, lx)data(mortality_world_sample_2015_2023) mortality_world_sample_2015_2023 |> dplyr::filter(country == "Colombia", sex == "both", x == 70) |> dplyr::select(year, pandemic_period, qx, lx)
A compact international sample of period life tables for selected countries in 2023. The dataset is intended for recent and simple examples involving central death rates, one-year death probabilities, survival probabilities, and life-table calculations.
mortality_world_sample_2023mortality_world_sample_2023
A tibble with 3,939 rows and 13 variables:
Country name.
Numeric ISO country code.
Continent.
Geographic region.
Calendar year.
Sex category: "male", "female", or "both".
Integer actuarial age, from 0 to 100.
Central death rate at age x.
One-year death probability between ages x and x + 1.
One-year survival probability between ages x and x + 1.
Number of survivors at exact age x, based on l0 = 100000.
Expected number of deaths between ages x and x + 1.
Data source.
The dataset is derived from central death rates mx. Death probabilities
qx were computed using the annual approximation
with . The last available age is closed by setting
qx = 1. Survivors lx and expected deaths dx are then
reconstructed recursively from l0 = 100000.
This dataset is a selected-country sample, not a complete world mortality database.
United Nations, World Population Prospects 2024.
data(mortality_world_sample_2023) mortality_world_sample_2023 |> dplyr::filter(country == "Colombia", sex == "both") |> dplyr::select(x, mx, qx, px, lx, dx)data(mortality_world_sample_2023) mortality_world_sample_2023 |> dplyr::filter(country == "Colombia", sex == "both") |> dplyr::select(x, mx, qx, px, lx, dx)
A small pedagogical annual multiple decrement dataset with three causes: death, disability, and withdrawal. It is intended for examples involving multiple decrement tables, total-decrement life tables, cause-specific decrement probabilities, and cause-specific insurance benefits.
A small pedagogical annual multiple decrement dataset with three causes: death, disability, and withdrawal. It is intended for examples involving multiple decrement tables, total-decrement life tables, cause-specific decrement probabilities, and cause-specific insurance benefits.
multiple_decrement_sample multiple_decrement_samplemultiple_decrement_sample multiple_decrement_sample
A tibble with 7 rows and 6 variables:
Integer actuarial age.
One-year death decrement probability.
One-year disability decrement probability.
One-year withdrawal decrement probability.
Total one-year decrement probability.
Total one-year survival probability.
A tibble with 7 rows and 6 variables:
Integer actuarial age.
One-year death decrement probability.
One-year disability decrement probability.
One-year withdrawal decrement probability.
Total one-year decrement probability.
Total one-year survival probability.
This dataset already follows the compact actuarial convention x for
age and q for decrement probabilities.
This dataset already follows the compact actuarial convention x for
age and q for decrement probabilities.
Synthetic pedagogical data created for tidyactuarial examples.
Synthetic pedagogical data created for tidyactuarial examples.
data(multiple_decrement_sample) multiple_decrement_sample |> dplyr::select(x, q_death, q_disability, q_withdrawal, q_total, p_total) data(multiple_decrement_sample) multiple_decrement_sample |> dplyr::select(x, q_death, q_disability, q_withdrawal, q_total, p_total)data(multiple_decrement_sample) multiple_decrement_sample |> dplyr::select(x, q_death, q_disability, q_withdrawal, q_total, p_total) data(multiple_decrement_sample) multiple_decrement_sample |> dplyr::select(x, q_death, q_disability, q_withdrawal, q_total, p_total)
Creates a professional cash-flow diagram with arrows representing inflows and outflows over time, using compact actuarial notation.
plot_cash_flow( .data = NULL, C, t = NULL, date = NULL, i = NULL, i_type = "effective", m = 1L, PV = NULL, payment = NULL, time = NULL, rate = NULL, pv = NULL, title = NULL, subtitle = NULL, x_label = NULL, amount_label = "Cash flow", financial = TRUE, normalize = FALSE, aggregate = TRUE, show_labels = TRUE, label_size = 3.5, arrow_size = 0.8, timeline_size = 0.7, label_digits = 2L, currency = "", col_inflow = "#1B9E77", col_outflow = "#D95F02", date_labels = "%Y-%m-%d", day_count = c("act/365", "act/360"), ... )plot_cash_flow( .data = NULL, C, t = NULL, date = NULL, i = NULL, i_type = "effective", m = 1L, PV = NULL, payment = NULL, time = NULL, rate = NULL, pv = NULL, title = NULL, subtitle = NULL, x_label = NULL, amount_label = "Cash flow", financial = TRUE, normalize = FALSE, aggregate = TRUE, show_labels = TRUE, label_size = 3.5, arrow_size = 0.8, timeline_size = 0.7, label_digits = 2L, currency = "", col_inflow = "#1B9E77", col_outflow = "#D95F02", date_labels = "%Y-%m-%d", day_count = c("act/365", "act/360"), ... )
.data |
Optional data.frame or tibble containing cash-flow columns. |
C |
Numeric vector of cash flows, or a column name when |
t |
Optional numeric vector of times in years, or a column name when |
date |
Optional date vector, or a column name when |
i |
Optional annual interest-rate input used to compute present value if |
i_type |
Character string indicating the interest-rate type. |
m |
Positive integer. Conversion frequency for nominal rates. |
PV |
Optional numeric present value to display. |
payment |
Deprecated. Use |
time |
Deprecated. Use |
rate |
Deprecated. Use |
pv |
Deprecated. Use |
title |
Optional plot title. |
subtitle |
Optional plot subtitle. |
x_label |
Optional x-axis label. |
amount_label |
Optional y-axis label when |
financial |
Logical. If |
normalize |
Logical. If |
aggregate |
Logical. If |
show_labels |
Logical. If |
label_size |
Numeric text size for labels. |
arrow_size |
Numeric line width for arrows. |
timeline_size |
Numeric line width for the time axis. |
label_digits |
Integer number of decimal digits for cash-flow labels. |
currency |
Optional currency or unit prefix, such as |
col_inflow |
Character color for inflow arrows. |
col_outflow |
Character color for outflow arrows. |
date_labels |
Character date-label format passed to |
day_count |
Day-count convention used when |
... |
Reserved for future extensions. |
This function uses compact actuarial notation: C denotes cash-flow amounts,
t denotes times in years, i denotes the interest-rate input, and PV
denotes present value.
A ggplot2 object.
pv_flow, fv_flow, irr_flow, standardize_interest
Other time-value:
future_value(),
fv_flow(),
irr_flow(),
irr_flow_multi(),
present_value(),
pv_flow()
plot_cash_flow( C = c(-1000, 300, 400, 500), t = c(0, 1, 2, 3), i = 0.08, currency = "$" ) cashflows <- tibble::tibble( t = c(0, 1, 2, 3), C = c(-1000, 300, 400, 500) ) cashflows |> plot_cash_flow(C = C, t = t, i = 0.08) dated_flows <- tibble::tibble( date = as.Date(c("2026-01-01", "2026-07-01", "2027-01-01")), C = c(-1000, 450, 700) ) dated_flows |> plot_cash_flow(C = C, date = date, i = 0.08) plot_cash_flow( payment = c(-1000, 300, 400, 500), time = c(0, 1, 2, 3), rate = 0.08, currency = "$" )plot_cash_flow( C = c(-1000, 300, 400, 500), t = c(0, 1, 2, 3), i = 0.08, currency = "$" ) cashflows <- tibble::tibble( t = c(0, 1, 2, 3), C = c(-1000, 300, 400, 500) ) cashflows |> plot_cash_flow(C = C, t = t, i = 0.08) dated_flows <- tibble::tibble( date = as.Date(c("2026-01-01", "2026-07-01", "2027-01-01")), C = c(-1000, 450, 700) ) dated_flows |> plot_cash_flow(C = C, date = date, i = 0.08) plot_cash_flow( payment = c(-1000, 300, 400, 500), time = c(0, 1, 2, 3), rate = 0.08, currency = "$" )
Computes and plots the difference between the present value of liabilities and the present value of an immunized asset portfolio under small interest rate changes. This allows visual evaluation of duration or duration-convexity immunization quality.
plot_immunization_gap( L, t, asset_cashflows, w, i, i_type = "effective", m = 1L, delta = 0.01, n_grid = 200L )plot_immunization_gap( L, t, asset_cashflows, w, i, i_type = "effective", m = 1L, delta = 0.01, n_grid = 200L )
L |
Numeric vector of liability payments. |
t |
Numeric vector of times of each liability payment. |
asset_cashflows |
A list where each element is a list with components
|
w |
Numeric vector of portfolio weights or units. Must have the same
length as |
i |
Base interest-rate input. |
i_type |
Character string indicating the interest-rate type. Allowed
values are |
m |
Positive integer. Conversion frequency for nominal rates. Ignored
for |
delta |
A numeric value defining the range of annual effective rates:
from |
n_grid |
Number of rate values to evaluate. |
This function follows the compact actuarial notation used throughout
tidyactuarial: L denotes liabilities, t denotes payment
times, w denotes asset weights, cf denotes cash flows,
i denotes the interest-rate input, i_type denotes the
interest-rate type, and m denotes the conversion frequency for
nominal rates.
Let . For a liability stream
at time :
For a portfolio of assets with weights :
The curve
illustrates immunization robustness. Under perfect duration immunization,
this curve is tangent to zero at the base rate and non-negative nearby if
the convexity condition is also met.
A ggplot2 object showing the PV difference curve
and a zero reference line.
immunize_duration,
immunize_duration_convexity,
bond_duration, bond_convexity
Other immunization:
immunize_duration(),
immunize_duration_convexity()
# Two-asset duration immunization gap plot_immunization_gap( L = c(5000, 8000), t = c(3, 7), asset_cashflows = list( list(cf = c(0, 0, 100), t = c(1, 2, 3)), list(cf = c(0, 0, 0, 0, 0, 0, 200), t = 1:7) ), w = c(5, 2.5), i = 0.05, delta = 0.02 )# Two-asset duration immunization gap plot_immunization_gap( L = c(5000, 8000), t = c(3, 7), asset_cashflows = list( list(cf = c(0, 0, 100), t = c(1, 2, 3)), list(cf = c(0, 0, 0, 0, 0, 0, 200), t = 1:7) ), w = c(5, 2.5), i = 0.05, delta = 0.02 )
Creates a step-function plot of the Kaplan–Meier survival estimate
with optional pointwise confidence bands. Designed to
work directly with the output of km_lifetable.
plot_km( km, time_col = "time", surv_col = "S", lower_col = "ci_low", upper_col = "ci_high", conf_int = TRUE, title = NULL )plot_km( km, time_col = "time", surv_col = "S", lower_col = "ci_low", upper_col = "ci_high", conf_int = TRUE, title = NULL )
km |
A data frame or tibble with at least columns for time and
survival. Can also be the full list returned by |
time_col |
Character. Name of the time column. Default |
surv_col |
Character. Name of the survival column. Default |
lower_col |
Character. Name of the lower CI column. Default
|
upper_col |
Character. Name of the upper CI column. Default
|
conf_int |
Logical. If |
title |
Optional character string for the plot title. |
Both the survival curve and the confidence band are rendered as step
functions (using geom_step), which is the correct
representation for the KM estimator - a right-continuous step function
that drops at each observed event time.
The confidence band uses geom_stepribbon logic: the data is
internally expanded so that a ribbon-fill follows the step pattern rather
than interpolating linearly between event times.
A ggplot object that can be further customised with
additional ggplot2 layers.
km_lifetable for fitting the KM estimator and
building the empirical life table.
set.seed(42) n <- 150 time <- rexp(n, rate = 0.05) status <- rbinom(n, 1, prob = 0.7) # Fit KM and plot directly out <- km_lifetable(time, status, breaks = 0:30) # Pass the full list - $km is extracted automatically plot_km(out) # Or pass just the km tibble plot_km(out$km) # Without confidence band plot_km(out, conf_int = FALSE, title = "KM Survival Curve") # Customise with ggplot2 layers if (requireNamespace("ggplot2", quietly = TRUE)) { plot_km(out) + ggplot2::geom_hline(yintercept = 0.5, linetype = "dashed") + ggplot2::labs(subtitle = "Dashed line = median survival") }set.seed(42) n <- 150 time <- rexp(n, rate = 0.05) status <- rbinom(n, 1, prob = 0.7) # Fit KM and plot directly out <- km_lifetable(time, status, breaks = 0:30) # Pass the full list - $km is extracted automatically plot_km(out) # Or pass just the km tibble plot_km(out$km) # Without confidence band plot_km(out, conf_int = FALSE, title = "KM Survival Curve") # Customise with ggplot2 layers if (requireNamespace("ggplot2", quietly = TRUE)) { plot_km(out) + ggplot2::geom_hline(yintercept = 0.5, linetype = "dashed") + ggplot2::labs(subtitle = "Dashed line = median survival") }
Computes portfolio convexity from individual position convexities using present values or market values as weights, using compact actuarial notation.
portfolio_convexity( .data = NULL, portfolio_id = NULL, P = NULL, C = NULL, col_portfolio = "portfolio_id", col_P = "P", col_C = "C", .out = "C_P", .out_value = "P_total", .out_n = "n_positions", .na = c("propagate", "error", "drop"), ... )portfolio_convexity( .data = NULL, portfolio_id = NULL, P = NULL, C = NULL, col_portfolio = "portfolio_id", col_P = "P", col_C = "C", .out = "C_P", .out_value = "P_total", .out_n = "n_positions", .na = c("propagate", "error", "drop"), ... )
.data |
A data.frame or tibble. If |
portfolio_id |
Optional vector of portfolio identifiers when
|
P |
Numeric vector of present values, prices, or market values when
|
C |
Numeric vector of individual convexities when |
col_portfolio |
Name of the portfolio identifier column. If |
col_P |
Name of the numeric column containing present values, prices, or market values. |
col_C |
Name of the numeric column containing individual convexities. |
.out |
Name of the output column containing portfolio convexity. |
.out_value |
Name of the output column containing total portfolio value. |
.out_n |
Name of the output column containing the number of positions used in the calculation. |
.na |
NA handling policy: |
... |
Transitional compatibility for older calls using
|
This is a summarise-style tibble-first function. Each input row represents one position, and each output row represents one portfolio.
The function does not compute individual convexities from bond terms or yields. Instead, it assumes that the input convexity column already contains valid convexity measures on a common basis within each portfolio.
The portfolio convexity is computed as:
where is the present value or market value of position ,
and is its convexity.
This function follows the compact actuarial notation used throughout
tidyactuarial: P denotes price, present value, or market value,
and C denotes convexity.
The function is deliberately agnostic about the convexity convention, but all individual convexities must be expressed on the same basis within each portfolio. For example, do not mix convexities measured in coupon periods with convexities measured in years.
A tibble with one row per portfolio and columns for portfolio convexity, total portfolio value, and number of positions used.
Marcel B. Finan, A Basic Course in the Theory of Interest and Derivatives Markets: A Preparation for the Actuarial Exam FM/2, Section 55: Redington Immunization and Convexity.
Kellison, S. G. The Theory of Interest, Chapter 11: Duration, Convexity and Immunization.
portfolio_duration,
bond_convexity, bond_duration
Other bonds:
bond_book_value(),
bond_callable_price(),
bond_convexity(),
bond_duration(),
bond_price(),
bond_ytm(),
portfolio_duration()
# Simple example: one portfolio portfolio_convexity( P = c(1000, 2000, 500), C = c(20, 12, 35) ) # Medium example: two portfolios positions <- tibble::tibble( portfolio_id = c("A", "A", "B", "B"), P = c(1000, 2000, 1000 / 1.08^2, 1000 / 1.08^4), C = c(20, 12, 6, 18) ) portfolio_convexity( positions, col_portfolio = "portfolio_id", col_P = "P", col_C = "C" )# Simple example: one portfolio portfolio_convexity( P = c(1000, 2000, 500), C = c(20, 12, 35) ) # Medium example: two portfolios positions <- tibble::tibble( portfolio_id = c("A", "A", "B", "B"), P = c(1000, 2000, 1000 / 1.08^2, 1000 / 1.08^4), C = c(20, 12, 6, 18) ) portfolio_convexity( positions, col_portfolio = "portfolio_id", col_P = "P", col_C = "C" )
Computes portfolio duration from individual position durations using present values, prices, or market values as weights, using compact actuarial notation.
portfolio_duration( .data = NULL, portfolio_id = NULL, P = NULL, D = NULL, col_portfolio = "portfolio_id", col_P = "P", col_D = "D", .out = "D_P", .out_value = "P_total", .out_n = "n_positions", .na = c("propagate", "error", "drop"), ... )portfolio_duration( .data = NULL, portfolio_id = NULL, P = NULL, D = NULL, col_portfolio = "portfolio_id", col_P = "P", col_D = "D", .out = "D_P", .out_value = "P_total", .out_n = "n_positions", .na = c("propagate", "error", "drop"), ... )
.data |
A data.frame or tibble. If |
portfolio_id |
Optional vector of portfolio identifiers when
|
P |
Numeric vector of present values, prices, or market values when
|
D |
Numeric vector of individual durations when |
col_portfolio |
Name of the portfolio identifier column. If |
col_P |
Name of the numeric column containing present values, prices, or market values. |
col_D |
Name of the numeric column containing individual durations. |
.out |
Name of the output column containing portfolio duration. |
.out_value |
Name of the output column containing total portfolio value. |
.out_n |
Name of the output column containing the number of positions used in the calculation. |
.na |
NA handling policy: |
... |
Transitional compatibility for older calls using
|
This is a summarise-style tibble-first function. Each input row represents one position, and each output row represents one portfolio.
The function does not compute individual durations from bond terms or yields. Instead, it assumes that the input duration column already contains valid duration measures on a common basis within each portfolio.
The portfolio duration is computed as:
where is the present value, price, or market value of position
, and is its duration.
This function follows the compact actuarial notation used throughout
tidyactuarial: P denotes price, present value, or market value,
and D denotes duration.
The function is deliberately agnostic about the duration convention, but all individual durations must be expressed on the same basis within each portfolio. For example, do not mix Macaulay durations in years with durations measured in coupon periods.
A tibble with one row per portfolio and columns for portfolio duration, total portfolio value, and number of positions used.
Marcel B. Finan, A Basic Course in the Theory of Interest and Derivatives Markets: A Preparation for the Actuarial Exam FM/2, Section 54: Macaulay and Modified Durations.
Kellison, S. G. The Theory of Interest, Chapter 11: Duration, Convexity and Immunization.
portfolio_convexity,
bond_duration, bond_convexity
Other bonds:
bond_book_value(),
bond_callable_price(),
bond_convexity(),
bond_duration(),
bond_price(),
bond_ytm(),
portfolio_convexity()
# Simple example: one portfolio portfolio_duration( P = c(1000, 2000, 500), D = c(7, 5, 10) ) # Medium example: two portfolios positions <- tibble::tibble( portfolio_id = c("A", "A", "B", "B"), P = c(1000, 2000, 1000 / 1.08^2, 1000 / 1.08^4), D = c(7, 5, 2, 4) ) portfolio_duration( positions, col_portfolio = "portfolio_id", col_P = "P", col_D = "D" )# Simple example: one portfolio portfolio_duration( P = c(1000, 2000, 500), D = c(7, 5, 10) ) # Medium example: two portfolios positions <- tibble::tibble( portfolio_id = c("A", "A", "B", "B"), P = c(1000, 2000, 1000 / 1.08^2, 1000 / 1.08^4), D = c(7, 5, 2, 4) ) portfolio_duration( positions, col_portfolio = "portfolio_id", col_P = "P", col_D = "D" )
Computes the present value of a future payment due at a given time, using the annual effective interest rate implied by the supplied interest-rate specification and compact actuarial notation.
present_value(C, i, i_type = "effective", m = 1, t, tidy = FALSE)present_value(C, i, i_type = "effective", m = 1, t, tidy = FALSE)
C |
Numeric vector of future payment amounts or capitals. |
i |
Numeric vector of interest-rate values. |
i_type |
Character vector indicating the interest-rate type.
Allowed values are |
m |
Positive integer vector giving the conversion frequency for nominal
rates. Ignored for |
t |
Numeric vector of times in years until payment. |
tidy |
Logical scalar. If |
The present value is computed as
where is the annual effective interest rate and
is the annual discount factor.
The input interest rate may be supplied as:
annual effective interest rate,
nominal annual interest rate,
nominal annual discount rate,
force of interest.
Internally, all rate specifications are first converted to the equivalent
annual effective interest rate using standardize_interest.
This function follows the compact actuarial notation used throughout
tidyactuarial: C denotes the future payment amount or capital,
t denotes time, i denotes the interest-rate input,
i_type denotes the interest-rate type, and m denotes the
conversion frequency for nominal rates.
Input vectors must have length 1 or a common length. Missing values are
propagated. This function does not accept dates; use pv_flow
for dated cash flows.
If tidy = FALSE, a numeric vector of present values.
If tidy = TRUE, a tibble with input values, equivalent rates,
discount factors, and present values.
standardize_interest, future_value,
pv_flow
Other time-value:
future_value(),
fv_flow(),
irr_flow(),
irr_flow_multi(),
plot_cash_flow(),
pv_flow()
# Numeric present value present_value(C = 1000, i = 0.08, t = 3) # Nominal interest converted monthly present_value( C = 1000, i = 0.12, i_type = "nominal_interest", m = 12, t = 5 ) # Tibble output for teaching or auditing present_value( C = 1000, i = 0.08, t = 3, tidy = TRUE ) # Vectorized example present_value( C = c(1000, 2500, 4000), i = c(0.08, 0.10, 0.12), i_type = c("effective", "nominal_interest", "force"), m = c(1, 12, 1), t = c(3, 5, 2) )# Numeric present value present_value(C = 1000, i = 0.08, t = 3) # Nominal interest converted monthly present_value( C = 1000, i = 0.12, i_type = "nominal_interest", m = 12, t = 5 ) # Tibble output for teaching or auditing present_value( C = 1000, i = 0.08, t = 3, tidy = TRUE ) # Vectorized example present_value( C = c(1000, 2500, 4000), i = c(0.08, 0.10, 0.12), i_type = c("effective", "nominal_interest", "force"), m = c(1, 12, 1), t = c(3, 5, 2) )
Computes the present value of a cash-flow vector under either:
a constant interest-rate specification, or
a term structure of spot rates, one rate per cash flow.
pv_flow( cf, i, i_type = "effective", m = 1L, t = NULL, date = NULL, day_count = c("act/365", "act/360") )pv_flow( cf, i, i_type = "effective", m = 1L, t = NULL, date = NULL, day_count = c("act/365", "act/360") )
cf |
Numeric vector of cash flows. |
i |
Numeric scalar or numeric vector of interest-rate values. |
i_type |
Character vector indicating the interest-rate type:
|
m |
Positive integer vector giving the conversion frequency for nominal
rates. May have length 1 or the same length as |
t |
Optional numeric vector of cash-flow times in years. |
date |
Optional vector of cash-flow dates. If supplied, the earliest date is treated as time 0. |
day_count |
Day-count convention used to convert dates to year fractions.
One of |
The cash flow is supplied explicitly through cf. Its timing is
supplied either through t (in years) or date (calendar dates).
If date is supplied, the earliest date is taken as time 0.
Interest-rate input:
If i has length 1, the same rate is used for all cash flows.
If i has the same length as cf, each rate is
interpreted as the spot rate associated with the corresponding
cash-flow time.
Rate types may be supplied in FM-style notation:
annual effective rate ,
nominal annual interest rate ,
nominal annual discount rate ,
force of interest .
Internally, all supplied rates are converted to annual effective rates using
standardize_interest.
This function follows the compact actuarial notation used throughout
tidyactuarial: cf denotes cash flows, t denotes time,
i denotes the interest rate, i_type denotes the interest-rate
type, and m denotes the conversion frequency for nominal rates.
When i is a vector of spot rates, the discounting formula is
where is the annual effective spot rate corresponding to
cash flow . When a single constant rate is supplied,
for all .
Numeric scalar: the present value of the cash flow.
fv_flow, present_value,
irr_flow, standardize_interest
Other time-value:
future_value(),
fv_flow(),
irr_flow(),
irr_flow_multi(),
plot_cash_flow(),
present_value()
# Constant annual effective rate pv_flow( cf = c(100, 150, 200), i = 0.08, i_type = "effective", t = c(0, 1, 2) ) # Spot rates, one per cash flow pv_flow( cf = c(100, 150, 200), i = c(0.05, 0.055, 0.06), i_type = "effective", t = c(1, 2, 3) ) # Using dates; earliest date is taken as t = 0 pv_flow( cf = c(100, 150, 200), i = c(0.05, 0.055, 0.06), i_type = "effective", date = as.Date(c("2026-01-10", "2027-01-10", "2028-01-10")) ) # Nominal rates by cash flow pv_flow( cf = c(100, 100, 100), i = c(0.12, 0.12, 0.12), i_type = "nominal_interest", m = c(12, 12, 12), t = c(1, 2, 3) )# Constant annual effective rate pv_flow( cf = c(100, 150, 200), i = 0.08, i_type = "effective", t = c(0, 1, 2) ) # Spot rates, one per cash flow pv_flow( cf = c(100, 150, 200), i = c(0.05, 0.055, 0.06), i_type = "effective", t = c(1, 2, 3) ) # Using dates; earliest date is taken as t = 0 pv_flow( cf = c(100, 150, 200), i = c(0.05, 0.055, 0.06), i_type = "effective", date = as.Date(c("2026-01-10", "2027-01-10", "2028-01-10")) ) # Nominal rates by cash flow pv_flow( cf = c(100, 100, 100), i = c(0.12, 0.12, 0.12), i_type = "nominal_interest", m = c(12, 12, 12), t = c(1, 2, 3) )
Computes terminal benefit reserves at selected policy durations for a fully discrete single-life insurance contract, using compact actuarial notation.
reserve_x( lt, x, i, i_type = "effective", m = 1L, type = c("whole", "term", "endowment"), n = Inf, benefit = 1, P = NULL, n_prem = NULL, t = NULL, method = c("prospective", "recursive"), tidy = TRUE, ... )reserve_x( lt, x, i, i_type = "effective", m = 1L, type = c("whole", "term", "endowment"), n = Inf, benefit = 1, P = NULL, n_prem = NULL, t = NULL, method = c("prospective", "recursive"), tidy = TRUE, ... )
lt |
A life table data frame with columns |
x |
Integer actuarial age at issue. |
i |
Annual interest-rate input. |
i_type |
Character string indicating the interest-rate type. Allowed
values are |
m |
Positive integer. Conversion frequency for nominal rates. Ignored
for |
type |
Character string. One of |
n |
Insurance term in years. Use |
benefit |
Numeric scalar. Insurance benefit amount. |
P |
Optional numeric scalar. Premium per annual payment. If |
n_prem |
Optional premium-paying term in years. If |
t |
Optional integer vector of policy durations at which to compute
reserves. If |
method |
Character string. Either |
tidy |
Logical scalar. If |
... |
Transitional compatibility for older calls using
|
The function supports whole-life, term, and endowment insurance. Reserves may
be computed prospectively or recursively. Premiums are assumed payable
annually in advance. Limited-payment policies are supported through
n_prem.
This function follows the compact actuarial notation used throughout
tidyactuarial: lt is the life table, x is the age at
issue, i is the interest-rate input, i_type is the
interest-rate type, m is the conversion frequency for nominal rates,
n is the contract term, P is the annual premium, and t
is the policy duration.
The prospective reserve is computed as
The recursive method uses the annual fully discrete recursion
When P = NULL, the net premium is computed directly from the life
table by applying the equivalence principle at issue.
If tidy = TRUE, a tibble with one row per selected duration.
If tidy = FALSE, a named numeric vector of reserves.
premium_x, insurance_x,
annuity_x, t_px
Other life-contingencies:
annuity_multi(),
annuity_x(),
annuity_xy(),
insurance_variable_k(),
insurance_x(),
insurance_xy(),
life_contract(),
premium_gross(),
premium_x(),
premium_xy(),
reserve_xy(),
simulate_annuity_x(),
simulate_insurance_x()
lt <- data.frame( x = 60:70, lx = c(100000, 99000, 97500, 95500, 93000, 90000, 86000, 81000, 75000, 68000, 60000) ) reserve_x( lt = lt, x = 60, i = 0.06, type = "whole" ) reserve_x( lt = lt, x = 60, i = 0.06, type = "endowment", n = 5, benefit = 100000 ) reserve_x( lt = lt, x = 60, i = 0.06, type = "term", n = 5, benefit = 100000, t = c(0, 1, 2, 3, 4, 5), tidy = FALSE )lt <- data.frame( x = 60:70, lx = c(100000, 99000, 97500, 95500, 93000, 90000, 86000, 81000, 75000, 68000, 60000) ) reserve_x( lt = lt, x = 60, i = 0.06, type = "whole" ) reserve_x( lt = lt, x = 60, i = 0.06, type = "endowment", n = 5, benefit = 100000 ) reserve_x( lt = lt, x = 60, i = 0.06, type = "term", n = 5, benefit = 100000, t = c(0, 1, 2, 3, 4, 5), tidy = FALSE )
Computes terminal benefit reserves at selected policy durations for a fully discrete two-life insurance contract, assuming independent future lifetimes and using compact actuarial notation.
reserve_xy( lt, x = NULL, y = NULL, i = NULL, i_type = "effective", m = 1L, type = c("whole", "term", "endowment"), status = c("joint", "last"), n = Inf, h = 0L, benefit = 1, P = NULL, n_prem = NULL, k = 1L, timing = c("due", "immediate"), premium_start = c("issue", "deferred"), frac = c("UDD", "CF", "CML", "Balducci"), t = NULL, method = c("prospective", "recursive"), tidy = TRUE, check = TRUE, tol = 1e-10, ... )reserve_xy( lt, x = NULL, y = NULL, i = NULL, i_type = "effective", m = 1L, type = c("whole", "term", "endowment"), status = c("joint", "last"), n = Inf, h = 0L, benefit = 1, P = NULL, n_prem = NULL, k = 1L, timing = c("due", "immediate"), premium_start = c("issue", "deferred"), frac = c("UDD", "CF", "CML", "Balducci"), t = NULL, method = c("prospective", "recursive"), tidy = TRUE, check = TRUE, tol = 1e-10, ... )
lt |
Either a single life table used for both lives, a list of two life
tables |
x |
Integer actuarial age for the first life at issue. |
y |
Integer actuarial age for the second life at issue. |
i |
Numeric scalar. Annual interest-rate input. |
i_type |
Character string indicating the interest-rate type. Allowed
values are |
m |
Positive integer. Conversion frequency for nominal rates. Ignored
for |
type |
Insurance type. One of |
status |
Two-life status definition. Use |
n |
Insurance term in years after deferment. Required as finite for
term and endowment insurance. Use |
h |
Nonnegative integer deferment period in years. |
benefit |
Numeric benefit amount. |
P |
Optional net premium per payment. If |
n_prem |
Optional premium-paying term in years, counted from
|
k |
Positive integer. Number of premium payments per year. |
timing |
Timing of premium payments. Use |
premium_start |
Start of premium payments. Use |
frac |
Fractional-age assumption used for status survival probabilities:
|
t |
Integer vector of policy durations at which to compute reserves.
If |
method |
Computation method. Use |
tidy |
Logical scalar. If |
check |
Logical scalar. If |
tol |
Numeric tolerance used for integer-grid checks. |
... |
Transitional compatibility for older calls using
|
The function supports joint-life and last-survivor statuses, one common life
table for both lives, or two different life tables supplied as
list(lt_x, lt_y).
This function follows the compact actuarial notation used throughout
tidyactuarial: lt is the life table input, x and
y are the two actuarial ages, i is the interest-rate input,
i_type is the interest-rate type, m is the conversion
frequency for nominal rates, n is the insurance term, h is the
deferment period, k is the premium payment frequency, P is the
premium per payment, and t is the policy duration.
The prospective reserve at duration is computed as
The recursive method is implemented only for nondeferred contracts with annual due premiums. For deferred or subannual premium structures, use the prospective method.
If tidy = TRUE, a tibble with reserve schedule details.
If tidy = FALSE, a named numeric vector.
reserve_x, premium_xy,
insurance_xy, annuity_xy, t_pxy
Other life-contingencies:
annuity_multi(),
annuity_x(),
annuity_xy(),
insurance_variable_k(),
insurance_x(),
insurance_xy(),
life_contract(),
premium_gross(),
premium_x(),
premium_xy(),
reserve_x(),
simulate_annuity_x(),
simulate_insurance_x()
lt <- data.frame( x = 60:70, lx = c(100000, 99000, 97500, 95500, 93000, 90000, 86000, 81000, 75000, 68000, 60000) ) reserve_xy( lt = lt, x = 60, y = 62, i = 0.06, type = "term", status = "joint", n = 4 ) reserve_xy( lt = lt, x = 60, y = 62, i = 0.06, type = "endowment", status = "last", n = 5, benefit = 100000 ) # Different life tables lt2 <- data.frame( x = 60:70, lx = c(100000, 99200, 98100, 96500, 94500, 92000, 89000, 85000, 80000, 74000, 67000) ) reserve_xy( lt = list(lt, lt2), x = 60, y = 62, i = 0.06, type = "term", status = "joint", n = 4, tidy = TRUE )lt <- data.frame( x = 60:70, lx = c(100000, 99000, 97500, 95500, 93000, 90000, 86000, 81000, 75000, 68000, 60000) ) reserve_xy( lt = lt, x = 60, y = 62, i = 0.06, type = "term", status = "joint", n = 4 ) reserve_xy( lt = lt, x = 60, y = 62, i = 0.06, type = "endowment", status = "last", n = 5, benefit = 100000 ) # Different life tables lt2 <- data.frame( x = 60:70, lx = c(100000, 99200, 98100, 96500, 94500, 92000, 89000, 85000, 80000, 74000, 67000) ) reserve_xy( lt = list(lt, lt2), x = 60, y = 62, i = 0.06, type = "term", status = "joint", n = 4, tidy = TRUE )
Computes the actuarial accumulation factor for a level annuity using compact actuarial notation.
s_angle( n, k = 1L, i, i_type = "effective", m = 1L, h = 0, timing = "immediate", payment = 1, tidy = FALSE )s_angle( n, k = 1L, i, i_type = "effective", m = 1L, h = 0, timing = "immediate", payment = 1, tidy = FALSE )
n |
Numeric vector of payment durations in years. Each value must be positive and finite. |
k |
Positive integer vector giving the number of discrete payments per year. Ignored for continuous annuities. |
i |
Numeric vector of interest-rate values. |
i_type |
Character vector indicating the interest-rate type. Allowed
values are |
m |
Positive integer vector giving the conversion frequency for nominal
rates. Ignored for |
h |
Numeric vector of deferment times in years. Must be greater than or equal to 0. Under the adopted horizon convention, this is metadata only for accumulation factors. |
timing |
Character vector. One of |
payment |
Numeric vector of level payment amounts. Used only when
|
tidy |
Logical scalar. If |
Supported timing conventions:
"immediate": annuity-immediate with discrete payments.
"due": annuity-due with discrete payments.
"continuous": continuous annuity.
For discrete annuities, k is the number of payments per year, so
payments are made every year. The function returns the accumulation
factor, assuming a unit payment at each payment time.
Horizon convention:
the future value is measured at the time of the last payment. Under this
convention, a pure deferment that shifts the entire payment block forward in
time does not change the accumulation factor when the payment pattern is
otherwise unchanged. Therefore, h is recorded and validated, but it
does not modify the factor.
The future value of a perpetuity diverges, so perpetuities are not supported
in s_angle().
This function follows the compact actuarial notation used throughout
tidyactuarial:
n: annuity term;
k: payment frequency;
i: interest rate;
i_type: interest-rate type;
m: conversion frequency for nominal rates;
h: deferment period.
The function first converts the supplied rate to the equivalent annual
effective interest rate using standardize_interest.
For finite discrete annuities:
For due annuities:
For continuous annuities:
Input vectors must have length 1 or a common length. Missing values are propagated.
If tidy = FALSE, a numeric vector of accumulation factors.
If tidy = TRUE, a tibble with input values, equivalent rates,
accumulation factors, payment amounts, and future values.
a_angle, standardize_interest,
future_value
Other annuities:
a_angle(),
annuity_arith(),
annuity_geom()
# Numeric accumulation factor s_angle(n = 10, i = 0.05) # Nominal interest converted monthly, with monthly payments s_angle( n = 10, i = 0.06, i_type = "nominal_interest", m = 12, k = 12 ) # Continuous annuity s_angle( n = 15, i = 0.04, i_type = "force", timing = "continuous" ) # Tibble output for teaching or auditing s_angle( n = 10, i = 0.05, payment = 1000, tidy = TRUE ) # Vectorized example s_angle( n = c(5, 10, 20), k = c(1, 12, 1), i = c(0.05, 0.06, 0.04), i_type = c("effective", "nominal_interest", "force"), m = c(1, 12, 1), h = c(0, 2, 3), timing = c("immediate", "due", "continuous") )# Numeric accumulation factor s_angle(n = 10, i = 0.05) # Nominal interest converted monthly, with monthly payments s_angle( n = 10, i = 0.06, i_type = "nominal_interest", m = 12, k = 12 ) # Continuous annuity s_angle( n = 15, i = 0.04, i_type = "force", timing = "continuous" ) # Tibble output for teaching or auditing s_angle( n = 10, i = 0.05, payment = 1000, tidy = TRUE ) # Vectorized example s_angle( n = c(5, 10, 20), k = c(1, 12, 1), i = c(0.05, 0.06, 0.04), i_type = c("effective", "nominal_interest", "force"), m = c(1, 12, 1), h = c(0, 2, 3), timing = c("immediate", "due", "continuous") )
Simulates the present value of a discrete single-life annuity using a life table and annual curtate future lifetimes, with compact actuarial notation.
simulate_annuity_x( lt, x = NULL, i = NULL, i_type = NULL, m = NULL, n = Inf, k = 1L, timing = c("due", "immediate"), payment = 1, method = c("inverse"), n_sim = 10000L, seed = NULL, output = c("simulations", "summary"), ... )simulate_annuity_x( lt, x = NULL, i = NULL, i_type = NULL, m = NULL, n = Inf, k = 1L, timing = c("due", "immediate"), payment = 1, method = c("inverse"), n_sim = 10000L, seed = NULL, output = c("simulations", "summary"), ... )
lt |
A life table or a |
x |
Integer actuarial age. Optional when |
i |
Numeric scalar. Annual interest-rate input. Optional when
|
i_type |
Character string indicating the interest-rate type. Allowed
values are |
m |
Positive integer. Conversion frequency for nominal rates. Ignored
for |
n |
Term in years. Use |
k |
Positive integer. Number of annuity payments per year. |
timing |
Character string. Either |
payment |
Numeric scalar. Level payment per payment period. |
method |
Simulation method. Currently |
n_sim |
Positive integer. Number of simulations. |
seed |
Optional seed for reproducibility. |
output |
Character string. Use |
... |
Transitional compatibility for older calls using
|
The function supports direct use with lt, x, and i, and
pipe workflows with life_contract.
This function follows the compact actuarial notation used throughout
tidyactuarial: lt is the life table, x is the age,
i is the interest-rate input, i_type is the interest-rate type,
m is the conversion frequency for nominal rates, n is the term,
and k is the payment frequency.
The simulation is based on the curtate future lifetime . For annual
payments, an annuity-due pays while the life is alive at the beginning of the
year, and an annuity-immediate pays at the end of completed years.
A tibble. If output = "simulations", the tibble contains one
row per simulation. If output = "summary", the tibble is the output
of summary_mc applied to the simulated present values.
Other simulation:
simulate_insurance_x()
Other life-contingencies:
annuity_multi(),
annuity_x(),
annuity_xy(),
insurance_variable_k(),
insurance_x(),
insurance_xy(),
life_contract(),
premium_gross(),
premium_x(),
premium_xy(),
reserve_x(),
reserve_xy(),
simulate_insurance_x()
lt <- data.frame( x = 60:66, lx = c(100000, 99000, 97500, 95500, 93000, 90000, 0) ) simulate_annuity_x( lt = lt, x = 60, i = 0.05, n_sim = 25, seed = 123 ) simulate_annuity_x( lt = lt, x = 60, i = 0.06, i_type = "nominal_interest", m = 12, n = 5, k = 12, n_sim = 25, seed = 123, output = "summary" )lt <- data.frame( x = 60:66, lx = c(100000, 99000, 97500, 95500, 93000, 90000, 0) ) simulate_annuity_x( lt = lt, x = 60, i = 0.05, n_sim = 25, seed = 123 ) simulate_annuity_x( lt = lt, x = 60, i = 0.06, i_type = "nominal_interest", m = 12, n = 5, k = 12, n_sim = 25, seed = 123, output = "summary" )
Simulates the present value of a discrete single-life insurance using a life table and annual curtate future lifetimes, with compact actuarial notation.
simulate_insurance_x( lt, x = NULL, i = NULL, i_type = NULL, m = NULL, type = c("whole", "term", "endowment"), n = Inf, benefit = 1, method = c("inverse"), n_sim = 10000L, seed = NULL, output = c("simulations", "summary"), ... )simulate_insurance_x( lt, x = NULL, i = NULL, i_type = NULL, m = NULL, type = c("whole", "term", "endowment"), n = Inf, benefit = 1, method = c("inverse"), n_sim = 10000L, seed = NULL, output = c("simulations", "summary"), ... )
lt |
A life table or a |
x |
Integer actuarial age. Optional when |
i |
Numeric scalar. Annual interest-rate input. Optional when
|
i_type |
Character string indicating the interest-rate type. Allowed
values are |
m |
Positive integer. Conversion frequency for nominal rates. Ignored
for |
type |
Character string. One of |
n |
Term in years. Required as finite for term and endowment insurance.
Use |
benefit |
Numeric scalar. Insurance benefit. |
method |
Simulation method. Currently |
n_sim |
Positive integer. Number of simulations. |
seed |
Optional seed for reproducibility. |
output |
Character string. Use |
... |
Transitional compatibility for older calls using
|
The function supports direct use with lt, x, and i, and
pipe workflows with life_contract.
This function follows the compact actuarial notation used throughout
tidyactuarial: lt is the life table, x is the age,
i is the interest-rate input, i_type is the interest-rate type,
m is the conversion frequency for nominal rates, and n is the
insurance term.
The benefit is paid at the end of the year of death for whole-life and term insurance. For endowment insurance, the benefit is paid at death within the term or at maturity if the life survives.
A tibble. If output = "simulations", the tibble contains one
row per simulation. If output = "summary", the tibble is the output
of summary_mc applied to the simulated present values.
Other simulation:
simulate_annuity_x()
Other life-contingencies:
annuity_multi(),
annuity_x(),
annuity_xy(),
insurance_variable_k(),
insurance_x(),
insurance_xy(),
life_contract(),
premium_gross(),
premium_x(),
premium_xy(),
reserve_x(),
reserve_xy(),
simulate_annuity_x()
lt <- data.frame( x = 60:66, lx = c(100000, 99000, 97500, 95500, 93000, 90000, 0) ) simulate_insurance_x( lt = lt, x = 60, i = 0.05, type = "whole", n_sim = 25, seed = 123 ) simulate_insurance_x( lt = lt, x = 60, i = 0.06, i_type = "nominal_interest", m = 12, type = "term", n = 5, benefit = 100000, n_sim = 25, seed = 123, output = "summary" )lt <- data.frame( x = 60:66, lx = c(100000, 99000, 97500, 95500, 93000, 90000, 0) ) simulate_insurance_x( lt = lt, x = 60, i = 0.05, type = "whole", n_sim = 25, seed = 123 ) simulate_insurance_x( lt = lt, x = 60, i = 0.06, i_type = "nominal_interest", m = 12, type = "term", n = 5, benefit = 100000, n_sim = 25, seed = 123, output = "summary" )
Simulates curtate and, optionally, complete future lifetimes from a life table containing one-year death probabilities, using compact actuarial notation.
simulate_lifetime( lt, x, n_sim = 10000L, x_col = "x", qx_col = "qx", method = c("inverse", "multinomial", "antithetic"), frac = c("udd", "constant_force", "none"), seed = NULL, include_distribution = FALSE )simulate_lifetime( lt, x, n_sim = 10000L, x_col = "x", qx_col = "qx", method = c("inverse", "multinomial", "antithetic"), frac = c("udd", "constant_force", "none"), seed = NULL, include_distribution = FALSE )
lt |
A data frame or tibble containing the life table. |
x |
Numeric scalar. Initial actuarial age of the individual. |
n_sim |
Positive integer. Number of Monte Carlo simulations. Default is
|
x_col |
Character string. Name of the age column in |
qx_col |
Character string. Name of the one-year death probability
column in |
method |
Character string specifying the simulation method for
|
frac |
Character string specifying how the fractional part of the
complete future lifetime is generated within the year of death. Available
options are |
seed |
Optional integer seed for reproducibility. Default is
|
include_distribution |
Logical. If |
This function is designed as the simulation engine for Monte Carlo life
contingency calculations in tidyactuarial. It generates simulated
values of the curtate future lifetime and a simulated complete
future lifetime . The output is a tidy tibble that can be used
naturally with pipes and downstream Monte Carlo functions.
For a life aged , the curtate future lifetime follows
where is the probability of surviving complete years
from age , and is the one-year probability of death at
attained age .
This function follows the compact actuarial notation used throughout
tidyactuarial: lt denotes the life table, x denotes the
actuarial age, and frac denotes the fractional-age simulation
assumption.
The function first constructs the conditional distribution of from
the selected age onward. Then it generates simulated values according to the
selected method.
The available simulation methods are:
"inverse": inverse transform simulation using the cumulative
distribution of .
"multinomial": direct sampling from the probability mass
function of .
"antithetic": inverse transform simulation using antithetic
uniforms and .
The frac argument controls the simulated complete future lifetime
. If frac = "udd", a uniform fractional lifetime is added to
. If frac = "constant_force", the fractional lifetime within
the year of death is generated under a constant force of mortality
assumption conditional on death during that year. If frac = "none",
the complete lifetime is returned as NA.
The probabilities are normalized internally to handle finite life tables. If the life table is truncated, the simulated distribution is conditional on death occurring within the available range of ages. In practical work, it is recommended that the last available death probability be equal to 1.
A tibble with one row per simulation and columns:
Simulation identifier.
Initial actuarial age.
Compatibility column equal to x.
Simulation method used.
Fractional-age simulation assumption.
Compatibility column equal to frac.
Simulated curtate future lifetime.
Simulated complete future lifetime. If frac = "none",
this column contains NA.
If include_distribution = TRUE, the output also includes a list-column
named distribution containing the probability mass function used for
the simulation.
Bowers, N. L., Gerber, H. U., Hickman, J. C., Jones, D. A., and Nesbitt, C. J. (1997). Actuarial Mathematics. Second Edition. Society of Actuaries.
mc_insurance, mc_annuity,
mc_premium, mc_loss
Other monte-carlo:
mc_annuity(),
mc_insurance(),
mc_loss(),
mc_premium(),
mc_reserve(),
summary_mc()
lt <- tibble::tibble( x = 40:100, qx = seq(0.002, 1, length.out = 61) ) # Basic simulation using inverse transform sampling lt |> simulate_lifetime( x = 40, n_sim = 25, method = "inverse", seed = 123 ) # Antithetic simulation lt |> simulate_lifetime( x = 40, n_sim = 25, method = "antithetic", seed = 123 ) # Returning the distribution used for simulation lt |> simulate_lifetime( x = 40, n_sim = 25, include_distribution = TRUE, seed = 123 )lt <- tibble::tibble( x = 40:100, qx = seq(0.002, 1, length.out = 61) ) # Basic simulation using inverse transform sampling lt |> simulate_lifetime( x = 40, n_sim = 25, method = "inverse", seed = 123 ) # Antithetic simulation lt |> simulate_lifetime( x = 40, n_sim = 25, method = "antithetic", seed = 123 ) # Returning the distribution used for simulation lt |> simulate_lifetime( x = 40, n_sim = 25, include_distribution = TRUE, seed = 123 )
Simulates curtate and complete future lifetimes from a life table.
This version is intentionally simple and defensive. It avoids using
findInterval() on a cumulative distribution that may contain missing values,
while preserving the column names expected by the Monte Carlo workflow:
sim_id, life_id, Kx, and Tx.
simulate_lifetimes(data, x, n_sim = 1000, frac = "udd", seed = NULL)simulate_lifetimes(data, x, n_sim = 1000, frac = "udd", seed = NULL)
data |
A data frame or tibble containing a life table. |
x |
Numeric vector of initial ages. |
n_sim |
Number of simulations per life. |
frac |
Fractional age assumption. One of |
seed |
Optional random seed. |
The input life table must contain an age column named x, age, or Age,
and at least one mortality column among qx, px, or lx.
If qx is not available, it is obtained from px as 1 - px, or from
consecutive lx values as 1 - lx[x + 1] / lx[x].
Invalid mortality values are handled defensively. Non-finite values, negative
values, and values greater than one are removed from the mortality basis.
Missing values are then treated as zero, and the final available age is forced
to have qx = 1 so that the lifetime distribution is closed.
A tibble with simulated curtate and complete future lifetimes.
lt <- tibble::tibble( x = 40:100, qx = seq(0.002, 1, length.out = 61) ) simulate_lifetimes( data = lt, x = c(60, 58), n_sim = 25, frac = "udd", seed = 123 )lt <- tibble::tibble( x = 40:100, qx = seq(0.002, 1, length.out = 61) ) simulate_lifetimes( data = lt, x = c(60, 58), n_sim = 25, frac = "udd", seed = 123 )
Builds a sinking fund schedule under a fixed loan rate and a fixed accumulation rate for the sinking fund, using compact actuarial notation.
sinking_fund_schedule( principal, n, i, j, k = 1L, i_type = "effective", j_type = "effective", m = 1L, j_m = 1L, deposit = NULL, tol = 1e-08 )sinking_fund_schedule( principal, n, i, j, k = 1L, i_type = "effective", j_type = "effective", m = 1L, j_m = 1L, deposit = NULL, tol = 1e-08 )
principal |
Numeric scalar. Initial loan amount. |
n |
Positive integer. Number of schedule periods. |
i |
Numeric scalar. Annual interest-rate input for the loan. |
j |
Numeric scalar. Annual accumulation-rate input for the sinking fund. |
k |
Positive integer. Number of schedule periods per year. |
i_type |
Character string indicating the loan interest-rate type.
Allowed values are |
j_type |
Character string indicating the sinking-fund accumulation-rate
type. Allowed values are |
m |
Positive integer. Conversion frequency for nominal loan rates.
Ignored for |
j_m |
Positive integer. Conversion frequency for nominal sinking-fund
rates. Ignored for |
deposit |
Optional numeric scalar. Level sinking-fund deposit per
period. If |
tol |
Numeric tolerance used for zero checks and final-balance checks. |
The borrower pays:
interest on the loan each period, and
a level deposit into the sinking fund.
At maturity, the sinking fund is used to redeem the principal.
This function follows the compact actuarial notation used throughout
tidyactuarial: i is the loan interest rate, j is the
sinking-fund accumulation rate, k is the number of schedule periods
per year, m is the conversion frequency for the loan rate, and
j_m is the conversion frequency for the sinking-fund rate.
The supplied annual rate specifications are converted to effective annual rates and then to effective rates per schedule period:
If deposit is NULL and the sinking-fund periodic rate
j_p is approximately zero, the deposit is computed as
principal / n.
Otherwise, the standard sinking-fund formula is used:
where
A tibble with one row per period and columns:
Period index.
Outstanding loan balance at the start of the period.
Interest paid on the loan during the period.
Deposit made into the sinking fund.
Fund balance at the start of the period.
Interest earned by the fund during the period.
Fund balance before final redemption.
Amount withdrawn from the fund to redeem the loan at maturity.
Fund balance after redemption.
Outstanding loan balance after redemption.
Borrower's external cash outflow during the period.
Equivalent annual effective loan rate.
Equivalent annual effective fund rate.
Effective loan rate per schedule period.
Effective fund rate per schedule period.
Schedule frequency.
Other amortization:
amort_schedule()
sinking_fund_schedule( principal = 100000, n = 12, i = 0.12, j = 0.096, i_type = "nominal_interest", j_type = "nominal_interest", m = 12, j_m = 12, k = 12 ) sinking_fund_schedule( principal = 50000, n = 10, i = 0.02, j = 0, deposit = NULL )sinking_fund_schedule( principal = 100000, n = 12, i = 0.12, j = 0.096, i_type = "nominal_interest", j_type = "nominal_interest", m = 12, j_m = 12, k = 12 ) sinking_fund_schedule( principal = 50000, n = 10, i = 0.02, j = 0, deposit = NULL )
This dataset is intended for reproducible examples, internal validation, and
benchmark tests for life-contingency functions such as annuity_x,
insurance_x, premium_x,
reserve_x, annuity_xy,
insurance_xy, premium_xy, and
reserve_xy.
soa08ltsoa08lt
A tibble with one row per integer age and the following columns:
Integer actuarial age.
Number of lives surviving to exact age x.
Number of deaths between exact ages x and x + 1.
One-year probability of death between exact ages x and
x + 1.
One-year probability of survival from exact age x to
x + 1.
A tidy version of the Society of Actuaries illustrative life table commonly used in life-contingencies examples and benchmark calculations.
The table is included as a convenient benchmark table for actuarial
calculations. The build script in data-raw/soa08lt.R constructs this
tidy dataset from the SOA illustrative actuarial table object distributed in
the lifecontingencies package.
The column names already follow the compact actuarial notation used in
tidyactuarial: x for age, lx for lives, dx for
deaths, qx for one-year death probability, and px for
one-year survival probability.
Society of Actuaries illustrative life table, commonly referenced in Bowers et al. (1997), Actuarial Mathematics, Appendix 2A.
Bowers, N. L., Gerber, H. U., Hickman, J. C., Jones, D. A., and Nesbitt, C. J. (1997). Actuarial Mathematics. Second edition. Society of Actuaries.
Spedicato, G. A. (2013). The lifecontingencies package: performing
financial and actuarial mathematics calculations in R.
data(soa08lt) head(soa08lt) annuity_x( lt = soa08lt, x = 65, i = 0.06, timing = "due" )data(soa08lt) head(soa08lt) annuity_x( lt = soa08lt, x = 65, i = 0.06, timing = "due" )
Converts common interest-rate specifications to the equivalent annual
effective interest rate i, using compact actuarial notation.
standardize_interest(i_type = "effective", i, m = 1, ...)standardize_interest(i_type = "effective", i, m = 1, ...)
i_type |
Character vector indicating the interest-rate type. Must be one
of |
i |
Numeric vector of interest-rate values. |
m |
Positive integer vector giving the conversion frequency for nominal
rates. Ignored for |
... |
Transitional compatibility for older internal calls using
|
This function follows the compact actuarial notation used throughout
tidyactuarial: i denotes the interest-rate value,
i_type denotes the interest-rate type, and m denotes the
conversion frequency for nominal rates.
The conversion formulas are:
(identity)
Input vectors must have length 1 or a common length.
Numeric vector of annual effective rates. Missing values are propagated.
interest_equivalents,
discount_factor_spot
Other interest:
discount_factor_spot(),
forward_rate(),
interest_equivalents(),
yield_curve()
# Scalar cases standardize_interest(i_type = "nominal_interest", i = 0.18, m = 4) standardize_interest(i_type = "nominal_discount", i = 0.10, m = 12) standardize_interest(i_type = "force", i = 0.12) # Vectorized case standardize_interest( i_type = c("nominal_interest", "force", "effective"), i = c(0.06, 0.05, 0.04), m = c(12, 1, 1) ) # Use inside a data pipeline if (requireNamespace("dplyr", quietly = TRUE) && requireNamespace("tibble", quietly = TRUE)) { portfolio <- tibble::tibble( policy_id = 1:3, i = c(0.05, 0.08, 0.10), i_type = c("force", "nominal_interest", "nominal_discount"), m = c(1, 4, 12) ) dplyr::mutate( portfolio, i_effective = standardize_interest( i_type = i_type, i = i, m = m ) ) }# Scalar cases standardize_interest(i_type = "nominal_interest", i = 0.18, m = 4) standardize_interest(i_type = "nominal_discount", i = 0.10, m = 12) standardize_interest(i_type = "force", i = 0.12) # Vectorized case standardize_interest( i_type = c("nominal_interest", "force", "effective"), i = c(0.06, 0.05, 0.04), m = c(12, 1, 1) ) # Use inside a data pipeline if (requireNamespace("dplyr", quietly = TRUE) && requireNamespace("tibble", quietly = TRUE)) { portfolio <- tibble::tibble( policy_id = 1:3, i = c(0.05, 0.08, 0.10), i_type = c("force", "nominal_interest", "nominal_discount"), m = c(1, 4, 12) ) dplyr::mutate( portfolio, i_effective = standardize_interest( i_type = i_type, i = i, m = m ) ) }
Computes tidy summary statistics from simulated actuarial values, using a
column-oriented interface consistent with the Monte Carlo functions in
tidyactuarial.
summary_mc( .data = NULL, col_value = "present_value", by = NULL, probs = c(0.025, 0.5, 0.975), var_probs = c(0.95, 0.99), na_rm = TRUE, ... )summary_mc( .data = NULL, col_value = "present_value", by = NULL, probs = c(0.025, 0.5, 0.975), var_probs = c(0.95, 0.99), na_rm = TRUE, ... )
.data |
A data.frame or tibble containing simulation output. |
col_value |
Character string. Name of the numeric column to summarise.
Defaults to |
by |
Optional character vector of grouping columns. If supplied, the
summary is computed separately within each group. If |
probs |
Numeric vector of probabilities for quantiles. |
var_probs |
Numeric vector of probabilities for VaR and TVaR. |
na_rm |
Logical scalar. If |
... |
Transitional compatibility for older calls using
|
This function is intentionally generic. It can summarise simulated present values from annuities, insurances, premiums, reserves, losses, or any other numeric actuarial indicator stored in a tidy simulation table.
This function follows the compact column-naming convention used throughout
the Monte Carlo layer of tidyactuarial: column arguments are prefixed
with col_. Thus, col_value identifies the simulated actuarial
value to summarise.
The function computes the number of simulations used, number of missing values, mean, variance, standard deviation, standard error, minimum, maximum, selected quantiles, empirical VaR, and empirical TVaR.
TVaR is computed empirically as the mean of simulated values greater than or equal to the corresponding empirical VaR.
If na_rm = TRUE, missing values in col_value are removed before
computing statistics. If na_rm = FALSE and missing values are present,
most numerical statistics are returned as NA_real_, avoiding accidental
silent deletion of missing reserve or loss scenarios.
A tibble with summary statistics.
Other monte-carlo:
mc_annuity(),
mc_insurance(),
mc_loss(),
mc_premium(),
mc_reserve(),
simulate_lifetime()
sim <- tibble::tibble( sim_id = 1:5, t = c(0, 0, 1, 1, 1), L_t = c(10, 12, 8, 15, 11) ) summary_mc(sim, col_value = "L_t") summary_mc(sim, col_value = "L_t", by = "t") # Transitional compatibility with older argument names summary_mc(sim, value_col = "L_t", group_cols = "t")sim <- tibble::tibble( sim_id = 1:5, t = c(0, 0, 1, 1, 1), L_t = c(10, 12, 8, 15, 11) ) summary_mc(sim, col_value = "L_t") summary_mc(sim, col_value = "L_t", by = "t") # Transitional compatibility with older argument names summary_mc(sim, value_col = "L_t", group_cols = "t")
Computes the actuarial present value of a pure endowment, i.e., the expected
present value of a payment of 1 made at time if and only if a life
aged survives to age :
t_Ex( lt, x, t, i, i_type = "effective", m = 1L, frac, tidy = FALSE, check = TRUE, tol = 1e-10 )t_Ex( lt, x, t, i, i_type = "effective", m = 1L, frac, tidy = FALSE, check = TRUE, tol = 1e-10 )
lt |
A lifetable object as produced by |
x |
Integer age(s) at which the endowment starts. |
t |
Nonnegative numeric duration(s) in years. Fractional durations are
allowed and are handled through |
i |
Annual interest-rate input(s). |
i_type |
Character vector indicating the interest-rate type. Allowed
values are |
m |
Positive integer vector giving the conversion frequency for nominal
rates. Ignored for |
frac |
Fractional-age assumption passed to |
tidy |
Logical. If |
check |
Logical. If |
tol |
Numeric tolerance for integer checks on |
This function follows the compact actuarial notation used throughout
tidyactuarial: lt is the life table, x is the age,
t is the duration, i is the interest-rate input,
i_type is the interest-rate type, and m is the conversion
frequency for nominal rates.
The pure endowment is a fundamental building block in life contingency mathematics. It serves as the actuarial discount factor, combining financial discounting with mortality:
The interest-rate input is converted to an annual effective rate before applying the discount factor:
Key identities involving :
Actuarial accumulated value:
.
Endowment insurance decomposition:
.
Deferred annuity:
.
For a constant force of mortality and force of interest
:
The variance of the pure endowment random variable is:
Numeric vector of , or a tibble if
tidy = TRUE.
t_px for survival probabilities without discounting,
insurance_x for insurance APVs, annuity_x for
life annuity APVs.
x <- 0:5 lx <- c(100000, 99500, 99000, 98200, 97000, 95000) lt <- lifetable(x = x, lx = lx, omega = 5, close = TRUE) # Basic pure endowment: 3_E_0 = v^3 * 3_p_0 t_Ex(lt, x = 0, t = 3, i = 0.06) # Verify manually: (1.06)^(-3) * t_px(lt, x = 0, t = 3) # Constant force of interest lt_exp <- lifetable(x = 0:50, lx = 100000 * exp(-0.05 * (0:50))) t_Ex( lt_exp, x = 30, t = 10, i = 0.10, i_type = "force" ) exp(-1.5) # Nominal annual interest rate convertible monthly t_Ex( lt, x = 0, t = 3, i = 0.06, i_type = "nominal_interest", m = 12 ) # Vectorized: multiple ages at once t_Ex(lt, x = c(0, 1, 2), t = 3, i = 0.05, tidy = TRUE) # Use in a tidy pipeline if (requireNamespace("dplyr", quietly = TRUE)) { tibble::tibble(x = 0:4, t = c(5, 4, 3, 2, 1)) |> dplyr::mutate(pure_endow = t_Ex(lt, x = x, t = t, i = 0.06)) }x <- 0:5 lx <- c(100000, 99500, 99000, 98200, 97000, 95000) lt <- lifetable(x = x, lx = lx, omega = 5, close = TRUE) # Basic pure endowment: 3_E_0 = v^3 * 3_p_0 t_Ex(lt, x = 0, t = 3, i = 0.06) # Verify manually: (1.06)^(-3) * t_px(lt, x = 0, t = 3) # Constant force of interest lt_exp <- lifetable(x = 0:50, lx = 100000 * exp(-0.05 * (0:50))) t_Ex( lt_exp, x = 30, t = 10, i = 0.10, i_type = "force" ) exp(-1.5) # Nominal annual interest rate convertible monthly t_Ex( lt, x = 0, t = 3, i = 0.06, i_type = "nominal_interest", m = 12 ) # Vectorized: multiple ages at once t_Ex(lt, x = c(0, 1, 2), t = 3, i = 0.05, tidy = TRUE) # Use in a tidy pipeline if (requireNamespace("dplyr", quietly = TRUE)) { tibble::tibble(x = 0:4, t = c(5, 4, 3, 2, 1)) |> dplyr::mutate(pure_endow = t_Ex(lt, x = x, t = t, i = 0.06)) }
Computes the t-year survival probability
using an annual life table, allowing for fractional ages under standard actuarial assumptions.
t_px(lt, x, t, frac, tidy = FALSE, check = TRUE, tol = 1e-10)t_px(lt, x, t, frac, tidy = FALSE, check = TRUE, tol = 1e-10)
lt |
A lifetable object as produced by |
x |
Integer age(s) at which survival starts. |
t |
Nonnegative numeric duration(s) in years (can be fractional). |
frac |
Fractional-age assumption:
|
tidy |
Logical. If |
check |
Logical. If |
tol |
Numeric tolerance for integer checks on |
The integer-year survival is obtained directly from the life table (Finan, Section 22):
For non-integer durations, let with
and . Then (Finan, Section 24):
The fractional-year factor depends on the assumption:
UDD (Finan, Sec. 24.1):
CF (Finan, Sec. 24.2):
Balducci (Finan, Sec. 24.3):
If (the terminal age), the function returns 0
since no survival is possible beyond the table's limiting age.
Numeric vector of , or a tibble if
tidy = TRUE.
Computes the survival probability for two independent lives with actuarial
ages x and y at time 0 under a joint-life or last-survivor
status.
t_pxy(lt, x, y, t, frac, status = c("joint", "last"))t_pxy(lt, x, y, t, frac, status = c("joint", "last"))
lt |
Either:
Each life table must contain columns |
x |
Integer actuarial age of the first life at time 0. |
y |
Integer actuarial age of the second life at time 0. |
t |
Nonnegative time (may be fractional). |
frac |
Fractional-age assumption: |
status |
Two-life status: |
Independence is assumed throughout (Finan, Sections 56–57).
Joint-life status (Finan, Section 56): the status survives as long as both lives are alive.
Last-survivor status (Finan, Section 57): the status survives as long as at least one life is alive.
Individual survival probabilities and are
computed via t_px, which supports fractional ages under UDD,
constant force, and Balducci assumptions (Finan, Section 24).
A single numeric value.
t_px for single-life survival,
e_xy for joint-life expectancy,
annuity_xy for two-life annuity APVs,
insurance_xy for two-life insurance APVs.
lt <- data.frame( x = 60:66, lx = c(100000, 99000, 97500, 95500, 93000, 90000, 86000) ) # Joint life, 2.5 years, UDD (Finan, Sec. 56) t_pxy(lt, x = 60, y = 62, t = 2.5, frac = "UDD", status = "joint") # Verify: joint = product of marginals t_px(lt, x = 60, t = 2.5, frac = "UDD") * t_px(lt, x = 62, t = 2.5, frac = "UDD") # Last survivor, 2.5 years, constant force (Finan, Sec. 57) t_pxy(lt, x = 60, y = 62, t = 2.5, frac = "CF", status = "last") # Same result if the same table is supplied explicitly for both lives t_pxy(list(lt, lt), x = 60, y = 62, t = 2.5, frac = "UDD", status = "joint") # Different life tables for the two lives lt_m <- data.frame( x = 60:66, lx = c(100000, 98500, 96800, 94800, 92400, 89500, 86000) ) lt_f <- data.frame( x = 60:66, lx = c(100000, 99000, 97800, 96400, 94700, 92700, 90300) ) t_pxy(list(lt_m, lt_f), x = 60, y = 62, t = 2.5, frac = "UDD", status = "joint") # Finan Example 56.2 style: integer survival # 10_p_{50:60} = 10_p_50 * 10_p_60 lt_ilt <- data.frame( x = 50:70, lx = c(8950901, 8879913, 8804189, 8723382, 8637048, 8544731, 8445974, 8340310, 8227261, 8106334, 7977338, 7839775, 7693040, 7536522, 7369603, 7191658, 7002051, 6800139, 6585264, 6356752, 6114913) ) t_pxy(lt_ilt, x = 50, y = 60, t = 10, status = "joint") # Finan Problem 56.1: t_q_xy = t_q_x + t_q_y - t_q_x * t_q_y p_joint <- t_pxy(lt, x = 60, y = 62, t = 3, status = "joint") q_joint <- 1 - p_joint qx <- 1 - t_px(lt, x = 60, t = 3) qy <- 1 - t_px(lt, x = 62, t = 3) c(q_joint = q_joint, q_sum = qx + qy - qx * qy) # should matchlt <- data.frame( x = 60:66, lx = c(100000, 99000, 97500, 95500, 93000, 90000, 86000) ) # Joint life, 2.5 years, UDD (Finan, Sec. 56) t_pxy(lt, x = 60, y = 62, t = 2.5, frac = "UDD", status = "joint") # Verify: joint = product of marginals t_px(lt, x = 60, t = 2.5, frac = "UDD") * t_px(lt, x = 62, t = 2.5, frac = "UDD") # Last survivor, 2.5 years, constant force (Finan, Sec. 57) t_pxy(lt, x = 60, y = 62, t = 2.5, frac = "CF", status = "last") # Same result if the same table is supplied explicitly for both lives t_pxy(list(lt, lt), x = 60, y = 62, t = 2.5, frac = "UDD", status = "joint") # Different life tables for the two lives lt_m <- data.frame( x = 60:66, lx = c(100000, 98500, 96800, 94800, 92400, 89500, 86000) ) lt_f <- data.frame( x = 60:66, lx = c(100000, 99000, 97800, 96400, 94700, 92700, 90300) ) t_pxy(list(lt_m, lt_f), x = 60, y = 62, t = 2.5, frac = "UDD", status = "joint") # Finan Example 56.2 style: integer survival # 10_p_{50:60} = 10_p_50 * 10_p_60 lt_ilt <- data.frame( x = 50:70, lx = c(8950901, 8879913, 8804189, 8723382, 8637048, 8544731, 8445974, 8340310, 8227261, 8106334, 7977338, 7839775, 7693040, 7536522, 7369603, 7191658, 7002051, 6800139, 6585264, 6356752, 6114913) ) t_pxy(lt_ilt, x = 50, y = 60, t = 10, status = "joint") # Finan Problem 56.1: t_q_xy = t_q_x + t_q_y - t_q_x * t_q_y p_joint <- t_pxy(lt, x = 60, y = 62, t = 3, status = "joint") q_joint <- 1 - p_joint qx <- 1 - t_px(lt, x = 60, t = 3) qy <- 1 - t_px(lt, x = 62, t = 3) c(q_joint = q_joint, q_sum = qx + qy - qx * qy) # should match
Computes the t-year death probability
using an annual life table, allowing for fractional ages under standard actuarial assumptions.
t_qx(lt, x, t, frac, tidy = FALSE, check = TRUE, tol = 1e-10)t_qx(lt, x, t, frac, tidy = FALSE, check = TRUE, tol = 1e-10)
lt |
A lifetable object as produced by |
x |
Integer age(s) at which the interval starts. |
t |
Nonnegative numeric duration(s) in years (can be fractional). |
frac |
Fractional-age assumption:
|
tidy |
Logical. If |
check |
Logical. If |
tol |
Numeric tolerance for integer checks on |
This is a thin wrapper around t_px:
The identity (Finan, Section 22) holds
for integer , where is the
expected number of deaths between ages and .
For fractional durations, the result depends on the chosen assumption
(UDD, CF, or Balducci); see t_px for details and formulas
(Finan, Section 24).
The deferred death probability can be obtained as
(Finan, Section 23.4):
Numeric vector of , or a tibble if
tidy = TRUE.
t_px for the complementary survival probability,
t_Ex for the pure endowment (discounted survival),
e_x for life expectancy,
lifetable for building the life table input.
x <- 0:5 lx <- c(100000, 99500, 99000, 98200, 97000, 95000) lt <- lifetable(x = x, lx = lx, omega = 5, close = TRUE) # Integer death probability (Finan, Section 22) t_qx(lt, x = 0, t = 3) # (l0 - l3) / l0 # t = 0 always returns 0 t_qx(lt, x = 0, t = 0) # Fractional age under UDD (Finan, Section 24.1) t_qx(lt, x = 0, t = 2.5, frac = "UDD") # Finan Example 22.2a: number of deaths between ages 2 and 5 # 3_d_2 = l_2 - l_5 = 98995 - 97468 = 1527 lt_22 <- lifetable( x = 0:5, lx = c(100000, 99499, 98995, 98489, 97980, 97468) ) t_qx(lt_22, x = 2, t = 3) * lt_22$lx[lt_22$x == 2] # 1527 # Deferred death probability (Finan, Section 23.4): # 2|1_q_0 = 2_p_0 * q_2 = 3_q_0 - 2_q_0 t_qx(lt, x = 0, t = 3) - t_qx(lt, x = 0, t = 2) # Vectorized with tidy output t_qx(lt, x = c(0, 1), t = c(1.5, 2.2), frac = "Balducci", tidy = TRUE) # Use in a tidy pipeline if (requireNamespace("dplyr", quietly = TRUE)) { tibble::tibble(age = c(0, 1, 2), duration = c(3, 2.5, 1.7)) |> dplyr::mutate( surv = t_px(lt, x = age, t = duration), death = t_qx(lt, x = age, t = duration) ) }x <- 0:5 lx <- c(100000, 99500, 99000, 98200, 97000, 95000) lt <- lifetable(x = x, lx = lx, omega = 5, close = TRUE) # Integer death probability (Finan, Section 22) t_qx(lt, x = 0, t = 3) # (l0 - l3) / l0 # t = 0 always returns 0 t_qx(lt, x = 0, t = 0) # Fractional age under UDD (Finan, Section 24.1) t_qx(lt, x = 0, t = 2.5, frac = "UDD") # Finan Example 22.2a: number of deaths between ages 2 and 5 # 3_d_2 = l_2 - l_5 = 98995 - 97468 = 1527 lt_22 <- lifetable( x = 0:5, lx = c(100000, 99499, 98995, 98489, 97980, 97468) ) t_qx(lt_22, x = 2, t = 3) * lt_22$lx[lt_22$x == 2] # 1527 # Deferred death probability (Finan, Section 23.4): # 2|1_q_0 = 2_p_0 * q_2 = 3_q_0 - 2_q_0 t_qx(lt, x = 0, t = 3) - t_qx(lt, x = 0, t = 2) # Vectorized with tidy output t_qx(lt, x = c(0, 1), t = c(1.5, 2.2), frac = "Balducci", tidy = TRUE) # Use in a tidy pipeline if (requireNamespace("dplyr", quietly = TRUE)) { tibble::tibble(age = c(0, 1, 2), duration = c(3, 2.5, 1.7)) |> dplyr::mutate( surv = t_px(lt, x = age, t = duration), death = t_qx(lt, x = age, t = duration) ) }
Computes , the probability that a life aged x
decrements by a specific cause j within t years, using a multiple
decrement table produced by md_table.
t_qxj(md, x, t, cause, frac = NULL, tidy = FALSE, check = TRUE, tol = 1e-10)t_qxj(md, x, t, cause, frac = NULL, tidy = FALSE, check = TRUE, tol = 1e-10)
md |
A multiple decrement table produced by |
x |
Numeric vector. Starting age(s) (integer-valued). |
t |
Numeric vector. Time horizon(s) in years (t >= 0). Can be non-integer
if |
cause |
Character. Name of the cause column in |
frac |
Character. Fractional-age assumption for non-integer |
tidy |
Logical. If |
check |
Logical. If |
tol |
Numeric tolerance for integer checks (default |
Let be the annual decrement probability for cause and
be the total decrement probability. For integer ,
For non-integer with and
, this function supports fractional-age assumptions specified
by frac and uses the additional convention that the within-year cause
proportions remain constant:
where
(and 0 when ).
Supported fractional-age assumptions for the total decrement:
"UDD": .
"CF": .
"Balducci": .
Numeric vector of (or tibble if tidy=TRUE).
qx_df <- tibble::tibble( x = 30:35, q_death = c(0.001, 0.0012, 0.0014, 0.0017, 0.0020, 1.0000), q_disability = c(0.002, 0.0021, 0.0022, 0.0023, 0.0024, 0.0000) ) md <- md_table(qx_df, radix = 1e5, close = TRUE) t_qxj(md, x = 30, t = 5, cause = "q_death") t_qxj(md, x = 30, t = 2.5, cause = "q_death", frac = "CF", tidy = TRUE)qx_df <- tibble::tibble( x = 30:35, q_death = c(0.001, 0.0012, 0.0014, 0.0017, 0.0020, 1.0000), q_disability = c(0.002, 0.0021, 0.0022, 0.0023, 0.0024, 0.0000) ) md <- md_table(qx_df, radix = 1e5, close = TRUE) t_qxj(md, x = 30, t = 5, cause = "q_death") t_qxj(md, x = 30, t = 2.5, cause = "q_death", frac = "CF", tidy = TRUE)
Builds a tibble-first representation of a discrete yield curve and computes the corresponding spot discount factors, using compact actuarial notation.
yield_curve( .data = NULL, t = NULL, i = NULL, col_t = "t", col_i = "i", i_type = "effective", m = 1L, plot = FALSE, .out = "v", .out_plot = "yield_curve_plot", .keep = c("all", "used", "none"), .na = c("propagate", "error", "drop") )yield_curve( .data = NULL, t = NULL, i = NULL, col_t = "t", col_i = "i", i_type = "effective", m = 1L, plot = FALSE, .out = "v", .out_plot = "yield_curve_plot", .keep = c("all", "used", "none"), .na = c("propagate", "error", "drop") )
.data |
A data frame or tibble. If |
t |
Numeric vector of maturities in years when |
i |
Numeric vector of spot-rate values when |
col_t |
Name of the list-column containing maturities. |
col_i |
Name of the list-column containing spot rates. |
i_type |
Character vector indicating the spot-rate type. Allowed values
are |
m |
Positive integer vector giving the conversion frequency for nominal spot rates. May have length 1 or the same length as each curve. |
plot |
Logical. If |
.out |
Name of the output list-column containing discount factors. |
.out_plot |
Name of the output list-column containing |
.keep |
One of |
.na |
Missing-value handling policy: |
Each row is treated as one curve. For tibble input, col_t and
col_i must identify list-columns of equal-length numeric vectors.
When .data = NULL, t and i must be numeric vectors and
a one-row tibble is returned.
The discount factors are computed as:
where is the annual effective spot rate for maturity .
If plot = TRUE, the function also returns a list-column of
ggplot2 objects showing the spot yield curve for each row.
This function follows the compact actuarial notation used throughout
tidyactuarial: t denotes maturity, i denotes the spot
rate, i_type denotes the interest-rate type, and m denotes the
conversion frequency for nominal spot rates.
The spot-rate input is converted to annual effective form through
standardize_interest before discount factors are computed.
A tibble. By default, it returns the original columns plus a new
list-column named by .out containing discount-factor vectors. If
plot = TRUE, it also adds a list-column named by .out_plot
containing ggplot2 objects.
Marcel B. Finan, A Basic Course in the Theory of Interest and Derivatives Markets: A Preparation for the Actuarial Exam FM/2, Section 53: The Term Structure of Interest Rates and Yield Curves.
Kellison, S. G. The Theory of Interest.
forward_rate,
discount_factor_spot, standardize_interest
Other interest:
discount_factor_spot(),
forward_rate(),
interest_equivalents(),
standardize_interest()
# Simple example res <- yield_curve( t = c(1, 2, 3, 4, 5), i = c(0.040, 0.045, 0.048, 0.050, 0.051), plot = TRUE ) res$yield_curve_plot[[1]] # Multiple curves in a tibble curves <- tibble::tibble( curve_id = c("A", "B"), t = list(c(1, 2, 3), c(1, 3, 5)), i = list(c(0.04, 0.05, 0.06), c(0.03, 0.035, 0.04)) ) res2 <- yield_curve( curves, col_t = "t", col_i = "i", plot = TRUE, .out = "v", .out_plot = "curve_plot" ) res2$curve_plot[[2]] # Nominal annual spot rates convertible semiannually yield_curve( t = c(1, 2, 3), i = c(0.05, 0.055, 0.06), i_type = "nominal_interest", m = 2 )# Simple example res <- yield_curve( t = c(1, 2, 3, 4, 5), i = c(0.040, 0.045, 0.048, 0.050, 0.051), plot = TRUE ) res$yield_curve_plot[[1]] # Multiple curves in a tibble curves <- tibble::tibble( curve_id = c("A", "B"), t = list(c(1, 2, 3), c(1, 3, 5)), i = list(c(0.04, 0.05, 0.06), c(0.03, 0.035, 0.04)) ) res2 <- yield_curve( curves, col_t = "t", col_i = "i", plot = TRUE, .out = "v", .out_plot = "curve_plot" ) res2$curve_plot[[2]] # Nominal annual spot rates convertible semiannually yield_curve( t = c(1, 2, 3), i = c(0.05, 0.055, 0.06), i_type = "nominal_interest", m = 2 )