Source code for nestedlife.lifetable

"""Source module to create ``LifeTable`` space from.

This is a source module to create ``LifeTable`` space and its
sub spaces from.

This module is passed to ``import_module`` method to create
a space that contains cells that defines life tables and commutation functions,
for a selected combination of ``Sex``, ``IntRate`` and ``MortalityTable``.

``MortalityTable`` and ``Sex`` are used in :py:func:`qx` below to identify
the mortality rates to be applied.

Example
    Sample script::

        from modelx import *
        space = new_model().import_module(module=lifetable)
        space.Sex = 'M'
        space.IntRate = 0.03
        space.MortalityTable = lambda sex, x: 0.001 if x < 110 else 1

References:
    * `International actuarial notation by F.S.Perryman <https://www.casact.org/pubs/proceed/proceed49/49123.pdf>`_

.. rubric:: Project Templates

This module is included in the following project templates.

* :mod:`simplelife`
* :mod:`nestedlife`

.. rubric:: References in Sub

Attributes:
    Sex: 'M' or 'F' to indicate male or female column in the mortality table.
    IntRate: The constant interest rate for discounting.
    MortalityTable: The ultimate mortality table by sex and age.

"""


[docs]def disc(): """The discount factor :math:`v = 1/(1 + i)`.""" return 1 / (1 + IntRate)
[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 dx(x): """The number of persons who die between ages ``x`` and ``x+1``""" return lx(x) * qx(x)
[docs]def qx(x): """Probability that a person at age ``x`` will die in one year.""" return MortalityTable(Sex, x)
[docs]def Dx(x): """The commutation column :math:`D_{x} = l_{x}v^{x}`. """ return lx(x) * disc ** x
[docs]def Cx(x): """The commutation column :math:`\\overline{C_x}`. """ return dx(x) * disc**(x+1/2)
[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 Mx(x): """The commutation column :math:`M_x`.""" if x >= 110: return Dx(x) else: return Mx(x+1) + Cx(x)
[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 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 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