Inspecting the Calculation Logic#

This notebook demonstrates how to inspect intermediate calculation results by outputting cached properties of various IScope objects.

In this notebook, we use the Template example. The last line of the code below executes template.py and imports workspace into this notebook.

Click the badge below to run this notebook online on Google Colab. You need a Google account and need to be logged in to it to run this notebook on Google Colab. Run on Google Colab

The next code cell below is relevant only when you run this notebook on Google Colab. It installs lifelib and creates a copy of the library for this notebook.

[1]:
import sys, os

if 'google.colab' in sys.modules:
    lib = 'ifrs17a'; lib_dir = '/content/'+ lib
    if not os.path.exists(lib_dir):
        !pip install lifelib
        import lifelib; lifelib.create(lib, lib_dir)

    %cd $lib_dir

The next code imports the necessary Python modules.

[2]:
import pandas as pd
from template import workspace

workspace is an instance of the IfrsWorkspace class. The models property of workspace holds a dictionary that contains IModel objects. These objects are keyed by ImportArgs objects, which represent the associated reporting node, reporting period, and import format.

[3]:
list(workspace.models.keys())
[3]:
[ImportArgs(ReportingNode='CH', Year=2020, Month=12, Periodicity=0, Scenario='', ImportFormat='Opening'),
 ImportArgs(ReportingNode='CH', Year=2020, Month=12, Periodicity=0, Scenario='', ImportFormat='Cashflow'),
 ImportArgs(ReportingNode='CH', Year=2020, Month=12, Periodicity=0, Scenario='', ImportFormat='Actual'),
 ImportArgs(ReportingNode='CH', Year=2021, Month=3, Periodicity=0, Scenario='', ImportFormat='Cashflow'),
 ImportArgs(ReportingNode='CH', Year=2021, Month=3, Periodicity=0, Scenario='', ImportFormat='Actual')]

Inspecting PresentValue IScope#

The code below assigns the second-to-last model in the dictionary to model_cf for later use.

[4]:
model_cf = list(workspace.models.values())[-2]

This model holds cached IScope objects that are created after importing the nominal cashflow data for the period ending March 2021. The cached IScopes are stored in a nested dictionary assigned to the scope_cache property of model_cf.

At the top level, scope_cache is keyed by IScope classes. The following code lists the classes of the cached IScopes.

[5]:
list(model_cf.scope_cache.keys())
[5]:
[ifrs17.ImportScopeCalculation.GetCashflowIdentities,
 ifrs17.ImportScopeCalculation.ComputeIfrsVarsCashflows,
 ifrs17.ImportScopeCalculation.PvLocked,
 ifrs17.ImportScopeCalculation.ValidAmountType,
 ifrs17.ImportScopeCalculation.EmptyValuesAocStep,
 ifrs17.ImportScopeCalculation.PvCurrent,
 ifrs17.ImportScopeCalculation.RaCurrent,
 ifrs17.ImportScopeCalculation.RaLocked,
 ifrs17.ImportScopeCalculation.CurrentPeriodAmortizationFactor,
 ifrs17.ImportScopeCalculation.MonthlyAmortizationFactorCashflow,
 ifrs17.ImportScopeCalculation.NominalCashflow,
 ifrs17.ImportScopeCalculation.ReferenceAocStep,
 ifrs17.ImportScopeCalculation.CoverageUnitCashflow,
 ifrs17.ImportScopeCalculation.DiscountedCashflow,
 ifrs17.ImportScopeCalculation.MonthlyRate,
 ifrs17.ImportScopeCalculation.DefaultValueBeExperienceAdjustmentForPremium,
 ifrs17.ImportScopeCalculation.PresentValueFromDiscountedCashflow,
 ifrs17.ImportScopeCalculation.CashflowAocStep,
 ifrs17.ImportScopeCalculation.BeExperienceAdjustmentForPremium,
 ifrs17.ImportScopeCalculation.PresentValue,
 ifrs17.ImportScopeCalculation.TelescopicDifference,
 ifrs17.ImportScopeCalculation.ParentAocStepForCreditRisk,
 ifrs17.ImportScopeCalculation.PresentValueWithInterestAccretion,
 ifrs17.ImportScopeCalculation.DiscountedCreditRiskCashflow,
 ifrs17.ImportScopeCalculation.AllClaimsCashflow,
 ifrs17.ImportScopeCalculation.CreditDefaultRiskNominalCashflow,
 ifrs17.ImportScopeCalculation.ParentAocStep,
 ifrs17.ImportScopeCalculation.PresentValueWithInterestAccretionForCreditRisk]
