diff --git a/ifrs17-template/Import/CloseImportTemplate.ipynb b/ifrs17-template/Import/CloseImportTemplate.ipynb index 92d5cc1f..df85f6f5 100644 --- a/ifrs17-template/Import/CloseImportTemplate.ipynb +++ b/ifrs17-template/Import/CloseImportTemplate.ipynb @@ -91,7 +91,7 @@ "\n
For the **ImportFormat**, the following options are expected:", "\n- ImportFormats.DataNode : [Portfolios](https://portal.systemorph.cloud/project/ifrs17/env/v1.2.0/DataModel/DataStructure#portfolios) and [Group of Contracts](https://portal.systemorph.cloud/project/ifrs17/env/v1.2.0/DataModel/DataStructure#group-of-contracts)", "\n- ImportFormats.DataNodeState : the [state of a data node](https://portal.systemorph.cloud/project/ifrs17/env/v1.2.0/DataModel/DataStructure#data-node-state) can be either active or inactive.", - "\n- ImportFormats.DataNodeParameter : parameters are described [here](https://portal.systemorph.cloud/project/ifrs17/env/v1.2.0/DataModel/DataStructure#data-node-parameters). For **Group of Insurance Contracts** a default [Premium Allocation factor](https://portal.systemorph.cloud/project/ifrs17/env/v1.2.0/Import/ImportScopeCalculation#experience-adjustment-on-premium) of 1 is applied if the parameter is not imported.", + "\n- ImportFormats.DataNodeParameter : parameters are described [here](https://portal.systemorph.cloud/project/ifrs17/env/v1.2.0/DataModel/DataStructure#data-node-parameters). For **Group of Insurance Contracts** a default [Premium Allocation factor](https://portal.systemorph.cloud/project/ifrs17/env/v1.2.0/Import/4ImportScope-TechnicalMargin#experience-adjustment-on-premium) of 1 is applied if the parameter is not imported.", "\n" ], "metadata": {}, diff --git a/ifrs17/DataModel/DataStructure.ipynb b/ifrs17/DataModel/DataStructure.ipynb index a27687cb..78f4144a 100644 --- a/ifrs17/DataModel/DataStructure.ipynb +++ b/ifrs17/DataModel/DataStructure.ipynb @@ -1796,7 +1796,7 @@ "source": [ "", "\n## Import Identity", - "\nThe Import Identity contains the data elements used to determine the data sets which are used when performing data manipulations, e.g. during a [data import](./Import/ImportScopeCalculation). In particular, an Import Identity is defined by: DataNode, AoC Type, Novelty, and whether it's reinsurance data or not." + "\nThe Import Identity contains the data elements used to determine the data sets which are used when performing data manipulations, e.g. during a [data import](./Import/1ImportScope-Identities). In particular, an Import Identity is defined by: DataNode, AoC Type, Novelty, and whether it's reinsurance data or not." ], "metadata": {}, "execution_count": 0, diff --git a/ifrs17/Import/1ImportScope-Identities.ipynb b/ifrs17/Import/1ImportScope-Identities.ipynb new file mode 100644 index 00000000..65703f90 --- /dev/null +++ b/ifrs17/Import/1ImportScope-Identities.ipynb @@ -0,0 +1,459 @@ +{ + "metadata": { + "authors": [], + "id": "1-Sd2C2w2kaytthWS3cL1F", + "kernelspec": { + "display_name": "Formula Framework", + "language": "C#", + "name": "C#" + }, + "language_info": { + "file_extension": ".cs", + "mimetype": "text/plain", + "name": "C#" + } + }, + "nbformat": 4, + "nbformat_minor": 5, + "cells": [ + { + "cell_type": "markdown", + "source": [ + "

IFRS 17 Methodology

", + "\n

Business Logic with Scopes

", + "\n" + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "This notebook contains the logic used to perform calculations upon import of data (actuals and cash flows). This is also called 'Data Loading' and the concept of Scope is used here to define the logic and provide the means of executing the logic. Scopes are used to define and perform data handling in a structured and easy-to-read-through fashion.", + "\n", + "\n

", + "\nIn this notebook the focus is on the defintion of the Identities and on the AoC Step structure and relations required for the computations. ", + "\n" + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "# References", + "\nLibraries and other notebooks which are needed for this notebook are imported below." + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "## Notebooks" + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "#!import \"ImportStorage\"" + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "# IModel ", + "\n", + "\nThe IModel interface below will be used to execute calculations (i.e. evaluate the scopes) based on imported data." + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "public interface IModel : IMutableScopeWithStorage{}" + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "# Generate Identities", + "\n", + "\nAn [Identity](../DataModel/DataStructure#import-identity) is a set of identifiers for a certain set of data. In particular, an identity consists of a certain [AoC Type](../DataModel/DataStructure#aoc-type), [Novelty](../DataModel/DataStructure#novelty), [Data Node](../DataModel/DataStructure#data-node), Accident Year, and information on whether the data is for reinsurance or not. ", + "\n", + "\nGiven a certain Data Node and Accident Year, the interface GetIdentities returns all the existing identities (e.g. for Actuals and Cash flows) which have that Data Node and Accident Year." + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "public interface AllCfIdentities : IScope // string represents a DataNode", + "\n{", + "\n public IEnumerable ids => GetStorage().GetAllAocSteps(InputSource.Cashflow)", + "\n .Select(aocStep => new ImportIdentity {", + "\n AocType = aocStep.AocType,", + "\n Novelty = aocStep.Novelty,", + "\n DataNode = Identity", + "\n });", + "\n}" + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "public interface GetIdentities : IScope", + "\n{", + "\n static ApplicabilityBuilder ScopeApplicabilityBuilder(ApplicabilityBuilder builder) =>", + "\n builder.ForScope(s => s.WithApplicability(x => x.GetStorage().IsSecondaryScope(x.Identity))", + "\n .WithApplicability(x => x.GetStorage().ImportFormat == ImportFormats.Actual)", + "\n .WithApplicability(x => x.GetStorage().ImportFormat == ImportFormats.Cashflow)", + "\n .WithApplicability(x => x.GetStorage().ImportFormat == ImportFormats.Opening)", + "\n );", + "\n ", + "\n private IEnumerable computedIdentities => new string[]{AocTypes.EA, AocTypes.AM, AocTypes.EOP}", + "\n .Select(aocType => new ImportIdentity {", + "\n AocType = aocType,", + "\n Novelty = Novelties.C,", + "\n DataNode = Identity", + "\n });", + "\n private IEnumerable allIdentities => ParsedIdentities.Concat(computedIdentities).Concat(SpecialIdentities).ToHashSet(); ", + "\n ", + "\n IEnumerable ParsedIdentities => Enumerable.Empty(); ", + "\n IEnumerable SpecialIdentities => Enumerable.Empty();", + "\n ", + "\n //Set DataNode properties and ProjectionPeriod", + "\n IEnumerable Identities => allIdentities.Select(id => id with { IsReinsurance = GetStorage().DataNodeDataBySystemName[id.DataNode].IsReinsurance,", + "\n ValuationApproach = GetStorage().DataNodeDataBySystemName[id.DataNode].ValuationApproach", + "\n });", + "\n /* .SelectMany(id => Enumerable.Range(0,GetStorage().GetProjectionCount() + 1)", + "\n .Select(pp => id with {ProjectionPeriod = pp })", + "\n );*/", + "\n}", + "\n", + "\npublic interface AllCashflowIdentities : GetIdentities", + "\n{", + "\n IEnumerable GetIdentities.SpecialIdentities => GetScope(Identity).ids;", + "\n}", + "\n", + "\n", + "\npublic interface GetActualIdentities : GetIdentities", + "\n{", + "\n private IEnumerable actualEstimateTypes => GetStorage().EstimateTypesByImportFormat[ImportFormats.Actual];", + "\n ", + "\n IEnumerable GetIdentities.ParsedIdentities => GetStorage().GetIfrsVariables(Identity).Where(iv => actualEstimateTypes.Contains(iv.EstimateType)).Select(v => new ImportIdentity(v));", + "\n IEnumerable GetIdentities.SpecialIdentities => GetScope(Identity).ids", + "\n .Concat(GetStorage().GetAllAocSteps(InputSource.Opening)", + "\n .Select(aocStep => new ImportIdentity {AocType = aocStep.AocType, ", + "\n Novelty = aocStep.Novelty,", + "\n DataNode = Identity", + "\n }));", + "\n}", + "\n", + "\npublic interface GetCashflowIdentities : GetIdentities", + "\n{", + "\n private bool isReinsurance => GetStorage().DataNodeDataBySystemName[Identity].IsReinsurance; //clean up in the next PR", + "\n ", + "\n IEnumerable GetIdentities.ParsedIdentities => GetStorage().GetRawVariables(Identity).Select(v => new ImportIdentity(v));", + "\n ", + "\n IEnumerable GetIdentities.SpecialIdentities => ParsedIdentities.Where(id => id.Novelty != Novelties.C)", + "\n .Select(id => id.Novelty).ToHashSet()", + "\n .SelectMany(n => (n == Novelties.N ", + "\n ? new string[]{AocTypes.IA, AocTypes.CF} //Add IA, CF, for New Business", + "\n : isReinsurance ", + "\n ? new string[]{AocTypes.IA, AocTypes.CF, AocTypes.YCU, AocTypes.CRU, AocTypes.RCU} //Add IA, CF, YCU, CRU, RCU for in force", + "\n : new string[]{AocTypes.IA, AocTypes.CF, AocTypes.YCU}) //Add IA, CF, YCU,", + "\n .Select(aocType => new ImportIdentity {", + "\n AocType = aocType,", + "\n Novelty = n,", + "\n DataNode = Identity }))", + "\n .Concat(new ImportIdentity {", + "\n AocType = AocTypes.CF, //Add CF for Deferral", + "\n Novelty = Novelties.C,", + "\n DataNode = Identity", + "\n }.RepeatOnce()) ", + "\n .Concat(GetStorage().GetAllAocSteps(InputSource.Opening)", + "\n .Select(aocStep => new ImportIdentity {AocType = aocStep.AocType, ", + "\n Novelty = aocStep.Novelty,", + "\n DataNode = Identity", + "\n })); ", + "\n}", + "\n", + "\npublic interface GetAllIdentities : GetIdentities", + "\n{", + "\n IEnumerable GetIdentities.SpecialIdentities => GetScope(Identity).ids", + "\n .Concat(GetStorage().GetAllAocSteps(InputSource.Actual)", + "\n .Select(aocStep => new ImportIdentity {AocType = aocStep.AocType, ", + "\n Novelty = aocStep.Novelty,", + "\n DataNode = Identity,", + "\n }));", + "\n}" + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "# Relevant Amount Types", + "\n", + "\nSimilarly, given a certain Data Node and Accident Year, the interface ValidAmountType returns all the amount types which are used in imported data with that Data Node and Accident Year." + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "public interface ValidAmountType : IScope", + "\n{", + "\n static ApplicabilityBuilder ScopeApplicabilityBuilder(ApplicabilityBuilder builder) =>", + "\n builder.ForScope(s => s.WithApplicability(x => x.GetStorage().ImportFormat != ImportFormats.Cashflow ||", + "\n x.GetStorage().IsSecondaryScope(x.Identity)));", + "\n ", + "\n IEnumerable BeAmountTypes => GetStorage().GetRawVariables(Identity)", + "\n .Where(rv => rv.AmountType != null)", + "\n .Select(x => x.AmountType)", + "\n .Concat(GetStorage().DataNodeDataBySystemName[Identity].IsReinsurance ? (AmountTypes.CDR).RepeatOnce() : Enumerable.Empty())", + "\n .ToHashSet();", + "\n ", + "\n ", + "\n IEnumerable ActualAmountTypes => GetStorage().GetIfrsVariables(Identity)", + "\n .Where(iv => GetStorage().ImportActualEstimateTypes.Contains(iv.EstimateType))", + "\n .Select(x => x.AmountType)", + "\n .ToHashSet();", + "\n}", + "\npublic interface BeAmountTypesFromIfrsVariables : ValidAmountType", + "\n{", + "\n IEnumerable ValidAmountType.BeAmountTypes => GetStorage().GetIfrsVariables(Identity)", + "\n .Where(iv => GetStorage().EstimateTypesByImportFormat[ImportFormats.Cashflow].Contains(iv.EstimateType) && iv.AmountType != null)", + "\n .Select(x => x.AmountType)", + "\n .ToHashSet();", + "\n}" + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "# AoC Step Structure", + "\n", + "\nThe AoC Step structure is constructed from the data which is delivered as input. It is assumed that it depends only on the Group of Contrat (i.e. it is invariant across Amount types or Accident Year). " + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "## Parent AoC Step ", + "\nThe **ParentAocStep** scope computes and provides an important piece of information for each [Identity](../DataModel/DataStructure#import-identity), i.e. for a certain [AoC Type](../DataModel/DataStructure#aoc-type) and [Novelty](../DataModel/DataStructure#novelty).", + "\n", + "\nIt provides the list of the adjacent AoC Steps prior to Identity one. It can be more than one only for the step **CL** where a parent for each novelty is considered.", + "\nParentAocStep is critical when computing the *telescoping* differences. ", + "\n", + "\nThey are defined as follows:", + "\n", + "\n$$", + "\n\\text{ParentAocStep}(\\text{AoC Step}) = \\left\\{", + "\n\\begin{array}{cl}", + "\n\\text{AoC Step with AoC Type YCU and Novelty I} & \\text{if AoC Type CRU} \\\\", + "\n\\text{The last AoC Step with Data Type != Calculated and same Novelty as the AoC Step} & \\text{if AoC Type YCU} \\\\", + "\n\\text{The AoC Step which comes before in terms of order (as defined by AoC Type)} & \\text{otherwise} \\\\", + "\n\\end{array}", + "\n\\right.", + "\n$$", + "\n" + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "public interface ParentAocStep : IScope<(ImportIdentity Id, string AmountType), ImportStorage>", + "\n{", + "\n static ApplicabilityBuilder ScopeApplicabilityBuilder(ApplicabilityBuilder builder) =>", + "\n builder.ForScope(s => s.WithApplicability(x => x.Identity.AmountType != AmountTypes.CDR));", + "\n ", + "\n private HashSet ParsedAocSteps => GetScope(Identity.Id.DataNode).ParsedIdentities.Select(id => new AocStep(id.AocType, id.Novelty)).ToHashSet();", + "\n private IEnumerable OrderedParsedAocSteps => ParsedAocSteps.Concat(CalculatedTelescopicAocStep).OrderBy(x => GetStorage().AocConfigurationByAocStep[x].Order);", + "\n ", + "\n private Dictionary> ParentParsedIdentities => GetPreviousIdentities(OrderedParsedAocSteps);", + "\n private AocStep identityAocStep => new AocStep(Identity.Id.AocType, Identity.Id.Novelty);", + "\n ", + "\n IEnumerable CalculatedTelescopicAocStep => GetStorage().GetCalculatedTelescopicAocSteps();", + "\n ", + "\n IEnumerable Values => ", + "\n Identity.Id.AocType switch {", + "\n AocTypes.CRU => new AocStep(AocTypes.YCU, Novelties.I).RepeatOnce(),", + "\n AocTypes.YCU => OrderedParsedAocSteps.GetReferenceAocStepForCalculated(GetStorage().AocConfigurationByAocStep, identityAocStep).RepeatOnce(),", + "\n _ => ParentParsedIdentities.TryGetValue(identityAocStep, out var parents) ? parents : Enumerable.Empty(),", + "\n };", + "\n}", + "\n", + "\npublic interface ParentAocStepForCreditRisk : ParentAocStep", + "\n{", + "\n IEnumerable ParentAocStep.CalculatedTelescopicAocStep => ", + "\n GetStorage().GetCalculatedTelescopicAocSteps().Where(aoc => aoc.AocType != AocTypes.CRU);", + "\n}" + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "## Reference AoC Step", + "\n", + "\nThe **ReferenceAocStep** scope provides the AoC Step from which to retrieve the data in order to compute its value (e.g. AoC Step EA retrieves Present Values, while AoC Step YCU retrieves Nominal).", + "\n", + "\nThey are defined as follows:", + "\n", + "\n$$", + "\n\\text{ReferenceAocStep}(\\text{AoC Step}) = \\left\\{", + "\n\\begin{array}{cl}", + "\n\\text{self} & \\text{if AoC Step InputSource is not Calculated} \\\\", + "\n\\text{The last AoC Step with Data Type != Calculated and same Novelty as the input AoC Step} ~, & \\text{if AoC Type } \\in \\text{\\{RCU, CF, IA, YCU, CRU\\}} \\\\", + "\n\\text{AoC Step with AoC Type CF and Novelty as the AoC Step} & \\text{if AoC Type EA} \\\\", + "\n\\text{AoC Step with AoC Type CL and Novelty C} & \\text{if AoC Type $\\in$ \\{AM, EOP\\}} \\\\", + "\n\\text{empty} & \\text{if AoC Type is BOP} \\\\", + "\n\\text{log NotSupportedAocStepReference error} & \\text{otherwise} \\\\", + "\n\\end{array}", + "\n\\right.", + "\n$$", + "\n", + "\nwhere the last AoC Step is obtained by ordering the AoC Steps according to their order (as defined by its AoC Type) and taking the last one." + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "public interface ReferenceAocStep : IScope ", + "\n{", + "\n private IEnumerable OrderedParsedAocSteps => GetScope(Identity.DataNode).ParsedIdentities", + "\n .Select(id => new AocStep(id.AocType, id.Novelty))", + "\n .Distinct()", + "\n .OrderBy(aocStep => GetStorage().AocConfigurationByAocStep[aocStep].Order);", + "\n private AocStep identityAocStep => new AocStep(Identity.AocType, Identity.Novelty);", + "\n private AocStep GetReferenceAocStep(string aocType) {", + "\n return aocType switch {", + "\n AocTypes.RCU or AocTypes.CF or AocTypes.IA or AocTypes.YCU or AocTypes.CRU => OrderedParsedAocSteps.GetReferenceAocStepForCalculated(GetStorage().AocConfigurationByAocStep, identityAocStep),", + "\n AocTypes.EA => new AocStep(AocTypes.CF, Identity.Novelty),", + "\n AocTypes.AM or AocTypes.EOP => new AocStep(AocTypes.CL, Novelties.C),", + "\n AocTypes.BOP => new AocStep(default, default), //BOP, C has DataType == Calculated. See ReferenceAocStep condition.", + "\n _ => (AocStep)ApplicationMessage.Log(Error.NotSupportedAocStepReference, Identity.AocType),", + "\n };", + "\n }", + "\n", + "\n // The Reference AocStep from which get data (Nominal or PV) to compute", + "\n AocStep Value => GetStorage().AocConfigurationByAocStep[identityAocStep].DataType == DataType.Calculated ", + "\n || GetStorage().AocConfigurationByAocStep[identityAocStep].DataType == DataType.CalculatedTelescopic ", + "\n ? GetReferenceAocStep(Identity.AocType)", + "\n : identityAocStep;", + "\n}" + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "## Previous AoC Steps", + "\nThe **PreviousAocSteps** scope computes and provides an other important piece of information for each [Identity](../DataModel/DataStructure#import-identity), i.e. for a certain [AoC Type](../DataModel/DataStructure#aoc-type) and [Novelty](../DataModel/DataStructure#novelty).", + "\n", + "\nIt provides the list of all previous AoC Steps up to the **BOP** step, whereby a Combined novelty will branch into the InForce and New Business AoC Types.", + "\n", + "\nPreviousAocSteps is critical when computing aggregated values along the various dimensions (such as for example Line of Business) and ", + "\nis formed by the ParentAocStep and its parent and so on until there is no parent.", + "\n", + "\n$$", + "\n\\text{PreviousAocSteps}(\\rm{AocStep}) = \\{PAS_1, PAS_2, \\ldots\\}", + "\n$$", + "\nwhere", + "\n$$", + "\n\\rm{PAS}_1 = \\rm{ParentAocStep}(\\rm{AoC Step})", + "\n$$", + "\n$$", + "\n\\rm{PAS}_2 = \\rm{ParentAocStep}(\\rm{PAS}_1).", + "\n$$", + "\n", + "\nThis scope depends on the InputSource (Actual or Cashflow) for which the PreviousSteps are requested due to the AocChain differences between Actual reports and the rest." + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "public interface PreviousAocSteps : IScope<(ImportIdentity Id, InputSource ScopeInputSource), ImportStorage> ", + "\n{ ", + "\n private AocStep identityAocStep => new AocStep(Identity.Id.AocType, Identity.Id.Novelty);", + "\n private int aocStepOrder => GetStorage().AocConfigurationByAocStep[identityAocStep].Order;", + "\n private HashSet allAocSteps => GetStorage().GetAllAocSteps(Identity.ScopeInputSource).ToHashSet();", + "\n IEnumerable Values => allAocSteps.Contains(identityAocStep)", + "\n ? GetScope(Identity.Id.DataNode).Identities", + "\n .Select(id => new AocStep(id.AocType, id.Novelty))", + "\n .Distinct()", + "\n .Where(aoc => allAocSteps.Contains(aoc) && ", + "\n GetStorage().AocConfigurationByAocStep[aoc].Order < aocStepOrder && ", + "\n (Identity.Id.Novelty != Novelties.C ? aoc.Novelty == Identity.Id.Novelty : true) )", + "\n .OrderBy(aoc => GetStorage().AocConfigurationByAocStep[aoc].Order)", + "\n : Enumerable.Empty();", + "\n} " + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "The exact structure being return depends on the **order** of the AoC Steps (which is set by the [AoC Type](../DataModel/DataStructure#aoc-type)), and on which AoC steps exist." + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "" + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + } + ] +} \ No newline at end of file diff --git a/ifrs17/Import/2ImportScope-PresentValue.ipynb b/ifrs17/Import/2ImportScope-PresentValue.ipynb new file mode 100644 index 00000000..97d7b5b5 --- /dev/null +++ b/ifrs17/Import/2ImportScope-PresentValue.ipynb @@ -0,0 +1,831 @@ +{ + "metadata": { + "authors": [], + "id": "1-Sd2C2w2kaytthWS3cL1B", + "kernelspec": { + "display_name": "Formula Framework", + "language": "C#", + "name": "C#" + }, + "language_info": { + "file_extension": ".cs", + "mimetype": "text/plain", + "name": "C#" + } + }, + "nbformat": 4, + "nbformat_minor": 5, + "cells": [ + { + "cell_type": "markdown", + "source": [ + "

IFRS 17 Methodology

", + "\n

Business Logic with Scopes

" + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "In this notebook the focus is on the calculation of present values. " + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "# References", + "\nLibraries and other notebooks which are needed for this notebook are imported below." + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "## Notebooks" + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "#!import \"1ImportScope-Identities\"" + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "# Discounting calculation", + "\n", + "\nThe calculation of IFRS 17 figures is based on cumulated discounted cash flows." + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "## Yield Curves", + "\n", + "\nThe Yield Curves used for the discounting calculations are functions of the [Currency](../DataModel/DataStructure#currency), the [Data Node](../DataModel/DataStructure#data-node) and the [Economic Basis](../DataModel/DataStructure#economic-basis).", + "\n", + "\nIn particular:", + "\n- For the **Locked-in** economic basis, the yield curve used is the latest available as per end of the DataNode's inception year;", + "\n- Whereas for the **Current** economic base, the yield curve used is the latest available as per the current period.", + "\n", + "\nThe algorithm which retrieves the latest available yield curve is [here](../Utils/Queries#yield-curve)." + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "## Interest and Discount Rates and Factors", + "\n", + "\nThe factors used for discounting have the same granularity as the cash flow, i.e. monthly. The yield curves have yearly granularity, so the annual Interest factor is 1 + interest rate. The monthly Interest Interest and Discount factors are obtained from the annual factors such that the product of 12 months results in the annual factors, as follows:", + "\n", + "\n$$", + "\n\\text{Discount}_i = ( 1 + \\text{YC}_i ) ^{-\\frac{1}{12}} ~,", + "\n$$", + "\nand ", + "\n$$", + "\n\\text{Interest}_i = ( 1 + \\text{YC}_i) ^{\\frac{1}{12}} ~,", + "\n$$", + "\n", + "\nwhere the index $i$ denotes years." + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "public interface MonthlyRate : IScope", + "\n{", + "\n private string EconomicBasis => GetContext();", + "\n ", + "\n private double[] YearlyYieldCurve => GetStorage().GetYearlyYieldCurve(Identity, EconomicBasis);", + "\n ", + "\n double[] Interest => YearlyYieldCurve.Select(rate => Math.Pow(1d + rate, 1d / 12d)).ToArray(); ", + "\n ", + "\n double[] Discount => Interest.Select(x => Math.Pow(x, -1)).ToArray();", + "\n}" + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "# Nominal Values", + "\n", + "\nThe nominal cash flow values correspond to the cash flows provided in the cash flow input file. ", + "\n
These values are stored in the database as [RawVariable](../DataModel/DataStructure#raw-variables).", + "\n
Refer to the ReferenceAocStep of the AocStructure calculation to identify the correct AoC Type and Novelty to retrieve.", + "\n
Due to the Credit Default Risk of a reinsurance partner, the logic to compute the Nominal Cash flows for this Amount Type must be defined separately." + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "public interface NominalCashflow : IScope<(ImportIdentity Id, string AmountType, string EstimateType, int? AccidentYear), ImportStorage>", + "\n{", + "\n static ApplicabilityBuilder ScopeApplicabilityBuilder(ApplicabilityBuilder builder) =>", + "\n builder.ForScope(s => s.WithApplicability(x => x.Identity.AmountType == AmountTypes.CDR && x.Identity.Id.AocType == AocTypes.CF)", + "\n .WithApplicability(x => x.Identity.AmountType == AmountTypes.CDR));", + "\n", + "\n AocStep referenceAocStep => GetScope(Identity.Id).Value;", + "\n double[] Values => GetStorage().GetValues(Identity.Id with {AocType = referenceAocStep.AocType, Novelty = referenceAocStep.Novelty}, Identity.AmountType, Identity.EstimateType, Identity.AccidentYear);", + "\n}", + "\n", + "\npublic interface CreditDefaultRiskNominalCashflow : NominalCashflow", + "\n{", + "\n private double[] NominalClaimsCashflow => GetStorage().GetClaims()", + "\n .Select(claim => GetStorage().GetValues(Identity.Id with {AocType = referenceAocStep.AocType, Novelty = referenceAocStep.Novelty}, claim, Identity.EstimateType, Identity.AccidentYear))", + "\n .AggregateDoubleArray();", + "\n ", + "\n private double nonPerformanceRiskRate => GetStorage().GetNonPerformanceRiskRate(Identity.Id);", + "\n ", + "\n private double[] PvCdrDecumulated { get {", + "\n var ret = new double[NominalClaimsCashflow.Length];", + "\n for (var i = NominalClaimsCashflow.Length - 1; i >= 0; i--)", + "\n ret[i] = Math.Exp(-nonPerformanceRiskRate) * ret.ElementAtOrDefault(i + 1) + NominalClaimsCashflow[i] - NominalClaimsCashflow.ElementAtOrDefault(i + 1);", + "\n return ret; } } ", + "\n ", + "\n double[] NominalCashflow.Values => Subtract(PvCdrDecumulated, NominalClaimsCashflow);", + "\n}", + "\n", + "\npublic interface AllClaimsCashflow : NominalCashflow", + "\n{", + "\n double[] NominalCashflow.Values => GetStorage().GetClaims()", + "\n .Select(claim => GetStorage().GetValues(Identity.Id with {AocType = referenceAocStep.AocType, Novelty = referenceAocStep.Novelty}, claim, Identity.EstimateType, Identity.AccidentYear))", + "\n .AggregateDoubleArray();", + "\n}" + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "For a given month $i$ they are denoted as $\\rm{Nominal}_i$." + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "# Present Values", + "\n", + "\nPresent Values are calculated during the import of the cash flows and stored on the database. They are computed for the relevant Economic Basis, depending on the Valuation Basis.", + "\n", + "\nTheir calculation is described in the following sections and is summarized in the $\\rm{PV}$ formula [below](#present-value)." + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "## Cumulated Discounted Cash flows", + "\n", + "\nCumulated and Discounted cash flows $\\rm{CDC}$ are computed using the monthly discount rates and in a recursive manner, as follows:", + "\n", + "\n$$", + "\n\\text{CDC}_i(\\text{AoC step}) = \\left\\{", + "\n\\begin{array}{cl}", + "\n\\text{Nominal}_i + \\text{CDC}_{i+1} \\cdot {\\text{Valid Discount}_{\\frac{i}{12}}} ~, & \\text{if Amount Type's Period Type is Beginning Of Period} \\\\", + "\n\\big( \\text{Nominal}_i + \\text{CDC}_{i+1} \\big) \\cdot {\\text{Valid Discount}_{\\frac{i}{12}}} ~, & \\text{if Amount Type's Period Type is End Of Period}", + "\n\\end{array}", + "\n\\right.", + "\n$$", + "\n", + "\nwhere Transaction Period depends on which Best Estimate value is being computed, in particular on what its [Amount Type](../DataModel/DataStructure#amount-type) is (each Amount Type has its own [Period Type](../Constants/Enums)); and $\\text{Valid Discount}$ stands for the fact that in case the Discount Curves are shorter than the required index, then their last element is returned. We also need to flip the sign of the discounted and cumulated values, to create a reserve view and be consistent with the usual [Cash flow Sign Convention](https://en.wikipedia.org/wiki/Cash_flow_sign_convention). ", + "\n", + "\n
Also here, the Credit Default Risk contribution is calculated separately. Since it is based on Claims, the Period Type is implicitly defined.", + "\nThe risk of default is included in the discounting formula as follows. First, we notice that one can explicitly write the discounting recursive relation above as:", + "\n$$", + "\n\\begin{array}{l}", + "\n\\text{CDC}_i = \\big( \\text{Nominal}_i + \\text{CDC}_{i+1} \\big) \\cdot {\\text{Valid Discount}_{\\frac{i}{12}}} ", + "\n\\Rightarrow \\text{CDC}_i = \\sum_{\\tau=i} \\big( \\text{Valid Discount}_{\\frac{i}{12}} \\big)^{\\tau-i+1} \\cdot \\text{Nominal}_\\tau ", + "\n\\end{array}", + "\n$$", + "\n", + "\nThus, the cumulated and discounted cashflow correction for default risk is assigned to the Amount Type Credit Default Risk (CDR) and it is obtained from the Amount Type Claims multiplying the right hand side of the previous formula by the corresponding risk factor", + "\n", + "\n$$", + "\n\\text{CDC}_i^{\\text{CDR}} = \\sum_{\\tau=i} \\big( \\text{Valid Discount}_{\\frac{i}{12}} \\big)^{\\tau-i+1} \\cdot \\text{Nominal}_\\tau^{\\text{Claim}} \\cdot \\big( e^{-\\gamma(\\tau-i)} -1 \\big)", + "\n$$" + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "public interface DiscountedCashflow : IScope<(ImportIdentity Id, string AmountType, string EstimateType, int? Accidentyear), ImportStorage>", + "\n{", + "\n private PeriodType periodType => GetStorage().GetPeriodType(Identity.AmountType, Identity.EstimateType); ", + "\n ", + "\n static ApplicabilityBuilder ScopeApplicabilityBuilder(ApplicabilityBuilder builder) =>", + "\n builder.ForScope(s => s.WithApplicability(x => x.Identity.Id.IsReinsurance && x.Identity.AmountType == AmountTypes.CDR));", + "\n", + "\n [NotVisible]", + "\n string EconomicBasis => GetContext();", + "\n", + "\n [NotVisible]", + "\n double[] MonthlyDiscounting => GetScope(Identity.Id).Discount;", + "\n ", + "\n [NotVisible]", + "\n double[] NominalValues => GetScope(Identity).Values;", + "\n", + "\n double[] Values => Multiply(-1d, NominalValues.ComputeDiscountAndCumulate(MonthlyDiscounting, periodType)); // we need to flip the sign to create a reserve view", + "\n}", + "\n", + "\npublic interface DiscountedCreditRiskCashflow : DiscountedCashflow", + "\n{ ", + "\n private double nonPerformanceRiskRate => GetStorage().GetNonPerformanceRiskRate(Identity.Id);", + "\n ", + "\n double[] DiscountedCashflow.Values => Multiply(-1d, NominalValues.ComputeDiscountAndCumulateWithCreditDefaultRisk(MonthlyDiscounting, nonPerformanceRiskRate)); // we need to flip the sign to create a reserve view", + "\n}" + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "## Telescoping Difference", + "\n", + "\n", + "\nPresent Value figures for a specific period are typically reported through an analysis of change, where for each [AoC Step](#aoc-step-structure) the variation with respect to the preceding AoC Step is shown.", + "\n", + "\nThe Telescoping Difference is basically the delta between two adjacent AoC Steps, whereby the [ParentAocStep](#aoc-step-structure) is used to determine the AoC Step. ", + "\n", + "\nIt is defined as follows:", + "\n", + "\n$$", + "\n\\text{TelescopingDifference}_i = ", + "\n\\text{CDC}_{i}\\big(\\text{current AoC Step}\\big) - \\text{CDC}_{i}\\big(\\text{parent AoC Step}\\big)", + "\n$$", + "\n", + "\nwhere AoC Type is the AoC Type of the AoC Step for which the calculations are being performed." + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "public interface TelescopicDifference : IScope<(ImportIdentity Id, string AmountType, string EstimateType, int? Accidentyear), ImportStorage>", + "\n{", + "\n [NotVisible]", + "\n string EconomicBasis => GetContext();", + "\n private double[] CurrentValues => GetScope(Identity).Values;", + "\n ", + "\n private double[] PreviousValues => (GetScope((Identity.Id, Identity.AmountType)))", + "\n .Values", + "\n .Select(aoc => GetScope((Identity.Id with {AocType = aoc.AocType, Novelty = aoc.Novelty}, Identity.AmountType, Identity.EstimateType, Identity.Accidentyear)).Values)", + "\n .Where(cf => cf.Count() > 0)", + "\n .AggregateDoubleArray();", + "\n ", + "\n double[] Values => Subtract(CurrentValues, PreviousValues);", + "\n}" + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "## Present Value", + "\n", + "\nThe present value ($\\rm{PV}$) can be determined by taking the appropriate elements of the cumulated discounted cash flows. This is done as function of the two [projection parameters](../DataModel/DataStructure#projection-configuration) $\\rm{Shift}$ ($S$) and $\\rm{TimeStep}$ ($TS$):", + "\n", + "\n$$", + "\n\\text{PV}(S, TS) = \\left\\{", + "\n\\begin{array}{cl}", + "\n\\text{PV}_{S} ~, & \\text{if Valuation Period is Beginning of Period} \\\\", + "\n\\text{PV}_{S+TS/2 -1} ~, & \\text{if Valuation Period is Mid of Period} \\\\", + "\n\\sum_{i=S}^{S + TS - 1}\\text{PV }_{i} ~, & \\text{if Valuation Period is Delta} \\\\", + "\n\\text{PV}_{S + TS} ~, & \\text{if Valuation Period is End of Period} \\\\", + "\n\\end{array}", + "\n\\right.", + "\n$$", + "\n", + "\nwhere the term $TS/2$ uses MidpointRounding.AwayFromZero (as defined by *https:[]()//docs.microsoft.com/en-us/dotnet/api/system.midpointrounding?view=net-6.0)*: rounding to the nearest number, away from zero in the exact halfway case. Furthermore, if the array is smaller than the index, then the last element is returned.", + "\n", + "\nFor instance, for the current year and year-to-date view we have $S=0$ and $TS=3$ for the first quarter, $TS=6$ for the 2nd quarter and so on.", + "\nFor the projection values of next year first quarter we would have $S=12$ and $TS=3$, etc." + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "public interface IWithGetValueFromValues : IScope<(ImportIdentity Id, string AmountType, string EstimateType, int? AccidentYear), ImportStorage>", + "\n{", + "\n private int shift => GetStorage().GetShift(0);//Identity.Id.ProjectionPeriod", + "\n private int timeStep => GetStorage().GetTimeStep(0);//Identity.Id.ProjectionPeriod", + "\n ", + "\n public double GetValueFromValues(double[] Values)", + "\n {", + "\n return GetStorage().GetValuationPeriod(Identity.Id) switch {", + "\n ValuationPeriod.BeginningOfPeriod => Values.ElementAtOrDefault(shift),", + "\n ValuationPeriod.MidOfPeriod => Values.ElementAtOrDefault(shift + Convert.ToInt32(Math.Round(timeStep / 2d, MidpointRounding.AwayFromZero)) - 1),", + "\n ValuationPeriod.Delta => Values.Skip(shift).Take(timeStep).Sum(),", + "\n ValuationPeriod.EndOfPeriod => Values.ElementAtOrDefault(shift + timeStep),", + "\n ValuationPeriod.NotApplicable => default", + "\n };", + "\n }", + "\n}" + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "## Interest Accretion", + "\n", + "\nSince the Interest Accretion cash flows are typically not provided as input (as they can be computed from its parent AoC Step), its present values can be computed as follows:", + "\n", + "\n$$", + "\n\\text{InterestAccretion}_i(\\text{AoC step}) = \\left\\{", + "\n\\begin{array}{cl}", + "\n\\big(\\text{CDC}_i(\\text{Parent AoC step}) - \\text{Nominal}_i(\\text{parent AoC step}) \\big) \\cdot \\big({\\text{Valid Interest}_{\\frac{i}{12}}} - 1 \\big)~, & \\text{if Amount Type's Transaction Period is Beginning of Period} \\\\", + "\n\\text{CDC}_i(\\text{parent AoC step}) \\cdot \\big({\\text{Valid Interest}_{\\frac{i}{12}}} - 1 \\big)~, & \\text{otherwise}", + "\n\\end{array}", + "\n\\right.", + "\n$$", + "\n", + "\n
Due to the Credit Default Risk of a reinsurance partner, the logic to compute the Interest Accretion for this Amount Type must be defined separately. Since it is based on Claims, the Period Type is implicitly defined." + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "public interface IWithInterestAccretion : IScope<(ImportIdentity Id, string AmountType, string EstimateType, int? AccidentYear), ImportStorage>", + "\n{", + "\n private double[] parentDiscountedValues => Multiply(-1d, GetScope(Identity).Values); ", + "\n private double[] parentNominalValues => GetScope(Identity).Values;", + "\n private double[] monthlyInterestFactor => GetScope(Identity.Id).Interest;", + "\n ", + "\n double[] GetInterestAccretion() ", + "\n {", + "\n var periodType = GetStorage().GetPeriodType(Identity.AmountType, Identity.EstimateType);", + "\n var ret = new double[parentDiscountedValues.Length];", + "\n ", + "\n switch (periodType) {", + "\n case PeriodType.BeginningOfPeriod :", + "\n for (var i = 0; i < parentDiscountedValues.Length; i++)", + "\n ret[i] = -1d * (parentDiscountedValues[i] - parentNominalValues[i]) * (monthlyInterestFactor.GetValidElement(i/12) - 1d );", + "\n break;", + "\n default :", + "\n for (var i = 0; i < parentDiscountedValues.Length; i++)", + "\n ret[i] = -1d * parentDiscountedValues[i] * (monthlyInterestFactor.GetValidElement(i/12) - 1d );", + "\n break;", + "\n }", + "\n ", + "\n return ret;", + "\n }", + "\n}", + "\n", + "\npublic interface IWithInterestAccretionForCreditRisk : IScope<(ImportIdentity Id, string AmountType, string EstimateType, int? AccidentYear), ImportStorage>", + "\n{", + "\n private double[] nominalClaimsCashflow => GetScope(Identity).Values;", + "\n private double[] nominalValuesCreditRisk => Multiply(-1, GetScope(Identity with {Id = Identity.Id with {AocType = AocTypes.CF}}).Values);", + "\n private double[] monthlyInterestFactor => GetScope(Identity.Id).Interest;", + "\n private double nonPerformanceRiskRate => GetStorage().GetNonPerformanceRiskRate(Identity.Id);", + "\n ", + "\n double[] GetInterestAccretion() ", + "\n {", + "\n var interestOnClaimsCashflow = new double[nominalClaimsCashflow.Length];", + "\n var interestOnClaimsCashflowCreditRisk = new double[nominalClaimsCashflow.Length];", + "\n var effectCreditRisk = new double[nominalClaimsCashflow.Length];", + "\n for (var i = nominalClaimsCashflow.Length - 1; i >= 0; i--) {", + "\n interestOnClaimsCashflow[i] = 1 / monthlyInterestFactor.GetValidElement(i/12) * (interestOnClaimsCashflow.ElementAtOrDefault(i + 1) + nominalClaimsCashflow[i] - nominalClaimsCashflow.ElementAtOrDefault(i + 1));", + "\n interestOnClaimsCashflowCreditRisk[i] = 1 / monthlyInterestFactor.GetValidElement(i/12) * (Math.Exp(-nonPerformanceRiskRate) * interestOnClaimsCashflowCreditRisk.ElementAtOrDefault(i + 1) + nominalClaimsCashflow[i] - nominalClaimsCashflow.ElementAtOrDefault(i + 1));", + "\n effectCreditRisk[i] = interestOnClaimsCashflow[i] - interestOnClaimsCashflowCreditRisk[i];", + "\n }", + "\n ", + "\n return Subtract(nominalValuesCreditRisk, effectCreditRisk);", + "\n }", + "\n}" + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "## Present Value", + "\n", + "\nThe PV values are valid for all choices of the [Economic Basis](../DataModel/DataStructure#economic-basis):", + "\n", + "\n$$", + "\n\\text{PV}_i (\\text{AoC step}) = \\left\\{", + "\n\\begin{array}{rl}", + "\n\\text{CDC}_i ~, & \\text{if AoC Type = BOP} \\\\", + "\n-\\text{Nominal}_i(\\text{Parent AoC Step}) ~, & \\text{if AoC Type = CF } \\\\", + "\n\\text{InterestAccretion}_i ~, & \\text{if AoC Type = IA } \\\\", + "\n0 ~, & \\text{if AoC Type = AM } \\\\\\", + "\n\\text{CDC}_i(\\text{Parent AoC step}) ~, & \\text{if AoC Type = EOP } \\\\", + "\n\\text{TelescopingDifference}_i ~, & \\text{otherwise}", + "\n\\end{array}", + "\n\\right.", + "\n$$", + "\n", + "\nwhere $i$ denotes the months, and the [$\\rm{TelescopingDifference}_i$](#telescopic-difference) and the [$\\rm{InterestAccretion}_i$](#interest-accretion) quantities are defined above." + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "public interface PresentValue : IWithGetValueFromValues", + "\n{ ", + "\n static ApplicabilityBuilder ScopeApplicabilityBuilder(ApplicabilityBuilder builder) =>", + "\n builder.ForScope(s => s", + "\n .WithApplicability(x => x.GetStorage().ImportFormat != ImportFormats.Cashflow || x.GetStorage().IsSecondaryScope(x.Identity.Id.DataNode))", + "\n .WithApplicability(x => (x.Identity.Id.AocType == AocTypes.BOP && x.Identity.Id.Novelty != Novelties.C) || x.Identity.Id.AocType == AocTypes.EOP)", + "\n .WithApplicability(x => x.Identity.Id.AocType == AocTypes.CF)", + "\n .WithApplicability(x => x.Identity.Id.IsReinsurance && x.Identity.AmountType == AmountTypes.CDR && x.Identity.Id.AocType == AocTypes.IA)", + "\n .WithApplicability(x => x.Identity.Id.AocType == AocTypes.IA)", + "\n .WithApplicability(x => new string[]{AocTypes.BOP, AocTypes.EA, AocTypes.AM, AocTypes.RCU}.Contains(x.Identity.Id.AocType) ) //add here combination CRU for At !CDR?", + "\n );", + "\n ", + "\n [NotVisible][IdentityProperty][Dimension(typeof(EconomicBasis))]", + "\n string EconomicBasis => GetContext();", + "\n ", + "\n [NotVisible]", + "\n double[] Values => GetScope(Identity).Values;", + "\n ", + "\n public double Value => GetValueFromValues(Values);", + "\n}", + "\n", + "\npublic interface ComputePresentValueWithIfrsVariable : PresentValue", + "\n{", + "\n double PresentValue.Value => GetStorage().GetValue(Identity.Id, Identity.AmountType, Identity.EstimateType, EconomicBasis, Identity.AccidentYear);", + "\n double[] PresentValue.Values => Enumerable.Empty().ToArray();", + "\n}", + "\n", + "\npublic interface PresentValueFromDiscountedCashflow : PresentValue", + "\n{", + "\n [NotVisible]", + "\n double[] PresentValue.Values => GetScope(Identity).Values;", + "\n}", + "\n", + "\npublic interface CashflowAocStep : PresentValue", + "\n{", + "\n [NotVisible]", + "\n double[] PresentValue.Values => GetScope(Identity).Values;", + "\n}", + "\n", + "\npublic interface PresentValueWithInterestAccretion : PresentValue, IWithInterestAccretion", + "\n{", + "\n [NotVisible]", + "\n double[] PresentValue.Values => GetInterestAccretion();", + "\n}", + "\n", + "\npublic interface PresentValueWithInterestAccretionForCreditRisk : PresentValue, IWithInterestAccretionForCreditRisk", + "\n{", + "\n [NotVisible]", + "\n double[] PresentValue.Values => GetInterestAccretion();", + "\n}", + "\n", + "\npublic interface EmptyValuesAocStep : PresentValue", + "\n{", + "\n [NotVisible]", + "\n double[] PresentValue.Values => Enumerable.Empty().ToArray();", + "\n}" + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "## Current and Locked", + "\n", + "\nPV Current and PV Locked below basically hold the Present Values [PV](#present-value) computed using the **Current** yield curves and the **Locked** yield curves, respectively.", + "\n", + "\nValues are available for each AmountType (by calling PvLocked.ByAmountType):", + "\n", + "\n$$", + "\n\\text{PV Locked}(\\text{AoC step}, \\text{Amount Type}) = \\text{PV}(\\text{AoC step}, \\text{Amount Type})|_{\\text{Economic Base = L}}", + "\n$$", + "\n", + "\n$$", + "\n\\text{PV Current}(\\text{AoC step}, \\text{Amount Type}) = \\text{PV}(\\text{AoC step}, \\text{Amount Type})|_{\\text{Economic Base = C}}", + "\n$$", + "\n", + "\n", + "\nAnd aggregated values are also available as the sum over all [Amount Types](../DataModel/DataStructure#amount-type) (by calling PvLocked.Value):", + "\n", + "\n$$", + "\n\\text{PV Locked}(\\text{AoC step}) = \\sum_{\\text{Amount Types}} \\text{PV}(\\text{AoC step}, \\text{Amount Type})|_{\\text{Economic Base = L}}", + "\n$$", + "\n", + "\n$$", + "\n\\text{PV Current}(\\text{AoC step}) = \\sum_{\\text{Amount Types}} \\text{PV}(\\text{AoC step}, \\text{Amount Type})|_{\\text{Economic Base = C}}", + "\n$$", + "\n", + "\nThese are used in the BBA methodology, whereby in the CSM calculations only PV Locked is used, and both of them are stored in the database under the [IfrsVariable](../DataModel/DataStructure#ifrs-variable) data structure." + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "public interface PvLocked : IScope", + "\n{ ", + "\n [IdentityProperty][NotVisible][Dimension(typeof(EconomicBasis))]", + "\n string EconomicBasis => EconomicBases.L;", + "\n ", + "\n [IdentityProperty][NotVisible][Dimension(typeof(EstimateType))]", + "\n string EstimateType => EstimateTypes.BE;", + "\n ", + "\n private int?[] accidentYears => GetStorage().GetAccidentYears(Identity.DataNode).ToArray(); ", + "\n ", + "\n [NotVisible]", + "\n PresentValue[] PresentValues => GetScope(Identity.DataNode).BeAmountTypes", + "\n .SelectMany(at => accidentYears", + "\n .Select(ay => GetScope((Identity, at, EstimateType, ay), o => o.WithContext(EconomicBasis))))", + "\n .ToArray();", + "\n double Value => PresentValues.Aggregate().Value;", + "\n}", + "\n", + "\npublic interface PvCurrent : IScope", + "\n{", + "\n [IdentityProperty][NotVisible][Dimension(typeof(EconomicBasis))]", + "\n string EconomicBasis => EconomicBases.C;", + "\n ", + "\n [IdentityProperty][NotVisible][Dimension(typeof(EstimateType))]", + "\n string EstimateType => EstimateTypes.BE;", + "\n ", + "\n private int?[] accidentYears => GetStorage().GetAccidentYears(Identity.DataNode).ToArray();", + "\n ", + "\n [NotVisible]", + "\n PresentValue[] PresentValues => GetScope(Identity.DataNode).BeAmountTypes", + "\n .SelectMany(at => accidentYears", + "\n .Select(ay => GetScope((Identity, at, EstimateType, ay), o => o.WithContext(EconomicBasis))))", + "\n .ToArray();", + "\n ", + "\n double Value => PresentValues.Aggregate().Value;", + "\n}" + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "# Risk Adjustment", + "\n", + "\nRisk Adjustment values ($\\rm{RA}$) are accessible from the [PresentValue](#present-value) data and have [Estimate Type](../DataModel/DataStructure#estimate-type) $RA$. In particular, the Locked-In and Current values are given by:", + "\n", + "\n$$", + "\n\\text{RA Locked}(\\text{AoC step}) = \\text{PV}(\\text{AoC step})|_{\\text{Calculation Type = RA},~ \\text{Economic Basis = L}}", + "\n$$", + "\n", + "\n$$", + "\n\\text{RA Current}(\\text{AoC step}) = \\text{PV}(\\text{AoC step})|_{\\text{Calculation Type = RA},~ \\text{Economic Basis = C}}", + "\n$$", + "\n", + "\nwhere PV is defined [above](#present-value) and uses the input cash flows with Calculation Type = RA." + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "public interface RaLocked : IScope", + "\n{ ", + "\n [IdentityProperty][NotVisible][Dimension(typeof(EconomicBasis))]", + "\n string EconomicBasis => EconomicBases.L;", + "\n ", + "\n [IdentityProperty][NotVisible][Dimension(typeof(EstimateType))]", + "\n string EstimateType => EstimateTypes.RA;", + "\n ", + "\n private int?[] accidentYears => GetStorage().GetAccidentYears(Identity.DataNode).ToArray(); ", + "\n ", + "\n PresentValue[] PresentValues => accidentYears.Select(ay => GetScope((Identity, (string)null, EstimateType, ay), o => o.WithContext(EconomicBasis))).ToArray();", + "\n ", + "\n double Value => PresentValues.Aggregate().Value;", + "\n}", + "\npublic interface RaCurrent : IScope", + "\n{", + "\n [IdentityProperty][NotVisible][Dimension(typeof(EconomicBasis))]", + "\n string EconomicBasis => EconomicBases.C;", + "\n ", + "\n [IdentityProperty][NotVisible][Dimension(typeof(EstimateType))]", + "\n string EstimateType => EstimateTypes.RA;", + "\n ", + "\n private int?[] accidentYears => GetStorage().GetAccidentYears(Identity.DataNode).ToArray(); ", + "\n ", + "\n PresentValue[] PresentValues => accidentYears.Select(ay => GetScope((Identity, (string)null, EstimateType, ay), o => o.WithContext(EconomicBasis))).ToArray(); ", + "\n ", + "\n double Value => PresentValues.Aggregate().Value;", + "\n}" + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "# Amortization", + "\n", + "\nFor the Amortization AoC Step (AoC Type **AM**), the amortization factors to be used are defined below." + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "## Coverage Units", + "\n", + "\nThe coverage unit (CU) of a GIC is introduced in the standard as the quantity of the service provided in that GIC. The service is", + "\nmeasured by considering the quantity of benefits provided as well as the expected coverage period of the GIC.", + "\n", + "\nThe cash flows of coverage units are retrieved from the discounted cash flows with [EstimateType](../DataModel/DataStructure#estimate-type) CU." + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "public interface CoverageUnitCashflow : IScope", + "\n{ ", + "\n [NotVisible] string EconomicBasis => GetContext();", + "\n ", + "\n [IdentityProperty][NotVisible][Dimension(typeof(EstimateType))]", + "\n string EstimateType => EstimateTypes.CU;", + "\n ", + "\n double[] Values => GetScope((Identity, (string)null, EstimateType, (int?)null)).Values;", + "\n}" + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "## Amortization Factor" + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "For a certain GIC, the monthly Amortization Factors $\\text{Monthly }AF_i$ are computed from the cash flows of the underlying coverage unit for that GIC:", + "\n", + "\n$$", + "\n\\text{Monthly }AF_i = 1 - \\frac{ \\text{Nominal}_i(CL)} {\\text{CDC}_i(CL) } ~.", + "\n$$", + "\n", + "\nwhere:", + "\n- $i$ denotes a monthly period;", + "\n- the nominal cash flows $\\text{Nominal}_i(CL)$ are the nominal cash flows of the coverage unit for the AoC Step **Combined Liability** (CL) (input data);", + "\n- and the corresponding cumulated discounted cash flows $\\text{CDC}_i$ are defined [above](#cumulated-discounted-cash-flows)." + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "public interface MonthlyAmortizationFactorCashflow : IScope", + "\n{", + "\n private double[] NominalCuCashflow => GetScope((Identity with {AocType = AocTypes.CL}, (string)null, EstimateTypes.CU, (int?)null)).Values;", + "\n private double[] DiscountedCuCashflow => Multiply(-1d, GetScope(Identity with {AocType = AocTypes.CL}, o => o.WithContext(EconomicBasis)).Values);", + "\n ", + "\n [NotVisible] string EconomicBasis => GetContext();", + "\n ", + "\n double[] MonthlyAmortizationFactors => Identity.AocType switch {", + "\n AocTypes.AM => NominalCuCashflow.Zip(DiscountedCuCashflow, //Extract to an other scope with month in the identity to avoid Zip?", + "\n (nominal, discountedCumulated) => Math.Abs(discountedCumulated) >= Precision ", + "\n ? 1 - nominal / discountedCumulated ", + "\n : 0).ToArray(),", + "\n _ => Enumerable.Empty().ToArray(),", + "\n };", + "\n}" + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "For a certain projection period - defined by the Shift, $S$, and the Time-Step, $TS$, parameters - the Amortization Factor is then given by the product of the corresponding monthly amortization factors:", + "\n", + "\n$$", + "\nAF = 1 - \\prod _{i = S}^{S + TS - 1} \\text{Monthly }AF_i ~.", + "\n$$", + "\n", + "\nEach GIC will have his own AF.", + "\n", + "\nIn order to run off the business of a given Group of Contract one should provide a cash flow of 0s for the AoC Step with AoC Type CL and Novelty C. When computing the AF this results in the product of the monthly amortization factors of the period to be 1. In this case, the computed AF does not follow the formula above but is 1 allowing for the full release of the Technical Margin in the AM AoC Step." + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "public interface CurrentPeriodAmortizationFactor : IScope", + "\n{", + "\n static ApplicabilityBuilder ScopeApplicabilityBuilder(ApplicabilityBuilder builder) =>", + "\n builder.ForScope(s => ", + "\n s.WithApplicability(x => x.GetStorage().ImportFormat != ImportFormats.Cashflow", + "\n || x.GetStorage().IsSecondaryScope(x.Identity.DataNode)));", + "\n", + "\n private int shift => GetStorage().GetShift(0);//Identity.ProjectionPeriod", + "\n private int timeStep => GetStorage().GetTimeStep(0);//Identity.ProjectionPeriod", + "\n private double amortizedFactor => GetScope(Identity)", + "\n .MonthlyAmortizationFactors", + "\n .Skip(shift)", + "\n .Take(timeStep)", + "\n .Aggregate(1d, (x, y) => x * y);", + "\n [NotVisible] string EconomicBasis => GetContext();", + "\n", + "\n string EstimateType => EstimateTypes.F;", + "\n double Value => Math.Abs(amortizedFactor - 1d) > Precision", + "\n ? 1d - amortizedFactor", + "\n : 1d;", + "\n}", + "\n", + "\npublic interface AmfFromIfrsVariable : CurrentPeriodAmortizationFactor", + "\n{", + "\n double CurrentPeriodAmortizationFactor.Value => GetStorage().GetValue(Identity, (string)null, EstimateType, EconomicBasis, (int?)null);", + "\n}" + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "" + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + } + ] +} \ No newline at end of file diff --git a/ifrs17/Import/3ImportScope-Actuals.ipynb b/ifrs17/Import/3ImportScope-Actuals.ipynb new file mode 100644 index 00000000..89d60ad9 --- /dev/null +++ b/ifrs17/Import/3ImportScope-Actuals.ipynb @@ -0,0 +1,344 @@ +{ + "metadata": { + "authors": [], + "id": "1-Sd2C2w2kaytthWS3cL1P", + "kernelspec": { + "display_name": "Formula Framework", + "language": "C#", + "name": "C#" + }, + "language_info": { + "file_extension": ".cs", + "mimetype": "text/plain", + "name": "C#" + } + }, + "nbformat": 4, + "nbformat_minor": 5, + "cells": [ + { + "cell_type": "markdown", + "source": [ + "

IFRS 17 Methodology

", + "\n

Business Logic with Scopes

" + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "In this notebook the focus is on the calculation of actuals values. " + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "# References", + "\nLibraries and other notebooks which are needed for this notebook are imported below." + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "## Notebooks" + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "#!import \"2ImportScope-PresentValue\"" + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "# Actual Values", + "\n", + "\nWe consider 4 types of Actual values, which are distinguished through their [Estimate Type](../DataModel/DataStructure#estimate-type):", + "\n- [Actuals](#actuals) (A)", + "\n- [Advance Actuals](#advance-actuals) (AA)", + "\n- [Overdue Actuals](#overdue-actuals) (OA)", + "\n- [Deferrable Actuals](#deferrable-actuals) (DA)", + "\n", + "\nwith the Estimate Type's system name shown between parenthesis above.", + "\n", + "\nThe following simplified AoC Chain applies for Advance and Overdue Actuals:", + "\n
 BOP", + "\n
 Release", + "\n
 Write-off", + "\n
 EOP" + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "## Actual Base", + "\n", + "\nThe Actual Base sets values for actual, advance, and overdue as follows:", + "\n", + "\n$$", + "\n\\text{Actual Base} (\\text{AoC step}) = \\left\\{", + "\n\\begin{array}{rl}", + "\n0 ~, & \\text{if AoC Step's AoC Type = AM} \\\\", + "\n\\text{Actual Base}(\\rm{BOP}) + \\text{Actual Base}(\\rm{CF}) + \\text{Actual Base}(\\rm{WO}) ~, & \\text{if AoC Step's AoC Type = EOP and EstimateType is not A} \\\\", + "\n\\text{Imported Actual} ~, & \\text{otherwise}", + "\n\\end{array}", + "\n\\right.", + "\n$$", + "\n", + "\nwhere the value is also function of the [Estimate Type](../DataModel/DataStructure#EstimateType) and [Amount Type](../DataModel/DataStructure#AmountType), and the $\\text{Imported Actual}$ value is described [here]()." + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "public interface ActualBase : IScope<(ImportIdentity Id, string AmountType, string EstimateType, int? AccidentYear), ImportStorage>", + "\n{", + "\n static ApplicabilityBuilder ScopeApplicabilityBuilder(ApplicabilityBuilder builder) =>", + "\n builder.ForScope(s => s.WithApplicability(x => x.GetStorage().ImportFormat == ImportFormats.Actual ", + "\n && !x.GetStorage().IsSecondaryScope(x.Identity.Id.DataNode)", + "\n && x.Identity.Id.AocType == AocTypes.AM)", + "\n .WithApplicability(x => x.GetStorage().ImportFormat != ImportFormats.Cashflow ", + "\n && !x.GetStorage().IsSecondaryScope(x.Identity.Id.DataNode)", + "\n && x.Identity.Id.AocType == AocTypes.EOP ", + "\n && x.Identity.EstimateType != EstimateTypes.A)", + "\n );", + "\n public double Value => GetStorage().GetValue(Identity.Id, Identity.AmountType, Identity.EstimateType, Identity.AccidentYear); ", + "\n}", + "\n", + "\npublic interface EndOfPeriodActual : ActualBase", + "\n{", + "\n double ActualBase.Value => GetScope((Identity.Id, InputSource.Actual)).Values", + "\n .Sum(aocStep => GetScope((Identity.Id with {AocType = aocStep.AocType, Novelty = aocStep.Novelty}, Identity.AmountType, Identity.EstimateType, Identity.AccidentYear)).Value);", + "\n}", + "\n", + "\npublic interface EmptyValuesActual : ActualBase", + "\n{", + "\n double ActualBase.Value => 0;", + "\n}" + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "## Actuals", + "\nThe Actuals correspond to ActualBase values with estimate type $A$.", + "\nThe only valid AoC Step is Release:", + "\n", + "\n$$", + "\n\\text{Actual} (\\text{Release}) = \\text{Actual Base} (\\text{Release})|_{\\text{Estimate Type} = A}", + "\n$$" + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "public interface Actual : IScope", + "\n{", + "\n [IdentityProperty][NotVisible][Dimension(typeof(EstimateType))]", + "\n string EstimateType => EstimateTypes.A;", + "\n ", + "\n private int?[] accidentYears => GetStorage().GetAccidentYears(Identity.DataNode).ToArray();", + "\n ", + "\n [NotVisible]", + "\n ActualBase[] Actuals => GetScope(Identity.DataNode).ActualAmountTypes", + "\n .SelectMany(at => accidentYears", + "\n .Select(ay => GetScope((Identity, at, EstimateType, ay)))).ToArray();", + "\n}" + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "## Advance Actuals", + "\n", + "\nAdvance Actuals are cash flows with due date inside the reporting period but occured *before* the reporting period - They include:", + "\n- Receivable Claims", + "\n- Receivable Expenses", + "\n- Payable Premiums", + "\n", + "\nAdvance Actuals are given by", + "\n", + "\n$$", + "\n\\text{Advance Actual} (\\text{AoC step}) = \\text{Actual Base} (\\text{AoC step})|_{\\text{Estimate Type} = AA}", + "\n$$" + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "public interface AdvanceActual : IScope", + "\n{", + "\n [IdentityProperty][NotVisible][Dimension(typeof(EstimateType))]", + "\n string EstimateType => EstimateTypes.AA;", + "\n ", + "\n private int?[] accidentYears => GetStorage().GetAccidentYears(Identity.DataNode).ToArray();", + "\n ", + "\n [NotVisible]", + "\n ActualBase[] Actuals => GetScope(Identity.DataNode).ActualAmountTypes", + "\n .SelectMany(at => accidentYears", + "\n .Select(ay => GetScope((Identity, at, EstimateType, ay)))).ToArray();", + "\n}" + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "## Overdue Actuals", + "\n", + "\nOverdue Actuals are cash flows with due date inside the reporting period but occur *after* the reporting period - They contain:", + "\n- Payable Claims", + "\n- Payable Expenses", + "\n- Receivable Premiums", + "\n", + "\nThe sign convention is the inverse of the default behavior - In particular: Premiums have positive value, whereas Claims and Expenses have negative value.", + "\n", + "\nThe Overdue Actuals are given by", + "\n", + "\n$$", + "\n\\text{Overdue Actual} (\\text{AoC step}) = \\text{Actual Base} (\\text{AoC step})|_{\\text{Estimate Type} = OA}", + "\n$$" + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "public interface OverdueActual : IScope", + "\n{", + "\n [IdentityProperty][NotVisible][Dimension(typeof(EstimateType))]", + "\n string EstimateType => EstimateTypes.OA;", + "\n ", + "\n private int?[] accidentYears => GetStorage().GetAccidentYears(Identity.DataNode).ToArray();", + "\n ", + "\n [NotVisible]", + "\n ActualBase[] Actuals => GetScope(Identity.DataNode).ActualAmountTypes", + "\n .SelectMany(at => accidentYears", + "\n .Select(ay => GetScope((Identity, at, EstimateType, ay)))).ToArray();", + "\n}" + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "## Deferrable Actuals", + "\n", + "\nFinally, Deferrable Actuals are given by", + "\n", + "\n$$", + "\n\\text{Deferrable Actual} (\\text{AoC step}) = \\left\\{", + "\n\\begin{array}{rl}", + "\n\\sum_{\\text{Amount Type}~\\in~\\text{\\{ACA, AEA}\\}}\\text{Actual Base}(\\rm{CF})|_{\\text{Estimate Type = A}} ~, & \\text{if AoC Step's AoC Type = CF } \\\\", + "\n- \\text{Amortization Factor} \\cdot \\big( \\text{Deferrable Actual}(\\rm{BOP}) + \\text{Deferrable Actual}(\\rm{CF}) \\big) ~, & \\text{if AoC Step's AoC Type = AM } \\\\", + "\n\\text{Deferrable Actual}(\\rm{BOP}) + \\text{Deferrable Actual}(\\rm{CF}) + \\text{Deferrable Actual}(\\rm{AM}) ~, & \\text{if AoC Step's AoC Type = EOP } \\\\", + "\n\\text{Input Actual}|_{\\text{Estimate Type = DA}} ~, & \\text{ otherwise } \\\\", + "\n\\end{array}", + "\n\\right.", + "\n$$", + "\n", + "\nwhere $ACA$ and $AEA$ are *Aquisition* Amount Types from **Attributable Commission** and **Attributable Expenses**, respectively." + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "public interface DeferrableActual : IScope", + "\n{", + "\n static ApplicabilityBuilder ScopeApplicabilityBuilder(ApplicabilityBuilder builder) =>", + "\n builder.ForScope(s => s.WithApplicability(x => x.Identity.ValuationApproach == ValuationApproaches.VFA, ", + "\n p => p.ForMember(s => s.EconomicBasis))", + "\n .WithApplicability(x => x.Identity.AocType == AocTypes.CF)", + "\n .WithApplicability(x => x.Identity.AocType == AocTypes.AM)", + "\n .WithApplicability(x => x.Identity.AocType == AocTypes.EOP)", + "\n );", + "\n ", + "\n [IdentityProperty][NotVisible][Dimension(typeof(EstimateType))]", + "\n string EstimateType => EstimateTypes.DA;", + "\n ", + "\n [NotVisible] string EconomicBasis => EconomicBases.L;", + "\n ", + "\n public double Value => GetStorage().GetValue(Identity, (string)null, EstimateType, (int?)null);", + "\n}", + "\n", + "\npublic interface DeferrableActualForCurrentBasis : DeferrableActual", + "\n{", + "\n [NotVisible] string DeferrableActual.EconomicBasis => EconomicBases.C;", + "\n}", + "\n", + "\npublic interface ReleaseDeferrable : DeferrableActual", + "\n{", + "\n double DeferrableActual.Value => GetStorage().GetAttributableExpenseAndCommissionAmountType().Sum(at => GetScope((Identity, at, EstimateTypes.A, (int?)null)).Value);", + "\n}", + "\n", + "\npublic interface AmortizationDeferrable : DeferrableActual", + "\n{", + "\n private double AmortizationFactor => GetScope(Identity, o => o.WithContext(EconomicBasis)).Value;", + "\n private double AggregatedDeferrable => GetScope((Identity, InputSource.Actual)).Values", + "\n .Sum(aocStep => GetScope(Identity with {AocType = aocStep.AocType, Novelty = aocStep.Novelty}).Value);", + "\n double DeferrableActual.Value => -1d * AggregatedDeferrable * AmortizationFactor;", + "\n}", + "\n", + "\npublic interface EndOfPeriodDeferrable : DeferrableActual", + "\n{", + "\n double DeferrableActual.Value => GetScope((Identity, InputSource.Actual)).Values", + "\n .Sum(aocStep => GetScope(Identity with {AocType = aocStep.AocType, Novelty = aocStep.Novelty}).Value);", + "\n}" + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "" + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + } + ] +} \ No newline at end of file diff --git a/ifrs17/Import/4ImportScope-TechnicalMargin.ipynb b/ifrs17/Import/4ImportScope-TechnicalMargin.ipynb new file mode 100644 index 00000000..5edb792a --- /dev/null +++ b/ifrs17/Import/4ImportScope-TechnicalMargin.ipynb @@ -0,0 +1,673 @@ +{ + "metadata": { + "authors": [], + "id": "1-Sd2C2w2kaytthWS3cL1X", + "kernelspec": { + "display_name": "Formula Framework", + "language": "C#", + "name": "C#" + }, + "language_info": { + "file_extension": ".cs", + "mimetype": "text/plain", + "name": "C#" + } + }, + "nbformat": 4, + "nbformat_minor": 5, + "cells": [ + { + "cell_type": "markdown", + "source": [ + "

IFRS 17 Methodology

", + "\n

Business Logic with Scopes

" + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "In this notebook the focus is on the calculation of Contractual Service Margin, Loss Component and Loss Recovery Component. ", + "\n

", + "\nThe Contractual Service Margin ($CSM$) denotes the unearned profit from an insurance contract or group of insurance contracts and plays a critical role in the calculation of profit & loss values. Similarly, the unearned loss is denoted by Loss Component ($LC$), Loss Recovery Component in the case of reinsurance contracts." + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "# References", + "\nLibraries and other notebooks which are needed for this notebook are imported below." + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "## Notebooks" + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "#!import \"3ImportScope-Actuals\"" + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "" + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "# Experience Adjustment on Premium" + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "The Experience Adjustment (EA) on Premiums weights the cash-flow (CF aocSteps) for premium amount types by the PremiumAllocationFactor input for each group of insurance contract. ", + "\nThe contributions of present values and actuals are computed separately.", + "\n", + "\n$$", + "\nEA (\\rm{PV}) = \\text{Premium Allocation Factor} \\cdot \\big( PV (\\text{AoC Type = CF}) \\big)~, \\\\", + "\n$$", + "\n$$", + "\nEA (\\text{Actual}) = \\text{Premium Allocation Factor} \\cdot \\big( \\text{Actual}(\\text{AoC Type = CF}) \\big) ~,", + "\n$$", + "\nwhere amount type premium and its children are considered, novelties in-force and new business are considered for $PV$ whereas novelty combined is considered for Actual. The allocation is always done in the finest granularity (novelty, line of business, ..) possible." + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "public interface BeExperienceAdjustmentForPremium : IScope", + "\n{", + "\n static ApplicabilityBuilder ScopeApplicabilityBuilder(ApplicabilityBuilder builder) =>", + "\n builder.ForScope(s => s", + "\n .WithApplicability(x => x.Identity.AocType != AocTypes.CF));", + "\n", + "\n string EstimateType => EstimateTypes.BEPA;", + "\n string EconomicBasis => EconomicBases.L;", + "\n ", + "\n PresentValue[] ByAmountType => GetStorage().GetPremiums().Select(pr => ", + "\n Multiply( GetStorage().GetPremiumAllocationFactor(Identity), ", + "\n GetScope((Identity, pr, EstimateTypes.BE, (int?)null), o => o.WithContext(EconomicBasis)) ) ).ToArray(); ", + "\n}", + "\n", + "\npublic interface DefaultValueBeExperienceAdjustmentForPremium : BeExperienceAdjustmentForPremium", + "\n{", + "\n PresentValue[] BeExperienceAdjustmentForPremium.ByAmountType => Enumerable.Empty().ToArray();", + "\n}" + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "public interface ActualExperienceAdjustmentOnPremium : IScope", + "\n{", + "\n static ApplicabilityBuilder ScopeApplicabilityBuilder(ApplicabilityBuilder builder) =>", + "\n builder.ForScope(s => s", + "\n .WithApplicability(x => x.Identity.AocType != AocTypes.CF));", + "\n ", + "\n public ActualBase[] ByAmountTypeAndEstimateType => GetStorage().GetPremiums().Select(pr =>", + "\n Multiply( GetStorage().GetPremiumAllocationFactor(Identity),", + "\n GetScope((Identity, pr, EstimateTypes.A, (int?)null))) ).ToArray();", + "\n}", + "\n", + "\npublic interface DefaultValueActualExperienceAdjustmentOnPremium : ActualExperienceAdjustmentOnPremium", + "\n{", + "\n ActualBase[] ActualExperienceAdjustmentOnPremium.ByAmountTypeAndEstimateType => Enumerable.Empty().ToArray();", + "\n}" + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "", + "\n# Technical Margin", + "\n", + "\nFor the computation of the $CSM$ or $LC$ component values for each step of the [AoC Step Structure](#aoc-step-structure), it is convenient to introduce the ", + "\nnotion of technical margin $TM$. In the case of BBA methodology, the Locked-in interest rates discounting is applied to obtain the PV and RA values.", + "\n", + "\nThis can be summarized as follows:", + "\n", + "\n$$", + "\nTM(s) = \\left\\{", + "\n\\begin{array}{rl}", + "\nTM(\\rm{EOP}) \\text{ of the previous period} ~ & \\text{if }s = \\text{BOP and Novelty is In-Force}.", + "\n\\\\", + "\n0 ~ & \\text{if }s = \\text{CF}.", + "\n\\\\", + "\nIAF \\cdot~\\text{Aggregated}~TM(\\text{IA}) ~ & \\text{if }s = \\text{IA and Novelty is In-Force}.", + "\n\\\\", + "\n\\rm{Premiums} + \\text{Attributable Expense and Commissions} + \\text{Investment Claims} ~ & \\text{if }s = \\text{EA}.", + "\n\\\\", + "\n-AF \\cdot~\\text{Aggregated}~TM(\\text{AM})~ & \\text{if }s = \\text{AM}.", + "\n\\\\", + "\n\\text{PV}(\\text{s})\\bigg|_{\\substack{\\text{Non Attributable} \\\\ \\text{Amount Types} \\\\ \\text{excluded}}} ", + "\n+ \\text{RA}(\\text{s})~ & \\text{otherwise} ", + "\n\\end{array}", + "\n\\right.", + "\n$$", + "\n", + "\nwhere", + "\n", + "\n$$", + "\n\\text{Aggregated}~TM (\\text{AoC step}) = \\sum_{s\\in\\text{ previous AoC steps}} TM(s)~.", + "\n$$", + "\n", + "\nand the Interest Accretion Factor ($IAF$) is given by", + "\n", + "\n$$", + "\nIAF = \\prod_{i=1}^{TS} \\text{Interest}_i - 1", + "\n$$", + "\n", + "\nwhere $\\text{Interest}_i$ is the monthly interest factor obtained from the [Yield Curve](#yield-curves) and $TS$ is the Time-Step.", + "\n", + "\nFinally, the Premiums, Attributable Expense and Commissions and Investment Claims terms are given by:", + "\n", + "\n$$", + "\n\\rm{Premiums} = \\sum_{\\text{Amount Type}\\in\\{\\text{PR and its children}\\}}", + "\nEA(\\rm{PV}) - EA(\\text{Actual}) ~,", + "\n$$", + "\n", + "\n$$", + "\n\\text{Attributable Expense and Commissions} = \\sum_{\\text{Amount Type}\\in\\{\\rm{ACA}, \\rm{AEA}\\}}", + "\n\\big(PV_{\\text{Novelty = I}} + PV_{\\text{Novelty = N}} \\big) - \\text{Actual}_{\\text{Novelty=C}} ~,", + "\n$$", + "\n", + "\n$$", + "\n\\text{Investment Claims } = \\sum_{\\text{Amount Type}\\in\\{\\text{ICO and its children}\\}}", + "\n\\big(PV_{\\text{Novelty = I}} + PV_{\\text{Novelty = N}} \\big) - \\text{Actual}_{\\text{Novelty=C}} ~,", + "\n$$", + "\n", + "\nwhere the AoC Step **CF** is implicit for all formulas, $PV$ is the [present value](#present-value) with Estimate Type **BE** (Best Estimate), and Actuals have Estimate Types **A** (see details [here](#actual-values)). Note that according to the applied sign convention, the sign of the CF AoC Step of Best Estimate Present Value and Actual is the same, accounting for the minus sign in the formula. " + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "public interface TechnicalMargin : IScope", + "\n{", + "\n static ApplicabilityBuilder ScopeApplicabilityBuilder(ApplicabilityBuilder builder) => ", + "\n builder.ForScope(s => s.WithApplicability(x => x.Identity.ValuationApproach == ValuationApproaches.VFA, p => p.ForMember(s => s.EconomicBasis))", + "\n .WithApplicability(x => x.Identity.AocType == AocTypes.BOP && x.Identity.Novelty == Novelties.I)", + "\n .WithApplicability(x => x.Identity.AocType == AocTypes.CF)", + "\n .WithApplicability(x => x.Identity.AocType == AocTypes.IA && x.Identity.Novelty == Novelties.I)", + "\n .WithApplicability(x => x.Identity.AocType == AocTypes.EA && !x.Identity.IsReinsurance)", + "\n .WithApplicability(x => x.Identity.AocType == AocTypes.AM)", + "\n );", + "\n ", + "\n [NotVisible] string EconomicBasis => EconomicBases.L;", + "\n ", + "\n double Value => GetScope(Identity.DataNode).BeAmountTypes", + "\n .Except(GetStorage().GetNonAttributableAmountType())", + "\n .Sum(at => GetScope((Identity, at, EstimateTypes.BE, (int?)null), o => o.WithContext(EconomicBasis)).Value) +", + "\n GetScope(Identity).Value;", + "\n ", + "\n double AggregatedValue => GetScope((Identity, InputSource.Cashflow)).Values", + "\n .Sum(aoc => GetScope(Identity with {AocType = aoc.AocType, Novelty = aoc.Novelty}).Value);", + "\n}", + "\n", + "\npublic interface TechnicalMarginForCurrentBasis : TechnicalMargin", + "\n{", + "\n [NotVisible] string TechnicalMargin.EconomicBasis => EconomicBases.C;", + "\n}", + "\n", + "\npublic interface TechnicalMarginForBOP : TechnicalMargin", + "\n{", + "\n private double ValueCsm => GetStorage().GetValue(Identity, null, EstimateTypes.C, null);", + "\n private double ValueLc => GetStorage().GetValue(Identity, null, EstimateTypes.L, null);", + "\n private double ValueLr => GetStorage().GetValue(Identity, null, EstimateTypes.LR, null);", + "\n ", + "\n double TechnicalMargin.Value => -1d * ValueCsm + ValueLc + ValueLr;", + "\n}", + "\n", + "\npublic interface TechnicalMarginDefaultValue : TechnicalMargin", + "\n{", + "\n double TechnicalMargin.Value => default;", + "\n}", + "\n", + "\npublic interface TechnicalMarginForIA : TechnicalMargin", + "\n{", + "\n private int timeStep => GetStorage().GetTimeStep(0);//Identity.Id.ProjectionPeriod", + "\n private int shift => GetStorage().GetShift(0);//Identity.Id.ProjectionPeriod", + "\n ", + "\n private double[] monthlyInterestFactor => GetScope(Identity, o => o.WithContext(EconomicBasis)).Interest;", + "\n ", + "\n private double interestAccretionFactor => Enumerable.Range(shift,timeStep)", + "\n .Select(i => monthlyInterestFactor.GetValidElement(i/12))", + "\n .Aggregate(1d, (x, y) => x * y ) - 1d;", + "\n ", + "\n double TechnicalMargin.Value => AggregatedValue * interestAccretionFactor;", + "\n}", + "\n", + "\npublic interface TechnicalMarginForEA : TechnicalMargin", + "\n{", + "\n static ApplicabilityBuilder ScopeApplicabilityBuilderInner(ApplicabilityBuilder builder) => ", + "\n builder.ForScope(s => s.WithApplicability(x => x.Identity.IsReinsurance));", + "\n ", + "\n private string referenceAocType => GetScope(Identity).Value.AocType;", + "\n ", + "\n private double premiums => GetStorage().GetNovelties(referenceAocType, InputSource.Cashflow)", + "\n .Sum(n => GetScope(Identity with {AocType = referenceAocType, Novelty = n}).ByAmountType.Sum(sc => sc.Value)) -", + "\n GetScope(Identity with {AocType = referenceAocType, Novelty = Novelties.C}).ByAmountTypeAndEstimateType.Sum(sc => sc.Value);", + "\n ", + "\n private double attributableExpenseAndCommissions => GetStorage().GetAttributableExpenseAndCommissionAmountType().Sum(d =>", + "\n GetStorage().GetNovelties(referenceAocType, InputSource.Cashflow)", + "\n .Sum(n => GetScope((Identity with {AocType = referenceAocType, Novelty = n}, d, EstimateTypes.BE, (int?)null), o => o.WithContext(EconomicBasis)).Value) -", + "\n GetScope((Identity with {AocType = referenceAocType, Novelty = Novelties.C}, d, EstimateTypes.A, (int?)null)).Value);", + "\n", + "\n private double investmentClaims => GetStorage().GetInvestmentClaims().Sum(ic =>", + "\n GetStorage().GetNovelties(referenceAocType, InputSource.Cashflow)", + "\n .Sum(n => GetScope((Identity with {AocType = referenceAocType, Novelty = n}, ic, EstimateTypes.BE, (int?)null), o => o.WithContext(EconomicBasis)).Value) -", + "\n GetScope((Identity with {AocType = referenceAocType, Novelty = Novelties.C}, ic, EstimateTypes.A, (int?)null)).Value);", + "\n ", + "\n double TechnicalMargin.Value => premiums + attributableExpenseAndCommissions + investmentClaims;", + "\n}", + "\n", + "\npublic interface TechnicalMarginForAM : TechnicalMargin", + "\n{", + "\n double TechnicalMargin.Value => -1d * AggregatedValue * GetScope(Identity, o => o.WithContext(EconomicBasis)).Value;", + "\n}" + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "# Switch Logic", + "\n ", + "\nThe $CSM$ and $LC$ components are computed from the [technical margin](#technical-margin). In particular, for a given AoC step $s$, TM is allocated to the $LC$ when $\\text{Aggregated } TM$ is positive whereas it is allocated to the $CSM$ when $\\text{Aggregated } TM$ is negative:", + "\n", + "\n$$", + "\n\\begin{array}{rl}", + "\nCSM({\\text{AoC Step}}) = 0,~~ LC({\\text{AoC step}}) = TM({\\text{AoC step}}) ~ & \\text{if }\\text{Aggregated }TM({\\text{AoC step}}) > 0.", + "\n\\\\", + "\nCSM({\\text{AoC Step}}) = - TM({\\text{AoC step}}),~~ LC({\\text{AoC step}}) = 0 ~ & \\text{otherwise} ", + "\n\\end{array}", + "\n$$", + "\n", + "\n", + "\nThe figures reported under CSM are the opposite of the TM value in order to satisfy our sign convention.", + "\n", + "\nIt is possible to switch from $CSM$ to $LC$ and from $LC$ to $CSM$ at any AoC step $s$ with the only exception of **Amortization** where there is no switch from the previous step.", + "\nWhen a switch occurs the total contribution to the $CSM$ ($LC$) prior the switching step is brought to 0 and the remaing amount is allocated to $LC$ ($CSM$).", + "\n", + "\n" + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "", + "\n## Gross case", + "\n", + "\nThe switch logic is applied ***separately*** to the In-Force and New Business novelties. The Combined Liability AoC Step **CL** will bring both contributions to CSM and LC together as the novelities are summed up.", + "\n", + "\nIn detail, and as we go through the AoC steps in the AoC chain, we have", + "\n", + "\n**A)** For the **BOP**:", + "\n$$", + "\n\\begin{array}{rl}", + "\nCSM(\\text{BOP}) &= CSM(\\text{EOP}) \\text{ of the previous period, for Novelty In-Force}", + "\n\\\\", + "\nLC(\\text{BOP}) &= LC(\\text{EOP}) \\text{ of the previous period, for Novelty In-Force}", + "\n\\end{array}", + "\n$$", + "\n", + "\n", + "\n**B)** For the **following AoC steps**, the switch logic is preferably formulated using the delta variations between steps, $\\Delta CSM$ and $\\Delta LC$ for the CSM and the LC respectively.", + "\n", + "\nThe switch logic for these AoC steps with the *exception* of Combined Liability is:", + "\n", + "\nIf $\\text{Aggregated }TM(\\text{AoC Step}) > 0$ and $\\text{Aggregated }TM(\\text{AoC Step}) + TM(\\text{AoC Step}) \\le 0$, then there is a switch from $LC$ to $CSM$:", + "\n", + "\n$$", + "\n\\begin{array}{rl}", + "\n\\Delta CSM(\\text{AoC step}) &= -TM(\\text{AoC Step}) -\\text{Aggregated } TM(\\text{AoC Step})", + "\n\\\\", + "\n\\Delta LC(\\text{AoC step}) &= -\\text{Aggregated } TM(\\text{AoC Step}) ", + "\n\\end{array}", + "\n$$", + "\n", + "\nOn the other hand, if $\\text{Aggregated }TM(\\text{AoC Step}) \\le 0$ and $\\text{Aggregated }TM(\\text{AoC Step}) + TM(\\text{AoC Step}) > 0$, then the switch is from $CSM$ to $LC$:", + "\n", + "\n$$", + "\n\\begin{array}{rl}", + "\n\\Delta CSM(\\text{AoC step}) &= \\text{Aggregated } TM(\\text{AoC Step}) ", + "\n\\\\", + "\n\\Delta LC(\\text{AoC step}) &= TM(\\text{AoC Step}) + \\text{Aggregated } TM(\\text{AoC Step}) ", + "\n\\end{array}", + "\n$$", + "\n", + "\nIf there is no switch from $CSM$, i.e. $\\text{Aggregated }TM(\\text{AoC Step}) \\le 0$ and $\\text{Aggregated }TM(\\text{AoC Step}) + TM(\\text{AoC Step}) \\le 0 $, then:", + "\n", + "\n$$", + "\n\\begin{array}{rl}", + "\n\\Delta CSM(\\text{AoC step}) &= -TM(\\text{AoC Step})", + "\n\\\\", + "\n\\Delta LC(\\text{AoC step}) &= 0", + "\n\\end{array}", + "\n$$", + "\n", + "\nAnd finally, if there is no switch from $LC$, i.e. $\\text{Aggregated }TM(\\text{AoC Step}) > 0$ and $\\text{Aggregated }TM(\\text{AoC Step}) + TM(\\text{AoC Step}) \\ge 0 $, then:", + "\n", + "\n$$", + "\n\\begin{array}{rl}", + "\n\\Delta CSM(\\text{AoC step}) &= 0", + "\n\\\\", + "\n\\Delta LC(\\text{AoC step}) &= TM(\\text{AoC Step})", + "\n\\end{array}", + "\n$$", + "\n", + "\n**C)** For the AoC step Combined Liability **CL**, the switch logic is similar to the one above, except that a switch from $LC$ to $CSM$ can happen **because of New Business and despite of In-Force**, in which case we have:", + "\n", + "\n$$", + "\n\\begin{array}{rl}", + "\n\\Delta CSM(\\text{AoC step}) &= -TM(\\text{AoC Step}) -\\big(\\text{Aggregated } TM(\\text{Last In-Force AoC step})+TM(\\text{Last In-Force AoC step}) \\big)", + "\n\\\\", + "\n\\Delta LC(\\text{AoC step}) &= -\\big(\\text{Aggregated } TM(\\text{Last In-Force AoC step}) + TM(\\text{Last In-Force AoC step}) \\big)", + "\n\\end{array}", + "\n$$", + "\n", + "\nIf, on the other hand, the switch from $LC$ to $CSM$ happens **because of In-Force and despite of New Business**, then we have:", + "\n", + "\n$$", + "\n\\begin{array}{rl}", + "\n\\Delta CSM(\\text{AoC step}) &= -TM(\\text{AoC Step}) -\\big(\\text{Aggregated } TM(\\text{Last NB AoC step})+TM(\\text{Last NB AoC step}) \\big)", + "\n\\\\", + "\n\\Delta LC(\\text{AoC step}) &= -\\big(\\text{Aggregated } TM(\\text{Last NB AoC step}) + TM(\\text{Last NB AoC step}) \\big)", + "\n\\end{array}", + "\n$$", + "\n", + "\nFor the switch in the other direction, i.e. from $CSM$ to $LC$ the formulas are similar except that LC and CSM are swapped.", + "\n", + "\n**D)** Finally, for the last AoC step, the **EOP**, we have:", + "\n", + "\n$$", + "\n\\begin{array}{rl}", + "\nCSM(\\text{EOP}) &= \\sum_{s~\\in~\\text{previous AoC steps}}\\Delta CSM(s)", + "\n\\\\", + "\nLC(\\text{EOP}) &= \\sum_{s~\\in~\\text{previous AoC steps}}\\Delta LC(s)", + "\n\\end{array}", + "\n$$", + "\n", + "\n" + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "", + "\n## Reinsurance case", + "\n", + "\nFor the reinsurance case, the switch logic is identical to the one described above, except that it uses the gross Technical Margins multiplied by the weights coming from the Reinsurance Coverage (RC) Parameter (see [Data Node Parameters](../DataModel/DataStructure#data-node-parameters)). In case a GRIC ($r$) has multiple GICs ($g$), then these weighted $TM$s are aggregated.", + "\n", + "\n$$", + "\n\\text{Weighted TM}(\\text{r}) = \\sum_{g~\\in~\\text{underlying GICs}} \\text{RC}_{g,r} \\text{TM}(g)", + "\n$$", + "\n", + "\nA Loss Recovery Component (LoReCo) for GRIC $r$ is going to be opened in case the $\\text{Weighted TM}(r)$ would be allocated to Loss Component following the above mentioned switch logic. The amount allocated to the Reinsurance CSM or LoReCo follows the computed Technical Margin computed for GRIC r as described in [Technical Margin](#technical-margin)." + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "public interface AllocateTechnicalMargin: IScope", + "\n{", + "\n //Switch", + "\n static ApplicabilityBuilder ScopeApplicabilityBuilder(ApplicabilityBuilder builder) => ", + "\n builder.ForScope(s => s", + "\n .WithApplicability(x => x.Identity.IsReinsurance && x.Identity.AocType == AocTypes.CL)", + "\n .WithApplicability(x => x.Identity.IsReinsurance, ", + "\n p => p.ForMember(s => s.ComputedEstimateType)", + "\n .ForMember(s => s.HasSwitch))", + "\n .WithApplicability(x => x.GetStorage().IsSecondaryScope(x.Identity.DataNode)) ", + "\n .WithApplicability(x => x.Identity.AocType == AocTypes.BOP)", + "\n .WithApplicability(x => x.Identity.AocType == AocTypes.CL)", + "\n .WithApplicability(x => x.Identity.AocType == AocTypes.EOP)", + "\n );", + "\n ", + "\n [NotVisible] double AggregatedTechnicalMargin => GetScope(Identity).AggregatedValue; ", + "\n [NotVisible] double TechnicalMargin => GetScope(Identity).Value;", + "\n [NotVisible] string ComputedEstimateType => ComputeEstimateType(GetScope(Identity).AggregatedValue + TechnicalMargin);", + "\n [NotVisible] bool HasSwitch => ComputedEstimateType != ComputeEstimateType(GetScope(Identity).AggregatedValue);", + "\n ", + "\n //Allocate", + "\n [NotVisible] string EstimateType => GetContext();", + "\n ", + "\n double Value => (HasSwitch, EstimateType == ComputedEstimateType) switch {", + "\n (true, true) => TechnicalMargin + AggregatedTechnicalMargin,", + "\n (true, false) => -1d * AggregatedTechnicalMargin,", + "\n (false, true) => TechnicalMargin,", + "\n _ => default", + "\n };", + "\n ", + "\n string ComputeEstimateType(double aggregatedTechnicalMargin) => aggregatedTechnicalMargin > Precision ? EstimateTypes.L : EstimateTypes.C;", + "\n}", + "\n", + "\npublic interface ComputeAllocateTechnicalMarginWithIfrsVariable : AllocateTechnicalMargin", + "\n{ ", + "\n double AllocateTechnicalMargin.TechnicalMargin => ComputeTechnicalMarginFromIfrsVariables(Identity);", + "\n double AllocateTechnicalMargin.AggregatedTechnicalMargin => GetScope((Identity, InputSource.Cashflow)).Values", + "\n .Sum(aoc => ComputeTechnicalMarginFromIfrsVariables(Identity with {AocType = aoc.AocType, Novelty = aoc.Novelty}));", + "\n ", + "\n private double ComputeTechnicalMarginFromIfrsVariables(ImportIdentity id)", + "\n {", + "\n return GetStorage().GetValue(Identity, null, EstimateTypes.LR, null) +", + "\n GetStorage().GetValue(Identity, null, EstimateTypes.L, null) - ", + "\n GetStorage().GetValue(Identity, null, EstimateTypes.C, null);", + "\n }", + "\n}", + "\n", + "\npublic interface AllocateTechnicalMarginForReinsurance : AllocateTechnicalMargin", + "\n{ ", + "\n //TODO add Reinsurance Coverage Update (RCU, Novelty=I) AocStep", + "\n private IEnumerable underlyingGic => GetStorage().GetUnderlyingGic(Identity);", + "\n ", + "\n private double weightedUnderlyingTM => underlyingGic.Sum(gic => GetStorage().GetReinsuranceCoverage(Identity, gic) * ", + "\n GetScope(Identity with {DataNode = gic}).Value);", + "\n ", + "\n private double weightedUnderlyingAggregatedTM => underlyingGic.Sum(gic => GetStorage().GetReinsuranceCoverage(Identity, gic) * ", + "\n GetScope(Identity with {DataNode = gic}).AggregatedValue);", + "\n ", + "\n private string ComputeReinsuranceEstimateType(double aggregatedFcf) => aggregatedFcf > Precision ? EstimateTypes.LR : EstimateTypes.C;", + "\n ", + "\n [NotVisible] string AllocateTechnicalMargin.ComputedEstimateType => ComputeReinsuranceEstimateType(weightedUnderlyingAggregatedTM + weightedUnderlyingTM);", + "\n [NotVisible] bool AllocateTechnicalMargin.HasSwitch => ComputedEstimateType != ComputeReinsuranceEstimateType(weightedUnderlyingAggregatedTM); ", + "\n}", + "\n", + "\npublic interface AllocateTechnicalMarginForReinsuranceCL : AllocateTechnicalMargin", + "\n{ ", + "\n //In common1", + "\n private IEnumerable underlyingGic => GetStorage().GetUnderlyingGic(Identity);", + "\n ", + "\n private double weightedUnderlyingTM => underlyingGic.Sum(gic => GetStorage().GetReinsuranceCoverage(Identity, gic) * ", + "\n GetScope(Identity with {DataNode = gic}).Value);", + "\n ", + "\n private double weightedUnderlyingAggregatedTM => underlyingGic.Sum(gic => GetStorage().GetReinsuranceCoverage(Identity, gic) * ", + "\n GetScope(Identity with {DataNode = gic}).AggregatedValue);", + "\n private string ComputeReinsuranceEstimateType(double aggregatedFcf) => aggregatedFcf > Precision ? EstimateTypes.LR : EstimateTypes.C;", + "\n ", + "\n string AllocateTechnicalMargin.ComputedEstimateType => ComputeReinsuranceEstimateType(weightedUnderlyingAggregatedTM + weightedUnderlyingTM);", + "\n //In common2", + "\n private double balancingValue => GetScope((Identity, InputSource.Cashflow))", + "\n .Values", + "\n .GroupBy(x => x.Novelty)", + "\n .Select(g => g.Last())", + "\n .Sum(aoc => { ", + "\n var id = Identity with {AocType = aoc.AocType, Novelty = aoc.Novelty};", + "\n return GetScope(id).ComputedEstimateType != ComputedEstimateType ? ", + "\n GetScope(id).TechnicalMargin + GetScope(id).AggregatedTechnicalMargin", + "\n : (double)default; });", + "\n ", + "\n [NotVisible] bool AllocateTechnicalMargin.HasSwitch => Math.Abs(balancingValue) > Precision;", + "\n [NotVisible] double AllocateTechnicalMargin.AggregatedTechnicalMargin => balancingValue; ", + "\n}", + "\n", + "\npublic interface AllocateTechnicalMarginForCl : AllocateTechnicalMargin", + "\n{", + "\n private double balancingValue => GetScope((Identity, InputSource.Cashflow))", + "\n .Values", + "\n .GroupBy(x => x.Novelty)", + "\n .Select(g => g.Last())", + "\n .Sum(aoc => { ", + "\n var id = Identity with {AocType = aoc.AocType, Novelty = aoc.Novelty};", + "\n return GetScope(id).ComputedEstimateType != ComputedEstimateType ? ", + "\n GetScope(id).TechnicalMargin + GetScope(id).AggregatedTechnicalMargin", + "\n : (double)default; });", + "\n", + "\n [NotVisible] bool AllocateTechnicalMargin.HasSwitch => Math.Abs(balancingValue) > Precision;", + "\n [NotVisible] double AllocateTechnicalMargin.AggregatedTechnicalMargin => balancingValue;", + "\n}", + "\n", + "\npublic interface AllocateTechnicalMarginForBop : AllocateTechnicalMargin", + "\n{ ", + "\n bool AllocateTechnicalMargin.HasSwitch => false;", + "\n}", + "\n", + "\npublic interface AllocateTechnicalMarginForEop : AllocateTechnicalMargin", + "\n{", + "\n double AllocateTechnicalMargin.Value => GetScope((Identity, InputSource.Cashflow)).Values", + "\n .Sum(aoc => GetScope(Identity with {AocType = aoc.AocType, Novelty = aoc.Novelty}).Value);", + "\n [NotVisible] string AllocateTechnicalMargin.ComputedEstimateType => ComputeEstimateType(AggregatedTechnicalMargin);", + "\n}" + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "For the **Group of Reinsurance Contracts** (GRICs), the switch is computed within the underlying GIC context and $CSM$ and $LR$ are then computed in the same manner as for the underlying GICs CSM and LC." + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "The scopes below are simply used to set the appropriate Estimate Type (C for $CSM$, L for $LC$ and LR for $LoReCo$), as well as to set $CSM$ values to be positive:" + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "# Contractual Service Margin" + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "public interface ContractualServiceMargin : IScope", + "\n{", + "\n [NotVisible]string EstimateType => EstimateTypes.C;", + "\n ", + "\n double Value => -1d * GetScope(Identity, o => o.WithContext(EstimateType)).Value;", + "\n}" + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "# Loss Component" + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "public interface LossComponent : IScope", + "\n{", + "\n [NotVisible]string EstimateType => EstimateTypes.L;", + "\n ", + "\n double Value => GetScope(Identity, o => o.WithContext(EstimateType)).Value;", + "\n}" + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "# Loss Recovery Component" + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "public interface LossRecoveryComponent : IScope", + "\n{ ", + "\n [NotVisible]string EstimateType => EstimateTypes.LR;", + "\n ", + "\n double Value => GetScope(Identity, o => o.WithContext(EstimateType)).Value;", + "\n}" + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + } + ] +} \ No newline at end of file diff --git a/ifrs17/Import/5ImportScope-ToIfrsVar.ipynb b/ifrs17/Import/5ImportScope-ToIfrsVar.ipynb new file mode 100644 index 00000000..5d4de6c8 --- /dev/null +++ b/ifrs17/Import/5ImportScope-ToIfrsVar.ipynb @@ -0,0 +1,295 @@ +{ + "metadata": { + "authors": [], + "id": "1-Sd2C2w2kaytthWS3cL1W", + "kernelspec": { + "display_name": "Formula Framework", + "language": "C#", + "name": "C#" + }, + "language_info": { + "file_extension": ".cs", + "mimetype": "text/plain", + "name": "C#" + } + }, + "nbformat": 4, + "nbformat_minor": 5, + "cells": [ + { + "cell_type": "markdown", + "source": [ + "

IFRS 17 Methodology

", + "\n

Business Logic with Scopes

" + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "In this notebook the focus is on the creation of Ifrs Variable from the Scopes. " + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "# References", + "\nLibraries and other notebooks which are needed for this notebook are imported below." + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "## Notebooks" + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "#!import \"4ImportScope-TechnicalMargin\"" + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "# Computing All Scopes", + "\n", + "\nSince all the calculations defined in the various scopes are to be performed together, it is useful to introduce the scopes: ComputeIfrsVarsActuals, ComputeIfrsVarsCashflows and the ComputeIfrsVarsOpenings below, which given a certain Import Format and Import Storage, performs all the calculations (defined above) based on the corresponding data:" + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "public interface PvToIfrsVariable: IScope", + "\n{", + "\n IEnumerable PvLocked => GetScope(Identity).PresentValues.Select(x => ", + "\n new IfrsVariable{ EconomicBasis = x.EconomicBasis, ", + "\n EstimateType = x.Identity.EstimateType, ", + "\n DataNode = x.Identity.Id.DataNode, ", + "\n AocType = x.Identity.Id.AocType, ", + "\n Novelty = x.Identity.Id.Novelty, ", + "\n AccidentYear = x.Identity.AccidentYear,", + "\n AmountType = x.Identity.AmountType,", + "\n Value = x.Value,", + "\n Partition = GetStorage().TargetPartition });", + "\n", + "\n IEnumerable PvCurrent => GetScope(Identity).PresentValues.Select(x => ", + "\n new IfrsVariable{ EconomicBasis = x.EconomicBasis, ", + "\n EstimateType = x.Identity.EstimateType, ", + "\n DataNode = x.Identity.Id.DataNode, ", + "\n AocType = x.Identity.Id.AocType, ", + "\n Novelty = x.Identity.Id.Novelty, ", + "\n AccidentYear = x.Identity.AccidentYear,", + "\n AmountType = x.Identity.AmountType,", + "\n Value = x.Value,", + "\n Partition = GetStorage().TargetPartition });", + "\n}" + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "public interface RaToIfrsVariable: IScope", + "\n{", + "\n IEnumerable RaCurrent => GetScope(Identity).PresentValues.Select(x => ", + "\n new IfrsVariable{ EconomicBasis = x.EconomicBasis, ", + "\n EstimateType = x.Identity.EstimateType, ", + "\n DataNode = x.Identity.Id.DataNode, ", + "\n AocType = x.Identity.Id.AocType, ", + "\n Novelty = x.Identity.Id.Novelty, ", + "\n AccidentYear = x.Identity.AccidentYear,", + "\n AmountType = null,", + "\n Value = x.Value,", + "\n Partition = GetStorage().TargetPartition });", + "\n ", + "\n IEnumerable RaLocked => GetScope(Identity).PresentValues.Select(x => ", + "\n new IfrsVariable{ EconomicBasis = x.EconomicBasis, ", + "\n EstimateType = x.Identity.EstimateType, ", + "\n DataNode = x.Identity.Id.DataNode, ", + "\n AocType = x.Identity.Id.AocType, ", + "\n Novelty = x.Identity.Id.Novelty, ", + "\n AccidentYear = x.Identity.AccidentYear,", + "\n AmountType = null,", + "\n Value = x.Value,", + "\n Partition = GetStorage().TargetPartition });", + "\n}" + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "public interface ActualToIfrsVariable: IScope", + "\n{", + "\n IEnumerable Actual => GetScope(Identity).Actuals.Select(x => ", + "\n new IfrsVariable{ EstimateType = x.Identity.EstimateType,", + "\n DataNode = x.Identity.Id.DataNode,", + "\n AocType = x.Identity.Id.AocType,", + "\n Novelty = x.Identity.Id.Novelty,", + "\n AccidentYear = x.Identity.AccidentYear,", + "\n AmountType = x.Identity.AmountType,", + "\n Value = x.Value,", + "\n Partition = GetStorage().TargetPartition });", + "\n ", + "\n IEnumerable AdvanceActual => GetScope(Identity).Actuals.Select(x => ", + "\n new IfrsVariable{ EstimateType = x.Identity.EstimateType,", + "\n DataNode = x.Identity.Id.DataNode,", + "\n AocType = x.Identity.Id.AocType,", + "\n Novelty = x.Identity.Id.Novelty,", + "\n AccidentYear = x.Identity.AccidentYear,", + "\n AmountType = x.Identity.AmountType,", + "\n Value = x.Value,", + "\n Partition = GetStorage().TargetPartition });", + "\n", + "\n IEnumerable OverdueActual => GetScope(Identity).Actuals.Select(x => ", + "\n new IfrsVariable{ EstimateType = x.Identity.EstimateType,", + "\n DataNode = x.Identity.Id.DataNode,", + "\n AocType = x.Identity.Id.AocType,", + "\n Novelty = x.Identity.Id.Novelty,", + "\n AccidentYear = x.Identity.AccidentYear,", + "\n AmountType = x.Identity.AmountType,", + "\n Value = x.Value,", + "\n Partition = GetStorage().TargetPartition });", + "\n}" + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "public interface DeferrableToIfrsVariable: IScope", + "\n{", + "\n IEnumerable DeferrableActual => GetScope(Identity).RepeatOnce().Select(x => ", + "\n new IfrsVariable{ EstimateType = x.EstimateType,", + "\n DataNode = x.Identity.DataNode,", + "\n AocType = x.Identity.AocType,", + "\n Novelty = x.Identity.Novelty,", + "\n AccidentYear = null,", + "\n Value = x.Value,", + "\n Partition = GetStorage().TargetPartition });", + "\n}" + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "public interface EaForPremiumToIfrsVariable: IScope", + "\n{", + "\n IEnumerable BeEAForPremium => GetStorage().DataNodeDataBySystemName[Identity.DataNode].LiabilityType == LiabilityTypes.LIC", + "\n || Identity.IsReinsurance", + "\n ? Enumerable.Empty()", + "\n : GetScope(Identity)", + "\n .ByAmountType", + "\n .Select(sc => new IfrsVariable{ EstimateType = GetScope(Identity).EstimateType, ", + "\n DataNode = sc.Identity.Id.DataNode, ", + "\n AocType = sc.Identity.Id.AocType, ", + "\n Novelty = sc.Identity.Id.Novelty, ", + "\n AccidentYear = sc.Identity.AccidentYear,", + "\n EconomicBasis = sc.EconomicBasis,", + "\n AmountType = sc.Identity.AmountType,", + "\n Value = sc.Value,", + "\n Partition = sc.GetStorage().TargetPartition });", + "\n ", + "\n IEnumerable ActEAForPremium => GetStorage().DataNodeDataBySystemName[Identity.DataNode].LiabilityType == LiabilityTypes.LIC", + "\n || Identity.IsReinsurance", + "\n ? Enumerable.Empty()", + "\n : GetScope(Identity)", + "\n .ByAmountTypeAndEstimateType", + "\n .Select(sc => new IfrsVariable{ EstimateType = GetStorage().ExperienceAdjustEstimateTypeMapping[sc.Identity.EstimateType], ", + "\n DataNode = sc.Identity.Id.DataNode, ", + "\n AocType = sc.Identity.Id.AocType, ", + "\n Novelty = sc.Identity.Id.Novelty, ", + "\n AccidentYear = sc.Identity.AccidentYear,", + "\n //EconomicBasis = scope.EconomicBasis,", + "\n AmountType = sc.Identity.AmountType,", + "\n Value = sc.Value,", + "\n Partition = GetStorage().TargetPartition });", + "\n}" + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "public interface TmToIfrsVariable: IScope", + "\n{", + "\n private string EconomicBasis => Identity.ValuationApproach == ValuationApproaches.VFA ? EconomicBases.C : EconomicBases.L;", + "\n IEnumerable AmortizationFactor => Identity.AocType == AocTypes.AM", + "\n ? GetScope(Identity, o => o.WithContext(EconomicBasis))", + "\n .RepeatOnce()", + "\n .Select(x => new IfrsVariable{ EstimateType = x.EstimateType,", + "\n DataNode = x.Identity.DataNode,", + "\n AocType = x.Identity.AocType,", + "\n Novelty = x.Identity.Novelty,", + "\n EconomicBasis = x.EconomicBasis,", + "\n Value = x.Value,", + "\n Partition = GetStorage().TargetPartition", + "\n })", + "\n : Enumerable.Empty();", + "\n IEnumerable Csms => GetStorage().DataNodeDataBySystemName[Identity.DataNode].LiabilityType == LiabilityTypes.LIC", + "\n ? Enumerable.Empty()", + "\n : GetScope(Identity).RepeatOnce()", + "\n .Select(x => new IfrsVariable{ EstimateType = x.EstimateType,", + "\n DataNode = x.Identity.DataNode,", + "\n AocType = x.Identity.AocType,", + "\n Novelty = x.Identity.Novelty,", + "\n Value = x.Value,", + "\n Partition = GetStorage().TargetPartition", + "\n });", + "\n", + "\n IEnumerable Loss => GetStorage().DataNodeDataBySystemName[Identity.DataNode].LiabilityType == LiabilityTypes.LIC", + "\n ? Enumerable.Empty()", + "\n : Identity.IsReinsurance ", + "\n ? GetScope(Identity).RepeatOnce()", + "\n .Select(x => new IfrsVariable{ EstimateType = x.EstimateType,", + "\n DataNode = x.Identity.DataNode,", + "\n AocType = x.Identity.AocType,", + "\n Novelty = x.Identity.Novelty,", + "\n Value = x.Value,", + "\n Partition = GetStorage().TargetPartition", + "\n })", + "\n : GetScope(Identity).RepeatOnce()", + "\n .Select(x => new IfrsVariable{ EstimateType = x.EstimateType,", + "\n DataNode = x.Identity.DataNode,", + "\n AocType = x.Identity.AocType,", + "\n Novelty = x.Identity.Novelty,", + "\n Value = x.Value,", + "\n Partition = GetStorage().TargetPartition", + "\n });", + "\n}" + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + } + ] +} \ No newline at end of file diff --git a/ifrs17/Import/6ImportScope-Compute.ipynb b/ifrs17/Import/6ImportScope-Compute.ipynb new file mode 100644 index 00000000..e9b47c45 --- /dev/null +++ b/ifrs17/Import/6ImportScope-Compute.ipynb @@ -0,0 +1,170 @@ +{ + "metadata": { + "authors": [], + "id": "1-Sd2C2w2kaytthWS3cL1L", + "kernelspec": { + "display_name": "Formula Framework", + "language": "C#", + "name": "C#" + }, + "language_info": { + "file_extension": ".cs", + "mimetype": "text/plain", + "name": "C#" + } + }, + "nbformat": 4, + "nbformat_minor": 5, + "cells": [ + { + "cell_type": "markdown", + "source": [ + "

IFRS 17 Methodology

", + "\n

Business Logic with Scopes

" + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "In this notebook the focus is on the calculation of the minimal set of Ifrs Variable given the import Format. " + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "# References", + "\nLibraries and other notebooks which are needed for this notebook are imported below." + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "## Notebooks" + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "#!import \"5ImportScope-ToIfrsVar\"" + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "# Actual dependent variables" + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "public interface ComputeIfrsVarsActuals : ActualToIfrsVariable, DeferrableToIfrsVariable, EaForPremiumToIfrsVariable, TmToIfrsVariable", + "\n{", + "\n IEnumerable CalculatedIfrsVariables => Actual.Concat(AdvanceActual)", + "\n .Concat(OverdueActual)", + "\n .Concat(ActEAForPremium)", + "\n .Concat(DeferrableActual)", + "\n .Concat(Csms)", + "\n .Concat(Loss);", + "\n}" + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "# Cashflow dependent variables" + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "public interface ComputeIfrsVarsCashflows : PvToIfrsVariable, RaToIfrsVariable, DeferrableToIfrsVariable, EaForPremiumToIfrsVariable, TmToIfrsVariable", + "\n{", + "\n IEnumerable CalculatedIfrsVariables => PvLocked.Concat(PvCurrent)", + "\n .Concat(RaCurrent)", + "\n .Concat(RaLocked)", + "\n .Concat(AmortizationFactor)", + "\n .Concat(BeEAForPremium)", + "\n .Concat(DeferrableActual)", + "\n .Concat(Csms)", + "\n .Concat(Loss);", + "\n}" + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "# Opening dependent variables" + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "public interface ComputeIfrsVarsOpenings : ActualToIfrsVariable, DeferrableToIfrsVariable, TmToIfrsVariable", + "\n{", + "\n IEnumerable CalculatedIfrsVariables => AdvanceActual.Concat(OverdueActual)", + "\n .Concat(DeferrableActual)", + "\n .Concat(Csms)", + "\n .Concat(Loss);", + "\n}" + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "# Compute " + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "public interface ComputeAllScopes: IScope", + "\n{", + "\n IEnumerable CalculatedIfrsVariables => GetStorage().ImportFormat switch {", + "\n ImportFormats.Actual => GetScope(Identity).CalculatedIfrsVariables,", + "\n ImportFormats.Cashflow => GetScope(Identity).CalculatedIfrsVariables,", + "\n ImportFormats.Opening => GetScope(Identity).CalculatedIfrsVariables,", + "\n };", + "\n}" + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + } + ] +} \ No newline at end of file diff --git a/ifrs17/Import/ImportScopeCalculation.ipynb b/ifrs17/Import/ImportScopeCalculation.ipynb deleted file mode 100644 index 3a357622..00000000 --- a/ifrs17/Import/ImportScopeCalculation.ipynb +++ /dev/null @@ -1,2352 +0,0 @@ -{ - "metadata": { - "authors": [], - "id": "1-Sd2C2w2kaytthWS3cL1Q", - "kernelspec": { - "display_name": "Formula Framework", - "language": "C#", - "name": "C#" - }, - "language_info": { - "file_extension": ".cs", - "mimetype": "text/plain", - "name": "C#" - } - }, - "nbformat": 4, - "nbformat_minor": 5, - "cells": [ - { - "cell_type": "markdown", - "source": [ - "", - "\n

Import Scopes (IFRS 17 Methodology Business Logic)

" - ], - "metadata": {}, - "execution_count": 0, - "outputs": [] - }, - { - "cell_type": "markdown", - "source": [ - "This notebook contains the logic used to perform calculations upon import of data (actuals and cash flows). This is also called 'Data Loading' and the concept of Scope is used here to define the logic and provide the means of executing the logic." - ], - "metadata": {}, - "execution_count": 0, - "outputs": [] - }, - { - "cell_type": "markdown", - "source": [ - "# References", - "\nLibraries and other notebooks which are needed for this notebook are imported below." - ], - "metadata": {}, - "execution_count": 0, - "outputs": [] - }, - { - "cell_type": "markdown", - "source": [ - "## Notebooks" - ], - "metadata": {}, - "execution_count": 0, - "outputs": [] - }, - { - "cell_type": "code", - "source": [ - "#!import \"ImportStorage\"" - ], - "metadata": {}, - "execution_count": 0, - "outputs": [] - }, - { - "cell_type": "markdown", - "source": [ - "", - "\n# Scopes", - "\nScopes are used to define and perform data handling in a structured and easy-to-read-through fashion.", - "\n", - "\nThe IModel interface below will be used to execute calculations (i.e. evaluate the scopes) based on imported data." - ], - "metadata": {}, - "execution_count": 0, - "outputs": [] - }, - { - "cell_type": "code", - "source": [ - "public interface IModel : IMutableScopeWithStorage{}" - ], - "metadata": {}, - "execution_count": 0, - "outputs": [] - }, - { - "cell_type": "markdown", - "source": [ - "## Getting Existing Identities", - "\n", - "\nAn [Identity](../DataModel/DataStructure#import-identity) is a set of identifiers for a certain set of data. In particular, an identity consists of a certain [AoC Type](../DataModel/DataStructure#aoc-type), [Novelty](../DataModel/DataStructure#novelty), [Data Node](../DataModel/DataStructure#data-node), Accident Year, and information on whether the data is for reinsurance or not. ", - "\n", - "\nGiven a certain Data Node and Accident Year, the interface GetIdentities returns all the existing identities (e.g. for Actuals and Cash flows) which have that Data Node and Accident Year." - ], - "metadata": {}, - "execution_count": 0, - "outputs": [] - }, - { - "cell_type": "code", - "source": [ - "public interface AllCfIdentities : IScope // string represents a DataNode", - "\n{", - "\n public IEnumerable ids => GetStorage().GetAllAocSteps(InputSource.Cashflow)", - "\n .Select(aocStep => new ImportIdentity {", - "\n AocType = aocStep.AocType,", - "\n Novelty = aocStep.Novelty,", - "\n DataNode = Identity", - "\n });", - "\n}" - ], - "metadata": {}, - "execution_count": 0, - "outputs": [] - }, - { - "cell_type": "code", - "source": [ - "public interface GetIdentities : IScope", - "\n{", - "\n static ApplicabilityBuilder ScopeApplicabilityBuilder(ApplicabilityBuilder builder) =>", - "\n builder.ForScope(s => s.WithApplicability(x => x.GetStorage().IsSecondaryScope(x.Identity))", - "\n .WithApplicability(x => x.GetStorage().ImportFormat == ImportFormats.Actual)", - "\n .WithApplicability(x => x.GetStorage().ImportFormat == ImportFormats.Cashflow)", - "\n .WithApplicability(x => x.GetStorage().ImportFormat == ImportFormats.Opening)", - "\n );", - "\n ", - "\n private IEnumerable computedIdentities => new string[]{AocTypes.EA, AocTypes.AM, AocTypes.EOP}", - "\n .Select(aocType => new ImportIdentity {", - "\n AocType = aocType,", - "\n Novelty = Novelties.C,", - "\n DataNode = Identity", - "\n });", - "\n private IEnumerable allIdentities => ParsedIdentities.Concat(computedIdentities).Concat(SpecialIdentities).ToHashSet(); ", - "\n ", - "\n IEnumerable ParsedIdentities => Enumerable.Empty(); ", - "\n IEnumerable SpecialIdentities => Enumerable.Empty();", - "\n ", - "\n //Set DataNode properties and ProjectionPeriod", - "\n IEnumerable Identities => allIdentities.Select(id => id with { IsReinsurance = GetStorage().DataNodeDataBySystemName[id.DataNode].IsReinsurance,", - "\n ValuationApproach = GetStorage().DataNodeDataBySystemName[id.DataNode].ValuationApproach", - "\n });", - "\n /* .SelectMany(id => Enumerable.Range(0,GetStorage().GetProjectionCount() + 1)", - "\n .Select(pp => id with {ProjectionPeriod = pp })", - "\n );*/", - "\n}", - "\n", - "\npublic interface AllCashflowIdentities : GetIdentities", - "\n{", - "\n IEnumerable GetIdentities.SpecialIdentities => GetScope(Identity).ids;", - "\n}", - "\n", - "\n", - "\npublic interface GetActualIdentities : GetIdentities", - "\n{", - "\n private IEnumerable actualEstimateTypes => GetStorage().EstimateTypesByImportFormat[ImportFormats.Actual];", - "\n ", - "\n IEnumerable GetIdentities.ParsedIdentities => GetStorage().GetIfrsVariables(Identity).Where(iv => actualEstimateTypes.Contains(iv.EstimateType)).Select(v => new ImportIdentity(v));", - "\n IEnumerable GetIdentities.SpecialIdentities => GetScope(Identity).ids", - "\n .Concat(GetStorage().GetAllAocSteps(InputSource.Opening)", - "\n .Select(aocStep => new ImportIdentity {AocType = aocStep.AocType, ", - "\n Novelty = aocStep.Novelty,", - "\n DataNode = Identity", - "\n }));", - "\n}", - "\n", - "\npublic interface GetCashflowIdentities : GetIdentities", - "\n{", - "\n private bool isReinsurance => GetStorage().DataNodeDataBySystemName[Identity].IsReinsurance; //clean up in the next PR", - "\n ", - "\n IEnumerable GetIdentities.ParsedIdentities => GetStorage().GetRawVariables(Identity).Select(v => new ImportIdentity(v));", - "\n ", - "\n IEnumerable GetIdentities.SpecialIdentities => ParsedIdentities.Where(id => id.Novelty != Novelties.C)", - "\n .Select(id => id.Novelty).ToHashSet()", - "\n .SelectMany(n => (n == Novelties.N ", - "\n ? new string[]{AocTypes.IA, AocTypes.CF} //Add IA, CF, for New Business", - "\n : isReinsurance ", - "\n ? new string[]{AocTypes.IA, AocTypes.CF, AocTypes.YCU, AocTypes.CRU, AocTypes.RCU} //Add IA, CF, YCU, CRU, RCU for in force", - "\n : new string[]{AocTypes.IA, AocTypes.CF, AocTypes.YCU}) //Add IA, CF, YCU,", - "\n .Select(aocType => new ImportIdentity {", - "\n AocType = aocType,", - "\n Novelty = n,", - "\n DataNode = Identity }))", - "\n .Concat(new ImportIdentity {", - "\n AocType = AocTypes.CF, //Add CF for Deferral", - "\n Novelty = Novelties.C,", - "\n DataNode = Identity", - "\n }.RepeatOnce()) ", - "\n .Concat(GetStorage().GetAllAocSteps(InputSource.Opening)", - "\n .Select(aocStep => new ImportIdentity {AocType = aocStep.AocType, ", - "\n Novelty = aocStep.Novelty,", - "\n DataNode = Identity", - "\n })); ", - "\n}", - "\n", - "\npublic interface GetAllIdentities : GetIdentities", - "\n{", - "\n IEnumerable GetIdentities.SpecialIdentities => GetScope(Identity).ids", - "\n .Concat(GetStorage().GetAllAocSteps(InputSource.Actual)", - "\n .Select(aocStep => new ImportIdentity {AocType = aocStep.AocType, ", - "\n Novelty = aocStep.Novelty,", - "\n DataNode = Identity,", - "\n }));", - "\n}" - ], - "metadata": {}, - "execution_count": 0, - "outputs": [] - }, - { - "cell_type": "markdown", - "source": [ - "## Getting Amount Types", - "\n", - "\nSimilarly, given a certain Data Node and Accident Year, the interface ValidAmountType returns all the amount types which are used in imported data with that Data Node and Accident Year." - ], - "metadata": {}, - "execution_count": 0, - "outputs": [] - }, - { - "cell_type": "code", - "source": [ - "public interface ValidAmountType : IScope", - "\n{", - "\n static ApplicabilityBuilder ScopeApplicabilityBuilder(ApplicabilityBuilder builder) =>", - "\n builder.ForScope(s => s.WithApplicability(x => x.GetStorage().ImportFormat != ImportFormats.Cashflow ||", - "\n x.GetStorage().IsSecondaryScope(x.Identity)));", - "\n ", - "\n IEnumerable BeAmountTypes => GetStorage().GetRawVariables(Identity)", - "\n .Where(rv => rv.AmountType != null)", - "\n .Select(x => x.AmountType)", - "\n .Concat(GetStorage().DataNodeDataBySystemName[Identity].IsReinsurance ? (AmountTypes.CDR).RepeatOnce() : Enumerable.Empty())", - "\n .ToHashSet();", - "\n ", - "\n ", - "\n IEnumerable ActualAmountTypes => GetStorage().GetIfrsVariables(Identity)", - "\n .Where(iv => GetStorage().ImportActualEstimateTypes.Contains(iv.EstimateType))", - "\n .Select(x => x.AmountType)", - "\n .ToHashSet();", - "\n}", - "\npublic interface BeAmountTypesFromIfrsVariables : ValidAmountType", - "\n{", - "\n IEnumerable ValidAmountType.BeAmountTypes => GetStorage().GetIfrsVariables(Identity)", - "\n .Where(iv => GetStorage().EstimateTypesByImportFormat[ImportFormats.Cashflow].Contains(iv.EstimateType) && iv.AmountType != null)", - "\n .Select(x => x.AmountType)", - "\n .ToHashSet();", - "\n}" - ], - "metadata": {}, - "execution_count": 0, - "outputs": [] - }, - { - "cell_type": "markdown", - "source": [ - "", - "\n## AoC Step Structure", - "\n", - "\nThe AoC Step structure is constructed from the data which is delivered as input. It is assumed that it depends only on the Group of Contrat (i.e. it is invariant across Amount types or Accident Year). " - ], - "metadata": {}, - "execution_count": 0, - "outputs": [] - }, - { - "cell_type": "markdown", - "source": [ - "### Parent AoC Step ", - "\nThe **ParentAocStep** scope computes and provides an important piece of information for each [Identity](../DataModel/DataStructure#import-identity), i.e. for a certain [AoC Type](../DataModel/DataStructure#aoc-type) and [Novelty](../DataModel/DataStructure#novelty).", - "\n", - "\nIt provides the list of the adjacent AoC Steps prior to Identity one. It can be more than one only for the step **CL** where a parent for each novelty is considered.", - "\nParentAocStep is critical when computing the *telescoping* differences. ", - "\n", - "\nThey are defined as follows:", - "\n", - "\n$$", - "\n\\text{ParentAocStep}(\\text{AoC Step}) = \\left\\{", - "\n\\begin{array}{cl}", - "\n\\text{AoC Step with AoC Type YCU and Novelty I} & \\text{if AoC Type CRU} \\\\", - "\n\\text{The last AoC Step with Data Type != Calculated and same Novelty as the AoC Step} & \\text{if AoC Type YCU} \\\\", - "\n\\text{The AoC Step which comes before in terms of order (as defined by AoC Type)} & \\text{otherwise} \\\\", - "\n\\end{array}", - "\n\\right.", - "\n$$", - "\n" - ], - "metadata": {}, - "execution_count": 0, - "outputs": [] - }, - { - "cell_type": "code", - "source": [ - "public interface ParentAocStep : IScope<(ImportIdentity Id, string AmountType), ImportStorage>", - "\n{", - "\n static ApplicabilityBuilder ScopeApplicabilityBuilder(ApplicabilityBuilder builder) =>", - "\n builder.ForScope(s => s.WithApplicability(x => x.Identity.AmountType != AmountTypes.CDR));", - "\n ", - "\n private HashSet ParsedAocSteps => GetScope(Identity.Id.DataNode).ParsedIdentities.Select(id => new AocStep(id.AocType, id.Novelty)).ToHashSet();", - "\n private IEnumerable OrderedParsedAocSteps => ParsedAocSteps.Concat(CalculatedTelescopicAocStep).OrderBy(x => GetStorage().AocConfigurationByAocStep[x].Order);", - "\n ", - "\n private Dictionary> ParentParsedIdentities => GetPreviousIdentities(OrderedParsedAocSteps);", - "\n private AocStep identityAocStep => new AocStep(Identity.Id.AocType, Identity.Id.Novelty);", - "\n ", - "\n IEnumerable CalculatedTelescopicAocStep => GetStorage().GetCalculatedTelescopicAocSteps();", - "\n ", - "\n IEnumerable Values => ", - "\n Identity.Id.AocType switch {", - "\n AocTypes.CRU => new AocStep(AocTypes.YCU, Novelties.I).RepeatOnce(),", - "\n AocTypes.YCU => OrderedParsedAocSteps.GetReferenceAocStepForCalculated(GetStorage().AocConfigurationByAocStep, identityAocStep).RepeatOnce(),", - "\n _ => ParentParsedIdentities.TryGetValue(identityAocStep, out var parents) ? parents : Enumerable.Empty(),", - "\n };", - "\n}", - "\n", - "\npublic interface ParentAocStepForCreditRisk : ParentAocStep", - "\n{", - "\n IEnumerable ParentAocStep.CalculatedTelescopicAocStep => ", - "\n GetStorage().GetCalculatedTelescopicAocSteps().Where(aoc => aoc.AocType != AocTypes.CRU);", - "\n}" - ], - "metadata": {}, - "execution_count": 0, - "outputs": [] - }, - { - "cell_type": "markdown", - "source": [ - "### Reference AoC Step", - "\n", - "\nThe **ReferenceAocStep** scope provides the AoC Step from which to retrieve the data in order to compute its value (e.g. AoC Step EA retrieves Present Values, while AoC Step YCU retrieves Nominal).", - "\n", - "\nThey are defined as follows:", - "\n", - "\n$$", - "\n\\text{ReferenceAocStep}(\\text{AoC Step}) = \\left\\{", - "\n\\begin{array}{cl}", - "\n\\text{self} & \\text{if AoC Step InputSource is not Calculated} \\\\", - "\n\\text{The last AoC Step with Data Type != Calculated and same Novelty as the input AoC Step} ~, & \\text{if AoC Type } \\in \\text{\\{RCU, CF, IA, YCU, CRU\\}} \\\\", - "\n\\text{AoC Step with AoC Type CF and Novelty as the AoC Step} & \\text{if AoC Type EA} \\\\", - "\n\\text{AoC Step with AoC Type CL and Novelty C} & \\text{if AoC Type $\\in$ \\{AM, EOP\\}} \\\\", - "\n\\text{empty} & \\text{if AoC Type is BOP} \\\\", - "\n\\text{log NotSupportedAocStepReference error} & \\text{otherwise} \\\\", - "\n\\end{array}", - "\n\\right.", - "\n$$", - "\n", - "\nwhere the last AoC Step is obtained by ordering the AoC Steps according to their order (as defined by its AoC Type) and taking the last one." - ], - "metadata": {}, - "execution_count": 0, - "outputs": [] - }, - { - "cell_type": "code", - "source": [ - "public interface ReferenceAocStep : IScope ", - "\n{", - "\n private IEnumerable OrderedParsedAocSteps => GetScope(Identity.DataNode).ParsedIdentities", - "\n .Select(id => new AocStep(id.AocType, id.Novelty))", - "\n .Distinct()", - "\n .OrderBy(aocStep => GetStorage().AocConfigurationByAocStep[aocStep].Order);", - "\n private AocStep identityAocStep => new AocStep(Identity.AocType, Identity.Novelty);", - "\n private AocStep GetReferenceAocStep(string aocType) {", - "\n return aocType switch {", - "\n AocTypes.RCU or AocTypes.CF or AocTypes.IA or AocTypes.YCU or AocTypes.CRU => OrderedParsedAocSteps.GetReferenceAocStepForCalculated(GetStorage().AocConfigurationByAocStep, identityAocStep),", - "\n AocTypes.EA => new AocStep(AocTypes.CF, Identity.Novelty),", - "\n AocTypes.AM or AocTypes.EOP => new AocStep(AocTypes.CL, Novelties.C),", - "\n AocTypes.BOP => new AocStep(default, default), //BOP, C has DataType == Calculated. See ReferenceAocStep condition.", - "\n _ => (AocStep)ApplicationMessage.Log(Error.NotSupportedAocStepReference, Identity.AocType),", - "\n };", - "\n }", - "\n", - "\n // The Reference AocStep from which get data (Nominal or PV) to compute", - "\n AocStep Value => GetStorage().AocConfigurationByAocStep[identityAocStep].DataType == DataType.Calculated ", - "\n || GetStorage().AocConfigurationByAocStep[identityAocStep].DataType == DataType.CalculatedTelescopic ", - "\n ? GetReferenceAocStep(Identity.AocType)", - "\n : identityAocStep;", - "\n}" - ], - "metadata": {}, - "execution_count": 0, - "outputs": [] - }, - { - "cell_type": "markdown", - "source": [ - "### Previous AoC Steps", - "\nThe **PreviousAocSteps** scope computes and provides an other important piece of information for each [Identity](../DataModel/DataStructure#import-identity), i.e. for a certain [AoC Type](../DataModel/DataStructure#aoc-type) and [Novelty](../DataModel/DataStructure#novelty).", - "\n", - "\nIt provides the list of all previous AoC Steps up to the **BOP** step, whereby a Combined novelty will branch into the InForce and New Business AoC Types.", - "\n", - "\nPreviousAocSteps is critical when computing aggregated values along the various dimensions (such as for example Line of Business) and ", - "\nis formed by the ParentAocStep and its parent and so on until there is no parent.", - "\n", - "\n$$", - "\n\\text{PreviousAocSteps}(\\rm{AocStep}) = \\{PAS_1, PAS_2, \\ldots\\}", - "\n$$", - "\nwhere", - "\n$$", - "\n\\rm{PAS}_1 = \\rm{ParentAocStep}(\\rm{AoC Step})", - "\n$$", - "\n$$", - "\n\\rm{PAS}_2 = \\rm{ParentAocStep}(\\rm{PAS}_1).", - "\n$$", - "\n", - "\nThis scope depends on the InputSource (Actual or Cashflow) for which the PreviousSteps are requested due to the AocChain differences between Actual reports and the rest." - ], - "metadata": {}, - "execution_count": 0, - "outputs": [] - }, - { - "cell_type": "code", - "source": [ - "public interface PreviousAocSteps : IScope<(ImportIdentity Id, InputSource ScopeInputSource), ImportStorage> ", - "\n{ ", - "\n private AocStep identityAocStep => new AocStep(Identity.Id.AocType, Identity.Id.Novelty);", - "\n private int aocStepOrder => GetStorage().AocConfigurationByAocStep[identityAocStep].Order;", - "\n private HashSet allAocSteps => GetStorage().GetAllAocSteps(Identity.ScopeInputSource).ToHashSet();", - "\n IEnumerable Values => allAocSteps.Contains(identityAocStep)", - "\n ? GetScope(Identity.Id.DataNode).Identities", - "\n .Select(id => new AocStep(id.AocType, id.Novelty))", - "\n .Distinct()", - "\n .Where(aoc => allAocSteps.Contains(aoc) && ", - "\n GetStorage().AocConfigurationByAocStep[aoc].Order < aocStepOrder && ", - "\n (Identity.Id.Novelty != Novelties.C ? aoc.Novelty == Identity.Id.Novelty : true) )", - "\n .OrderBy(aoc => GetStorage().AocConfigurationByAocStep[aoc].Order)", - "\n : Enumerable.Empty();", - "\n} " - ], - "metadata": {}, - "execution_count": 0, - "outputs": [] - }, - { - "cell_type": "markdown", - "source": [ - "The exact structure being return depends on the **order** of the AoC Steps (which is set by the [AoC Type](../DataModel/DataStructure#aoc-type)), and on which AoC steps exist." - ], - "metadata": {}, - "execution_count": 0, - "outputs": [] - }, - { - "cell_type": "markdown", - "source": [ - "", - "\n## Discounting", - "\n", - "\nThe calculation of IFRS 17 figures is based on cumulated discounted cash flows." - ], - "metadata": {}, - "execution_count": 0, - "outputs": [] - }, - { - "cell_type": "markdown", - "source": [ - "", - "\n### Yield Curves", - "\n", - "\nThe Yield Curves used for the discounting calculations are functions of the [Currency](../DataModel/DataStructure#currency), the [Data Node](../DataModel/DataStructure#data-node) and the [Economic Basis](../DataModel/DataStructure#economic-basis).", - "\n", - "\nIn particular:", - "\n- For the **Locked-in** economic basis, the yield curve used is the latest available as per end of the DataNode's inception year;", - "\n- Whereas for the **Current** economic base, the yield curve used is the latest available as per the current period.", - "\n", - "\nThe algorithm which retrieves the latest available yield curve is [here](../Utils/Queries#yield-curve)." - ], - "metadata": {}, - "execution_count": 0, - "outputs": [] - }, - { - "cell_type": "markdown", - "source": [ - "", - "\n### Interest and Discount Rates and Factors", - "\n", - "\nThe factors used for discounting have the same granularity as the cash flow, i.e. monthly. The yield curves have yearly granularity, so the annual Interest factor is 1 + interest rate. The monthly Interest Interest and Discount factors are obtained from the annual factors such that the product of 12 months results in the annual factors, as follows:", - "\n", - "\n$$", - "\n\\text{Discount}_i = ( 1 + \\text{YC}_i ) ^{-\\frac{1}{12}} ~,", - "\n$$", - "\nand ", - "\n$$", - "\n\\text{Interest}_i = ( 1 + \\text{YC}_i) ^{\\frac{1}{12}} ~,", - "\n$$", - "\n", - "\nwhere the index $i$ denotes years." - ], - "metadata": {}, - "execution_count": 0, - "outputs": [] - }, - { - "cell_type": "code", - "source": [ - "public interface MonthlyRate : IScope", - "\n{", - "\n private string EconomicBasis => GetContext();", - "\n ", - "\n private double[] YearlyYieldCurve => GetStorage().GetYearlyYieldCurve(Identity, EconomicBasis);", - "\n ", - "\n private double Perturbation => 0; //GetStorage().GetYieldCurvePerturbation(); => switch Args.Scenario { 10ptsU => 0.1, 10ptsD => -0.1, _ => default)", - "\n ", - "\n double[] Interest => YearlyYieldCurve.Select(rate => Math.Pow(1d + rate, 1d / 12d) + Perturbation).ToArray(); ", - "\n ", - "\n double[] Discount => Interest.Select(x => Math.Pow(x, -1)).ToArray();", - "\n}" - ], - "metadata": {}, - "execution_count": 0, - "outputs": [] - }, - { - "cell_type": "markdown", - "source": [ - "", - "\n## Nominal Values", - "\n", - "\nThe nominal cash flow values correspond to the cash flows provided in the cash flow input file. ", - "\n
These values are stored in the database as [RawVariable](../DataModel/DataStructure#raw-variables).", - "\n
Refer to the ReferenceAocStep of the AocStructure calculation to identify the correct AoC Type and Novelty to retrieve.", - "\n
Due to the Credit Default Risk of a reinsurance partner, the logic to compute the Nominal Cash flows for this Amount Type must be defined separately." - ], - "metadata": {}, - "execution_count": 0, - "outputs": [] - }, - { - "cell_type": "code", - "source": [ - "public interface NominalCashflow : IScope<(ImportIdentity Id, string AmountType, string EstimateType, int? AccidentYear), ImportStorage>", - "\n{", - "\n static ApplicabilityBuilder ScopeApplicabilityBuilder(ApplicabilityBuilder builder) =>", - "\n builder.ForScope(s => s.WithApplicability(x => x.Identity.AmountType == AmountTypes.CDR && x.Identity.Id.AocType == AocTypes.CF)", - "\n .WithApplicability(x => x.Identity.AmountType == AmountTypes.CDR));", - "\n", - "\n AocStep referenceAocStep => GetScope(Identity.Id).Value;", - "\n double[] Values => GetStorage().GetValues(Identity.Id with {AocType = referenceAocStep.AocType, Novelty = referenceAocStep.Novelty}, Identity.AmountType, Identity.EstimateType, Identity.AccidentYear);", - "\n}", - "\n", - "\npublic interface CreditDefaultRiskNominalCashflow : NominalCashflow", - "\n{", - "\n private double[] NominalClaimsCashflow => GetStorage().GetClaims()", - "\n .Select(claim => GetStorage().GetValues(Identity.Id with {AocType = referenceAocStep.AocType, Novelty = referenceAocStep.Novelty}, claim, Identity.EstimateType, Identity.AccidentYear))", - "\n .AggregateDoubleArray();", - "\n ", - "\n private double nonPerformanceRiskRate => GetStorage().GetNonPerformanceRiskRate(Identity.Id);", - "\n ", - "\n private double[] PvCdrDecumulated { get {", - "\n var ret = new double[NominalClaimsCashflow.Length];", - "\n for (var i = NominalClaimsCashflow.Length - 1; i >= 0; i--)", - "\n ret[i] = Math.Exp(-nonPerformanceRiskRate) * ret.ElementAtOrDefault(i + 1) + NominalClaimsCashflow[i] - NominalClaimsCashflow.ElementAtOrDefault(i + 1);", - "\n return ret; } } ", - "\n ", - "\n double[] NominalCashflow.Values => Subtract(PvCdrDecumulated, NominalClaimsCashflow);", - "\n}", - "\n", - "\npublic interface AllClaimsCashflow : NominalCashflow", - "\n{", - "\n double[] NominalCashflow.Values => GetStorage().GetClaims()", - "\n .Select(claim => GetStorage().GetValues(Identity.Id with {AocType = referenceAocStep.AocType, Novelty = referenceAocStep.Novelty}, claim, Identity.EstimateType, Identity.AccidentYear))", - "\n .AggregateDoubleArray();", - "\n}" - ], - "metadata": {}, - "execution_count": 0, - "outputs": [] - }, - { - "cell_type": "markdown", - "source": [ - "For a given month $i$ they are denoted as $\\rm{Nominal}_i$." - ], - "metadata": {}, - "execution_count": 0, - "outputs": [] - }, - { - "cell_type": "markdown", - "source": [ - "", - "\n## Present Values", - "\n", - "\nPresent Values are calculated during the import of the cash flows and stored on the database. They are computed for the relevant Economic Basis, depending on the Valuation Basis.", - "\n", - "\nTheir calculation is described in the following sections and is summarized in the $\\rm{PV}$ formula [below](#present-value)." - ], - "metadata": {}, - "execution_count": 0, - "outputs": [] - }, - { - "cell_type": "markdown", - "source": [ - "", - "\n### Cumulated Discounted Cash flows", - "\n", - "\nCumulated and Discounted cash flows $\\rm{CDC}$ are computed using the monthly discount rates and in a recursive manner, as follows:", - "\n", - "\n$$", - "\n\\text{CDC}_i(\\text{AoC step}) = \\left\\{", - "\n\\begin{array}{cl}", - "\n\\text{Nominal}_i + \\text{CDC}_{i+1} \\cdot {\\text{Valid Discount}_{\\frac{i}{12}}} ~, & \\text{if Amount Type's Period Type is Beginning Of Period} \\\\", - "\n\\big( \\text{Nominal}_i + \\text{CDC}_{i+1} \\big) \\cdot {\\text{Valid Discount}_{\\frac{i}{12}}} ~, & \\text{if Amount Type's Period Type is End Of Period}", - "\n\\end{array}", - "\n\\right.", - "\n$$", - "\n", - "\nwhere Transaction Period depends on which Best Estimate value is being computed, in particular on what its [Amount Type](../DataModel/DataStructure#amount-type) is (each Amount Type has its own [Period Type](../Constants/Enums)); and $\\text{Valid Discount}$ stands for the fact that in case the Discount Curves are shorter than the required index, then their last element is returned. We also need to flip the sign of the discounted and cumulated values, to create a reserve view and be consistent with the usual [Cash flow Sign Convention](https://en.wikipedia.org/wiki/Cash_flow_sign_convention). ", - "\n", - "\n
Also here, the Credit Default Risk contribution is calculated separately. Since it is based on Claims, the Period Type is implicitly defined.", - "\nThe risk of default is included in the discounting formula as follows. First, we notice that one can explicitly write the discounting recursive relation above as:", - "\n$$", - "\n\\begin{array}{l}", - "\n\\text{CDC}_i = \\big( \\text{Nominal}_i + \\text{CDC}_{i+1} \\big) \\cdot {\\text{Valid Discount}_{\\frac{i}{12}}} ", - "\n\\Rightarrow \\text{CDC}_i = \\sum_{\\tau=i} \\big( \\text{Valid Discount}_{\\frac{i}{12}} \\big)^{\\tau-i+1} \\cdot \\text{Nominal}_\\tau ", - "\n\\end{array}", - "\n$$", - "\n", - "\nThus, the cumulated and discounted cashflow correction for default risk is assigned to the Amount Type Credit Default Risk (CDR) and it is obtained from the Amount Type Claims multiplying the right hand side of the previous formula by the corresponding risk factor", - "\n", - "\n$$", - "\n\\text{CDC}_i^{\\text{CDR}} = \\sum_{\\tau=i} \\big( \\text{Valid Discount}_{\\frac{i}{12}} \\big)^{\\tau-i+1} \\cdot \\text{Nominal}_\\tau^{\\text{Claim}} \\cdot \\big( e^{-\\gamma(\\tau-i)} -1 \\big)", - "\n$$" - ], - "metadata": {}, - "execution_count": 0, - "outputs": [] - }, - { - "cell_type": "code", - "source": [ - "public interface DiscountedCashflow : IScope<(ImportIdentity Id, string AmountType, string EstimateType, int? Accidentyear), ImportStorage>", - "\n{", - "\n private PeriodType periodType => GetStorage().GetPeriodType(Identity.AmountType, Identity.EstimateType); ", - "\n ", - "\n static ApplicabilityBuilder ScopeApplicabilityBuilder(ApplicabilityBuilder builder) =>", - "\n builder.ForScope(s => s.WithApplicability(x => x.Identity.Id.IsReinsurance && x.Identity.AmountType == AmountTypes.CDR));", - "\n", - "\n [NotVisible]", - "\n string EconomicBasis => GetContext();", - "\n", - "\n [NotVisible]", - "\n double[] MonthlyDiscounting => GetScope(Identity.Id).Discount;", - "\n ", - "\n [NotVisible]", - "\n double[] NominalValues => GetScope(Identity).Values;", - "\n", - "\n double[] Values => Multiply(-1d, NominalValues.ComputeDiscountAndCumulate(MonthlyDiscounting, periodType)); // we need to flip the sign to create a reserve view", - "\n}", - "\n", - "\npublic interface DiscountedCreditRiskCashflow : DiscountedCashflow", - "\n{ ", - "\n private double nonPerformanceRiskRate => GetStorage().GetNonPerformanceRiskRate(Identity.Id);", - "\n ", - "\n double[] DiscountedCashflow.Values => Multiply(-1d, NominalValues.ComputeDiscountAndCumulateWithCreditDefaultRisk(MonthlyDiscounting, nonPerformanceRiskRate)); // we need to flip the sign to create a reserve view", - "\n}" - ], - "metadata": {}, - "execution_count": 0, - "outputs": [] - }, - { - "cell_type": "markdown", - "source": [ - "", - "\n### Telescoping Difference", - "\n", - "\n", - "\nPresent Value figures for a specific period are typically reported through an analysis of change, where for each [AoC Step](#aoc-step-structure) the variation with respect to the preceding AoC Step is shown.", - "\n", - "\nThe Telescoping Difference is basically the delta between two adjacent AoC Steps, whereby the [ParentAocStep](#aoc-step-structure) is used to determine the AoC Step. ", - "\n", - "\nIt is defined as follows:", - "\n", - "\n$$", - "\n\\text{TelescopingDifference}_i = ", - "\n\\text{CDC}_{i}\\big(\\text{current AoC Step}\\big) - \\text{CDC}_{i}\\big(\\text{parent AoC Step}\\big)", - "\n$$", - "\n", - "\nwhere AoC Type is the AoC Type of the AoC Step for which the calculations are being performed." - ], - "metadata": {}, - "execution_count": 0, - "outputs": [] - }, - { - "cell_type": "code", - "source": [ - "public interface TelescopicDifference : IScope<(ImportIdentity Id, string AmountType, string EstimateType, int? Accidentyear), ImportStorage>", - "\n{", - "\n [NotVisible]", - "\n string EconomicBasis => GetContext();", - "\n private double[] CurrentValues => GetScope(Identity).Values;", - "\n ", - "\n private double[] PreviousValues => (GetScope((Identity.Id, Identity.AmountType)))", - "\n .Values", - "\n .Select(aoc => GetScope((Identity.Id with {AocType = aoc.AocType, Novelty = aoc.Novelty}, Identity.AmountType, Identity.EstimateType, Identity.Accidentyear)).Values)", - "\n .Where(cf => cf.Count() > 0)", - "\n .AggregateDoubleArray();", - "\n ", - "\n double[] Values => Subtract(CurrentValues, PreviousValues);", - "\n}" - ], - "metadata": {}, - "execution_count": 0, - "outputs": [] - }, - { - "cell_type": "markdown", - "source": [ - "", - "\n### Present Value", - "\n", - "\nThe present value ($\\rm{PV}$) can be determined by taking the appropriate elements of the cumulated discounted cash flows. This is done as function of the two [projection parameters](../DataModel/DataStructure#projection-configuration) $\\rm{Shift}$ ($S$) and $\\rm{TimeStep}$ ($TS$):", - "\n", - "\n$$", - "\n\\text{PV}(S, TS) = \\left\\{", - "\n\\begin{array}{cl}", - "\n\\text{PV}_{S} ~, & \\text{if Valuation Period is Beginning of Period} \\\\", - "\n\\text{PV}_{S+TS/2 -1} ~, & \\text{if Valuation Period is Mid of Period} \\\\", - "\n\\sum_{i=S}^{S + TS - 1}\\text{PV }_{i} ~, & \\text{if Valuation Period is Delta} \\\\", - "\n\\text{PV}_{S + TS} ~, & \\text{if Valuation Period is End of Period} \\\\", - "\n\\end{array}", - "\n\\right.", - "\n$$", - "\n", - "\nwhere the term $TS/2$ uses MidpointRounding.AwayFromZero (as defined by *https:[]()//docs.microsoft.com/en-us/dotnet/api/system.midpointrounding?view=net-6.0)*: rounding to the nearest number, away from zero in the exact halfway case. Furthermore, if the array is smaller than the index, then the last element is returned.", - "\n", - "\nFor instance, for the current year and year-to-date view we have $S=0$ and $TS=3$ for the first quarter, $TS=6$ for the 2nd quarter and so on.", - "\nFor the projection values of next year first quarter we would have $S=12$ and $TS=3$, etc." - ], - "metadata": {}, - "execution_count": 0, - "outputs": [] - }, - { - "cell_type": "code", - "source": [ - "public interface IWithGetValueFromValues : IScope<(ImportIdentity Id, string AmountType, string EstimateType, int? AccidentYear), ImportStorage>", - "\n{", - "\n private int shift => GetStorage().GetShift(0);//Identity.Id.ProjectionPeriod", - "\n private int timeStep => GetStorage().GetTimeStep(0);//Identity.Id.ProjectionPeriod", - "\n ", - "\n public double GetValueFromValues(double[] Values)", - "\n {", - "\n return GetStorage().GetValuationPeriod(Identity.Id) switch {", - "\n ValuationPeriod.BeginningOfPeriod => Values.ElementAtOrDefault(shift),", - "\n ValuationPeriod.MidOfPeriod => Values.ElementAtOrDefault(shift + Convert.ToInt32(Math.Round(timeStep / 2d, MidpointRounding.AwayFromZero)) - 1),", - "\n ValuationPeriod.Delta => Values.Skip(shift).Take(timeStep).Sum(),", - "\n ValuationPeriod.EndOfPeriod => Values.ElementAtOrDefault(shift + timeStep),", - "\n ValuationPeriod.NotApplicable => default", - "\n };", - "\n }", - "\n}" - ], - "metadata": {}, - "execution_count": 0, - "outputs": [] - }, - { - "cell_type": "markdown", - "source": [ - "", - "\n### Interest Accretion", - "\n", - "\nSince the Interest Accretion cash flows are typically not provided as input (as they can be computed from its parent AoC Step), its present values can be computed as follows:", - "\n", - "\n$$", - "\n\\text{InterestAccretion}_i(\\text{AoC step}) = \\left\\{", - "\n\\begin{array}{cl}", - "\n\\big(\\text{CDC}_i(\\text{Parent AoC step}) - \\text{Nominal}_i(\\text{parent AoC step}) \\big) \\cdot \\big({\\text{Valid Interest}_{\\frac{i}{12}}} - 1 \\big)~, & \\text{if Amount Type's Transaction Period is Beginning of Period} \\\\", - "\n\\text{CDC}_i(\\text{parent AoC step}) \\cdot \\big({\\text{Valid Interest}_{\\frac{i}{12}}} - 1 \\big)~, & \\text{otherwise}", - "\n\\end{array}", - "\n\\right.", - "\n$$", - "\n", - "\n
Due to the Credit Default Risk of a reinsurance partner, the logic to compute the Interest Accretion for this Amount Type must be defined separately. Since it is based on Claims, the Period Type is implicitly defined." - ], - "metadata": {}, - "execution_count": 0, - "outputs": [] - }, - { - "cell_type": "code", - "source": [ - "public interface IWithInterestAccretion : IScope<(ImportIdentity Id, string AmountType, string EstimateType, int? AccidentYear), ImportStorage>", - "\n{", - "\n private double[] parentDiscountedValues => Multiply(-1d, GetScope(Identity).Values); ", - "\n private double[] parentNominalValues => GetScope(Identity).Values;", - "\n private double[] monthlyInterestFactor => GetScope(Identity.Id).Interest;", - "\n ", - "\n double[] GetInterestAccretion() ", - "\n {", - "\n var periodType = GetStorage().GetPeriodType(Identity.AmountType, Identity.EstimateType);", - "\n var ret = new double[parentDiscountedValues.Length];", - "\n ", - "\n switch (periodType) {", - "\n case PeriodType.BeginningOfPeriod :", - "\n for (var i = 0; i < parentDiscountedValues.Length; i++)", - "\n ret[i] = -1d * (parentDiscountedValues[i] - parentNominalValues[i]) * (monthlyInterestFactor.GetValidElement(i/12) - 1d );", - "\n break;", - "\n default :", - "\n for (var i = 0; i < parentDiscountedValues.Length; i++)", - "\n ret[i] = -1d * parentDiscountedValues[i] * (monthlyInterestFactor.GetValidElement(i/12) - 1d );", - "\n break;", - "\n }", - "\n ", - "\n return ret;", - "\n }", - "\n}", - "\n", - "\npublic interface IWithInterestAccretionForCreditRisk : IScope<(ImportIdentity Id, string AmountType, string EstimateType, int? AccidentYear), ImportStorage>", - "\n{", - "\n private double[] nominalClaimsCashflow => GetScope(Identity).Values;", - "\n private double[] nominalValuesCreditRisk => Multiply(-1, GetScope(Identity with {Id = Identity.Id with {AocType = AocTypes.CF}}).Values);", - "\n private double[] monthlyInterestFactor => GetScope(Identity.Id).Interest;", - "\n private double nonPerformanceRiskRate => GetStorage().GetNonPerformanceRiskRate(Identity.Id);", - "\n ", - "\n double[] GetInterestAccretion() ", - "\n {", - "\n var interestOnClaimsCashflow = new double[nominalClaimsCashflow.Length];", - "\n var interestOnClaimsCashflowCreditRisk = new double[nominalClaimsCashflow.Length];", - "\n var effectCreditRisk = new double[nominalClaimsCashflow.Length];", - "\n for (var i = nominalClaimsCashflow.Length - 1; i >= 0; i--) {", - "\n interestOnClaimsCashflow[i] = 1 / monthlyInterestFactor.GetValidElement(i/12) * (interestOnClaimsCashflow.ElementAtOrDefault(i + 1) + nominalClaimsCashflow[i] - nominalClaimsCashflow.ElementAtOrDefault(i + 1));", - "\n interestOnClaimsCashflowCreditRisk[i] = 1 / monthlyInterestFactor.GetValidElement(i/12) * (Math.Exp(-nonPerformanceRiskRate) * interestOnClaimsCashflowCreditRisk.ElementAtOrDefault(i + 1) + nominalClaimsCashflow[i] - nominalClaimsCashflow.ElementAtOrDefault(i + 1));", - "\n effectCreditRisk[i] = interestOnClaimsCashflow[i] - interestOnClaimsCashflowCreditRisk[i];", - "\n }", - "\n ", - "\n return Subtract(nominalValuesCreditRisk, effectCreditRisk);", - "\n }", - "\n}" - ], - "metadata": {}, - "execution_count": 0, - "outputs": [] - }, - { - "cell_type": "markdown", - "source": [ - "", - "\n### Present Value", - "\n", - "\nThe PV values are valid for all choices of the [Economic Basis](../DataModel/DataStructure#economic-basis):", - "\n", - "\n$$", - "\n\\text{PV}_i (\\text{AoC step}) = \\left\\{", - "\n\\begin{array}{rl}", - "\n\\text{CDC}_i ~, & \\text{if AoC Type = BOP} \\\\", - "\n-\\text{Nominal}_i(\\text{Parent AoC Step}) ~, & \\text{if AoC Type = CF } \\\\", - "\n\\text{InterestAccretion}_i ~, & \\text{if AoC Type = IA } \\\\", - "\n0 ~, & \\text{if AoC Type = AM } \\\\\\", - "\n\\text{CDC}_i(\\text{Parent AoC step}) ~, & \\text{if AoC Type = EOP } \\\\", - "\n\\text{TelescopingDifference}_i ~, & \\text{otherwise}", - "\n\\end{array}", - "\n\\right.", - "\n$$", - "\n", - "\nwhere $i$ denotes the months, and the [$\\rm{TelescopingDifference}_i$](#telescopic-difference) and the [$\\rm{InterestAccretion}_i$](#interest-accretion) quantities are defined above." - ], - "metadata": {}, - "execution_count": 0, - "outputs": [] - }, - { - "cell_type": "code", - "source": [ - "public interface PresentValue : IWithGetValueFromValues", - "\n{ ", - "\n static ApplicabilityBuilder ScopeApplicabilityBuilder(ApplicabilityBuilder builder) =>", - "\n builder.ForScope(s => s", - "\n .WithApplicability(x => x.GetStorage().ImportFormat != ImportFormats.Cashflow || x.GetStorage().IsSecondaryScope(x.Identity.Id.DataNode))", - "\n .WithApplicability(x => (x.Identity.Id.AocType == AocTypes.BOP && x.Identity.Id.Novelty != Novelties.C) || x.Identity.Id.AocType == AocTypes.EOP)", - "\n .WithApplicability(x => x.Identity.Id.AocType == AocTypes.CF)", - "\n .WithApplicability(x => x.Identity.Id.IsReinsurance && x.Identity.AmountType == AmountTypes.CDR && x.Identity.Id.AocType == AocTypes.IA)", - "\n .WithApplicability(x => x.Identity.Id.AocType == AocTypes.IA)", - "\n .WithApplicability(x => new string[]{AocTypes.BOP, AocTypes.EA, AocTypes.AM, AocTypes.RCU}.Contains(x.Identity.Id.AocType) ) //add here combination CRU for At !CDR?", - "\n );", - "\n ", - "\n [NotVisible][IdentityProperty][Dimension(typeof(EconomicBasis))]", - "\n string EconomicBasis => GetContext();", - "\n ", - "\n [NotVisible]", - "\n double[] Values => GetScope(Identity).Values;", - "\n ", - "\n public double Value => GetValueFromValues(Values);", - "\n}", - "\n", - "\npublic interface ComputePresentValueWithIfrsVariable : PresentValue", - "\n{", - "\n double PresentValue.Value => GetStorage().GetValue(Identity.Id, Identity.AmountType, Identity.EstimateType, EconomicBasis, Identity.AccidentYear);", - "\n double[] PresentValue.Values => Enumerable.Empty().ToArray();", - "\n}", - "\n", - "\npublic interface PresentValueFromDiscountedCashflow : PresentValue", - "\n{", - "\n [NotVisible]", - "\n double[] PresentValue.Values => GetScope(Identity).Values;", - "\n}", - "\n", - "\npublic interface CashflowAocStep : PresentValue", - "\n{", - "\n [NotVisible]", - "\n double[] PresentValue.Values => GetScope(Identity).Values;", - "\n}", - "\n", - "\npublic interface PresentValueWithInterestAccretion : PresentValue, IWithInterestAccretion", - "\n{", - "\n [NotVisible]", - "\n double[] PresentValue.Values => GetInterestAccretion();", - "\n}", - "\n", - "\npublic interface PresentValueWithInterestAccretionForCreditRisk : PresentValue, IWithInterestAccretionForCreditRisk", - "\n{", - "\n [NotVisible]", - "\n double[] PresentValue.Values => GetInterestAccretion();", - "\n}", - "\n", - "\npublic interface EmptyValuesAocStep : PresentValue", - "\n{", - "\n [NotVisible]", - "\n double[] PresentValue.Values => Enumerable.Empty().ToArray();", - "\n}" - ], - "metadata": {}, - "execution_count": 0, - "outputs": [] - }, - { - "cell_type": "markdown", - "source": [ - "", - "\n### Current and Locked", - "\n", - "\nPV Current and PV Locked below basically hold the Present Values [PV](#present-value) computed using the **Current** yield curves and the **Locked** yield curves, respectively.", - "\n", - "\nValues are available for each AmountType (by calling PvLocked.ByAmountType):", - "\n", - "\n$$", - "\n\\text{PV Locked}(\\text{AoC step}, \\text{Amount Type}) = \\text{PV}(\\text{AoC step}, \\text{Amount Type})|_{\\text{Economic Base = L}}", - "\n$$", - "\n", - "\n$$", - "\n\\text{PV Current}(\\text{AoC step}, \\text{Amount Type}) = \\text{PV}(\\text{AoC step}, \\text{Amount Type})|_{\\text{Economic Base = C}}", - "\n$$", - "\n", - "\n", - "\nAnd aggregated values are also available as the sum over all [Amount Types](../DataModel/DataStructure#amount-type) (by calling PvLocked.Value):", - "\n", - "\n$$", - "\n\\text{PV Locked}(\\text{AoC step}) = \\sum_{\\text{Amount Types}} \\text{PV}(\\text{AoC step}, \\text{Amount Type})|_{\\text{Economic Base = L}}", - "\n$$", - "\n", - "\n$$", - "\n\\text{PV Current}(\\text{AoC step}) = \\sum_{\\text{Amount Types}} \\text{PV}(\\text{AoC step}, \\text{Amount Type})|_{\\text{Economic Base = C}}", - "\n$$", - "\n", - "\nThese are used in the BBA methodology, whereby in the CSM calculations only PV Locked is used, and both of them are stored in the database under the [IfrsVariable](../DataModel/DataStructure#ifrs-variable) data structure." - ], - "metadata": {}, - "execution_count": 0, - "outputs": [] - }, - { - "cell_type": "code", - "source": [ - "public interface PvLocked : IScope", - "\n{ ", - "\n [IdentityProperty][NotVisible][Dimension(typeof(EconomicBasis))]", - "\n string EconomicBasis => EconomicBases.L;", - "\n ", - "\n [IdentityProperty][NotVisible][Dimension(typeof(EstimateType))]", - "\n string EstimateType => EstimateTypes.BE;", - "\n ", - "\n private int?[] accidentYears => GetStorage().GetAccidentYears(Identity.DataNode).ToArray(); ", - "\n ", - "\n [NotVisible]", - "\n PresentValue[] PresentValues => GetScope(Identity.DataNode).BeAmountTypes", - "\n .SelectMany(at => accidentYears", - "\n .Select(ay => GetScope((Identity, at, EstimateType, ay), o => o.WithContext(EconomicBasis))))", - "\n .ToArray();", - "\n double Value => PresentValues.Aggregate().Value;", - "\n}", - "\n", - "\npublic interface PvCurrent : IScope", - "\n{", - "\n [IdentityProperty][NotVisible][Dimension(typeof(EconomicBasis))]", - "\n string EconomicBasis => EconomicBases.C;", - "\n ", - "\n [IdentityProperty][NotVisible][Dimension(typeof(EstimateType))]", - "\n string EstimateType => EstimateTypes.BE;", - "\n ", - "\n private int?[] accidentYears => GetStorage().GetAccidentYears(Identity.DataNode).ToArray();", - "\n ", - "\n [NotVisible]", - "\n PresentValue[] PresentValues => GetScope(Identity.DataNode).BeAmountTypes", - "\n .SelectMany(at => accidentYears", - "\n .Select(ay => GetScope((Identity, at, EstimateType, ay), o => o.WithContext(EconomicBasis))))", - "\n .ToArray();", - "\n ", - "\n double Value => PresentValues.Aggregate().Value;", - "\n}" - ], - "metadata": {}, - "execution_count": 0, - "outputs": [] - }, - { - "cell_type": "markdown", - "source": [ - "", - "\n## Risk Adjustment", - "\n", - "\nRisk Adjustment values ($\\rm{RA}$) are accessible from the [PresentValue](#present-value) data and have [Estimate Type](../DataModel/DataStructure#estimate-type) $RA$. In particular, the Locked-In and Current values are given by:", - "\n", - "\n$$", - "\n\\text{RA Locked}(\\text{AoC step}) = \\text{PV}(\\text{AoC step})|_{\\text{Calculation Type = RA},~ \\text{Economic Basis = L}}", - "\n$$", - "\n", - "\n$$", - "\n\\text{RA Current}(\\text{AoC step}) = \\text{PV}(\\text{AoC step})|_{\\text{Calculation Type = RA},~ \\text{Economic Basis = C}}", - "\n$$", - "\n", - "\nwhere PV is defined [above](#present-value) and uses the input cash flows with Calculation Type = RA." - ], - "metadata": {}, - "execution_count": 0, - "outputs": [] - }, - { - "cell_type": "code", - "source": [ - "public interface RaLocked : IScope", - "\n{ ", - "\n [IdentityProperty][NotVisible][Dimension(typeof(EconomicBasis))]", - "\n string EconomicBasis => EconomicBases.L;", - "\n ", - "\n [IdentityProperty][NotVisible][Dimension(typeof(EstimateType))]", - "\n string EstimateType => EstimateTypes.RA;", - "\n ", - "\n private int?[] accidentYears => GetStorage().GetAccidentYears(Identity.DataNode).ToArray(); ", - "\n ", - "\n PresentValue[] PresentValues => accidentYears.Select(ay => GetScope((Identity, (string)null, EstimateType, ay), o => o.WithContext(EconomicBasis))).ToArray();", - "\n ", - "\n double Value => PresentValues.Aggregate().Value;", - "\n}", - "\npublic interface RaCurrent : IScope", - "\n{", - "\n [IdentityProperty][NotVisible][Dimension(typeof(EconomicBasis))]", - "\n string EconomicBasis => EconomicBases.C;", - "\n ", - "\n [IdentityProperty][NotVisible][Dimension(typeof(EstimateType))]", - "\n string EstimateType => EstimateTypes.RA;", - "\n ", - "\n private int?[] accidentYears => GetStorage().GetAccidentYears(Identity.DataNode).ToArray(); ", - "\n ", - "\n PresentValue[] PresentValues => accidentYears.Select(ay => GetScope((Identity, (string)null, EstimateType, ay), o => o.WithContext(EconomicBasis))).ToArray(); ", - "\n ", - "\n double Value => PresentValues.Aggregate().Value;", - "\n}" - ], - "metadata": {}, - "execution_count": 0, - "outputs": [] - }, - { - "cell_type": "markdown", - "source": [ - "", - "\n## Amortization", - "\n", - "\nFor the Amortization AoC Step (AoC Type **AM**), the amortization factors to be used are defined below." - ], - "metadata": {}, - "execution_count": 0, - "outputs": [] - }, - { - "cell_type": "markdown", - "source": [ - "", - "\n### Coverage Units", - "\n", - "\nThe coverage unit (CU) of a GIC is introduced in the standard as the quantity of the service provided in that GIC. The service is", - "\nmeasured by considering the quantity of benefits provided as well as the expected coverage period of the GIC.", - "\n", - "\nThe cash flows of coverage units are retrieved from the discounted cash flows with [EstimateType](../DataModel/DataStructure#estimate-type) CU." - ], - "metadata": {}, - "execution_count": 0, - "outputs": [] - }, - { - "cell_type": "code", - "source": [ - "public interface CoverageUnitCashflow : IScope", - "\n{ ", - "\n [NotVisible] string EconomicBasis => GetContext();", - "\n ", - "\n [IdentityProperty][NotVisible][Dimension(typeof(EstimateType))]", - "\n string EstimateType => EstimateTypes.CU;", - "\n ", - "\n double[] Values => GetScope((Identity, (string)null, EstimateType, (int?)null)).Values;", - "\n}" - ], - "metadata": {}, - "execution_count": 0, - "outputs": [] - }, - { - "cell_type": "markdown", - "source": [ - "", - "\n### Amortization Factor" - ], - "metadata": {}, - "execution_count": 0, - "outputs": [] - }, - { - "cell_type": "markdown", - "source": [ - "For a certain GIC, the monthly Amortization Factors $\\text{Monthly }AF_i$ are computed from the cash flows of the underlying coverage unit for that GIC:", - "\n", - "\n$$", - "\n\\text{Monthly }AF_i = 1 - \\frac{ \\text{Nominal}_i(CL)} {\\text{CDC}_i(CL) } ~.", - "\n$$", - "\n", - "\nwhere:", - "\n- $i$ denotes a monthly period;", - "\n- the nominal cash flows $\\text{Nominal}_i(CL)$ are the nominal cash flows of the coverage unit for the AoC Step **Combined Liability** (CL) (input data);", - "\n- and the corresponding cumulated discounted cash flows $\\text{CDC}_i$ are defined [above](#cumulated-discounted-cash-flows)." - ], - "metadata": {}, - "execution_count": 0, - "outputs": [] - }, - { - "cell_type": "code", - "source": [ - "public interface MonthlyAmortizationFactorCashflow : IScope", - "\n{", - "\n private double[] NominalCuCashflow => GetScope((Identity with {AocType = AocTypes.CL}, (string)null, EstimateTypes.CU, (int?)null)).Values;", - "\n private double[] DiscountedCuCashflow => Multiply(-1d, GetScope(Identity with {AocType = AocTypes.CL}, o => o.WithContext(EconomicBasis)).Values);", - "\n ", - "\n [NotVisible] string EconomicBasis => GetContext();", - "\n ", - "\n double[] MonthlyAmortizationFactors => Identity.AocType switch {", - "\n AocTypes.AM => NominalCuCashflow.Zip(DiscountedCuCashflow, //Extract to an other scope with month in the identity to avoid Zip?", - "\n (nominal, discountedCumulated) => Math.Abs(discountedCumulated) >= Precision ", - "\n ? 1 - nominal / discountedCumulated ", - "\n : 0).ToArray(),", - "\n _ => Enumerable.Empty().ToArray(),", - "\n };", - "\n}" - ], - "metadata": {}, - "execution_count": 0, - "outputs": [] - }, - { - "cell_type": "markdown", - "source": [ - "For a certain projection period - defined by the Shift, $S$, and the Time-Step, $TS$, parameters - the Amortization Factor is then given by the product of the corresponding monthly amortization factors:", - "\n", - "\n$$", - "\nAF = 1 - \\prod _{i = S}^{S + TS - 1} \\text{Monthly }AF_i ~.", - "\n$$", - "\n", - "\nEach GIC will have his own AF.", - "\n", - "\nIn order to run off the business of a given Group of Contract one should provide a cash flow of 0s for the AoC Step with AoC Type CL and Novelty C. When computing the AF this results in the product of the monthly amortization factors of the period to be 1. In this case, the computed AF does not follow the formula above but is 1 allowing for the full release of the Technical Margin in the AM AoC Step." - ], - "metadata": {}, - "execution_count": 0, - "outputs": [] - }, - { - "cell_type": "code", - "source": [ - "public interface CurrentPeriodAmortizationFactor : IScope", - "\n{", - "\n static ApplicabilityBuilder ScopeApplicabilityBuilder(ApplicabilityBuilder builder) =>", - "\n builder.ForScope(s => ", - "\n s.WithApplicability(x => x.GetStorage().ImportFormat != ImportFormats.Cashflow", - "\n || x.GetStorage().IsSecondaryScope(x.Identity.DataNode)));", - "\n", - "\n private int shift => GetStorage().GetShift(0);//Identity.ProjectionPeriod", - "\n private int timeStep => GetStorage().GetTimeStep(0);//Identity.ProjectionPeriod", - "\n private double amortizedFactor => GetScope(Identity)", - "\n .MonthlyAmortizationFactors", - "\n .Skip(shift)", - "\n .Take(timeStep)", - "\n .Aggregate(1d, (x, y) => x * y);", - "\n [NotVisible] string EconomicBasis => GetContext();", - "\n", - "\n string EstimateType => EstimateTypes.F;", - "\n double Value => Math.Abs(amortizedFactor - 1d) > Precision", - "\n ? 1d - amortizedFactor", - "\n : 1d;", - "\n}", - "\n", - "\npublic interface AmfFromIfrsVariable : CurrentPeriodAmortizationFactor", - "\n{", - "\n double CurrentPeriodAmortizationFactor.Value => GetStorage().GetValue(Identity, (string)null, EstimateType, EconomicBasis, (int?)null);", - "\n}" - ], - "metadata": {}, - "execution_count": 0, - "outputs": [] - }, - { - "cell_type": "markdown", - "source": [ - "", - "\n## Actual Values", - "\n", - "\nWe consider 4 types of Actual values, which are distinguished through their [Estimate Type](../DataModel/DataStructure#estimate-type):", - "\n- [Actuals](#actuals) (A)", - "\n- [Advance Actuals](#advance-actuals) (AA)", - "\n- [Overdue Actuals](#overdue-actuals) (OA)", - "\n- [Deferrable Actuals](#deferrable-actuals) (DA)", - "\n", - "\nwith the Estimate Type's system name shown between parenthesis above.", - "\n", - "\nThe following simplified AoC Chain applies for Advance and Overdue Actuals:", - "\n
 BOP", - "\n
 Release", - "\n
 Write-off", - "\n
 EOP" - ], - "metadata": {}, - "execution_count": 0, - "outputs": [] - }, - { - "cell_type": "markdown", - "source": [ - "", - "\n### Actual Base", - "\n", - "\nThe Actual Base sets values for actual, advance, and overdue as follows:", - "\n", - "\n$$", - "\n\\text{Actual Base} (\\text{AoC step}) = \\left\\{", - "\n\\begin{array}{rl}", - "\n0 ~, & \\text{if AoC Step's AoC Type = AM} \\\\", - "\n\\text{Actual Base}(\\rm{BOP}) + \\text{Actual Base}(\\rm{CF}) + \\text{Actual Base}(\\rm{WO}) ~, & \\text{if AoC Step's AoC Type = EOP and EstimateType is not A} \\\\", - "\n\\text{Imported Actual} ~, & \\text{otherwise}", - "\n\\end{array}", - "\n\\right.", - "\n$$", - "\n", - "\nwhere the value is also function of the [Estimate Type](../DataModel/DataStructure#EstimateType) and [Amount Type](../DataModel/DataStructure#AmountType), and the $\\text{Imported Actual}$ value is described [here]()." - ], - "metadata": {}, - "execution_count": 0, - "outputs": [] - }, - { - "cell_type": "code", - "source": [ - "public interface ActualBase : IScope<(ImportIdentity Id, string AmountType, string EstimateType, int? AccidentYear), ImportStorage>", - "\n{", - "\n static ApplicabilityBuilder ScopeApplicabilityBuilder(ApplicabilityBuilder builder) =>", - "\n builder.ForScope(s => s.WithApplicability(x => x.GetStorage().ImportFormat == ImportFormats.Actual ", - "\n && !x.GetStorage().IsSecondaryScope(x.Identity.Id.DataNode)", - "\n && x.Identity.Id.AocType == AocTypes.AM)", - "\n .WithApplicability(x => x.GetStorage().ImportFormat != ImportFormats.Cashflow ", - "\n && !x.GetStorage().IsSecondaryScope(x.Identity.Id.DataNode)", - "\n && x.Identity.Id.AocType == AocTypes.EOP ", - "\n && x.Identity.EstimateType != EstimateTypes.A)", - "\n );", - "\n public double Value => GetStorage().GetValue(Identity.Id, Identity.AmountType, Identity.EstimateType, Identity.AccidentYear); ", - "\n}", - "\n", - "\npublic interface EndOfPeriodActual : ActualBase", - "\n{", - "\n double ActualBase.Value => GetScope((Identity.Id, InputSource.Actual)).Values", - "\n .Sum(aocStep => GetScope((Identity.Id with {AocType = aocStep.AocType, Novelty = aocStep.Novelty}, Identity.AmountType, Identity.EstimateType, Identity.AccidentYear)).Value);", - "\n}", - "\n", - "\npublic interface EmptyValuesActual : ActualBase", - "\n{", - "\n double ActualBase.Value => 0;", - "\n}" - ], - "metadata": {}, - "execution_count": 0, - "outputs": [] - }, - { - "cell_type": "markdown", - "source": [ - "", - "\n### Actuals", - "\nThe Actuals correspond to ActualBase values with estimate type $A$.", - "\nThe only valid AoC Step is Release:", - "\n", - "\n$$", - "\n\\text{Actual} (\\text{Release}) = \\text{Actual Base} (\\text{Release})|_{\\text{Estimate Type} = A}", - "\n$$" - ], - "metadata": {}, - "execution_count": 0, - "outputs": [] - }, - { - "cell_type": "code", - "source": [ - "public interface Actual : IScope", - "\n{", - "\n [IdentityProperty][NotVisible][Dimension(typeof(EstimateType))]", - "\n string EstimateType => EstimateTypes.A;", - "\n ", - "\n private int?[] accidentYears => GetStorage().GetAccidentYears(Identity.DataNode).ToArray();", - "\n ", - "\n [NotVisible]", - "\n ActualBase[] Actuals => GetScope(Identity.DataNode).ActualAmountTypes", - "\n .SelectMany(at => accidentYears", - "\n .Select(ay => GetScope((Identity, at, EstimateType, ay)))).ToArray();", - "\n}" - ], - "metadata": {}, - "execution_count": 0, - "outputs": [] - }, - { - "cell_type": "markdown", - "source": [ - "", - "\n### Advance Actuals", - "\n", - "\nAdvance Actuals are cash flows with due date inside the reporting period but occured *before* the reporting period - They include:", - "\n- Receivable Claims", - "\n- Receivable Expenses", - "\n- Payable Premiums", - "\n", - "\nAdvance Actuals are given by", - "\n", - "\n$$", - "\n\\text{Advance Actual} (\\text{AoC step}) = \\text{Actual Base} (\\text{AoC step})|_{\\text{Estimate Type} = AA}", - "\n$$" - ], - "metadata": {}, - "execution_count": 0, - "outputs": [] - }, - { - "cell_type": "code", - "source": [ - "public interface AdvanceActual : IScope", - "\n{", - "\n [IdentityProperty][NotVisible][Dimension(typeof(EstimateType))]", - "\n string EstimateType => EstimateTypes.AA;", - "\n ", - "\n private int?[] accidentYears => GetStorage().GetAccidentYears(Identity.DataNode).ToArray();", - "\n ", - "\n [NotVisible]", - "\n ActualBase[] Actuals => GetScope(Identity.DataNode).ActualAmountTypes", - "\n .SelectMany(at => accidentYears", - "\n .Select(ay => GetScope((Identity, at, EstimateType, ay)))).ToArray();", - "\n}" - ], - "metadata": {}, - "execution_count": 0, - "outputs": [] - }, - { - "cell_type": "markdown", - "source": [ - "", - "\n### Overdue Actuals", - "\n", - "\nOverdue Actuals are cash flows with due date inside the reporting period but occur *after* the reporting period - They contain:", - "\n- Payable Claims", - "\n- Payable Expenses", - "\n- Receivable Premiums", - "\n", - "\nThe sign convention is the inverse of the default behavior - In particular: Premiums have positive value, whereas Claims and Expenses have negative value.", - "\n", - "\nThe Overdue Actuals are given by", - "\n", - "\n$$", - "\n\\text{Overdue Actual} (\\text{AoC step}) = \\text{Actual Base} (\\text{AoC step})|_{\\text{Estimate Type} = OA}", - "\n$$" - ], - "metadata": {}, - "execution_count": 0, - "outputs": [] - }, - { - "cell_type": "code", - "source": [ - "public interface OverdueActual : IScope", - "\n{", - "\n [IdentityProperty][NotVisible][Dimension(typeof(EstimateType))]", - "\n string EstimateType => EstimateTypes.OA;", - "\n ", - "\n private int?[] accidentYears => GetStorage().GetAccidentYears(Identity.DataNode).ToArray();", - "\n ", - "\n [NotVisible]", - "\n ActualBase[] Actuals => GetScope(Identity.DataNode).ActualAmountTypes", - "\n .SelectMany(at => accidentYears", - "\n .Select(ay => GetScope((Identity, at, EstimateType, ay)))).ToArray();", - "\n}" - ], - "metadata": {}, - "execution_count": 0, - "outputs": [] - }, - { - "cell_type": "markdown", - "source": [ - "", - "\n### Deferrable Actuals", - "\n", - "\nFinally, Deferrable Actuals are given by", - "\n", - "\n$$", - "\n\\text{Deferrable Actual} (\\text{AoC step}) = \\left\\{", - "\n\\begin{array}{rl}", - "\n\\sum_{\\text{Amount Type}~\\in~\\text{\\{ACA, AEA}\\}}\\text{Actual Base}(\\rm{CF})|_{\\text{Estimate Type = A}} ~, & \\text{if AoC Step's AoC Type = CF } \\\\", - "\n- \\text{Amortization Factor} \\cdot \\big( \\text{Deferrable Actual}(\\rm{BOP}) + \\text{Deferrable Actual}(\\rm{CF}) \\big) ~, & \\text{if AoC Step's AoC Type = AM } \\\\", - "\n\\text{Deferrable Actual}(\\rm{BOP}) + \\text{Deferrable Actual}(\\rm{CF}) + \\text{Deferrable Actual}(\\rm{AM}) ~, & \\text{if AoC Step's AoC Type = EOP } \\\\", - "\n\\text{Input Actual}|_{\\text{Estimate Type = DA}} ~, & \\text{ otherwise } \\\\", - "\n\\end{array}", - "\n\\right.", - "\n$$", - "\n", - "\nwhere $ACA$ and $AEA$ are *Aquisition* Amount Types from **Attributable Commission** and **Attributable Expenses**, respectively." - ], - "metadata": {}, - "execution_count": 0, - "outputs": [] - }, - { - "cell_type": "code", - "source": [ - "public interface DeferrableActual : IScope", - "\n{", - "\n static ApplicabilityBuilder ScopeApplicabilityBuilder(ApplicabilityBuilder builder) =>", - "\n builder.ForScope(s => s.WithApplicability(x => x.Identity.ValuationApproach == ValuationApproaches.VFA, ", - "\n p => p.ForMember(s => s.EconomicBasis))", - "\n .WithApplicability(x => x.Identity.AocType == AocTypes.CF)", - "\n .WithApplicability(x => x.Identity.AocType == AocTypes.AM)", - "\n .WithApplicability(x => x.Identity.AocType == AocTypes.EOP)", - "\n );", - "\n ", - "\n [IdentityProperty][NotVisible][Dimension(typeof(EstimateType))]", - "\n string EstimateType => EstimateTypes.DA;", - "\n ", - "\n [NotVisible] string EconomicBasis => EconomicBases.L;", - "\n ", - "\n public double Value => GetStorage().GetValue(Identity, (string)null, EstimateType, (int?)null);", - "\n}", - "\n", - "\npublic interface DeferrableActualForCurrentBasis : DeferrableActual", - "\n{", - "\n [NotVisible] string DeferrableActual.EconomicBasis => EconomicBases.C;", - "\n}", - "\n", - "\npublic interface ReleaseDeferrable : DeferrableActual", - "\n{", - "\n double DeferrableActual.Value => GetStorage().GetAttributableExpenseAndCommissionAmountType().Sum(at => GetScope((Identity, at, EstimateTypes.A, (int?)null)).Value);", - "\n}", - "\n", - "\npublic interface AmortizationDeferrable : DeferrableActual", - "\n{", - "\n private double AmortizationFactor => GetScope(Identity, o => o.WithContext(EconomicBasis)).Value;", - "\n private double AggregatedDeferrable => GetScope((Identity, InputSource.Actual)).Values", - "\n .Sum(aocStep => GetScope(Identity with {AocType = aocStep.AocType, Novelty = aocStep.Novelty}).Value);", - "\n double DeferrableActual.Value => -1d * AggregatedDeferrable * AmortizationFactor;", - "\n}", - "\n", - "\npublic interface EndOfPeriodDeferrable : DeferrableActual", - "\n{", - "\n double DeferrableActual.Value => GetScope((Identity, InputSource.Actual)).Values", - "\n .Sum(aocStep => GetScope(Identity with {AocType = aocStep.AocType, Novelty = aocStep.Novelty}).Value);", - "\n}" - ], - "metadata": {}, - "execution_count": 0, - "outputs": [] - }, - { - "cell_type": "markdown", - "source": [ - "", - "\n## Contractual Service Margin, Loss Component and Loss Recovery Component", - "\n", - "\nThe Contractual Service Margin ($CSM$) denotes the unearned profit from an insurance contract or group of insurance contracts and plays a critical role in the calculation of profit & loss values. Similarly, the unearned loss is denoted by Loss Component ($LC$), Loss Recovery Component in the case of reinsurance contracts." - ], - "metadata": {}, - "execution_count": 0, - "outputs": [] - }, - { - "cell_type": "markdown", - "source": [ - "## Experience Adjustment on Premium" - ], - "metadata": {}, - "execution_count": 0, - "outputs": [] - }, - { - "cell_type": "markdown", - "source": [ - "The Experience Adjustment (EA) on Premiums weights the cash-flow (CF aocSteps) for premium amount types by the PremiumAllocationFactor input for each group of insurance contract. ", - "\nThe contributions of present values and actuals are computed separately.", - "\n", - "\n$$", - "\nEA (\\rm{PV}) = \\text{Premium Allocation Factor} \\cdot \\big( PV (\\text{AoC Type = CF}) \\big)~, \\\\", - "\n$$", - "\n$$", - "\nEA (\\text{Actual}) = \\text{Premium Allocation Factor} \\cdot \\big( \\text{Actual}(\\text{AoC Type = CF}) \\big) ~,", - "\n$$", - "\nwhere amount type premium and its children are considered, novelties in-force and new business are considered for $PV$ whereas novelty combined is considered for Actual. The allocation is always done in the finest granularity (novelty, line of business, ..) possible." - ], - "metadata": {}, - "execution_count": 0, - "outputs": [] - }, - { - "cell_type": "code", - "source": [ - "public interface BeExperienceAdjustmentForPremium : IScope", - "\n{", - "\n static ApplicabilityBuilder ScopeApplicabilityBuilder(ApplicabilityBuilder builder) =>", - "\n builder.ForScope(s => s", - "\n .WithApplicability(x => x.Identity.AocType != AocTypes.CF));", - "\n", - "\n string EstimateType => EstimateTypes.BEPA;", - "\n string EconomicBasis => EconomicBases.L;", - "\n ", - "\n PresentValue[] ByAmountType => GetStorage().GetPremiums().Select(pr => ", - "\n Multiply( GetStorage().GetPremiumAllocationFactor(Identity), ", - "\n GetScope((Identity, pr, EstimateTypes.BE, (int?)null), o => o.WithContext(EconomicBasis)) ) ).ToArray(); ", - "\n}", - "\n", - "\npublic interface DefaultValueBeExperienceAdjustmentForPremium : BeExperienceAdjustmentForPremium", - "\n{", - "\n PresentValue[] BeExperienceAdjustmentForPremium.ByAmountType => Enumerable.Empty().ToArray();", - "\n}" - ], - "metadata": {}, - "execution_count": 0, - "outputs": [] - }, - { - "cell_type": "code", - "source": [ - "public interface ActualExperienceAdjustmentOnPremium : IScope", - "\n{", - "\n static ApplicabilityBuilder ScopeApplicabilityBuilder(ApplicabilityBuilder builder) =>", - "\n builder.ForScope(s => s", - "\n .WithApplicability(x => x.Identity.AocType != AocTypes.CF));", - "\n ", - "\n public ActualBase[] ByAmountTypeAndEstimateType => GetStorage().GetPremiums().Select(pr =>", - "\n Multiply( GetStorage().GetPremiumAllocationFactor(Identity),", - "\n GetScope((Identity, pr, EstimateTypes.A, (int?)null))) ).ToArray();", - "\n}", - "\n", - "\npublic interface DefaultValueActualExperienceAdjustmentOnPremium : ActualExperienceAdjustmentOnPremium", - "\n{", - "\n ActualBase[] ActualExperienceAdjustmentOnPremium.ByAmountTypeAndEstimateType => Enumerable.Empty().ToArray();", - "\n}" - ], - "metadata": {}, - "execution_count": 0, - "outputs": [] - }, - { - "cell_type": "markdown", - "source": [ - "", - "\n## Technical Margin", - "\n", - "\nFor the computation of the $CSM$ or $LC$ component values for each step of the [AoC Step Structure](#aoc-step-structure), it is convenient to introduce the ", - "\nnotion of technical margin $TM$. In the case of BBA methodology, the Locked-in interest rates discounting is applied to obtain the PV and RA values.", - "\n", - "\nThis can be summarized as follows:", - "\n", - "\n$$", - "\nTM(s) = \\left\\{", - "\n\\begin{array}{rl}", - "\nTM(\\rm{EOP}) \\text{ of the previous period} ~ & \\text{if }s = \\text{BOP and Novelty is In-Force}.", - "\n\\\\", - "\n0 ~ & \\text{if }s = \\text{CF}.", - "\n\\\\", - "\nIAF \\cdot~\\text{Aggregated}~TM(\\text{IA}) ~ & \\text{if }s = \\text{IA and Novelty is In-Force}.", - "\n\\\\", - "\n\\rm{Premiums} + \\text{Attributable Expense and Commissions} + \\text{Investment Claims} ~ & \\text{if }s = \\text{EA}.", - "\n\\\\", - "\n-AF \\cdot~\\text{Aggregated}~TM(\\text{AM})~ & \\text{if }s = \\text{AM}.", - "\n\\\\", - "\n\\text{PV}(\\text{s})\\bigg|_{\\substack{\\text{Non Attributable} \\\\ \\text{Amount Types} \\\\ \\text{excluded}}} ", - "\n+ \\text{RA}(\\text{s})~ & \\text{otherwise} ", - "\n\\end{array}", - "\n\\right.", - "\n$$", - "\n", - "\nwhere", - "\n", - "\n$$", - "\n\\text{Aggregated}~TM (\\text{AoC step}) = \\sum_{s\\in\\text{ previous AoC steps}} TM(s)~.", - "\n$$", - "\n", - "\nand the Interest Accretion Factor ($IAF$) is given by", - "\n", - "\n$$", - "\nIAF = \\prod_{i=1}^{TS} \\text{Interest}_i - 1", - "\n$$", - "\n", - "\nwhere $\\text{Interest}_i$ is the monthly interest factor obtained from the [Yield Curve](#yield-curves) and $TS$ is the Time-Step.", - "\n", - "\nFinally, the Premiums, Attributable Expense and Commissions and Investment Claims terms are given by:", - "\n", - "\n$$", - "\n\\rm{Premiums} = \\sum_{\\text{Amount Type}\\in\\{\\text{PR and its children}\\}}", - "\nEA(\\rm{PV}) - EA(\\text{Actual}) ~,", - "\n$$", - "\n", - "\n$$", - "\n\\text{Attributable Expense and Commissions} = \\sum_{\\text{Amount Type}\\in\\{\\rm{ACA}, \\rm{AEA}\\}}", - "\n\\big(PV_{\\text{Novelty = I}} + PV_{\\text{Novelty = N}} \\big) - \\text{Actual}_{\\text{Novelty=C}} ~,", - "\n$$", - "\n", - "\n$$", - "\n\\text{Investment Claims } = \\sum_{\\text{Amount Type}\\in\\{\\text{ICO and its children}\\}}", - "\n\\big(PV_{\\text{Novelty = I}} + PV_{\\text{Novelty = N}} \\big) - \\text{Actual}_{\\text{Novelty=C}} ~,", - "\n$$", - "\n", - "\nwhere the AoC Step **CF** is implicit for all formulas, $PV$ is the [present value](#present-value) with Estimate Type **BE** (Best Estimate), and Actuals have Estimate Types **A** (see details [here](#actual-values)). Note that according to the applied sign convention, the sign of the CF AoC Step of Best Estimate Present Value and Actual is the same, accounting for the minus sign in the formula. " - ], - "metadata": {}, - "execution_count": 0, - "outputs": [] - }, - { - "cell_type": "code", - "source": [ - "public interface TechnicalMargin : IScope", - "\n{", - "\n static ApplicabilityBuilder ScopeApplicabilityBuilder(ApplicabilityBuilder builder) => ", - "\n builder.ForScope(s => s.WithApplicability(x => x.Identity.ValuationApproach == ValuationApproaches.VFA, p => p.ForMember(s => s.EconomicBasis))", - "\n .WithApplicability(x => x.Identity.AocType == AocTypes.BOP && x.Identity.Novelty == Novelties.I)", - "\n .WithApplicability(x => x.Identity.AocType == AocTypes.CF)", - "\n .WithApplicability(x => x.Identity.AocType == AocTypes.IA && x.Identity.Novelty == Novelties.I)", - "\n .WithApplicability(x => x.Identity.AocType == AocTypes.EA && !x.Identity.IsReinsurance)", - "\n .WithApplicability(x => x.Identity.AocType == AocTypes.AM)", - "\n );", - "\n ", - "\n [NotVisible] string EconomicBasis => EconomicBases.L;", - "\n ", - "\n double Value => GetScope(Identity.DataNode).BeAmountTypes", - "\n .Except(GetStorage().GetNonAttributableAmountType())", - "\n .Sum(at => GetScope((Identity, at, EstimateTypes.BE, (int?)null), o => o.WithContext(EconomicBasis)).Value) +", - "\n GetScope(Identity).Value;", - "\n ", - "\n double AggregatedValue => GetScope((Identity, InputSource.Cashflow)).Values", - "\n .Sum(aoc => GetScope(Identity with {AocType = aoc.AocType, Novelty = aoc.Novelty}).Value);", - "\n}", - "\n", - "\npublic interface TechnicalMarginForCurrentBasis : TechnicalMargin", - "\n{", - "\n [NotVisible] string TechnicalMargin.EconomicBasis => EconomicBases.C;", - "\n}", - "\n", - "\npublic interface TechnicalMarginForBOP : TechnicalMargin", - "\n{", - "\n private double ValueCsm => GetStorage().GetValue(Identity, null, EstimateTypes.C, null);", - "\n private double ValueLc => GetStorage().GetValue(Identity, null, EstimateTypes.L, null);", - "\n private double ValueLr => GetStorage().GetValue(Identity, null, EstimateTypes.LR, null);", - "\n ", - "\n double TechnicalMargin.Value => -1d * ValueCsm + ValueLc + ValueLr;", - "\n}", - "\n", - "\npublic interface TechnicalMarginDefaultValue : TechnicalMargin", - "\n{", - "\n double TechnicalMargin.Value => default;", - "\n}", - "\n", - "\npublic interface TechnicalMarginForIA : TechnicalMargin", - "\n{", - "\n private int timeStep => GetStorage().GetTimeStep(0);//Identity.Id.ProjectionPeriod", - "\n private int shift => GetStorage().GetShift(0);//Identity.Id.ProjectionPeriod", - "\n ", - "\n private double[] monthlyInterestFactor => GetScope(Identity, o => o.WithContext(EconomicBasis)).Interest;", - "\n ", - "\n private double interestAccretionFactor => Enumerable.Range(shift,timeStep)", - "\n .Select(i => monthlyInterestFactor.GetValidElement(i/12))", - "\n .Aggregate(1d, (x, y) => x * y ) - 1d;", - "\n ", - "\n double TechnicalMargin.Value => AggregatedValue * interestAccretionFactor;", - "\n}", - "\n", - "\npublic interface TechnicalMarginForEA : TechnicalMargin", - "\n{", - "\n static ApplicabilityBuilder ScopeApplicabilityBuilderInner(ApplicabilityBuilder builder) => ", - "\n builder.ForScope(s => s.WithApplicability(x => x.Identity.IsReinsurance));", - "\n ", - "\n private string referenceAocType => GetScope(Identity).Value.AocType;", - "\n ", - "\n private double premiums => GetStorage().GetNovelties(referenceAocType, InputSource.Cashflow)", - "\n .Sum(n => GetScope(Identity with {AocType = referenceAocType, Novelty = n}).ByAmountType.Sum(sc => sc.Value)) -", - "\n GetScope(Identity with {AocType = referenceAocType, Novelty = Novelties.C}).ByAmountTypeAndEstimateType.Sum(sc => sc.Value);", - "\n ", - "\n private double attributableExpenseAndCommissions => GetStorage().GetAttributableExpenseAndCommissionAmountType().Sum(d =>", - "\n GetStorage().GetNovelties(referenceAocType, InputSource.Cashflow)", - "\n .Sum(n => GetScope((Identity with {AocType = referenceAocType, Novelty = n}, d, EstimateTypes.BE, (int?)null), o => o.WithContext(EconomicBasis)).Value) -", - "\n GetScope((Identity with {AocType = referenceAocType, Novelty = Novelties.C}, d, EstimateTypes.A, (int?)null)).Value);", - "\n", - "\n private double investmentClaims => GetStorage().GetInvestmentClaims().Sum(ic =>", - "\n GetStorage().GetNovelties(referenceAocType, InputSource.Cashflow)", - "\n .Sum(n => GetScope((Identity with {AocType = referenceAocType, Novelty = n}, ic, EstimateTypes.BE, (int?)null), o => o.WithContext(EconomicBasis)).Value) -", - "\n GetScope((Identity with {AocType = referenceAocType, Novelty = Novelties.C}, ic, EstimateTypes.A, (int?)null)).Value);", - "\n ", - "\n double TechnicalMargin.Value => premiums + attributableExpenseAndCommissions + investmentClaims;", - "\n}", - "\n", - "\npublic interface TechnicalMarginForAM : TechnicalMargin", - "\n{", - "\n double TechnicalMargin.Value => -1d * AggregatedValue * GetScope(Identity, o => o.WithContext(EconomicBasis)).Value;", - "\n}" - ], - "metadata": {}, - "execution_count": 0, - "outputs": [] - }, - { - "cell_type": "markdown", - "source": [ - "", - "\n## Switch Logic", - "\n ", - "\nThe $CSM$ and $LC$ components are computed from the [technical margin](#technical-margin). In particular, for a given AoC step $s$, TM is allocated to the $LC$ when $\\text{Aggregated } TM$ is positive whereas it is allocated to the $CSM$ when $\\text{Aggregated } TM$ is negative:", - "\n", - "\n$$", - "\n\\begin{array}{rl}", - "\nCSM({\\text{AoC Step}}) = 0,~~ LC({\\text{AoC step}}) = TM({\\text{AoC step}}) ~ & \\text{if }\\text{Aggregated }TM({\\text{AoC step}}) > 0.", - "\n\\\\", - "\nCSM({\\text{AoC Step}}) = - TM({\\text{AoC step}}),~~ LC({\\text{AoC step}}) = 0 ~ & \\text{otherwise} ", - "\n\\end{array}", - "\n$$", - "\n", - "\n", - "\nThe figures reported under CSM are the opposite of the TM value in order to satisfy our sign convention.", - "\n", - "\nIt is possible to switch from $CSM$ to $LC$ and from $LC$ to $CSM$ at any AoC step $s$ with the only exception of **Amortization** where there is no switch from the previous step.", - "\nWhen a switch occurs the total contribution to the $CSM$ ($LC$) prior the switching step is brought to 0 and the remaing amount is allocated to $LC$ ($CSM$).", - "\n", - "\n", - "\n### Gross case (i.e. no reinsurance)", - "\n", - "\nThe switch logic is applied ***separately*** to the In-Force and New Business novelties. The Combined Liability AoC Step **CL** will bring both contributions to CSM and LC together as the novelities are summed up.", - "\n", - "\nIn detail, and as we go through the AoC steps in the AoC chain, we have", - "\n", - "\n**A)** For the **BOP**:", - "\n$$", - "\n\\begin{array}{rl}", - "\nCSM(\\text{BOP}) &= CSM(\\text{EOP}) \\text{ of the previous period, for Novelty In-Force}", - "\n\\\\", - "\nLC(\\text{BOP}) &= LC(\\text{EOP}) \\text{ of the previous period, for Novelty In-Force}", - "\n\\end{array}", - "\n$$", - "\n", - "\n", - "\n**B)** For the **following AoC steps**, the switch logic is preferably formulated using the delta variations between steps, $\\Delta CSM$ and $\\Delta LC$ for the CSM and the LC respectively.", - "\n", - "\nThe switch logic for these AoC steps with the *exception* of Combined Liability is:", - "\n", - "\nIf $\\text{Aggregated }TM(\\text{AoC Step}) > 0$ and $\\text{Aggregated }TM(\\text{AoC Step}) + TM(\\text{AoC Step}) \\le 0$, then there is a switch from $LC$ to $CSM$:", - "\n", - "\n$$", - "\n\\begin{array}{rl}", - "\n\\Delta CSM(\\text{AoC step}) &= -TM(\\text{AoC Step}) -\\text{Aggregated } TM(\\text{AoC Step})", - "\n\\\\", - "\n\\Delta LC(\\text{AoC step}) &= -\\text{Aggregated } TM(\\text{AoC Step}) ", - "\n\\end{array}", - "\n$$", - "\n", - "\nOn the other hand, if $\\text{Aggregated }TM(\\text{AoC Step}) \\le 0$ and $\\text{Aggregated }TM(\\text{AoC Step}) + TM(\\text{AoC Step}) > 0$, then the switch is from $CSM$ to $LC$:", - "\n", - "\n$$", - "\n\\begin{array}{rl}", - "\n\\Delta CSM(\\text{AoC step}) &= \\text{Aggregated } TM(\\text{AoC Step}) ", - "\n\\\\", - "\n\\Delta LC(\\text{AoC step}) &= TM(\\text{AoC Step}) + \\text{Aggregated } TM(\\text{AoC Step}) ", - "\n\\end{array}", - "\n$$", - "\n", - "\nIf there is no switch from $CSM$, i.e. $\\text{Aggregated }TM(\\text{AoC Step}) \\le 0$ and $\\text{Aggregated }TM(\\text{AoC Step}) + TM(\\text{AoC Step}) \\le 0 $, then:", - "\n", - "\n$$", - "\n\\begin{array}{rl}", - "\n\\Delta CSM(\\text{AoC step}) &= -TM(\\text{AoC Step})", - "\n\\\\", - "\n\\Delta LC(\\text{AoC step}) &= 0", - "\n\\end{array}", - "\n$$", - "\n", - "\nAnd finally, if there is no switch from $LC$, i.e. $\\text{Aggregated }TM(\\text{AoC Step}) > 0$ and $\\text{Aggregated }TM(\\text{AoC Step}) + TM(\\text{AoC Step}) \\ge 0 $, then:", - "\n", - "\n$$", - "\n\\begin{array}{rl}", - "\n\\Delta CSM(\\text{AoC step}) &= 0", - "\n\\\\", - "\n\\Delta LC(\\text{AoC step}) &= TM(\\text{AoC Step})", - "\n\\end{array}", - "\n$$", - "\n", - "\n**C)** For the AoC step Combined Liability **CL**, the switch logic is similar to the one above, except that a switch from $LC$ to $CSM$ can happen **because of New Business and despite of In-Force**, in which case we have:", - "\n", - "\n$$", - "\n\\begin{array}{rl}", - "\n\\Delta CSM(\\text{AoC step}) &= -TM(\\text{AoC Step}) -\\big(\\text{Aggregated } TM(\\text{Last In-Force AoC step})+TM(\\text{Last In-Force AoC step}) \\big)", - "\n\\\\", - "\n\\Delta LC(\\text{AoC step}) &= -\\big(\\text{Aggregated } TM(\\text{Last In-Force AoC step}) + TM(\\text{Last In-Force AoC step}) \\big)", - "\n\\end{array}", - "\n$$", - "\n", - "\nIf, on the other hand, the switch from $LC$ to $CSM$ happens **because of In-Force and despite of New Business**, then we have:", - "\n", - "\n$$", - "\n\\begin{array}{rl}", - "\n\\Delta CSM(\\text{AoC step}) &= -TM(\\text{AoC Step}) -\\big(\\text{Aggregated } TM(\\text{Last NB AoC step})+TM(\\text{Last NB AoC step}) \\big)", - "\n\\\\", - "\n\\Delta LC(\\text{AoC step}) &= -\\big(\\text{Aggregated } TM(\\text{Last NB AoC step}) + TM(\\text{Last NB AoC step}) \\big)", - "\n\\end{array}", - "\n$$", - "\n", - "\nFor the switch in the other direction, i.e. from $CSM$ to $LC$ the formulas are similar except that LC and CSM are swapped.", - "\n", - "\n**D)** Finally, for the last AoC step, the **EOP**, we have:", - "\n", - "\n$$", - "\n\\begin{array}{rl}", - "\nCSM(\\text{EOP}) &= \\sum_{s~\\in~\\text{previous AoC steps}}\\Delta CSM(s)", - "\n\\\\", - "\nLC(\\text{EOP}) &= \\sum_{s~\\in~\\text{previous AoC steps}}\\Delta LC(s)", - "\n\\end{array}", - "\n$$", - "\n", - "\n", - "\n### Reinsurance case", - "\n", - "\nFor the reinsurance case, the switch logic is identical to the one described above, except that it uses the gross Technical Margins multiplied by the weights coming from the Reinsurance Coverage (RC) Parameter (see [Data Node Parameters](../DataModel/DataStructure#data-node-parameters)). In case a GRIC ($r$) has multiple GICs ($g$), then these weighted $TM$s are aggregated.", - "\n", - "\n$$", - "\n\\text{Weighted TM}(\\text{r}) = \\sum_{g~\\in~\\text{underlying GICs}} \\text{RC}_{g,r} \\text{TM}(g)", - "\n$$", - "\n", - "\nA Loss Recovery Component (LoReCo) for GRIC $r$ is going to be opened in case the $\\text{Weighted TM}(r)$ would be allocated to Loss Component following the above mentioned switch logic. The amount allocated to the Reinsurance CSM or LoReCo follows the computed Technical Margin computed for GRIC r as described in [Technical Margin](#technical-margin)." - ], - "metadata": {}, - "execution_count": 0, - "outputs": [] - }, - { - "cell_type": "code", - "source": [ - "public interface AllocateTechnicalMargin: IScope", - "\n{", - "\n //Switch", - "\n static ApplicabilityBuilder ScopeApplicabilityBuilder(ApplicabilityBuilder builder) => ", - "\n builder.ForScope(s => s", - "\n .WithApplicability(x => x.Identity.IsReinsurance && x.Identity.AocType == AocTypes.CL)", - "\n .WithApplicability(x => x.Identity.IsReinsurance, ", - "\n p => p.ForMember(s => s.ComputedEstimateType)", - "\n .ForMember(s => s.HasSwitch))", - "\n .WithApplicability(x => x.GetStorage().IsSecondaryScope(x.Identity.DataNode)) ", - "\n .WithApplicability(x => x.Identity.AocType == AocTypes.BOP)", - "\n .WithApplicability(x => x.Identity.AocType == AocTypes.CL)", - "\n .WithApplicability(x => x.Identity.AocType == AocTypes.EOP)", - "\n );", - "\n ", - "\n [NotVisible] double AggregatedTechnicalMargin => GetScope(Identity).AggregatedValue; ", - "\n [NotVisible] double TechnicalMargin => GetScope(Identity).Value;", - "\n [NotVisible] string ComputedEstimateType => ComputeEstimateType(GetScope(Identity).AggregatedValue + TechnicalMargin);", - "\n [NotVisible] bool HasSwitch => ComputedEstimateType != ComputeEstimateType(GetScope(Identity).AggregatedValue);", - "\n ", - "\n //Allocate", - "\n [NotVisible] string EstimateType => GetContext();", - "\n ", - "\n double Value => (HasSwitch, EstimateType == ComputedEstimateType) switch {", - "\n (true, true) => TechnicalMargin + AggregatedTechnicalMargin,", - "\n (true, false) => -1d * AggregatedTechnicalMargin,", - "\n (false, true) => TechnicalMargin,", - "\n _ => default", - "\n };", - "\n ", - "\n string ComputeEstimateType(double aggregatedTechnicalMargin) => aggregatedTechnicalMargin > Precision ? EstimateTypes.L : EstimateTypes.C;", - "\n}", - "\n", - "\npublic interface ComputeAllocateTechnicalMarginWithIfrsVariable : AllocateTechnicalMargin", - "\n{ ", - "\n double AllocateTechnicalMargin.TechnicalMargin => ComputeTechnicalMarginFromIfrsVariables(Identity);", - "\n double AllocateTechnicalMargin.AggregatedTechnicalMargin => GetScope((Identity, InputSource.Cashflow)).Values", - "\n .Sum(aoc => ComputeTechnicalMarginFromIfrsVariables(Identity with {AocType = aoc.AocType, Novelty = aoc.Novelty}));", - "\n ", - "\n private double ComputeTechnicalMarginFromIfrsVariables(ImportIdentity id)", - "\n {", - "\n return GetStorage().GetValue(Identity, null, EstimateTypes.LR, null) +", - "\n GetStorage().GetValue(Identity, null, EstimateTypes.L, null) - ", - "\n GetStorage().GetValue(Identity, null, EstimateTypes.C, null);", - "\n }", - "\n}", - "\n", - "\npublic interface AllocateTechnicalMarginForReinsurance : AllocateTechnicalMargin", - "\n{ ", - "\n //TODO add Reinsurance Coverage Update (RCU, Novelty=I) AocStep", - "\n private IEnumerable underlyingGic => GetStorage().GetUnderlyingGic(Identity);", - "\n ", - "\n private double weightedUnderlyingTM => underlyingGic.Sum(gic => GetStorage().GetReinsuranceCoverage(Identity, gic) * ", - "\n GetScope(Identity with {DataNode = gic}).Value);", - "\n ", - "\n private double weightedUnderlyingAggregatedTM => underlyingGic.Sum(gic => GetStorage().GetReinsuranceCoverage(Identity, gic) * ", - "\n GetScope(Identity with {DataNode = gic}).AggregatedValue);", - "\n ", - "\n private string ComputeReinsuranceEstimateType(double aggregatedFcf) => aggregatedFcf > Precision ? EstimateTypes.LR : EstimateTypes.C;", - "\n ", - "\n [NotVisible] string AllocateTechnicalMargin.ComputedEstimateType => ComputeReinsuranceEstimateType(weightedUnderlyingAggregatedTM + weightedUnderlyingTM);", - "\n [NotVisible] bool AllocateTechnicalMargin.HasSwitch => ComputedEstimateType != ComputeReinsuranceEstimateType(weightedUnderlyingAggregatedTM); ", - "\n}", - "\n", - "\npublic interface AllocateTechnicalMarginForReinsuranceCL : AllocateTechnicalMargin", - "\n{ ", - "\n //In common1", - "\n private IEnumerable underlyingGic => GetStorage().GetUnderlyingGic(Identity);", - "\n ", - "\n private double weightedUnderlyingTM => underlyingGic.Sum(gic => GetStorage().GetReinsuranceCoverage(Identity, gic) * ", - "\n GetScope(Identity with {DataNode = gic}).Value);", - "\n ", - "\n private double weightedUnderlyingAggregatedTM => underlyingGic.Sum(gic => GetStorage().GetReinsuranceCoverage(Identity, gic) * ", - "\n GetScope(Identity with {DataNode = gic}).AggregatedValue);", - "\n private string ComputeReinsuranceEstimateType(double aggregatedFcf) => aggregatedFcf > Precision ? EstimateTypes.LR : EstimateTypes.C;", - "\n ", - "\n string AllocateTechnicalMargin.ComputedEstimateType => ComputeReinsuranceEstimateType(weightedUnderlyingAggregatedTM + weightedUnderlyingTM);", - "\n //In common2", - "\n private double balancingValue => GetScope((Identity, InputSource.Cashflow))", - "\n .Values", - "\n .GroupBy(x => x.Novelty)", - "\n .Select(g => g.Last())", - "\n .Sum(aoc => { ", - "\n var id = Identity with {AocType = aoc.AocType, Novelty = aoc.Novelty};", - "\n return GetScope(id).ComputedEstimateType != ComputedEstimateType ? ", - "\n GetScope(id).TechnicalMargin + GetScope(id).AggregatedTechnicalMargin", - "\n : (double)default; });", - "\n ", - "\n [NotVisible] bool AllocateTechnicalMargin.HasSwitch => Math.Abs(balancingValue) > Precision;", - "\n [NotVisible] double AllocateTechnicalMargin.AggregatedTechnicalMargin => balancingValue; ", - "\n}", - "\n", - "\npublic interface AllocateTechnicalMarginForCl : AllocateTechnicalMargin", - "\n{", - "\n private double balancingValue => GetScope((Identity, InputSource.Cashflow))", - "\n .Values", - "\n .GroupBy(x => x.Novelty)", - "\n .Select(g => g.Last())", - "\n .Sum(aoc => { ", - "\n var id = Identity with {AocType = aoc.AocType, Novelty = aoc.Novelty};", - "\n return GetScope(id).ComputedEstimateType != ComputedEstimateType ? ", - "\n GetScope(id).TechnicalMargin + GetScope(id).AggregatedTechnicalMargin", - "\n : (double)default; });", - "\n", - "\n [NotVisible] bool AllocateTechnicalMargin.HasSwitch => Math.Abs(balancingValue) > Precision;", - "\n [NotVisible] double AllocateTechnicalMargin.AggregatedTechnicalMargin => balancingValue;", - "\n}", - "\n", - "\npublic interface AllocateTechnicalMarginForBop : AllocateTechnicalMargin", - "\n{ ", - "\n bool AllocateTechnicalMargin.HasSwitch => false;", - "\n}", - "\n", - "\npublic interface AllocateTechnicalMarginForEop : AllocateTechnicalMargin", - "\n{", - "\n double AllocateTechnicalMargin.Value => GetScope((Identity, InputSource.Cashflow)).Values", - "\n .Sum(aoc => GetScope(Identity with {AocType = aoc.AocType, Novelty = aoc.Novelty}).Value);", - "\n [NotVisible] string AllocateTechnicalMargin.ComputedEstimateType => ComputeEstimateType(AggregatedTechnicalMargin);", - "\n}" - ], - "metadata": {}, - "execution_count": 0, - "outputs": [] - }, - { - "cell_type": "markdown", - "source": [ - "For the **Group of Reinsurance Contracts** (GRICs), the switch is computed within the underlying GIC context and $CSM$ and $LR$ are then computed in the same manner as for the underlying GICs CSM and LC." - ], - "metadata": {}, - "execution_count": 0, - "outputs": [] - }, - { - "cell_type": "markdown", - "source": [ - "The scopes below are simply used to set the appropriate Estimate Type (C for $CSM$, L for $LC$ and LR for $LoReCo$), as well as to set $CSM$ values to be positive:" - ], - "metadata": {}, - "execution_count": 0, - "outputs": [] - }, - { - "cell_type": "code", - "source": [ - "public interface ContractualServiceMargin : IScope", - "\n{", - "\n [NotVisible]string EstimateType => EstimateTypes.C;", - "\n ", - "\n double Value => -1d * GetScope(Identity, o => o.WithContext(EstimateType)).Value;", - "\n}" - ], - "metadata": {}, - "execution_count": 0, - "outputs": [] - }, - { - "cell_type": "code", - "source": [ - "public interface LossComponent : IScope", - "\n{", - "\n [NotVisible]string EstimateType => EstimateTypes.L;", - "\n ", - "\n double Value => GetScope(Identity, o => o.WithContext(EstimateType)).Value;", - "\n}" - ], - "metadata": {}, - "execution_count": 0, - "outputs": [] - }, - { - "cell_type": "code", - "source": [ - "public interface LossRecoveryComponent : IScope", - "\n{ ", - "\n [NotVisible]string EstimateType => EstimateTypes.LR;", - "\n ", - "\n double Value => GetScope(Identity, o => o.WithContext(EstimateType)).Value;", - "\n}" - ], - "metadata": {}, - "execution_count": 0, - "outputs": [] - }, - { - "cell_type": "markdown", - "source": [ - "## Computing All Scopes", - "\n", - "\nSince all the calculations defined in the various scopes are to be performed together, it is useful to introduce the scopes: ComputeIfrsVarsActuals, ComputeIfrsVarsCashflows and the ComputeIfrsVarsOpenings below, which given a certain Import Format and Import Storage, performs all the calculations (defined above) based on the corresponding data:" - ], - "metadata": {}, - "execution_count": 0, - "outputs": [] - }, - { - "cell_type": "code", - "source": [ - "public interface PvToIfrsVariable: IScope", - "\n{", - "\n IEnumerable PvLocked => GetScope(Identity).PresentValues.Select(x => ", - "\n new IfrsVariable{ EconomicBasis = x.EconomicBasis, ", - "\n EstimateType = x.Identity.EstimateType, ", - "\n DataNode = x.Identity.Id.DataNode, ", - "\n AocType = x.Identity.Id.AocType, ", - "\n Novelty = x.Identity.Id.Novelty, ", - "\n AccidentYear = x.Identity.AccidentYear,", - "\n AmountType = x.Identity.AmountType,", - "\n Value = x.Value,", - "\n Partition = GetStorage().TargetPartition });", - "\n", - "\n IEnumerable PvCurrent => GetScope(Identity).PresentValues.Select(x => ", - "\n new IfrsVariable{ EconomicBasis = x.EconomicBasis, ", - "\n EstimateType = x.Identity.EstimateType, ", - "\n DataNode = x.Identity.Id.DataNode, ", - "\n AocType = x.Identity.Id.AocType, ", - "\n Novelty = x.Identity.Id.Novelty, ", - "\n AccidentYear = x.Identity.AccidentYear,", - "\n AmountType = x.Identity.AmountType,", - "\n Value = x.Value,", - "\n Partition = GetStorage().TargetPartition });", - "\n}" - ], - "metadata": {}, - "execution_count": 0, - "outputs": [] - }, - { - "cell_type": "code", - "source": [ - "public interface RaToIfrsVariable: IScope", - "\n{", - "\n IEnumerable RaCurrent => GetScope(Identity).PresentValues.Select(x => ", - "\n new IfrsVariable{ EconomicBasis = x.EconomicBasis, ", - "\n EstimateType = x.Identity.EstimateType, ", - "\n DataNode = x.Identity.Id.DataNode, ", - "\n AocType = x.Identity.Id.AocType, ", - "\n Novelty = x.Identity.Id.Novelty, ", - "\n AccidentYear = x.Identity.AccidentYear,", - "\n AmountType = null,", - "\n Value = x.Value,", - "\n Partition = GetStorage().TargetPartition });", - "\n ", - "\n IEnumerable RaLocked => GetScope(Identity).PresentValues.Select(x => ", - "\n new IfrsVariable{ EconomicBasis = x.EconomicBasis, ", - "\n EstimateType = x.Identity.EstimateType, ", - "\n DataNode = x.Identity.Id.DataNode, ", - "\n AocType = x.Identity.Id.AocType, ", - "\n Novelty = x.Identity.Id.Novelty, ", - "\n AccidentYear = x.Identity.AccidentYear,", - "\n AmountType = null,", - "\n Value = x.Value,", - "\n Partition = GetStorage().TargetPartition });", - "\n}" - ], - "metadata": {}, - "execution_count": 0, - "outputs": [] - }, - { - "cell_type": "code", - "source": [ - "public interface ActualToIfrsVariable: IScope", - "\n{", - "\n IEnumerable Actual => GetScope(Identity).Actuals.Select(x => ", - "\n new IfrsVariable{ EstimateType = x.Identity.EstimateType,", - "\n DataNode = x.Identity.Id.DataNode,", - "\n AocType = x.Identity.Id.AocType,", - "\n Novelty = x.Identity.Id.Novelty,", - "\n AccidentYear = x.Identity.AccidentYear,", - "\n AmountType = x.Identity.AmountType,", - "\n Value = x.Value,", - "\n Partition = GetStorage().TargetPartition });", - "\n ", - "\n IEnumerable AdvanceActual => GetScope(Identity).Actuals.Select(x => ", - "\n new IfrsVariable{ EstimateType = x.Identity.EstimateType,", - "\n DataNode = x.Identity.Id.DataNode,", - "\n AocType = x.Identity.Id.AocType,", - "\n Novelty = x.Identity.Id.Novelty,", - "\n AccidentYear = x.Identity.AccidentYear,", - "\n AmountType = x.Identity.AmountType,", - "\n Value = x.Value,", - "\n Partition = GetStorage().TargetPartition });", - "\n", - "\n IEnumerable OverdueActual => GetScope(Identity).Actuals.Select(x => ", - "\n new IfrsVariable{ EstimateType = x.Identity.EstimateType,", - "\n DataNode = x.Identity.Id.DataNode,", - "\n AocType = x.Identity.Id.AocType,", - "\n Novelty = x.Identity.Id.Novelty,", - "\n AccidentYear = x.Identity.AccidentYear,", - "\n AmountType = x.Identity.AmountType,", - "\n Value = x.Value,", - "\n Partition = GetStorage().TargetPartition });", - "\n}" - ], - "metadata": {}, - "execution_count": 0, - "outputs": [] - }, - { - "cell_type": "code", - "source": [ - "public interface DeferrableToIfrsVariable: IScope", - "\n{", - "\n IEnumerable DeferrableActual => GetScope(Identity).RepeatOnce().Select(x => ", - "\n new IfrsVariable{ EstimateType = x.EstimateType,", - "\n DataNode = x.Identity.DataNode,", - "\n AocType = x.Identity.AocType,", - "\n Novelty = x.Identity.Novelty,", - "\n AccidentYear = null,", - "\n Value = x.Value,", - "\n Partition = GetStorage().TargetPartition });", - "\n}" - ], - "metadata": {}, - "execution_count": 0, - "outputs": [] - }, - { - "cell_type": "code", - "source": [ - "public interface EaForPremiumToIfrsVariable: IScope", - "\n{", - "\n IEnumerable BeEAForPremium => GetStorage().DataNodeDataBySystemName[Identity.DataNode].LiabilityType == LiabilityTypes.LIC", - "\n || Identity.IsReinsurance", - "\n ? Enumerable.Empty()", - "\n : GetScope(Identity)", - "\n .ByAmountType", - "\n .Select(sc => new IfrsVariable{ EstimateType = GetScope(Identity).EstimateType, ", - "\n DataNode = sc.Identity.Id.DataNode, ", - "\n AocType = sc.Identity.Id.AocType, ", - "\n Novelty = sc.Identity.Id.Novelty, ", - "\n AccidentYear = sc.Identity.AccidentYear,", - "\n EconomicBasis = sc.EconomicBasis,", - "\n AmountType = sc.Identity.AmountType,", - "\n Value = sc.Value,", - "\n Partition = sc.GetStorage().TargetPartition });", - "\n ", - "\n IEnumerable ActEAForPremium => GetStorage().DataNodeDataBySystemName[Identity.DataNode].LiabilityType == LiabilityTypes.LIC", - "\n || Identity.IsReinsurance", - "\n ? Enumerable.Empty()", - "\n : GetScope(Identity)", - "\n .ByAmountTypeAndEstimateType", - "\n .Select(sc => new IfrsVariable{ EstimateType = GetStorage().ExperienceAdjustEstimateTypeMapping[sc.Identity.EstimateType], ", - "\n DataNode = sc.Identity.Id.DataNode, ", - "\n AocType = sc.Identity.Id.AocType, ", - "\n Novelty = sc.Identity.Id.Novelty, ", - "\n AccidentYear = sc.Identity.AccidentYear,", - "\n //EconomicBasis = scope.EconomicBasis,", - "\n AmountType = sc.Identity.AmountType,", - "\n Value = sc.Value,", - "\n Partition = GetStorage().TargetPartition });", - "\n}" - ], - "metadata": {}, - "execution_count": 0, - "outputs": [] - }, - { - "cell_type": "code", - "source": [ - "public interface TmToIfrsVariable: IScope", - "\n{", - "\n private string EconomicBasis => Identity.ValuationApproach == ValuationApproaches.VFA ? EconomicBases.C : EconomicBases.L;", - "\n IEnumerable AmortizationFactor => Identity.AocType == AocTypes.AM", - "\n ? GetScope(Identity, o => o.WithContext(EconomicBasis))", - "\n .RepeatOnce()", - "\n .Select(x => new IfrsVariable{ EstimateType = x.EstimateType,", - "\n DataNode = x.Identity.DataNode,", - "\n AocType = x.Identity.AocType,", - "\n Novelty = x.Identity.Novelty,", - "\n EconomicBasis = x.EconomicBasis,", - "\n Value = x.Value,", - "\n Partition = GetStorage().TargetPartition", - "\n })", - "\n : Enumerable.Empty();", - "\n IEnumerable Csms => GetStorage().DataNodeDataBySystemName[Identity.DataNode].LiabilityType == LiabilityTypes.LIC", - "\n ? Enumerable.Empty()", - "\n : GetScope(Identity).RepeatOnce()", - "\n .Select(x => new IfrsVariable{ EstimateType = x.EstimateType,", - "\n DataNode = x.Identity.DataNode,", - "\n AocType = x.Identity.AocType,", - "\n Novelty = x.Identity.Novelty,", - "\n Value = x.Value,", - "\n Partition = GetStorage().TargetPartition", - "\n });", - "\n", - "\n IEnumerable Loss => GetStorage().DataNodeDataBySystemName[Identity.DataNode].LiabilityType == LiabilityTypes.LIC", - "\n ? Enumerable.Empty()", - "\n : Identity.IsReinsurance ", - "\n ? GetScope(Identity).RepeatOnce()", - "\n .Select(x => new IfrsVariable{ EstimateType = x.EstimateType,", - "\n DataNode = x.Identity.DataNode,", - "\n AocType = x.Identity.AocType,", - "\n Novelty = x.Identity.Novelty,", - "\n Value = x.Value,", - "\n Partition = GetStorage().TargetPartition", - "\n })", - "\n : GetScope(Identity).RepeatOnce()", - "\n .Select(x => new IfrsVariable{ EstimateType = x.EstimateType,", - "\n DataNode = x.Identity.DataNode,", - "\n AocType = x.Identity.AocType,", - "\n Novelty = x.Identity.Novelty,", - "\n Value = x.Value,", - "\n Partition = GetStorage().TargetPartition", - "\n });", - "\n}" - ], - "metadata": {}, - "execution_count": 0, - "outputs": [] - }, - { - "cell_type": "code", - "source": [ - "public interface ComputeIfrsVarsActuals : ActualToIfrsVariable, DeferrableToIfrsVariable, EaForPremiumToIfrsVariable, TmToIfrsVariable", - "\n{", - "\n IEnumerable CalculatedIfrsVariables => Actual.Concat(AdvanceActual)", - "\n .Concat(OverdueActual)", - "\n .Concat(ActEAForPremium)", - "\n .Concat(DeferrableActual)", - "\n .Concat(Csms)", - "\n .Concat(Loss);", - "\n}" - ], - "metadata": {}, - "execution_count": 0, - "outputs": [] - }, - { - "cell_type": "code", - "source": [ - "public interface ComputeIfrsVarsCashflows : PvToIfrsVariable, RaToIfrsVariable, DeferrableToIfrsVariable, EaForPremiumToIfrsVariable, TmToIfrsVariable", - "\n{", - "\n IEnumerable CalculatedIfrsVariables => PvLocked.Concat(PvCurrent)", - "\n .Concat(RaCurrent)", - "\n .Concat(RaLocked)", - "\n .Concat(AmortizationFactor)", - "\n .Concat(BeEAForPremium)", - "\n .Concat(DeferrableActual)", - "\n .Concat(Csms)", - "\n .Concat(Loss);", - "\n}" - ], - "metadata": {}, - "execution_count": 0, - "outputs": [] - }, - { - "cell_type": "code", - "source": [ - "public interface ComputeIfrsVarsOpenings : ActualToIfrsVariable, DeferrableToIfrsVariable, TmToIfrsVariable", - "\n{", - "\n IEnumerable CalculatedIfrsVariables => AdvanceActual.Concat(OverdueActual)", - "\n .Concat(DeferrableActual)", - "\n .Concat(Csms)", - "\n .Concat(Loss);", - "\n}" - ], - "metadata": {}, - "execution_count": 0, - "outputs": [] - }, - { - "cell_type": "code", - "source": [ - "public interface ComputeAllScopes: IScope", - "\n{", - "\n IEnumerable CalculatedIfrsVariables => GetStorage().ImportFormat switch {", - "\n ImportFormats.Actual => GetScope(Identity).CalculatedIfrsVariables,", - "\n ImportFormats.Cashflow => GetScope(Identity).CalculatedIfrsVariables,", - "\n ImportFormats.Opening => GetScope(Identity).CalculatedIfrsVariables,", - "\n };", - "\n}" - ], - "metadata": {}, - "execution_count": 0, - "outputs": [] - } - ] -} \ No newline at end of file diff --git a/ifrs17/Import/ImportStorage.ipynb b/ifrs17/Import/ImportStorage.ipynb index 7b3bd562..26630fe1 100644 --- a/ifrs17/Import/ImportStorage.ipynb +++ b/ifrs17/Import/ImportStorage.ipynb @@ -37,7 +37,14 @@ "\n- [EstimateType](../DataModel/DataStructure)", "\n- [DataNodes](../DataModel/DataStructure)", "\n", - "\nSuch storage is then passed to calculations defined in the corresponding [Import Scopes](./ImportScopeCalculation)." + "\nSuch storage is then passed to calculations defined in the corresponding Import Scopes:", + "\n", + "\n- [1ImportScope-Identities](./1ImportScope-Identities)", + "\n- [2ImportScope-PresentValue](./2ImportScope-PresentValue)", + "\n- [3ImportScope-Actuals](./3ImportScope-Actuals)", + "\n- [4ImportScope-TechnicalMargin](./4ImportScope-TechnicalMargin)", + "\n- [5ImportScope-ToIfrsVar](./5ImportScope-ToIfrsVar)", + "\n- [6ImportScope-Compute](./6ImportScope-Compute)" ], "metadata": {}, "execution_count": 0, diff --git a/ifrs17/Import/Importers.ipynb b/ifrs17/Import/Importers.ipynb index 87a517db..d275d21a 100644 --- a/ifrs17/Import/Importers.ipynb +++ b/ifrs17/Import/Importers.ipynb @@ -30,7 +30,7 @@ { "cell_type": "code", "source": [ - "#!import \"ImportScopeCalculation\"" + "#!import \"6ImportScope-Compute\"" ], "metadata": {}, "execution_count": 0, diff --git a/ifrs17/OverviewCalculationEngine.ipynb b/ifrs17/OverviewCalculationEngine.ipynb index 2ba37ea6..27e70a33 100644 --- a/ifrs17/OverviewCalculationEngine.ipynb +++ b/ifrs17/OverviewCalculationEngine.ipynb @@ -34,7 +34,7 @@ "\n", "\nThis notebook provides an **overview** of Systemorph IFRS 17 Calculation Engine with brief introductions to all the main steps.", "\n", - "\nThere are numerous **links** to several notebooks of the Calculation Engine. These notebooks contain specifications, code and also some detailed explanations with formulas in markdown blocks. The most important ones in this respect are [DataStructure](./DataModel/DataStructure#data-structure), [ImportScopes](./Import/ImportScopeCalculation#import-scope-calculation) and [ReportScopes](./Report/ReportScopes#report-scopes)." + "\nThere are numerous **links** to several notebooks of the Calculation Engine. These notebooks contain specifications, code and also some detailed explanations with formulas in markdown blocks. The most important ones in this respect are [DataStructure](./DataModel/DataStructure#data-structure), ImportScopes family starting from [identities](./Import/1ImportScope-Identities) and [ReportScopes](./Report/ReportScopes#report-scopes)." ], "metadata": {}, "execution_count": 0, @@ -85,7 +85,7 @@ "\n", "\nThe IFRS 17 calculations are based on a well-defined [DataModel](./DataModel/DataStructure#data-structure). The data input files are set up according to the data model, and the data import and all the ensuing calculations up to the final report generation respect the data model conventions.", "\n", - "\nThe IFRS 17 calculations occur on the fly, meaning that reports are generated based on the data available to the system at the time the report was requested. For performance reasons, some of these calculations need to be performed at data import time due to the data granularity required (e.g. CSM Amortization). Therefore, the more complex calculations are pre-computed. The more complex IFRS 17 Business Logic is defined in the [ImportScopes](./Import/ImportScopeCalculation#import-scope-calculation) notebook.", + "\nThe IFRS 17 calculations occur on the fly, meaning that reports are generated based on the data available to the system at the time the report was requested. For performance reasons, some of these calculations need to be performed at data import time due to the data granularity required (e.g. CSM Amortization). Therefore, the more complex calculations are pre-computed. The more complex IFRS 17 Business Logic is defined in the ImportScopes family starting from [identities](./Import/1ImportScope-Identities) notebook.", "\n", "\nOther simpler calculations occur at report generation (e.g FX conversion), as they do not require a very high data granularity and therefore do not impact the reports significantly. This IFRS 17 Business Logic is defined in the [ReportScopes](./Report/ReportScopes#report-scopes) notebook. ", "\n", @@ -119,11 +119,11 @@ "", "\n## Data import and related calculations", "\n", - "\nSeveral notebooks organize the data import. Methods for importing and accessing data are in the [Importers](./Import/Importers) notebook. The [ImportStorage](./Import/ImportStorage#import-storage) prepare the data to perfom the calculation required. Finally, methods for the calculations are in [ImportScopeCalculation](./Import/ImportScopeCalculation#import-scope-calculation).", + "\nSeveral notebooks organize the data import. Methods for importing and accessing data are in the [Importers](./Import/Importers) notebook. The [ImportStorage](./Import/ImportStorage#import-storage) prepare the data to perfom the calculation required. Finally, methods for the calculations are in ImportScopes family notebooks starting from [identities](./Import/1ImportScope-Identities).", "\n", - "\nHowever, the import as such is conducted by other notebooks which use the methods of Importers, ImportStorage and ImportScopeCalculation in a chain of notebook imports:", + "\nHowever, the import as such is conducted by other notebooks which use the methods of Importers, ImportStorage and ImportScope family in a chain of notebook imports:", "\n", - "\nImportStorage --> ImportScopeCalculation --> Importers", + "\nImportStorage --> ImportScope Family --> Importers", "\n", "\nThe calculations of ImportScopeCalculation cover a large part of the IFRS 17 methodology and are explained in the section below." ], @@ -137,40 +137,40 @@ "", "\n# IFRS 17 Model Calculations", "\n", - "\nThe notebook **[ImportScopeCalculation](./Import/ImportScopeCalculation#import-scope-calculation)** has all the calculations to be executed upon data import. The methods used are explained there with formulas. The centerpiece is the Analysis of Change (AoC) of the insurance business over one period (here: quarter). The formulas often use acronyms (System Names) as listed in the input file *DimensionsAndPartitions*.", + "\nThe notebook family **ImportScopes** starting with [identites](./Import/1ImportScope-Identities) has all the calculations to be executed upon data import. The methods used are explained there with formulas. The centerpiece is the Analysis of Change (AoC) of the insurance business over one period (here: quarter). The formulas often use acronyms (System Names) as listed in the input file *DimensionsAndPartitions*.", "\n", - "\nThe main concepts and parts of ImportScopeCalculation are listed here, with links.", - "\n- Structure and sequence of the **[Analysis of Change (AoC)](./Import/ImportScopeCalculation#aoc-step-structure)** steps for the given period", + "\nThe main concepts and parts of ImportScope family notebooks are listed here, with links.", + "\n- Structure and sequence of the **[Analysis of Change (AoC)](./Import/1ImportScope-Identities)** steps for the given period", "\n$$", "\n$$", - "\n- **[Discounting](./Import/ImportScopeCalculation#discounting-calculation)** projected cash flows using [yield curves](#data-input-parameters) (current or locked in)", + "\n- **[Discounting](./Import/2ImportScope-PresentValue#discounting-calculation)** projected cash flows using yield curves (current or locked in)", "\n$$", "\n$$", - "\n- **[Nominal](./Import/ImportScopeCalculation#nominal-values)** cash flow amounts per AoC step", + "\n- **[Nominal](./Import/2ImportScope-PresentValue#nominal-values)** cash flow amounts per AoC step", "\n$$", "\n$$", - "\n- **[Present Values (PV)](./Import/ImportScopeCalculation#present-values)** of cash flow amounts for all AoC steps:", - "\n - [Cumulated discounted](./Import/ImportScopeCalculation#cumulated-discounted-cash-flows) cash flow amounts for all AoC steps", - "\n - [Telescoping difference](./Import/ImportScopeCalculation#telescopic-difference) calculation of cumulated discounted cash flows per AoC step, where the total PV change over the period is the telescoping sum of all these differences", - "\n - [Present Value calculation](./Import/ImportScopeCalculation#present-value) at the beginning and end of the period, with its underlying calculations for different AoC types and for [current and locked-in](./Import/ImportScopeCalculation#current-and-locked) yield curves", - "\n - [Interest accretion](./Import/ImportScopeCalculation#interest-accretion) cash flow calculation (one of the AoC steps)", - "\n- **[Risk Adjustment (RA)](./Import/ImportScopeCalculation#risk-adjustment)** calculation, a requirement of the IFRS 17 standard", + "\n- **[Present Values (PV)](./Import/2ImportScope-PresentValue#present-values)** of cash flow amounts for all AoC steps:", + "\n - [Cumulated discounted](./Import/2ImportScope-PresentValue#cumulated-discounted-cash-flows) cash flow amounts for all AoC steps", + "\n - [Telescoping difference](./Import/2ImportScope-PresentValue#telescoping-difference) calculation of cumulated discounted cash flows per AoC step, where the total PV change over the period is the telescoping sum of all these differences", + "\n - [Present Value calculation](./Import/2ImportScope-PresentValue#present-value) at the beginning and end of the period, with its underlying calculations for different AoC types and for [current and locked-in](./Import/2ImportScope-PresentValue#current-and-locked) yield curves", + "\n - [Interest accretion](./Import/2ImportScope-PresentValue#interest-accretion) cash flow calculation (one of the AoC steps)", + "\n- **[Risk Adjustment (RA)](./Import/2ImportScope-PresentValue#risk-adjustment)** calculation, a requirement of the IFRS 17 standard", "\n$$", "\n$$", - "\n- **[Amortization](./Import/ImportScopeCalculation#amortization)**, the AoC step dealing with the reduction of the remaining exposure over the period:", - "\n - [Coverage Unit (CU)](./Import/ImportScopeCalculation#coverage-units), the quantity of services provided by a given GIC, considering one period (reflecting the run-off pattern of the GIC)", - "\n - [Amortization factor](./Import/ImportScopeCalculation#amortization-factor), the relative size of the amortization of a GIC, monthly and for a longer time interval", + "\n- **[Amortization](./Import/2ImportScope-PresentValue#amortization)**, the AoC step dealing with the reduction of the remaining exposure over the period:", + "\n - [Coverage Unit (CU)](./Import/2ImportScope-PresentValue#coverage-units), the quantity of services provided by a given GIC, considering one period (reflecting the run-off pattern of the GIC)", + "\n - [Amortization factor](./Import/2ImportScope-PresentValue#amortization-factor), the relative size of the amortization of a GIC, monthly and for a longer time interval", "\n$$", "\n$$", - "\n- **[Actuals](./Import/ImportScopeCalculation#actual-values)**, treatment of actual values per GIC or GRIC, distinguished according to by their Estimate Type: Ordinary Actuals, Advance Actuals, Overdue Actuals and Deferrable Actuals", - "\n - Calculation of [Actuals Base](./Import/ImportScopeCalculation#actual-base) values for a given GIC and per Estimate Type and Amount Type", - "\n - Different Estimate Types of Actuals and their calculations: Written [Actuals](./Import/ImportScopeCalculation#actuals), [Advance Actuals](./Import/ImportScopeCalculation#advance-actuals) paid before the due date which is inside the AoC period, [Overdue Actuals](./Import/ImportScopeCalculation#overdue-actuals) paid after the AoC period, [Deferrable Actuals](./Import/ImportScopeCalculation#overdue-actuals) whose recognition is deferred (typically used for expenses of different kinds)", + "\n- **[Actuals](./Import/3ImportScope-Actuals)**, treatment of actual values per GIC or GRIC, distinguished according to by their Estimate Type: Ordinary Actuals, Advance Actuals, Overdue Actuals and Deferrable Actuals", + "\n - Calculation of [Actuals Base](./Import/3ImportScope-Actuals#actual-base) values for a given GIC and per Estimate Type and Amount Type", + "\n - Different Estimate Types of Actuals and their calculations: Written [Actuals](./Import/3ImportScope-Actuals#actuals), [Advance Actuals](./Import/3ImportScope-Actuals#advance-actuals) paid before the due date which is inside the AoC period, [Overdue Actuals](./Import/3ImportScope-Actuals#overdue-actuals) paid after the AoC period, [Deferrable Actuals](./Import/3ImportScope-Actuals#deferrable-actuals) whose recognition is deferred (typically used for expenses of different kinds)", "\n", "\n$$", "\n$$", - "\n- **[Contractual Service Margin (CSM), Loss Component LC) and Loss Recovery Component (LoReCo)](./Import/ImportScopeCalculation#csm)**, modeling the treatment of unearned profits (CSM) and losses (LC, LRC) as required by the IFRS 17 standard, per GIC or GRIC:", - "\n - [Technical Margin](./Import/ImportScopeCalculation#technical-margin), which is the sum of best estimate and risk adjustment PV with special rules for different AoC steps including the Amortization step, also using and calculating the Interest Accretion Factor, Premiums, Deferrals and Investment Claims", - "\n - [Switch Logic for CSM and LC](./Import/ImportScopeCalculation#technical-margin), switching between CSM and LC for a given AoC step in the AoC period; one of the two is always zero depending on the sign of the Technical Margin; distinguishing the [gross case](./Import/ImportScopeCalculation#gross-case) (no reinsurance) from the [reinsurance case](./Import/ImportScopeCalculation#reinsurance-case) which applies reinsurance coverage weights" + "\n- **[Contractual Service Margin (CSM), Loss Component LC) and Loss Recovery Component (LoReCo)](./Import/4ImportScope-TechnicalMargin)**, modeling the treatment of unearned profits (CSM) and losses (LC, LRC) as required by the IFRS 17 standard, per GIC or GRIC:", + "\n - [Technical Margin](./Import/4ImportScope-TechnicalMargin#technical-margin), which is the sum of best estimate and risk adjustment PV with special rules for different AoC steps including the Amortization step, also using and calculating the Interest Accretion Factor, Premiums, Deferrals and Investment Claims", + "\n - [Switch Logic for CSM and LC](./Import/4ImportScope-TechnicalMargin#switch-logic), switching between CSM and LC for a given AoC step in the AoC period; one of the two is always zero depending on the sign of the Technical Margin; distinguishing the [gross case](./Import/4ImportScope-TechnicalMargin#gross-case) (no reinsurance) from the [reinsurance case](./Import/4ImportScope-TechnicalMargin#reinsurance-case) which applies reinsurance coverage weights" ], "metadata": {}, "execution_count": 0, diff --git a/ifrs17/Report/ReportScopes.ipynb b/ifrs17/Report/ReportScopes.ipynb index fd8e37c1..6d4c0434 100644 --- a/ifrs17/Report/ReportScopes.ipynb +++ b/ifrs17/Report/ReportScopes.ipynb @@ -258,7 +258,7 @@ "", "\n### Best Estimate", "\n", - "\nBest Estimate of Present Value (PV) report includes contributions from the [Present Value](../Import/ImportScopeCalculation#present-values) calculation. The result of the Locked-in calculation is used when the Valuation Approach is BBA and the flag for Oci is active." + "\nBest Estimate of Present Value (PV) report includes contributions from the [Present Value](../Import/2ImportScope-PresentValue#present-values) calculation. The result of the Locked-in calculation is used when the Valuation Approach is BBA and the flag for Oci is active." ], "metadata": {}, "execution_count": 0, @@ -293,7 +293,7 @@ "", "\n### Risk Adjustment", "\n", - "\nRisk Adjustment (RA) report includes contributions from the [Risk Adjustment](../Import/ImportScopeCalculation#risk-adjustment) calculation. The result of the Locked-in calculation is used when the Valuation Approach is BBA and the flag for Oci is active." + "\nRisk Adjustment (RA) report includes contributions from the [Risk Adjustment](../Import/2ImportScope-PresentValue#risk-adjustment) calculation. The result of the Locked-in calculation is used when the Valuation Approach is BBA and the flag for Oci is active." ], "metadata": {}, "execution_count": 0, @@ -367,7 +367,7 @@ "", "\n## LRC Technical Margin: CSM, LC, LoReCo", "\n", - "\nThe LRC [Technical Margin](../Import/ImportScopeCalculation#technical-margin) is allocated to either Contractual Service Margin (CSM) or Loss Component (LC) or Loss Recovery Component (LoReCo). Therefore, the correponding report is available only for Liability for Remaining Coverage (LRC) and includes contributions from the calculation of [CSM](../Import/ImportScopeCalculation#csm), [LC](../Import/ImportScopeCalculation#csm), and [LoReCo](../Import/ImportScopeCalculation#csm)." + "\nThe LRC [Technical Margin](../Import/4ImportScope-TechnicalMargin#technical-margin) is allocated to either Contractual Service Margin (CSM) or Loss Component (LC) or Loss Recovery Component (LoReCo). Therefore, the correponding report is available only for Liability for Remaining Coverage (LRC) and includes contributions from the calculation of [CSM](../Import/4ImportScope-TechnicalMargin#contractual-service-margin), [LC](../Import/4ImportScope-TechnicalMargin#loss-component), and [LoReCo](../Import/4ImportScope-TechnicalMargin#loss-recovery-component)." ], "metadata": {}, "execution_count": 0, @@ -427,9 +427,9 @@ "", "\n## Written, Accruals and Deferrals ", "\n", - "\nWritten Actual (Actual) report includes contributions from the [Actual](../Import/ImportScopeCalculation#actuals) import. ", - "\n
Accrual Actuals (Advance, Overdue Actual) report includes contributions from the [Advance](../Import/ImportScopeCalculation#advance-actuals) and [Overdue](../Import/ImportScopeCalculation#overdue-actuals) Actual calculation.", - "\n
Deferral (Deferral Actual) report includes contributions from the calculation of [Deferral](../Import/ImportScopeCalculation#deferrable-actuals) Actual." + "\nWritten Actual (Actual) report includes contributions from the [Actual](../Import/3ImportScope-Actuals#actuals) import. ", + "\n
Accrual Actuals (Advance, Overdue Actual) report includes contributions from the [Advance](../Import/3ImportScope-Actuals#advance-actuals) and [Overdue](../Import/3ImportScope-Actuals#overdue-actuals) Actual calculation.", + "\n
Deferral (Deferral Actual) report includes contributions from the calculation of [Deferral](../Import/3ImportScope-Actuals#deferrable-actuals) Actual." ], "metadata": {}, "execution_count": 0,