Source code for annuallife.TradLife_A.CommTable
# modelx: pseudo-python
# This file is part of a modelx model.
# It can be imported as a Python module, but functions defined herein
# are model formulas and may not be executable as standard Python.
"""Commutation functions and actuarial notations.
The :mod:`~annuallife.TradLife_A.CommTable` Space provides commutation
functions and actuarial notations, such as :math:`D_{x}` and
:math:`\\require{enclose}{}_{f|}\\overline{A}_{x}`.
Mortality tables are read from the ``MortalityTables`` range in
*input.xlsx* through
:func:`~annuallife.TradLife_A.InputData.mortality_tables` and indexed
through :func:`mortality_rates`.
Parameters and References
-------------------------
This Space is parameterized with :attr:`Sex`, :attr:`IntRate` and
:attr:`TableID`::
>>> m.CommTable.parameters
('Sex', 'IntRate', 'Table')
Each ItemSpace represents commutation functions and actuarial notations
for a combination of :attr:`Sex`, :attr:`IntRate` and :attr:`TableID`.
For example, ``CommTable[SexID.M, 0.03, 1]`` contains commutation
functions and actuarial notations for Male, an interest rate of 3% and
mortality table 1.
Attributes:
Sex: A :mod:`~annuallife.TradLife_A.Enums.SexID` code identifying
the column in the mortality table.
IntRate(:obj:`float`): The constant interest rate for discounting.
Table: Identifier of the mortality table within
:func:`~annuallife.TradLife_A.InputData.mortality_tables`.
.. rubric:: References
Attributes:
mortality_tables: Alias for
:func:`~annuallife.TradLife_A.InputData.mortality_tables`.
Example:
An example of :mod:`~annuallife.TradLife_A.CommTable`::
>>> m.CommTable[SexID.M, 0.03, 1].AnnDuenx(40, 10)
8.725179890621531
External Links:
* `International actuarial notation by F.S.Perryman <https://www.casact.org/pubs/proceed/proceed49/49123.pdf>`_
* `Actuarial notations on Wikipedia <https://en.wikipedia.org/wiki/Actuarial_notation>`_
Cells Summary
-------------
Life Table
^^^^^^^^^^
The underlying life-table columns — survivors, deaths, mortality
probability and the per-age mortality rates selected for this Space's
sex and table.
.. autosummary::
~lx
~dx
~qx
~mortality_rates
Commutation Columns
^^^^^^^^^^^^^^^^^^^
The discount factor and the commutation columns :math:`D_x`,
:math:`C_x`, :math:`M_x` and :math:`N_x` built from the life table.
.. autosummary::
~disc
~Dx
~Cx
~Mx
~Nx
Assurances and Endowments
^^^^^^^^^^^^^^^^^^^^^^^^^
Present values of whole-life and term assurances and of pure
endowments.
.. autosummary::
~Ax
~Axn
~Exn
Annuities
^^^^^^^^^
Present values of temporary and lifetime annuities-due, with optional
split payments and deferment.
.. autosummary::
~AnnDuenx
~AnnDuex
"""
from modelx.serialize.jsonvalues import *
_formula = lambda Sex, IntRate, Table: None
_bases = []
_allow_none = None
_spaces = []
# ---------------------------------------------------------------------------
# Cells
[docs]
def AnnDuenx(x, n, k=1, f=0):
""" The present value of an annuity-due.
.. math::
\\require{enclose}{}_{f|}\\ddot{a}_{x:\\enclose{actuarial}{n}}^{(k)}
Args:
x(int): age
n(int): length of annuity payments in years
k(int, optional): number of split payments in a year
f(int, optional): waiting period in years
"""
if Dx(x) == 0:
return 0
result = (Nx(x+f) - Nx(x+f+n)) / Dx(x)
if k > 1:
return result - (k-1) / (2*k) * (1 - Dx(x+f+n) / Dx(x))
else:
return result
[docs]
def AnnDuex(x, k, f=0):
"""The present value of a lifetime annuity due.
Args:
x(int): age
k(int, optional): number of split payments in a year
f(int, optional): waiting period in years
"""
if Dx(x) == 0:
return 0
result = (Nx(x+f)) / Dx(x)
if k > 1:
return result - (k-1) / (2*k)
else:
return result
[docs]
def Ax(x, f=0):
"""The present value of a lifetime assurance on a person at age ``x``
payable immediately upon death, optionally with an waiting period of ``f`` years.
.. math::
\\require{enclose}{}_{f|}\\overline{A}_{x}
"""
if Dx(x) == 0:
return 0
else:
return Mx(x+f) / Dx(x)
[docs]
def Axn(x, n, f=0):
"""The present value of an assurance on a person at age ``x`` payable
immediately upon death, optionally with an waiting period of ``f`` years.
.. math::
\\require{enclose}{}_{f|}\\overline{A}^{1}_{x:\\enclose{actuarial}{n}}
"""
if Dx(x) == 0:
return 0
else:
return (Mx(x+f) - Mx(x+f+n)) / Dx(x)
[docs]
def Cx(x):
"""The commutation column :math:`\\overline{C_x}`.
"""
return dx(x) * disc()**(x+1/2)
[docs]
def Dx(x):
"""The commutation column :math:`D_{x} = l_{x}v^{x}`.
"""
return lx(x) * disc() ** x
[docs]
def Exn(x, n):
""" The value of an endowment on a person at age ``x``
payable after n years
.. math::
{}_{n}E_x
"""
if Dx(x) == 0:
return 0
else:
return Dx(x+n) / Dx(x)
[docs]
def Mx(x):
"""The commutation column :math:`M_x`."""
if x >= 110:
return Dx(x)
else:
return Mx(x+1) + Cx(x)
[docs]
def Nx(x):
"""The commutation column :math:`N_x`."""
if x >= 110: # TODO: Get the last age from the table
return Dx(x)
else:
return Nx(x+1) + Dx(x)
[docs]
def disc():
"""The discount factor :math:`v = 1/(1 + i)`."""
return 1 / (1 + IntRate)
[docs]
def dx(x):
"""The number of persons who die between ages ``x`` and ``x+1``"""
return lx(x) * qx(x)
[docs]
def lx(x):
"""The number of persons remaining at age ``x``. """
if x == 0:
return 100000
else:
return lx(x-1) - dx(x-1)
[docs]
def qx(x):
"""Probability that a person at age ``x`` will die in one year."""
return mortality_rates()[x]
[docs]
def mortality_rates():
"""Mortality rates for the selected ``Sex`` and ``Table``.
Selects the column of :func:`~annuallife.TradLife_A.InputData.mortality_tables`
matching this Space's :attr:`Table` and :attr:`Sex` parameters and
returns the resulting per-age mortality rate Series.
"""
pos = list((t, getattr(SexID, s)) for t, s in mortality_tables().columns).index((Table, Sex))
return mortality_tables().iloc[:, pos]
# ---------------------------------------------------------------------------
# References
Sex = "M"
IntRate = 0.01
TableID = 1
mortality_tables = ("Interface", ("..", "InputData", "mortality_tables"), "absolute")