Source code for fastlife.model.Projection.Policy

"""Policy data and attributes

This Space contains policy data and Cells associated with
policy attributes and policy values.

.. rubric:: References

Attributes:
    PolicyData: `PandasData`_ object holding model point data as a pandas
        DataFrame read from the model point file.
    ProductSpec: `ExcelRange`_ object which is a dict like object for associating
        product spec parameters to model point keys.
    LifeTable: Alias for :mod:`~fastlife.model.LifeTable`
    PremTerm: Alias for :func:`PolicyTerm`


.. _PandasData:
   https://docs.modelx.io/en/latest/reference/dataclient.html#pandasdata

.. _ExcelRange:
   https://docs.modelx.io/en/latest/reference/dataclient.html#excelrange

"""

from modelx.serialize.jsonvalues import *

_formula = None

_bases = []

_allow_none = True

_spaces = []

# ---------------------------------------------------------------------------
# Cells

[docs]def AnnPremRate(): """Annualized Premium Rate per Sum Assured""" return GrossPremRate() * PremFreq().mask(PremFreq() == 0, other=1/10)
[docs]def CashValueRate(t): """Cash Value Rate per Sum Assured""" return np.maximum(ReserveNLP_Rate('PREM', t) - SurrCharge(t), 0)
[docs]def GrossPremRate(): """Gross Premium Rate per Sum Assured per payment""" def get_value(pol): prod = pol['Product'] alpha = pol['LoadAcqSA'] beta = pol['LoadMaintPrem'] delta = pol['LoadMaintPrem2'] gamma = pol['LoadMaintSA'] gamma2 = pol['LoadMaintSA2'] freq = pol['PremFreq'] x, n, m = pol['IssueAge'], pol['PolicyTerm'], pol['PolicyTerm'] comf = LifeTable[pol['Sex'], pol['IntRate_PREM'], pol['TableID_PREM']] if prod == 'TERM' or prod == 'WL': return (comf.Axn(x, n) + alpha + gamma * comf.AnnDuenx(x, n, freq) + gamma2 * comf.AnnDuenx(x, n-m, 1, m)) / (1-beta-delta) / freq / comf.AnnDuenx(x, m, freq) elif prod == 'ENDW': return (comf.Exn(x, n) + comf.Axn(x, n) + alpha + gamma * comf.AnnDuenx(x, n, freq) + gamma2 * comf.AnnDuenx(x, n-m, 1, m)) / (1-beta-delta) / freq / comf.AnnDuenx(x, m, freq) else: raise ValueError('invalid product') result = PolicyDataExt1().apply(get_value, axis=1) result.name = 'GrossPremRate' return result
[docs]def GrossPremTable(): """Gross premium table""" return None
[docs]def InitSurrCharge(): """Initial Surrender Charge Rate""" def get_value(pol): prod, polt, gen = pol['Product'], pol['PolicyType'], pol['Gen'] term = pol['PolicyTerm'] param1 = SpecLookup.match("SurrChargeParam1", prod, polt, gen).value param2 = SpecLookup.match("SurrChargeParam2", prod, polt, gen).value if param1 is None or param2 is None: raise ValueError('SurrChargeParam not found') return param1 + param2 * min(term / 10, 1) result = PolicyData().apply(get_value, axis=1) result.name = 'InitSurrCharge' return result
[docs]def IntRate(RateBasis): """Interest Rate""" if RateBasis == 'PREM': basis = 'IntRatePrem' elif RateBasis == 'VAL': basis = 'IntRateVal' else: raise ValueError('invalid RateBasis') def get_value(pol): result = SpecLookup.match(basis, pol["Product"], pol["PolicyType"], pol["Gen"]).value if result is not None: return result else: raise ValueError('lookup failed') result = PolicyData().apply(get_value, axis=1) result.name = 'IntRate_' + RateBasis return result
[docs]def LoadAcqSA(): """Acquisition Loading per Sum Assured""" param1 = Product().apply(lambda prod: SpecLookup("LoadAcqSAParam1", prod)) param2 = Product().apply(lambda prod: SpecLookup("LoadAcqSAParam2", prod)) result = param1 + param2 * np.minimum(PolicyTerm() / 10, 1) result.name = 'LoadAcqSA' return result
[docs]def LoadMaintPrem(): """Maintenance Loading per Gross Premium""" def get_value(pol): if SpecLookup("LoadMaintPremParam1", pol["Product"]) is not None: return SpecLookup("LoadMaintPremParam1", pol["Product"]) elif SpecLookup("LoadMaintPremParam2", pol["Product"]) is not None: param = SpecLookup("LoadMaintPremParam2", pol["Product"]) return (param + min(10, pol["PolicyTerm"])) / 100 else: raise ValueError('LoadMaintPrem parameters not found') result = PolicyData().apply(get_value, axis=1) result.name = 'LoadMaintPrem' return result
[docs]def LoadMaintSA(): """Maintenance Loading per Sum Assured during Premium Payment""" def get_value(pol): result = SpecLookup.match("LoadMaintSA", pol["Product"], pol["PolicyType"], pol["Gen"]).value if result is not None: return result else: raise ValueError('lookup failed') result = PolicyData().apply(get_value, axis=1) result.name = 'LoadMaintSA' return result
[docs]def LoadMaintSA2(): """Maintenance Loading per Sum Assured after Premium Payment""" def get_value(pol): result = SpecLookup.match("LoadMaintSA2", pol["Product"], pol["PolicyType"], pol["Gen"]).value if result is not None: return result else: raise ValueError('lookup failed') result = PolicyData().apply(get_value, axis=1) result.name = 'LoadMaintSA2' return result
[docs]def NetPremRate(basis): """Net Premium Rate""" def get_value(pol): prod = pol['Product'] gamma2 = pol['LoadMaintSA2'] x, n, m = pol['IssueAge'], pol['PolicyTerm'], pol['PolicyTerm'] comf = LifeTable[pol['Sex'], pol['IntRate_' + basis], pol['TableID_' + basis]] if prod == 'TERM' or prod == 'WL': return (comf.Axn(x, n) + gamma2 * comf.AnnDuenx(x, n-m, 1, m)) / comf.AnnDuenx(x, n) elif prod == 'ENDW': return (comf.Axn(x, n) + gamma2 * comf.AnnDuenx(x, n-m, 1, m)) / comf.AnnDuenx(x, n) else: raise ValueError('invalid product') result = PolicyDataExt1().apply(get_value, axis=1) result.name = 'NetPremRate_' + basis return result
[docs]def ReserveNLP_Rate(basis, t): """Net level premium reserve rate""" def get_value(pol): prod = pol['Product'] gamma2 = pol['LoadMaintSA2'] netp = pol['NetPremRate_' + basis] x, n, m = pol['IssueAge'], pol['PolicyTerm'], pol['PolicyTerm'] lt = LifeTable[pol['Sex'], pol['IntRate_' + basis], pol['TableID_' + basis]] if t <= m: return lt.Axn(x+t, n-t) + (gamma2 * lt.AnnDuenx(x+t, n-m, 1, m-t) - netp * lt.AnnDuenx(x+t, m-t)) elif t <=n: return lt.Axn(x+t, n-t) + gamma2 * lt.AnnDuenx(x+t, n-m, 1, m-t) else: return 0 result = PolicyDataExt2().apply(get_value, axis=1) result.name = 'ReserveNLP_Rate' return result
[docs]def ReserveRate(): """Valuation Reserve Rate per Sum Assured""" return None
[docs]def SurrCharge(t): """Surrender Charge Rate per Sum Assured""" m = PremTerm() return InitSurrCharge() * np.maximum((np.minimum(m, 10) - t) / np.minimum(m, 10), 0)
[docs]def TableID(RateBasis): """Mortality Table ID""" if RateBasis == 'PREM': basis = "MortTablePrem" elif RateBasis == 'VAL': basis = "MortTableVal" else: raise ValueError('invalid RateBasis') def get_value(pol): result = SpecLookup.match(basis, pol["Product"], pol["PolicyType"], pol["Gen"]).value if result is not None: return result else: raise ValueError('lookup failed') result = PolicyData().apply(get_value, axis=1) result.name = 'TableID_' + RateBasis return result
[docs]def UernPremRate(): """Unearned Premium Rate""" return None
Product = lambda: PolicyData()['Product'] PolicyType = lambda: PolicyData()['PolicyType'] Gen = lambda: PolicyData()['Gen'] Channel = lambda: PolicyData()['Channel'] Sex = lambda: PolicyData()['Sex'] Duration = lambda: PolicyData()['Duration'] IssueAge = lambda: PolicyData()['IssueAge'] PremFreq = lambda: PolicyData()['PremFreq'] PolicyTerm = lambda: PolicyData()['PolicyTerm'] PolicyCount = lambda: PolicyData()['PolicyCount'] SumAssured = lambda: PolicyData()['SumAssured']
[docs]def LoadMaintPrem2(): """Maintenance Loading per Gross Premium for Premium Waiver""" result = pd.Series(0.002, index=PolicyData().index) result[PremTerm() < 10] = 0.001 result[PremTerm() < 5] = 0.0005 result.name = 'LoadMaintPrem2' return result
[docs]def PolicyDataExt1(): """Extended Poicy Data""" data = pd.concat([PolicyData(), LoadAcqSA(), LoadMaintPrem(), LoadMaintPrem2(), LoadMaintSA(), LoadMaintSA2(), IntRate('PREM'), TableID('PREM')], axis=1) return data
[docs]def PolicyDataExt2(): """Extended Poicy Data""" data = pd.concat([PolicyDataExt1(), NetPremRate('PREM')], axis=1) return data
[docs]def SpecLookup(spec, prod=None, polt=None, gen=None): """Look up product specs""" return ProductSpec.get((spec, prod, polt, gen), None)
# --------------------------------------------------------------------------- # References LifeTable = ("Interface", ("...", "LifeTable"), "auto") PremTerm = ("Interface", (".", "PolicyTerm"), "auto") ProductSpec = ("Pickle", 3020542092744) PolicyData = ("Pickle", 3020548337160)