LifeContingencies.jl
LifeContingencies is a package enabling actuarial life contingent calculations.
Features
- Integration with other JuliaActuary packages such as MortalityTables.jl
- Fast calculations, with some parts utilizing parallel processing power automatically
- Use functions that look more like the math you are used to (e.g.
A
,ä
) with Unicode support - All of the power, speed, convenience, tooling, and ecosystem of Julia
- Flexible and modular modeling approach
Package Overview
- Leverages MortalityTables.jl for the mortality calculations
- Contains common insurance calculations such as:
Insurance(life,yield)
: Whole lifeInsurance(life,yield,n)
: Term life forn
yearsä(life,yield)
:present_value
of Life contingent annuityä(life,yield)
:present_value
of Life contingent annuity due forn
years
- Contains various commutation functions such as
D(x)
,M(x)
,C(x)
, etc. SingleLife
andJointLife
capable- Interest rate mechanics via
Yields.jl
- More documentation available by clicking the DOCS badges at the top of this README
Examples
Basic Functions
Calculate various items for a 30-year-old male nonsmoker using 2015 VBT base table and a 5% interest rate
using LifeContingencies
using MortalityTables
using Yields
import LifeConingencies: V, ä # pull the shortform notation into scope
# load mortality rates from MortalityTables.jl
vbt2001 = MortalityTables.table("2001 VBT Residual Standard Select and Ultimate - Male Nonsmoker, ANB")
issue_age = 30
life = SingleLife( # The life underlying the risk
mort = vbt2001.select[issue_age], # -- Mortality rates
)
yield = Yields.Constant(0.05) # Using a flat 5% interest rate
lc = LifeContingency(life, yield) # LifeContingency joins the risk with interest
ins = Insurance(lc) # Whole Life insurance
ins = Insurance(life, yield) # alternate way to construct
With the above life contingent data, we can calculate vectors of relevant information:
cashflows(ins) # A vector of the unit cashflows
timepoints(ins) # The timepoints associated with the cashflows
survival(ins) # The survival vector
benefit(ins) # The unit benefit vector
probability(ins) # The probability of beneift payment
Or calculate summary scalars:
present_value(ins) # The actuarial present value
premium_net(lc) # Net whole life premium
V(lc,5) # Net premium reserve for whole life insurance at time 5
Other types of life contingent benefits:
Insurance(lc,n=10) # 10 year term insurance
AnnuityImmediate(lc) # Whole life annuity due
AnnuityDue(lc) # Whole life annuity due
ä(lc) # Shortform notation
ä(lc, n=5) # 5 year annuity due
ä(lc, n=5, certain=5,frequency=4) # 5 year annuity due, with 5 year certain payable 4x per year
... # and more!
Constructing Lives
SingleLife(vbt2001.select[50]) # no keywords, just a mortality vector
SingleLife(vbt2001.select[50],issue_age = 60) # select at 50, but now 60
SingleLife(vbt2001.select,issue_age = 50) # use issue_age to pick the right select vector
SingleLife(mort=vbt2001.select,issue_age = 50) # mort can also be a keyword
Net Premium for Term Policy with Stochastic rates
Use a stochastic interest rate calculation to price a term policy:
using LifeContingencies, MortalityTables
using Distributions
vbt2001 = MortalityTables.table("2001 VBT Residual Standard Select and Ultimate - Male Nonsmoker, ANB")
# use an interest rate that's normally distirbuted
μ = 0.05
σ = 0.01
years = 100
int = Yields.Forward(rand(Normal(μ,σ), years))
life = SingleLife(
mort = vbt2001.select[30],
issue_age = 30
)
term = 10
Insurance(lc, n=term) # around 0.055
Extending example to use autocorrelated interest rates
You can use autocorrelated interest rates - substitute the following in the prior example using the ability to self reference:
σ = 0.01
initial_rate = 0.05
vec = fill(initial_rate,years)
for i in 2:length(vec)
vec[i] = rand(Normal(vec[i-1],σ))
end
int = Yields.Forward(vec)
Premium comparison across Mortality Tables
Compare the cost of annual premium, whole life insurance between multiple tables visually:
using LifeContingencies, MortalityTables, Plots
tables = [
MortalityTables.table("1980 CET - Male Nonsmoker, ANB"),
MortalityTables.table("2001 VBT Residual Standard Select and Ultimate - Male Nonsmoker, ANB"),
MortalityTables.table("2015 VBT Male Non-Smoker RR100 ANB"),
]
issue_ages = 30:90
int = Yields.Constant(0.05)
whole_life_costs = map(tables) do t
map(issue_ages) do ia
lc = LifeContingency(
SingleLife(
mort=t.ultimate,
issue_age=ia
),
int
)
premium_net(lc)
end
end
plt = plot(ylabel="Annual Premium per unit", xlabel="Issue Age",
legend=:topleft, legendfontsize=8,size=(800,600))
for (i,t) in enumerate(tables)
plot!(plt,issue_ages,whole_life_costs[i], label="$(t.d.name)")
end
display(plt)
Joint Life
m1 = MortalityTables.table("1986-92 CIA – Male Smoker, ANB")
m2 = MortalityTables.table("1986-92 CIA – Female Nonsmoker, ANB")
l1 = SingleLife(mort = m1.ultimate, issue_age = 40)
l2 = SingleLife(mort = m2.ultimate, issue_age = 37)
jl = JointLife(lives=(l1, l2), contingency=LastSurvivor(), joint_assumption=Frasier())
Insurance(jl) # whole life insurance
... # similar functions as shown in the first example above
Commutation and Unexported Function shorthand
Because it's so common to use certain variables in your own code, LifeContingencies avoids exporting certain variables/functions so that it doesn't collide with your own usage. For example, you may find yourself doing something like:
a = ...
b = ...
result = b - a
If you imported using LifeContingencies
and the package exported a
(annuity_immediate
) then you could have problems if you tried to do the above. To avoid this, we only export long-form functions like annuity_immediate
. To utilize the shorthand, you can include them into your code's scope like so:
using LifeContingencies # brings all the default functions into your scope
using LifeContingencies: a, ä # also brings the short-form annuity functions into scope
Or you can do the following:
using LifeContingencies # brings all the default functions into your scope
... # later on in the code
LifeContingencies.ä(...) # utilize the unexported function with the module name
For more on module scoping, see the Julia Manual section.
Actuarial notation shorthand
V => reserve_premium_net
v => discount
A => present value of Insurance
ä => present value of AnnuityDue
a => present value of AnnuityImmediate
P => premium_net
ω => omega
Commutation functions
l,
D,
M,
N,
C,
References
- Life Insurance Mathematics, Gerber
- Actuarial Mathematics and Life-Table Statistics, Slud
- Commutation Functions, MacDonald