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.
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]
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.''
(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 |