diff --git a/ifrs17-template/Images/CsmLc.png b/ifrs17-template/Images/CsmLc.png new file mode 100644 index 00000000..90eea1e7 Binary files /dev/null and b/ifrs17-template/Images/CsmLc.png differ diff --git a/ifrs17-template/Images/Switch.png b/ifrs17-template/Images/Switch.png new file mode 100644 index 00000000..83ebb2bd Binary files /dev/null and b/ifrs17-template/Images/Switch.png differ diff --git a/ifrs17-template/PracticalUseCases/SingleVsMultipleCsmSwitch/CsmSwitchReports.ipynb b/ifrs17-template/PracticalUseCases/SingleVsMultipleCsmSwitch/CsmSwitchReports.ipynb index d570764a..2805affe 100644 --- a/ifrs17-template/PracticalUseCases/SingleVsMultipleCsmSwitch/CsmSwitchReports.ipynb +++ b/ifrs17-template/PracticalUseCases/SingleVsMultipleCsmSwitch/CsmSwitchReports.ipynb @@ -31,16 +31,47 @@ { "cell_type": "markdown", "source": [ - "In this case study we look at the allocation of the Technical Margin into Contractual Service Margin (CSM) or Loss Component (LC) and its impact on the Financial Performance and Balance Sheet. ", + "# Theory ", + "\nA fundamental concept introduced by IFRS 17 is the Contractual Service Margin (CSM). The CSM represents the unearned profit that an entity expects to earn as it provides services. It is defined at the minimum granularity being the Group of Insurance Contract (Unit Of Account) and it is relevant for all Liability of Remaining Coverage (LRC) approaches with the exception of the Premium Allocation Approach.", + "\n", + "\nThe main principles to understand the Contractual Sevice Margin and Loss Component in IFRS 17 are: ", + "\n", + "\n**Principle 1**: When an insurer writes profitable business, it must not be allowed to recognise the expected profits immediately and instead *must spread those profits over time*.", + "\n", + "\n**Principle 2**: When an insurer writes loss-making business, it must not be allowed to spread the expected losses for that business over time and instead *must recognise those losses immediately*.", + "\n

", + "\n", + "\n
", + "\n


", + "\n", + "\n**Principle 3**: The CSM must be adjusted for all changes (AoC Step) that relate to future service e.g. favourable mortality updates must increase the CSM; unfavourable lapse experience must decrease the CSM.", + "\n", + "\n**Principle 4**: When an insurer recognises that written business, that was previously expected to be profitable, is now expected to be loss-making, e.g. because of changes relating to future service, it must not be allowed to spread the expected losses for that business over time and instead must recognise those losses immediately. It will do so by first extinguishing the CSM and then establishing a Loss Component (LC) in respect of the remaining excess. This represents a switch of the CSM to LC. ", + "\n

", + "\n", + "\n
" + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "# Case Study", + "\nIn this case study we look at the allocation of the Technical Margin into Contractual Service Margin or Loss Component and its impact on the Financial Performance and Balance Sheet. ", "\n
In particular, we are going to consider two possible approaches for the **switch logic**, which determines how the Technical Margin turns from CSM to LC and vice versa throughout the Analysis of Change (AoC). ", "\n", "\nFor this exercise, we consider two hypothetical GICs with identical inputs: the same parameters, modelled cash flows, actuals, etc... We will then analyze the results obtained by applying two different implementations of the **switch logic** and its implications to financial figures.", "\n", "\nWe have defined the following GICs:", "\n - **MZ 1.1 Multiple Switches**: in this case the allocation of the Technical Margin to either CSM or LC can happen multiple times between the Beginning of Period (BoP) and End of Period (EoP). This means whenever the cumulative Technical Margin changes its sign due to the corresponding AoC contributions, a switch from CSM to LC (and vice versa) is observed.", + "\n ", "\n - **MZ 1.2 Single Switch**: in this case the allocation of the Technical Margin to either CSM or LC can happen only once between the Beginning of Period (BoP) and End of Period (EoP). This means only if there is an effective switch (i.e. the cumulative Technical Margin at the Beginning of Period (BoP) and at the End of Period (EoP) have different signs), a single switch is observed. Otherwise there is no switch.", "\n", - "\nWe will look at the relevant reports for the first quarter of year 2021 (2021 3)." + "\nWe will look at the relevant reports for the first quarter of year 2021 (2021 3).", + "\n", + "\nIt is worth to mention that in our starndard implementation, we consider *In Force* and *New business* contributions seperately as most analysts consider the new business part of the CSM an important Key Performance Indicator (KPI)." ], "metadata": {}, "execution_count": 0, diff --git a/ifrs17-template/Test/PracticalCasesTest.ipynb b/ifrs17-template/Test/PracticalCasesTest.ipynb new file mode 100644 index 00000000..52e24619 --- /dev/null +++ b/ifrs17-template/Test/PracticalCasesTest.ipynb @@ -0,0 +1,277 @@ +{ + "metadata": { + "authors": [], + "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": [ + "

Test Practical Cases

" + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "# Csm Switch : Single vs Multiple" + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "#!import \"../PracticalUseCases/SingleVsMultipleCsmSwitch/CsmSwitchReports\"" + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "using FluentAssertions;" + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "## Fulfillment Cashflows" + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "var fcf = fulfillmentCashflows.GetDataCube().ToDictionaryGrouped(x => x.GroupOfContract, x => x.ToArray());" + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "fcf.Keys.Count.Should().Be(2);", + "\nfcf[fcf.Keys.First()].All(x => Math.Abs(fcf[fcf.Keys.Last()].Single(y => y.VariableType == x.VariableType && y.Novelty == x.Novelty && ", + "\n y.EstimateType == x.EstimateType && y.EconomicBasis == x.EconomicBasis &&", + "\n y.AmountType == x.AmountType).Value - x.Value) < 10E-4)", + "\n .Should().BeTrue();" + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "## Actuals" + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "var actuals = writtenActual.GetDataCube().ToDictionaryGrouped(x => x.GroupOfContract, x => x.ToArray());" + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "actuals.Keys.Count.Should().Be(2);", + "\nactuals[actuals.Keys.First()].All(x => Math.Abs(actuals[actuals.Keys.Last()].Single(y => y.VariableType == x.VariableType && y.Novelty == x.Novelty && ", + "\n y.EstimateType == x.EstimateType && y.EconomicBasis == x.EconomicBasis &&", + "\n y.AmountType == x.AmountType).Value - x.Value) < 10E-4)", + "\n .Should().BeTrue();" + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "## Allocated Technical Margin" + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "allocatedTechnicalMargins.GetDataCube().Select(x => x.GroupOfContract).Distinct().Count().Should().Be(2);" + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "var eops = allocatedTechnicalMargins.GetDataCube().Where(x => x.VariableType == \"EOP\");" + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "eops.Where(x => x.EstimateType == \"C\").Count().Should().Be(2);", + "\neops.Where(x => x.EstimateType == \"C\").All(x => Math.Abs(x.Value - 5.71) < 0.01).Should().BeTrue();", + "\neops.Single(x => x.EstimateType == \"L\").Value.Should().BeApproximately(0,Precision);" + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "var lc = allocatedTechnicalMargins.GetDataCube().Where(x => x.EstimateType == \"L\");", + "\nvar lcIa = lc.Single(x => x.VariableType == \"IA\").Value;" + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "lc.All(x => x.Novelty != \"I\" && x.GroupOfContract == \"MZ1.1\").Should().BeTrue();" + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "var lcCombined = lc.Where(x => x.Novelty == \"C\" && x.GroupOfContract == \"MZ1.1\");" + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "lcCombined.Count().Should().Be(2);", + "\nlcCombined.Where(x => x.VariableType == \"CL\").Count().Should().Be(1);", + "\nlcCombined.Where(x => x.VariableType == \"EOP\").Count().Should().Be(1);" + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "## Financial Performance" + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "var mz11 = financialPerformance.GetDataCube().Where(x => x.GroupOfContract == \"MZ1.1\");", + "\nvar mz12 = financialPerformance.GetDataCube().Where(x => x.GroupOfContract == \"MZ1.2\");" + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "mz11.Sum(x => x.Value).Should().BeApproximately(mz12.Sum(x => x.Value), 10E-4);" + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "mz11.Single(x => x.VariableType == \"IR5\" && x.EstimateType ==\"C\").Value", + "\n .Should().BeApproximately(", + "\n mz12.Single(x => x.VariableType == \"IR5\" && x.EstimateType ==\"C\").Value + lcIa,", + "\n Precision", + "\n );" + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "mz11.Single(x => x.VariableType == \"ISE11\").Value.Should().BeApproximately(lcIa,Precision);", + "\nmz12.SingleOrDefault(x => x.VariableType == \"ISE11\")?.Value.Should().BeApproximately(0,Precision);" + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "mz11.Single(x => x.VariableType == \"IFIE1\" && x.EstimateType ==\"C\").Value", + "\n .Should().BeApproximately(", + "\n mz12.Single(x => x.VariableType == \"IFIE1\" && x.EstimateType ==\"C\").Value - lcIa,", + "\n Precision", + "\n );" + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "mz11.Single(x => x.VariableType == \"IFIE1\" && x.EstimateType == \"L\").Value.Should().BeApproximately(-lcIa,Precision);", + "\nmz12.SingleOrDefault(x => x.VariableType == \"IFIE1\" && x.EstimateType == \"L\")?.Value.Should().BeApproximately(0,Precision);" + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "" + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + } + ] +} \ No newline at end of file diff --git a/ifrs17-template/Test/Tests.ipynb b/ifrs17-template/Test/Tests.ipynb index d4442366..c493097e 100644 --- a/ifrs17-template/Test/Tests.ipynb +++ b/ifrs17-template/Test/Tests.ipynb @@ -30,7 +30,7 @@ "cell_type": "markdown", "source": [ "Comprehensive collection of tests executed on top of the Systemorph use cases (initialization).", - "\n
Execute this Notebook using at least 9Gb RAM." + "\n
Execute this Notebook using at least 16Gb RAM." ], "metadata": {}, "execution_count": 0, @@ -135,6 +135,15 @@ "execution_count": 0, "outputs": [] }, + { + "cell_type": "code", + "source": [ + "#!eval-notebook \"PracticalCasesTest\"" + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, { "cell_type": "code", "source": [