JuliaActuary is focused on building packages that enable actuaries everywhere to build solutions using open-source tools.
The packages utilize all of the benefits of the Julia language and:
provide easy access and clean interface to mortality tables (MortalityTables.jl)
bundle a set of commonly used financial and math functions (ActuaryUtiltities.jl)
provide an easy interface to many common life contingent maths (LifeContingencies.jl)
Simple, yet powerful interest rate and yield curve functions (Yields.jl)
Exposure calculations with ExperienceAnalysis.jl
These packages are available for use in your project. Keep scrolling down for more info on each one.
Name | Description | Development Status |
---|---|---|
MortalityTables.jl | Easily work with standard mort.SOA.org tables and parametric models with common survival calculations. | Stable |
LifeContingencies.jl | Insurance, annuity, premium, and reserve maths. | Stable |
ActuaryUtilities.jl | Robust and fast calculations for internal_rate_of_return , duration , convexity , present_value , breakeven , and more. New! Copy/paste to and from Excel. | Stable |
Yields.jl | Simple and composable yield curves and calculations. | Developing Functionality is mostly built-out, but the API may change. |
ExperienceAnalysis.jl | Meeting your exposure calculation needs. | Developing Functionality is mostly built-out, but the API may change. |
There are two ways to add packages:
In the code itself: using Pkg; Pkg.add("MortalityTables")
In the REPL, hit ]
to enter Pkg mode and type add MortalityTables
More info can be found at the Pkg manager documentation.
To use packages in your code:
using PackageName
Hassle-free mortality and other rate tables.
Lots of bundled SOA mort.soa.org tables
survival
and decrement
functions to calculate decrements over period of time
Partial year mortality calculations (Uniform, Constant, Balducci)
Friendly syntax and flexible usage
Extensive set of parametric mortality models.
Loading the package and bundled tables:
julia> using MortalityTables
julia> tables = MortalityTables.tables()
Dict{String,MortalityTable} with 266 entries:
"2015 VBT Female Non-Smoker RR90 ALB" => SelectUltimateTable{OffsetArray{OffsetArray{Float64,1,Array{Float64,1}},1,Array{OffsetArray{F…
"2017 Loaded CSO Preferred Structure Nonsmoker Preferred Female ANB" => SelectUltimateTable{OffsetArray{OffsetArray{Float64,1,Array{Float64,1}},1,Array{OffsetArray{F…
⋮ => ⋮
Get information about a particular table:
julia> vbt2001 = tables["2001 VBT Residual Standard Select and Ultimate - Male Nonsmoker, ANB"]
MortalityTable (Insured Lives Mortality):
Name:
2001 VBT Residual Standard Select and Ultimate - Male Nonsmoker, ANB
Fields:
(:select, :ultimate, :metadata)
Provider:
Society of Actuaries
mort.SOA.org ID:
1118
mort.SOA.org link:
https://mort.soa.org/ViewTable.aspx?&TableIdentity=1118
Description:
2001 Valuation Basic Table (VBT) Residual Standard Select and Ultimate Table - Male Nonsmoker.
Basis: Age Nearest Birthday.
Minimum Select Age: 0.
Maximum Select Age: 99.
Minimum Ultimate Age: 25.
Maximum Ultimate Age: 120
The package revolves around easy-to-access vectors which are indexed by attained age:
julia> vbt2001.select[35] # vector of rates for issue age 35
0.00036
0.00048
⋮
0.94729
1.0
julia> vbt2001.select[35][35] #issue age 35, attained age 35
0.00036
julia> vbt2001.ultimate[95] # ultimate vectors only need to be called with the attained age
0.24298
Calculate the force of mortality or survival over a range of time:
julia> survival(vbt2001.ultimate,30,40) # the survival between ages 30 and 40
0.9894404665434904
julia> decrement(vbt2001.ultimate,30,40) # the decrement between ages 30 and 40
0.010559533456509618
Over 20 different models included. Example with the Gompertz
model
m = MortalityTables.Gompertz(a=0.01,b=0.2)
m[20] # the mortality rate at age 20
decrement(m,20,25) # the five year cumulative mortality rate
survival(m,20,25) # the five year survival rate
MortalityTables package on Github 🡭
A collection of common functions/manipulations used in Actuarial Calculations.
duration
:
Calculate the Macaulay
, Modified
, or DV01
durations for a set of cashflows
convexity
for price sensitivity
Flexible interest rate options via the Yields.jl
package.
internal_rate_of_return
or irr
to calculate the IRR given cashflows (including at timepoints like Excel's XIRR
)
breakeven
to calculate the breakeven time for a set of cashflows
accum_offset
to calculate accumulations like survivorship from a mortality vector
duration
:
Calculate the duration given an issue date and date (a.k.a. policy duration)
You can also copy/paste to/from Excel:
xlcopy()
copies and parses Excel content on the clipboard
xlcopy(data)
will copy Julia data into your clipboard for pasting into Excel.
ActuaryUtilities package on GitHub 🡭
Common life contingent calculations with a convenient interface.
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
Leverages MortalityTables.jl for
the mortality calculations
Contains common insurance calculations such as:
Insurance(life,yield)
: Whole life
Insurance(life,yield,n)
: Term life for n
years
ä(life,yield)
: Life contingent annuity due
ä(life,yield)
: Life contingent annuity due for n
years
Contains various commutation functions such as D(x)
,M(x)
,C(x)
, etc.
SingleLife
and JointLife
capable
Interest rate mechanics via Yields.jl
More documentation available by clicking the DOCS badges at the top of this README
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
tbls = MortalityTables.tables()
vbt2001 = tbls["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!
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
LifeContingencies package on GitHub 🡭
Flexible and composable yield curves and interest functions.
Provides a simple interface for constructing, manipulating, and using yield curves for modeling purposes.
It's intended to provide common functionality around modeling interest rates, spreads, and miscellaneous yields across the JuliaActuary ecosystem (though not limited to use in JuliaActuary packages).
using Yields
riskfree_maturities = [0.5, 1.0, 1.5, 2.0]
riskfree = [5.0, 5.8, 6.4, 6.8] ./ 100 #spot rates
spread_maturities = [0.5, 1.0, 1.5, 3.0] # different maturities
spread = [1.0, 1.8, 1.4, 1.8] ./ 100 # spot spreads
rf_curve = Yields.Zero(riskfree,riskfree_maturities)
spread_curve = Yields.Zero(spread,spread_maturities)
yield = rf_curve + spread_curve # additive combination of the two curves
discount(yield,1.0) # 1 / (1 + 0.058 + 0.018)
Meeting your exposure calculation needs.
using ExperienceAnalysis
using Dates
issue = Date(2016, 7, 4)
termination = Date(2020, 1, 17)
basis = ExperienceAnalysis.Anniversary(Year(1))
exposure(basis, issue, termination)
This will return an array of tuples with a from
and to
date:
4-element Array{NamedTuple{(:from, :to),Tuple{Date,Date}},1}:
(from = Date("2016-07-04"), to = Date("2017-07-04"))
(from = Date("2017-07-04"), to = Date("2018-07-04"))
(from = Date("2018-07-04"), to = Date("2019-07-04"))
(from = Date("2019-07-04"), to = Date("2020-01-17"))
ExperienceAnalysis.Anniversary(period)
will give exposures periods based on the first date
ExperienceAnalysis.Calendar(period)
will follow calendar periods (e.g. month or year)
ExperienceAnalysis.AnniversaryCalendar(period,period)
will split into the smaller of the calendar or policy period.
Where period
is a Period Type from the Dates standard library.
Calculate exposures with exposures(basis,from,to,continue_exposure)
.
continue_exposures
indicates whether the exposure should be extended through the full exposure period rather than terminate at the to
date.
ExperienceAnalysis package on GitHub 🡭
Resources to help get started.
JuliaLang.org, the home site with the downloads to get started, and links to learning resources.
JuliaHub indexes open-source Julia packages and makes the entire ecosystem and documentation searchable from one place.
JuliaAcademy, which has free short courses in Data Science, Introduction to Julia, DataFrames.jl, Machine Learning, and more.
Data Science Tutorials from the Alan Turing Institute.
Learn Julia in Y minutes, a great quick-start if you are already comfortable with coding.
Think Julia, a free e-book (or paid print edition) book which introduces programming from the start and teaches you valuable ways of thinking.
Design Patterns and Best Practices, a book that will help you as you transition from smaller, one-off scripts to designing larger packages and projects.
Each package includes examples on the Github site and in the documentation.
Coming soon!
Interactive exploration of the AAA's Economic Scenario Generator
Interactive mortality table comparison tool for any mort.soa.org
table
Universal Life Policy Account Mechanics as a Differential Equation
You can also access help text when using the packages in the REPL by activating help mode, e.g.:
julia> ? survival
survival(mortality_vector,to_age)
survival(mortality_vector,from_age,to_age)
Returns the survival through attained age to_age. The start of the
calculation is either the start of the vector, or attained age `from_age`
and `to_age` need to be Integers.
Add a DeathDistribution as the last argument to handle floating point
and non-whole ages:
survival(mortality_vector,to_age,::DeathDistribution)
survival(mortality_vector,from_age,to_age,::DeathDistribution)
If given a negative to_age, it will return 1.0. Aside from simplifying the code,
this makes sense as for something to exist in order to decrement in the first place,
it must have existed and surived to the point of being able to be decremented.
Examples
≡≡≡≡≡≡≡≡≡≡
julia> qs = UltimateMortality([0.1,0.3,0.6,1]);
julia> survival(qs,0)
1.0
julia> survival(qs,1)
0.9
julia> survival(qs,1,1)
1.0
julia> survival(qs,1,2)
0.7
julia> survival(qs,0.5,Uniform())
0.95
Julia integrates with other languages, allowing you to leverage existing scripts and packages in R via RCall and in Python via PyCall.
Thank you for your interest in modern actuarial solutions, no matter how you participate in the community.Help by contributing code, asking questions, or reporting issues.
The packages in JuliaActuary are open-source and liberally licensed (MIT License) to allow wide private and commercial usage of the packages, like the base Julia language and many other packages in the ecosystem.
JuliaActuary is open source; you are free to modify, use, or change your copy of the code - but if you make enhancements please consider opening a pull request (basic walkthrough here).
If you find issues, please open an issue on the relevant package's repository and we will try and address it as soon as possible.
If you have other ideas or questions, feel free to also open an issue, or discuss on the community Zulip or Slack #actuary channel. We welcome all actuarial and related disciplines!
For more directed inquires, please send email to inquiry@JuliaActuary.org.
Building the insurance company of tomorrow by being a 10x actuary.
Why Julia works so well for actuarial science.