For each class key, a nested dictionary is assigned. The keys of this nested dictionary represent the context of the stored IScope objects. For most IScope objects, context signifies the EconomicBasis key. However, for certain IScope objects, such as AllocateTechnicalMargin, context corresponds to EstimateTypes. The valid_context attribute defined in each IScope class indicates what context values are acceptable for the class.
If an IScope does not have a context, the '' (empty string) is assigned.

The code below reveals that two context keys, L and C, are found for the PresentValue IScope.

[6]:
from ifrs17.ImportScopeCalculation import PresentValue
list(model_cf.scope_cache[PresentValue].keys())
[6]:
['L', 'C']

The innermost dictionaries in the nested scope_cache dictionary store IScope objects keyed by identity objects. The code blow lists the first 5 keys for the PresentValue IScope with context L.

[7]:
list(model_cf.scope_cache[PresentValue]['L'].keys())[:5]
[7]:
[IdentityTuple(Id=ImportIdentity(DataNode='DT1.1', AocType='CL', Novelty='C', IsReinsurance=False, ValuationApproach='BBA', ProjectionPeriod=0, ImportScope=None), AmountType='ICO', EstimateType='BE', AccidentYear=0.0, Scale=1.0),
 IdentityTuple(Id=ImportIdentity(DataNode='DT1.1', AocType='CL', Novelty='C', IsReinsurance=False, ValuationApproach='BBA', ProjectionPeriod=0, ImportScope=None), AmountType='NIC', EstimateType='BE', AccidentYear=0.0, Scale=1.0),
 IdentityTuple(Id=ImportIdentity(DataNode='DT1.1', AocType='CL', Novelty='C', IsReinsurance=False, ValuationApproach='BBA', ProjectionPeriod=0, ImportScope=None), AmountType='PR', EstimateType='BE', AccidentYear=0.0, Scale=1.0),
 IdentityTuple(Id=ImportIdentity(DataNode='DT1.1', AocType='CL', Novelty='C', IsReinsurance=False, ValuationApproach='BBA', ProjectionPeriod=0, ImportScope=None), AmountType='', EstimateType='RA', AccidentYear=0.0, Scale=1.0),
 IdentityTuple(Id=ImportIdentity(DataNode='DT1.1', AocType='EV', Novelty='N', IsReinsurance=False, ValuationApproach='BBA', ProjectionPeriod=0, ImportScope=None), AmountType='ICO', EstimateType='BE', AccidentYear=0.0, Scale=1.0)]

Types of the identity objects vary by IScopes. In the case of PresentValue, IdentityTuple is used. Other types, such as IdentityTuple2 or IdentityTuple3 are used for some other IScopes.

To view the cached values of an IScope’s properties, you can use the debug method, which outputs the values as a DataFrame. The first parameter is the name of the IScope to examine. The debug method can also accept additional parameters to filter the results. These parameters can be object identities, such as AocType, Novelty, and AmountType. Additionally, context can be used to filter the results.

The code below outputs PresentValue IScopes for DataNode=’DT1.1’, Novelty=’N’, EconomicBasis=’L’ and EstimateType=’BE’. Note the parameter name should be context to indicate EconomicBasis, not EconomicBasis itself.

