"""Source module for IFRS17 CSM amortization simulation
This module contains formulas to simulate amortization of
contract service margin (CSM) defined in IFRS17.
This module is a mix-in module to projection module in nestedlife project.
"""
from modelx.serialize.jsonvalues import *
_formula = None
_bases = []
_allow_none = None
_spaces = []
# ---------------------------------------------------------------------------
# Cells
[docs]def AccumCF(t):
    """Accumulated cashflows"""
    return -NetInsurAssets(t) 
[docs]def AcqPremRatio():
    """Ratio of PV Acquisiton Cashflows to PV Premiums.
    The ratio is determined by the expectation at issue.
    """
    pvs = InnerProj(0).PV(0)
    return ((pvs.PV_ExpsCommTotal(0) + pvs.PV_ExpsAcq(0))
            / pvs.PV_PremIncome(0)) 
[docs]def ActualNetCF(t):
    """Acutal net cashflow"""
    return NetInsurCF(t) + IntAccumCF(t) 
[docs]def AdjCSM_FlufCF(t):
    """Adjustment to CSM for changes in fulfilment cashflows (44(c)->B96-B100)
    Warnings:
        Only B96(b) changes in PV of the future cashflows are implemented.
    TODO: Risk Adjustment is yet to be implemented. At the momement
    this adjustment only considers present value of future cashflows.
    TODO: Loss component for onerous contracts are yet to be implemented.
    At the momemnt this adjustment allows negative CSM.
    """
    return PV_Cashflow(t + 1, t + 1, 0) - PV_Cashflow(t, t + 1, 0) 
[docs]def AdjLCO_FulfCF(t):
    """Adjustment to Loss Component for changes in fulfilment cashflows"""
    if LossComp(t) > 0:
        return min(LossComp(t), EstClaim(t) + EstExps(t) + RelsRiskAdj(t))
    else:
        return 0 
[docs]def AmortAcqCashflow(t):
    """Amortization of Acquisition Cash Flows
    Warning:
        Implemented as a constant percentage of actual premiums,
        thus not totalling the original amount if actual != expected.
    """
    return -AcqPremRatio * PremIncome(t) 
[docs]def AsmpChangeImpact(t):
    """Non-financial assumption changes"""
    return PV_Cashflow(t + 1, t + 1, 0) - PV_Cashflow(t, t + 1, 0) 
[docs]def CSM(t):
    """floored CSM (38, 44)"""
    if t == 0:
        # Initial recognition (38)
        return max(0, PV_FutureCF(t) - RiskAdjustment(t))
    else:
        # Subsequent recognition (44)
        return max(0, (CSM(t - 1)
                + IntAccrCSM(t - 1)
                + AdjCSM_FlufCF(t - 1)
                - TransServices(t - 1))) 
[docs]def CSM_Unfloored(t):
    """Unfloored CSM (38, 44)"""
    if t == 0:
        # Initial recognition (38)
        return PV_FutureCF(t) - RiskAdjustment(t)
    else:
        # Subsequent recognition (44)
        return (CSM_Unfloored(t-1)
                + IntAccrCSM(t-1)
                + AdjCSM_FlufCF(t-1)
                - TransServices(t-1)) 
[docs]def CovUnitsBeg1(t):
    """The number of coverage units at `t` after new business"""
    return InsurIF_Beg1(t) 
[docs]def CovUnitsEnd(t):
    """The number of coverage units at `t`"""
    return InsurIF_End(t) 
[docs]def EstAcqCashflow(t):
    """Expected Acquisition Cashflow"""
    est = InnerProj(t)
    return (est.ExpsCommInit(t)
            + est.ExpsCommRen(t)
            + est.ExpsAcq(t)) 
[docs]def EstClaim(t):
    """Expected Claims
    Warning:
        Using actuarl invest componets as proxy.
    """
    est = InnerProj(t)
    return est.BenefitTotal(t) - InvstComponent(t) 
[docs]def EstExps(t):
    """Expected Expenses"""
    est = InnerProj(t)
    return (est.ExpsTotal(t)
            - est.ExpsCommInit(t)
            - est.ExpsCommRen(t)
            - est.ExpsAcq(t)) 
[docs]def EstIntOnCF(t):
    """Expected Interest on future cashflows"""
    return InnerProj(t).PV(t).InterestNetCF(t) 
[docs]def EstPremIncome(t):
    """Expected Premium Income"""
    return InnerProj(t).PremIncome(t) 
