Actuarial Python

Actuarial Python#

The actuarialmath package is written in and requires Python (currently: version 3.10). Though the comparable R language possesses other desirable qualities, object-oriented programming is more straightforward in Python: since our sequence of actuarial concepts logically build upon each other, they are naturally developed as a hieararchy of Python classes with inherited methods and properties.

Installation#

Install either by using pip:

  • pip install actuarialmath

or cloning from github:

  • git clone https://github.com/terence-lim/actuarialmath.git

Overview#

Each section of this document introduces a class, along with the actuarial concepts it implements, arranged logically in three groups. To use the package, a suitable subclass should first be selected from the last group to load the given actuarial assumptions. Then the appropriate computational methods can be called, which may be inherited from the other general classes or make use of any shortcut formulas that can be obtained from the specific survival model assumed.

  1. Implement general actuarial methods

    • Basic interest theory and probability laws

    • Survival functions, expected future lifetimes and fractional ages

    • Insurance, annuity, premiums, policy values, and reserves calculations

  2. Adjust results for

    • Extra mortality risks

    • 1/mthly payment frequency using UDD or Woolhouse approaches

  3. Specify survival models and assumptions, and implement associated shortcut formulas

    • Recursion inputs

    • Life table, select life table, or standard ultimate life table

    • Mortality laws, such as constant force of maturity, beta and uniform distributions, or Makeham’s and Gompertz’s laws

License#

MIT License

Copyright (c) 2022-2023 Terence Lim

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

Methods#

The Actuarial base class provides some common helpful utility functions and definitions of constants, that are needed by other classes in the package.

from actuarialmath import Actuarial
import math
import describe
describe.methods(Actuarial)
class Actuarial - Define constants and common utility functions

    Constants:
      VARIANCE : select variance as the statistical moment to calculate

      WHOLE : indicates that term of insurance or annuity is Whole Life

    Methods:
    --------

    solve(fun, target, grid, mad):
      Solve root, or parameter that minimizes absolute value, of a function

    add_term(t, n):
      Add two terms, either term may be Whole Life

    max_term(x, t, u):
      Decrease term t if adding deferral period u to (x) exceeds maxage

    isclose(r, target, abs_tol):
      Is close to zero or target value

Examples#

The solve() method is called to impute the value of a parameter such that its function output value is equal to a specified target value, by either returning the zero root (set argument mad = False, by default) or minimizing the absolute difference (set mad = True). As a simple example, to solve for the median of the exponential cumulative distribution:

Actuarial.solve(fun=lambda x: 1 - math.exp(-x), target=0.5, grid=[0, 2])
0.6931471805599453

The add_term method adds two terms, while handling the case where either may not be a fixed term, i.e. they may be whole life and indicated with the constant WHOLE. The max_term method trims the value of a term t, such that its sum with age x and deferral period u is no larger than the maximum age

actuarial = Actuarial()

def as_term(t): return "WHOLE_LIFE" if t == Actuarial.WHOLE else t

for a,b in [(3, Actuarial.WHOLE), (Actuarial.WHOLE, -1), (3, 2), (3, -1)]:
    print(f"{as_term(a)} + {as_term(b)} =", as_term(actuarial.add_term(a, b)))
print()
for t in [10, 50, Actuarial.WHOLE]:
    print(as_term(t), '->', actuarial.max_term(x=65, t=t, u=20))
3 + WHOLE_LIFE = WHOLE_LIFE
WHOLE_LIFE + -1 = WHOLE_LIFE
3 + 2 = 5
3 + -1 = 2

10 -> 10
50 -> 15
WHOLE_LIFE -> 15