[8]:
model_cf.debug('PresentValue', DataNode='DT1.1', Novelty='N', context='L', EstimateType='BE')
[8]:
Scope DataNode AocType Novelty AmountType EstimateType AccidentYear Scale Values EconomicBasis Value shift timeStep parentDiscountedValues parentNominalValues monthlyInterestFactor
0 PresentValueFromDiscountedCashflow DT1.1 BOP N ICO BE 0.0 1.0 [11.987021987769438, 10.98901799575347, 9.9908... L 11.987022 0.0 3.0 NaN NaN NaN
1 PresentValueFromDiscountedCashflow DT1.1 BOP N NIC BE 0.0 1.0 [47.94808795107775, 43.95607198301388, 39.9633... L 47.948088 0.0 3.0 NaN NaN NaN
2 PresentValueFromDiscountedCashflow DT1.1 BOP N PR BE 0.0 1.0 [-39.963392949885524, -39.97004741764894, -29.... L -39.963393 0.0 3.0 NaN NaN NaN
3 CashflowAocStep DT1.1 CF N ICO BE 0.0 1.0 [-1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.... L -3.000000 0.0 3.0 NaN NaN NaN
4 CashflowAocStep DT1.1 CF N NIC BE 0.0 1.0 [-4.0, -4.0, -4.0, -4.0, -4.0, -4.0, -4.0, -4.... L -12.000000 0.0 3.0 NaN NaN NaN
5 CashflowAocStep DT1.1 CF N PR BE 0.0 1.0 [0.0, 10.0, 0.0, 0.0, 10.0, 0.0, 0.0, 10.0, 0.... L 10.000000 0.0 3.0 NaN NaN NaN
6 CashflowAocStep DT1.1 CF N PR BE 0.0 0.8 [0.0, 10.0, 0.0, 0.0, 10.0, 0.0, 0.0, 10.0, 0.... L 8.000000 0.0 3.0 NaN NaN NaN
7 PresentValue DT1.1 EV N ICO BE 0.0 1.0 [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ... L 0.000000 0.0 3.0 NaN NaN NaN
8 PresentValue DT1.1 EV N NIC BE 0.0 1.0 [59.93510993884718, 54.945089978767335, 49.954... L 44.962557 0.0 3.0 NaN NaN NaN
9 PresentValue DT1.1 EV N PR BE 0.0 1.0 [19.981696474942762, 19.98502370882447, 14.987... L 14.990015 0.0 3.0 NaN NaN NaN
10 PresentValueWithInterestAccretion DT1.1 IA N ICO BE 0.0 1.0 [0.001996007984032429, 0.0018298262636524544, ... L 0.005489 0.0 3.0 [-11.987021987769438, -10.98901799575347, -9.9... [-1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.... [1.0001665140838207, 1.0001665140838207, 1.000...
11 PresentValueWithInterestAccretion DT1.1 IA N NIC BE 0.0 1.0 [0.007984031936129716, 0.0073193050546098174, ... L 0.021958 0.0 3.0 [-47.94808795107775, -43.95607198301388, -39.9... [-4.0, -4.0, -4.0, -4.0, -4.0, -4.0, -4.0, -4.... [1.0001665140838207, 1.0001665140838207, 1.000...
12 PresentValueWithInterestAccretion DT1.1 IA N PR BE 0.0 1.0 [-0.006654467763418193, -0.0049904349878137876... L -0.016636 0.0 3.0 [39.963392949885524, 39.97004741764894, 29.975... [0.0, 10.0, 0.0, 0.0, 10.0, 0.0, 0.0, 10.0, 0.... [1.0001665140838207, 1.0001665140838207, 1.000...

By default, debug includes the results of sub classes of the specified IScope class. To exclude them, set the include_sub paramter to False.

[9]:
model_cf.debug('PresentValue', DataNode='DT1.1', Novelty='N', context='L', EstimateType='BE', include_sub=False)
[9]:
Scope DataNode AocType Novelty AmountType EstimateType AccidentYear Scale EconomicBasis Values Value shift timeStep
0 PresentValue DT1.1 EV N ICO BE 0.0 1.0 L [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ... 0.000000 0 3
1 PresentValue DT1.1 EV N NIC BE 0.0 1.0 L [59.93510993884718, 54.945089978767335, 49.954... 44.962557 0 3
2 PresentValue DT1.1 EV N PR BE 0.0 1.0 L [19.981696474942762, 19.98502370882447, 14.987... 14.990015 0 3

Inspecting AllocateTechnical Margin#

In the same way as we did above for the PresentValue IScope, let’s take a look at AllocateTechnicalMargin. The code below extracts the last model in the models proeprty of workspace.

[10]:
model_act = list(workspace.models.values())[-1]

The code below lists IScope types calculated after importing the actual cashflow.

[11]:
list(model_act.scope_cache.keys())
[11]:
[ifrs17.ImportScopeCalculation.GetActualIdentities,
 ifrs17.ImportScopeCalculation.AllCfIdentities,
 ifrs17.ImportScopeCalculation.ComputeIfrsVarsActuals,
 ifrs17.ImportScopeCalculation.Actual,
 ifrs17.ImportScopeCalculation.BeAmountTypesFromIfrsVariables,
 ifrs17.ImportScopeCalculation.EmptyValuesActual,
 ifrs17.ImportScopeCalculation.AdvanceActual,
 ifrs17.ImportScopeCalculation.OverdueActual,
 ifrs17.ImportScopeCalculation.DefaultValueActualExperienceAdjustmentOnPremium,
 ifrs17.ImportScopeCalculation.AmortizationDeferrable,
 ifrs17.ImportScopeCalculation.PreviousAocSteps,
 ifrs17.ImportScopeCalculation.DeferrableActual,
 ifrs17.ImportScopeCalculation.ReleaseDeferrable,
 ifrs17.ImportScopeCalculation.ActualBase,
 ifrs17.ImportScopeCalculation.AmfFromIfrsVariable,
 ifrs17.ImportScopeCalculation.ContractualServiceMargin,
 ifrs17.ImportScopeCalculation.AllocateTechnicalMargin,
 ifrs17.ImportScopeCalculation.TechnicalMarginForAM,
 ifrs17.ImportScopeCalculation.TechnicalMarginForBOP,
 ifrs17.ImportScopeCalculation.TechnicalMargin,
 ifrs17.ImportScopeCalculation.ComputePresentValueWithIfrsVariable,
 ifrs17.ImportScopeCalculation.RaLocked,
 ifrs17.ImportScopeCalculation.TechnicalMarginDefaultValue,
 ifrs17.ImportScopeCalculation.TechnicalMarginForIA,
 ifrs17.ImportScopeCalculation.MonthlyRate,
 ifrs17.ImportScopeCalculation.TechnicalMarginForEA,
 ifrs17.ImportScopeCalculation.ReferenceAocStep,
 ifrs17.ImportScopeCalculation.BeExperienceAdjustmentForPremium,
 ifrs17.ImportScopeCalculation.ActualExperienceAdjustmentOnPremium,
 ifrs17.ImportScopeCalculation.LossComponent,
 ifrs17.ImportScopeCalculation.AllocateTechnicalMarginForBop,
 ifrs17.ImportScopeCalculation.AllocateTechnicalMarginForCl,
 ifrs17.ImportScopeCalculation.EndOfPeriodActual,
 ifrs17.ImportScopeCalculation.EndOfPeriodDeferrable,
 ifrs17.ImportScopeCalculation.AllocateTechnicalMarginForEop,
 ifrs17.ImportScopeCalculation.AllocateTechnicalMarginForReinsurance,
 ifrs17.ImportScopeCalculation.LossRecoveryComponent,
 ifrs17.ImportScopeCalculation.AllocateTechnicalMarginForReinsuranceCL]

The code below outputs AllocateTechnicalMargin values for CSM of DataNode=’DT1.1’. Note the paramter context now indicates EstimateType to be selected. 'C' indicates Contractural Service Margin, where L and LR indicates Loss Component and Loss Recovery Component respectively.

[12]:
model_act.debug('AllocateTechnicalMargin', DataNode='DT1.1', context='C') # context='L' selects Loss Component.
[12]:
Scope DataNode AocType Novelty AggregatedTechnicalMargin TechnicalMargin ComputedEstimateType HasSwitch EstimateType Value balancingValue
0 AllocateTechnicalMargin DT1.1 AM C -19.503146 6.289625 C False C 6.289625 NaN
1 AllocateTechnicalMargin DT1.1 AU I -148.934502 0.000000 C False C 0.000000 NaN
2 AllocateTechnicalMargin DT1.1 AU N 31.975040 0.000000 L False C 0.000000 NaN
3 AllocateTechnicalMargin DT1.1 CF C 0.000000 0.000000 C False C 0.000000 NaN
4 AllocateTechnicalMargin DT1.1 CF I -148.860127 0.000000 C False C 0.000000 NaN
5 AllocateTechnicalMargin DT1.1 CF N 31.958739 0.000000 L False C 0.000000 NaN
6 AllocateTechnicalMargin DT1.1 EV I -148.934502 0.000000 C False C 0.000000 NaN
7 AllocateTechnicalMargin DT1.1 EV N 31.975040 55.456316 L False C 0.000000 NaN
8 AllocateTechnicalMargin DT1.1 CRU I -148.934502 0.000000 C False C 0.000000 NaN
9 AllocateTechnicalMargin DT1.1 EA C -61.503146 42.000000 C False C 42.000000 NaN
10 AllocateTechnicalMargin DT1.1 MC I -42.968114 -105.892014 C False C -105.892014 NaN
11 AllocateTechnicalMargin DT1.1 RCU I -148.860127 0.000000 C False C 0.000000 NaN
12 AllocateTechnicalMargin DT1.1 IA I -148.860127 -0.074374 C False C -0.074374 NaN
13 AllocateTechnicalMargin DT1.1 YCU I -148.934502 0.000000 C False C 0.000000 NaN
14 AllocateTechnicalMargin DT1.1 IA N 31.958739 0.016301 L False C 0.000000 NaN
15 AllocateTechnicalMarginForBop DT1.1 BOP I 0.000000 -42.968114 C False C -42.968114 NaN
16 AllocateTechnicalMarginForBop DT1.1 BOP N 0.000000 31.958739 L False C 0.000000 NaN
17 AllocateTechnicalMarginForCl DT1.1 CL C 87.431356 0.000000 C True C 87.431356 87.431356
18 AllocateTechnicalMarginForEop DT1.1 EOP C -13.213521 -52.513713 C False C -13.213521 NaN