[docs]def Incr_LossComp(t):
    """Increase in Loss Component"""
    if t == 0:
        return LossComp(t)
    else:
        return max(0, LossComp(t) - LossComp(t - 1)) 
[docs]def IncurClaim(t):
    """Incurred Claims"""
    return BenefitTotal(t) - InvstComponent(t) 
[docs]def IncurExps(t):
    """Incurred Expenses"""
    return (ExpsTotal(t) - ExpsCommTotal(t) - ExpsAcq(t)) 
[docs]def InsServiceResult(t):
    """Insurance Service Result (80(a), 83-86)"""  
    return InsurRevenue(t) - InsurServiceExps(t) 
[docs]def InsurFinIncomeExps(t):
    """Insurance Finance Income or Expenses (80(b), 87-92, B128-B136)
    Warning:
        Accounting Policy Choice 88(b) not implemented.
    """
    chg_discrate = (PV_Cashflow(t + 1, t + 1, t + 1)
                    - PV_Cashflow(t + 1, t + 1, t))
    return (EstIntOnCF(t) + chg_discrate 
            - IntAccrCSM(t) + IntAccumCF(t)) 
[docs]def InsurRevenue(t):
    """Insurance Revenue (82-85, B120-B125)"""
    return (EstClaim(t)
            + EstExps(t)
            + RelsRiskAdj(t)
            + TransServices(t)
            + AmortAcqCashflow(t)
            - AdjLCO_FulfCF(t)) 
[docs]def InsurServiceExps(t):
    """Insurance Service Expense (103(b))"""
    return (IncurClaim(t)
            + IncurExps(t)
            + AmortAcqCashflow(t)
            + Incr_LossComp(t)
            - AdjLCO_FulfCF(t)) 
[docs]def IntAccrCSM(t):
    """Interest accreted on CSM (44(b))"""
    return CSM(t) * DiscRate(t, 0) 
[docs]def InvstComponent(t):
    """Investment Components in Incur Claims
    Warning:
        To be implemented.
    """
    return 0 
[docs]def LossComp(t):
    """Loss Component"""
    if t == 0:
        # Initial recognition
        return - min(0, PV_FutureCF(t) - RiskAdjustment(t))
    else:
        # Subsequent recognition
        return max(0, LossComp(t - 1) - AdjLCO_FulfCF(t - 1)) 
[docs]def NetBalance(t):
    """Net insurance assets plus accumulated cashflows."""
    return NetInsurAssets(t) + AccumCF(t) 
[docs]def NetInsurAssets(t):
    """Net Insurance Assets or Liabilities
    Warnings:
        The liabilities for incurred claims are not implemented. 
    """    
    return (PV_FutureCF(t)
            - RiskAdjustment(t)
            - CSM(t)) 
[docs]def PV_Cashflow(t, t_at, t_rate):
    """Present value of future cashflows
    This formula takes 3 time parameters.
    The projection starts from `t`, and the projected cashflows are
    discounted back to `t_at`.
    The discount rates applied are the ones at `t_rate`.
    Args:
        t: Time from which the projection
        t_at: Time discount rates at which are used.
        t_rate: Time to which the cashflows are discounted.
    """
    return InnerProj(t).PV(t_rate).PV_NetCashflow(t_at) 
[docs]def PV_FutureCF(t):
    """Present value of future cashflows"""
    return PV_Cashflow(t, t, t) 
[docs]def PV_SumCovUnits(t, t_rate):
    """Present value of cumulatvie coverage units
    The non-economic assumptions used for future estimation are the
    current estimate at time `t`.
    The discount rates used are the ones at time `t_rate`.
    """
    return InnerProj(t).PV(t_rate).PV_SumInsurIF(t) 
[docs]def ProfitBefTax(t):
    """IFRS Profit before tax"""
    return InsServiceResult(t) + InsurFinIncomeExps(t) 
[docs]def RelsRiskAdj(t):
    """Release of Risk Adjustment to Revenue
    Warning:
        To be implemented.
    """
    return 0 
[docs]def RiskAdjustment(t):
    """Risk Adjustment
    Warnings:
        To be implemented
    """
    return 0 
[docs]def TransServices(t):
    """Transfer of services (44(e)->B119)
    """
    csm_pre_rel = (CSM(t)
                   + IntAccrCSM(t)
                   + AdjCSM_FlufCF(t))
    diff_covunits = CovUnitsBeg1(t) * (1 + InnerProj(0).scen.DiscRate(t))
    pv_sumcovunits_end = PV_SumCovUnits(t + 1, 0)
    return csm_pre_rel * diff_covunits / (diff_covunits + pv_sumcovunits_end)