From 314439aff8585a17e17b11ec4c05bc961040e0e1 Mon Sep 17 00:00:00 2001 From: Slavomir Batka Date: Mon, 3 Apr 2023 09:58:41 +0200 Subject: [PATCH 1/9] 1st stab --- ifrs17/Constants/Enums.ipynb | 18 ++++++++++ ifrs17/Constants/Validations.ipynb | 3 +- ifrs17/DataModel/DataStructure.ipynb | 10 ++++++ ifrs17/Import/Importers.ipynb | 21 ++++++++--- ifrs17/Utils/ImportCalculationMethods.ipynb | 39 +++++++++++++++++++++ ifrs17/Utils/Queries.ipynb | 2 +- 6 files changed, 87 insertions(+), 6 deletions(-) diff --git a/ifrs17/Constants/Enums.ipynb b/ifrs17/Constants/Enums.ipynb index aa5231be..49c3423f 100644 --- a/ifrs17/Constants/Enums.ipynb +++ b/ifrs17/Constants/Enums.ipynb @@ -206,6 +206,24 @@ "execution_count": 0, "outputs": [] }, + { + "cell_type": "markdown", + "source": [ + "## Interpolation Method" + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "public enum InterpolationMethod { Uniform, Linear, Start, End, Custom }" + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, { "cell_type": "markdown", "source": [ diff --git a/ifrs17/Constants/Validations.ipynb b/ifrs17/Constants/Validations.ipynb index e214b58a..7205c8c0 100644 --- a/ifrs17/Constants/Validations.ipynb +++ b/ifrs17/Constants/Validations.ipynb @@ -76,7 +76,7 @@ "\n // Data Note State", "\n ChangeDataNodeState, InactiveDataNodeState,", "\n // Parameters", - "\n ReinsuranceCoverageDataNode, DuplicateInterDataNode, DuplicateSingleDataNode, InvalidDataNode, InvalidDataNodeForOpening,", + "\n ReinsuranceCoverageDataNode, DuplicateInterDataNode, DuplicateSingleDataNode, InvalidDataNode, InvalidDataNodeForOpening, MissingDataNodeParameter,", "\n // Storage", "\n DataNodeNotFound, PartnerNotFound, RatingNotFound, CreditDefaultRateNotFound, MissingPremiumAllocation, ReinsuranceCoverage, ", "\n YieldCurveNotFound, YieldCurvePeriodNotApplicable, EconomicBasisNotFound, AccountingVariableTypeNotFound,", @@ -151,6 +151,7 @@ "\n (Error.DuplicateSingleDataNode , 1) => $\"Duplicated Single-DataNode parameter for {s[0]} is found.\",", "\n (Error.InvalidDataNode , 1) => $\"Data imported for invalid Data Node {s[0]}.\",", "\n (Error.InvalidDataNodeForOpening , 1) => $\"Data imported for invalid Data Node or for a Data Node after its inception year {s[0]}.\",", + "\n (Error.MissingDataNodeParameter , 1) => $\"Single Data Node Parameter for Data Node {s[0]} is missing.\",", "\n // Storage", "\n (Error.DataNodeNotFound , 1) => $\"DataNode {s[0]} not found.\",", "\n (Error.PartnerNotFound , 1) => $\"Partner not found for DataNode {s[0]}.\",", diff --git a/ifrs17/DataModel/DataStructure.ipynb b/ifrs17/DataModel/DataStructure.ipynb index 78f4144a..9707dd58 100644 --- a/ifrs17/DataModel/DataStructure.ipynb +++ b/ifrs17/DataModel/DataStructure.ipynb @@ -1594,6 +1594,16 @@ "\n [DefaultValue(DefaultPremiumExperienceAdjustmentFactor)]", "\n [Range(0, 1, ErrorMessage = \"Value for {0} must be between {1} and {2}.\")]", "\n public double PremiumAllocation { get; init; } = DefaultPremiumExperienceAdjustmentFactor;", + "\n", + "\n [IdentityProperty]", + "\n [Dimension(typeof(Periodicity))]", + "\n [DefaultValue(Periodicity.Monthly)]", + "\n public Periodicity CashFlowPeriodicity { get; init; } = Periodicity.Monthly;", + "\n ", + "\n [IdentityProperty]", + "\n [Dimension(typeof(InterpolationMethod))]", + "\n [DefaultValue(InterpolationMethod.Uniform)]", + "\n public InterpolationMethod InterpolationMethod { get; init; } = InterpolationMethod.Uniform;", "\n}", "\n", "\npublic record InterDataNodeParameter : DataNodeParameter {", diff --git a/ifrs17/Import/Importers.ipynb b/ifrs17/Import/Importers.ipynb index d275d21a..a72c7d83 100644 --- a/ifrs17/Import/Importers.ipynb +++ b/ifrs17/Import/Importers.ipynb @@ -74,7 +74,8 @@ "\n private Dictionary> amountTypesByEstimateType => GetAmountTypesByEstimateType(HierarchyCache);", "\n public HashSet TechnicalMarginEstimateTypes => GetTechnicalMarginEstimateType(); ", "\n public Dictionary> DimensionsWithExternalId;", - "\n ", + "\n public Dictionary> SingleDataNodeParametersByGoc { get; private set; }", + "\n", "\n // Partitions", "\n public PartitionByReportingNode TargetPartitionByReportingNode;", "\n public PartitionByReportingNodeAndPeriod TargetPartitionByReportingNodeAndPeriod;", @@ -141,6 +142,9 @@ "\n DataNodeDataBySystemName = args.ImportFormat == ImportFormats.Opening ", "\n ? (await LoadDataNodesAsync(dataSource, args)).Where(kvp => kvp.Value.Year == args.Year).ToDictionary(kvp => kvp.Key, kvp => kvp.Value)", "\n : await LoadDataNodesAsync(dataSource, args);", + "\n", + "\n SingleDataNodeParametersByGoc = await dataSource.LoadSingleDataNodeParametersAsync(args);", + "\n", "\n // Dimensions", "\n EstimateType = (await dataSource.Query().ToArrayAsync()).ToDictionary(x => x.SystemName);", "\n AmountType = (await dataSource.Query().Where(x =>!(x is DeferrableAmountType)).ToArrayAsync()).ToDictionary(x => x.SystemName);", @@ -185,7 +189,13 @@ "\n // Getters", "\n public bool IsDataNodeReinsurance(string goc) => DataNodeDataBySystemName[goc].IsReinsurance;", "\n public bool IsValidDataNode(string goc) => DataNodeDataBySystemName.ContainsKey(goc);", - "\n ", + "\n", + "\n public (Periodicity, InterpolationMethod) GetCashFlowPeriodicityAndInterpolationMethod(string goc) {", + "\n if(!SingleDataNodeParametersByGoc.TryGetValue(goc, out var inner))", + "\n ApplicationMessage.Log(Error.MissingDataNodeParameter, goc);", + "\n return (inner[CurrentPeriod].CashFlowPeriodicity, inner[CurrentPeriod].InterpolationMethod); ", + "\n }", + "\n", "\n // Validations", "\n public string ValidateEstimateType(string et, string goc) {", "\n var allowedEstimateTypes = estimateTypes;", @@ -1288,7 +1298,10 @@ "\n values = values.Prune();", "\n if(values.Length == 0 && !parsingStorage.MandatoryAocSteps.Contains(new AocStep(aocType, novelty))) return null;", "\n }", - "\n ", + "\n ", + "\n var cashFlowParameters = parsingStorage.GetCashFlowPeriodicityAndInterpolationMethod(dataNode);", + "\n var valuesInterpolated = Interpolate(cashFlowParameters.Item1, cashFlowParameters.Item2, values);", + "\n", "\n var item = new RawVariable {", "\n DataNode = dataNode,", "\n AocType = aocType,", @@ -1299,7 +1312,7 @@ "\n ? accidentYear", "\n : (int?)null,", "\n Partition = parsingStorage.TargetPartitionByReportingNodeAndPeriod.Id,", - "\n Values = Multiply(GetSign(ImportFormats.Cashflow, (aocType, valueType.AmountType, valueType.EstimateType, dataNodeData.IsReinsurance), parsingStorage.HierarchyCache), values)", + "\n Values = Multiply(GetSign(ImportFormats.Cashflow, (aocType, valueType.AmountType, valueType.EstimateType, dataNodeData.IsReinsurance), parsingStorage.HierarchyCache), valuesInterpolated)", "\n };", "\n return item;", "\n }, ImportFormats.Cashflow", diff --git a/ifrs17/Utils/ImportCalculationMethods.ipynb b/ifrs17/Utils/ImportCalculationMethods.ipynb index c1c3de8a..2d217dd2 100644 --- a/ifrs17/Utils/ImportCalculationMethods.ipynb +++ b/ifrs17/Utils/ImportCalculationMethods.ipynb @@ -206,6 +206,45 @@ "execution_count": 0, "outputs": [] }, + { + "cell_type": "markdown", + "source": [ + "## Interpolate" + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "public static double[] Interpolate(Periodicity periodicity, InterpolationMethod interpolationMethod, double[] cashflowValues)", + "\n{ ", + "\n var frequency = periodicity switch {", + "\n Periodicity.Yearly => 12,", + "\n Periodicity.Quarterly => 4,", + "\n _ => 1", + "\n };", + "\n ", + "\n return interpolationMethod switch {", + "\n InterpolationMethod.Uniform or _ => cashflowValues.SelectMany(v => Enumerable.Range(0, frequency).Select( (y,i) => v / (double)frequency)).ToArray()", + "\n };", + "\n", + "\n}" + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "Interpolate(Periodicity.Yearly, InterpolationMethod.End, new double[] {120,180,2,3,4})" + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, { "cell_type": "markdown", "source": [ diff --git a/ifrs17/Utils/Queries.ipynb b/ifrs17/Utils/Queries.ipynb index 809fe695..e56cd20e 100644 --- a/ifrs17/Utils/Queries.ipynb +++ b/ifrs17/Utils/Queries.ipynb @@ -186,7 +186,7 @@ "\n", "\n{", "\n var lockedInYieldCurveByGoc = new Dictionary();", - "\n foreach (var dn in dataNodes.Where(x => x.ValuationApproach == ValuationApproaches.BBA))", + "\n foreach (var dn in dataNodes.Where(x => x.ValuationApproach != ValuationApproaches.VFA))", "\n {", "\n var monthUpperLimit = args.Year == dn.Year ? args.Month : MonthInAYear;", "\n var argsNew = args with {Year = dn.Year, Month = monthUpperLimit, Scenario = args.Scenario};", From 58a28eb0d1f4c67f608423825cd7bdac3341ee05 Mon Sep 17 00:00:00 2001 From: Slavomir Batka Date: Mon, 3 Apr 2023 15:41:58 +0200 Subject: [PATCH 2/9] add tests --- ...t.ipynb => AggregateInterpolateTest.ipynb} | 54 ++++++++++++++++++- ifrs17/Utils/ImportCalculationMethods.ipynb | 9 ---- 2 files changed, 52 insertions(+), 11 deletions(-) rename ifrs17/Test/{AggregateDoubleArrayTest.ipynb => AggregateInterpolateTest.ipynb} (69%) diff --git a/ifrs17/Test/AggregateDoubleArrayTest.ipynb b/ifrs17/Test/AggregateInterpolateTest.ipynb similarity index 69% rename from ifrs17/Test/AggregateDoubleArrayTest.ipynb rename to ifrs17/Test/AggregateInterpolateTest.ipynb index 9d9a9b35..1f5b296f 100644 --- a/ifrs17/Test/AggregateDoubleArrayTest.ipynb +++ b/ifrs17/Test/AggregateInterpolateTest.ipynb @@ -19,13 +19,22 @@ { "cell_type": "code", "source": [ - "#!import \"../Utils/Extensions\"", + "#!import \"../Utils/ImportCalculationMethods\"", "\n#!import \"../Utils/TestHelper\"" ], "metadata": {}, "execution_count": 0, "outputs": [] }, + { + "cell_type": "markdown", + "source": [ + "# Aggregation" + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, { "cell_type": "code", "source": [ @@ -119,10 +128,51 @@ "execution_count": 0, "outputs": [] }, + { + "cell_type": "markdown", + "source": [ + "# Values Interpolation" + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "var cashflow = new double [] {120, 180} ;", + "\nvar yearly = Interpolate(Periodicity.Yearly, InterpolationMethod.Uniform, cashflow);", + "\n(yearly[0], yearly[11], yearly[12], yearly[23]).Should().Be((10, 10, 15, 15));" + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "var quarterly = Interpolate(Periodicity.Quarterly, InterpolationMethod.Uniform, cashflow);", + "\n(quarterly[0], quarterly[3], quarterly[4], quarterly[6]).Should().Be((30, 30, 45, 45));" + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "var monthly = Interpolate(Periodicity.Monthly, InterpolationMethod.Uniform, cashflow);", + "\n(monthly[0], monthly[1]).Should().Be((120,180));" + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, { "cell_type": "code", "source": [ - "" + "var yearly = Interpolate(Periodicity.Yearly, InterpolationMethod.Start, cashflow);", + "\n(yearly[0], yearly[11], yearly[12], yearly[23]).Should().Be((10, 10, 15, 15));" ], "metadata": {}, "execution_count": 0, diff --git a/ifrs17/Utils/ImportCalculationMethods.ipynb b/ifrs17/Utils/ImportCalculationMethods.ipynb index 2d217dd2..b36b174e 100644 --- a/ifrs17/Utils/ImportCalculationMethods.ipynb +++ b/ifrs17/Utils/ImportCalculationMethods.ipynb @@ -236,15 +236,6 @@ "execution_count": 0, "outputs": [] }, - { - "cell_type": "code", - "source": [ - "Interpolate(Periodicity.Yearly, InterpolationMethod.End, new double[] {120,180,2,3,4})" - ], - "metadata": {}, - "execution_count": 0, - "outputs": [] - }, { "cell_type": "markdown", "source": [ From d47011a227c0c3cb2f9f78a932c0a6dee1f050bf Mon Sep 17 00:00:00 2001 From: Slavomir Batka Date: Mon, 3 Apr 2023 18:06:08 +0200 Subject: [PATCH 3/9] improve and cleanup --- ifrs17/Constants/Enums.ipynb | 20 +++++++++++++++++++- ifrs17/DataModel/DataStructure.ipynb | 9 ++++----- ifrs17/Import/Importers.ipynb | 4 +++- ifrs17/Test/AggregateInterpolateTest.ipynb | 8 ++++---- ifrs17/Test/Tests.ipynb | 2 +- ifrs17/Utils/ImportCalculationMethods.ipynb | 9 ++++++--- 6 files changed, 37 insertions(+), 15 deletions(-) diff --git a/ifrs17/Constants/Enums.ipynb b/ifrs17/Constants/Enums.ipynb index 49c3423f..9094ea09 100644 --- a/ifrs17/Constants/Enums.ipynb +++ b/ifrs17/Constants/Enums.ipynb @@ -206,6 +206,24 @@ "execution_count": 0, "outputs": [] }, + { + "cell_type": "markdown", + "source": [ + "## CashFlowPeriodicity" + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "public enum CashFlowPeriodicity { Monthly, Quarterly, Yearly }" + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, { "cell_type": "markdown", "source": [ @@ -218,7 +236,7 @@ { "cell_type": "code", "source": [ - "public enum InterpolationMethod { Uniform, Linear, Start, End, Custom }" + "public enum InterpolationMethod { NotApplicable, Uniform /*, Linear, Start, End, Custom*/ }" ], "metadata": {}, "execution_count": 0, diff --git a/ifrs17/DataModel/DataStructure.ipynb b/ifrs17/DataModel/DataStructure.ipynb index 9707dd58..da1ad5ad 100644 --- a/ifrs17/DataModel/DataStructure.ipynb +++ b/ifrs17/DataModel/DataStructure.ipynb @@ -1596,14 +1596,13 @@ "\n public double PremiumAllocation { get; init; } = DefaultPremiumExperienceAdjustmentFactor;", "\n", "\n [IdentityProperty]", - "\n [Dimension(typeof(Periodicity))]", - "\n [DefaultValue(Periodicity.Monthly)]", - "\n public Periodicity CashFlowPeriodicity { get; init; } = Periodicity.Monthly;", + "\n [Dimension(typeof(CashFlowPeriodicity))]", + "\n public CashFlowPeriodicity CashFlowPeriodicity { get; init; }", "\n ", "\n [IdentityProperty]", "\n [Dimension(typeof(InterpolationMethod))]", - "\n [DefaultValue(InterpolationMethod.Uniform)]", - "\n public InterpolationMethod InterpolationMethod { get; init; } = InterpolationMethod.Uniform;", + "\n public InterpolationMethod InterpolationMethod { get; init; }", + "\n ", "\n}", "\n", "\npublic record InterDataNodeParameter : DataNodeParameter {", diff --git a/ifrs17/Import/Importers.ipynb b/ifrs17/Import/Importers.ipynb index a72c7d83..aabcb6bb 100644 --- a/ifrs17/Import/Importers.ipynb +++ b/ifrs17/Import/Importers.ipynb @@ -190,7 +190,7 @@ "\n public bool IsDataNodeReinsurance(string goc) => DataNodeDataBySystemName[goc].IsReinsurance;", "\n public bool IsValidDataNode(string goc) => DataNodeDataBySystemName.ContainsKey(goc);", "\n", - "\n public (Periodicity, InterpolationMethod) GetCashFlowPeriodicityAndInterpolationMethod(string goc) {", + "\n public (CashFlowPeriodicity, InterpolationMethod) GetCashFlowPeriodicityAndInterpolationMethod(string goc) {", "\n if(!SingleDataNodeParametersByGoc.TryGetValue(goc, out var inner))", "\n ApplicationMessage.Log(Error.MissingDataNodeParameter, goc);", "\n return (inner[CurrentPeriod].CashFlowPeriodicity, inner[CurrentPeriod].InterpolationMethod); ", @@ -1131,6 +1131,8 @@ "\n Scenario = args.Scenario,", "\n Partition = storage.TargetPartitionByReportingNode.Id,", "\n DataNode = dataNode,", + "\n CashFlowPeriodicity = (CashFlowPeriodicity)Enum.Parse(typeof(CashFlowPeriodicity), datarow.Field(nameof(SingleDataNodeParameter.CashFlowPeriodicity))),", + "\n InterpolationMethod = (InterpolationMethod)Enum.Parse(typeof(InterpolationMethod), datarow.Field(nameof(SingleDataNodeParameter.InterpolationMethod))),", "\n PremiumAllocation = (datarow.Field(nameof(SingleDataNodeParameter.PremiumAllocation)))", "\n .ToString().CheckStringForExponentialAndConvertToDouble(),", "\n };", diff --git a/ifrs17/Test/AggregateInterpolateTest.ipynb b/ifrs17/Test/AggregateInterpolateTest.ipynb index 1f5b296f..c3de6c30 100644 --- a/ifrs17/Test/AggregateInterpolateTest.ipynb +++ b/ifrs17/Test/AggregateInterpolateTest.ipynb @@ -141,7 +141,7 @@ "cell_type": "code", "source": [ "var cashflow = new double [] {120, 180} ;", - "\nvar yearly = Interpolate(Periodicity.Yearly, InterpolationMethod.Uniform, cashflow);", + "\nvar yearly = Interpolate(CashFlowPeriodicity.Yearly, InterpolationMethod.Uniform, cashflow);", "\n(yearly[0], yearly[11], yearly[12], yearly[23]).Should().Be((10, 10, 15, 15));" ], "metadata": {}, @@ -151,7 +151,7 @@ { "cell_type": "code", "source": [ - "var quarterly = Interpolate(Periodicity.Quarterly, InterpolationMethod.Uniform, cashflow);", + "var quarterly = Interpolate(CashFlowPeriodicity.Quarterly, InterpolationMethod.Uniform, cashflow);", "\n(quarterly[0], quarterly[3], quarterly[4], quarterly[6]).Should().Be((30, 30, 45, 45));" ], "metadata": {}, @@ -161,7 +161,7 @@ { "cell_type": "code", "source": [ - "var monthly = Interpolate(Periodicity.Monthly, InterpolationMethod.Uniform, cashflow);", + "var monthly = Interpolate(CashFlowPeriodicity.Monthly, InterpolationMethod.Uniform, cashflow);", "\n(monthly[0], monthly[1]).Should().Be((120,180));" ], "metadata": {}, @@ -171,7 +171,7 @@ { "cell_type": "code", "source": [ - "var yearly = Interpolate(Periodicity.Yearly, InterpolationMethod.Start, cashflow);", + "var yearly = Interpolate(CashFlowPeriodicity.Yearly, InterpolationMethod.NotApplicable, cashflow);", "\n(yearly[0], yearly[11], yearly[12], yearly[23]).Should().Be((10, 10, 15, 15));" ], "metadata": {}, diff --git a/ifrs17/Test/Tests.ipynb b/ifrs17/Test/Tests.ipynb index 5a6b070d..31977d75 100644 --- a/ifrs17/Test/Tests.ipynb +++ b/ifrs17/Test/Tests.ipynb @@ -55,7 +55,7 @@ { "cell_type": "code", "source": [ - "#!eval-notebook \"AggregateDoubleArrayTest\"" + "#!eval-notebook \"AggregateInterpolateTest\"" ], "metadata": {}, "execution_count": 0, diff --git a/ifrs17/Utils/ImportCalculationMethods.ipynb b/ifrs17/Utils/ImportCalculationMethods.ipynb index b36b174e..b1641d05 100644 --- a/ifrs17/Utils/ImportCalculationMethods.ipynb +++ b/ifrs17/Utils/ImportCalculationMethods.ipynb @@ -218,11 +218,14 @@ { "cell_type": "code", "source": [ - "public static double[] Interpolate(Periodicity periodicity, InterpolationMethod interpolationMethod, double[] cashflowValues)", + "public static double[] Interpolate(CashFlowPeriodicity periodicity, InterpolationMethod interpolationMethod, double[] cashflowValues)", "\n{ ", + "\n if (periodicity == CashFlowPeriodicity.Monthly || periodicity == null)", + "\n return cashflowValues;", + "\n ", "\n var frequency = periodicity switch {", - "\n Periodicity.Yearly => 12,", - "\n Periodicity.Quarterly => 4,", + "\n CashFlowPeriodicity.Yearly => 12,", + "\n CashFlowPeriodicity.Quarterly => 4,", "\n _ => 1", "\n };", "\n ", From 700840e2c3ca6e680f772b79e2aabfa83a3932f9 Mon Sep 17 00:00:00 2001 From: Slavomir Batka Date: Mon, 3 Apr 2023 20:20:32 +0200 Subject: [PATCH 4/9] cleanup --- ifrs17/Import/Importers.ipynb | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/ifrs17/Import/Importers.ipynb b/ifrs17/Import/Importers.ipynb index aabcb6bb..6f64f52c 100644 --- a/ifrs17/Import/Importers.ipynb +++ b/ifrs17/Import/Importers.ipynb @@ -190,10 +190,16 @@ "\n public bool IsDataNodeReinsurance(string goc) => DataNodeDataBySystemName[goc].IsReinsurance;", "\n public bool IsValidDataNode(string goc) => DataNodeDataBySystemName.ContainsKey(goc);", "\n", - "\n public (CashFlowPeriodicity, InterpolationMethod) GetCashFlowPeriodicityAndInterpolationMethod(string goc) {", + "\n public CashFlowPeriodicity GetCashFlowPeriodicity(string goc) {", "\n if(!SingleDataNodeParametersByGoc.TryGetValue(goc, out var inner))", "\n ApplicationMessage.Log(Error.MissingDataNodeParameter, goc);", - "\n return (inner[CurrentPeriod].CashFlowPeriodicity, inner[CurrentPeriod].InterpolationMethod); ", + "\n return inner[CurrentPeriod].CashFlowPeriodicity; ", + "\n }", + "\n", + "\n public InterpolationMethod GetInterpolationMethod(string goc) {", + "\n if(!SingleDataNodeParametersByGoc.TryGetValue(goc, out var inner))", + "\n ApplicationMessage.Log(Error.MissingDataNodeParameter, goc);", + "\n return inner[CurrentPeriod].InterpolationMethod; ", "\n }", "\n", "\n // Validations", @@ -1301,8 +1307,9 @@ "\n if(values.Length == 0 && !parsingStorage.MandatoryAocSteps.Contains(new AocStep(aocType, novelty))) return null;", "\n }", "\n ", - "\n var cashFlowParameters = parsingStorage.GetCashFlowPeriodicityAndInterpolationMethod(dataNode);", - "\n var valuesInterpolated = Interpolate(cashFlowParameters.Item1, cashFlowParameters.Item2, values);", + "\n var cashFlowPeriodicity = parsingStorage.GetCashFlowPeriodicity(dataNode);", + "\n var interpolationMethod = parsingStorage.GetInterpolationMethod(dataNode); ", + "\n var valuesInterpolated = Interpolate(cashFlowPeriodicity, interpolationMethod, values);", "\n", "\n var item = new RawVariable {", "\n DataNode = dataNode,", From 5511161ba11b844e05ea6c80ec21b091b14db86e Mon Sep 17 00:00:00 2001 From: Slavomir Batka Date: Tue, 4 Apr 2023 17:56:25 +0200 Subject: [PATCH 5/9] add some tests, refactor the parser (not working yet) --- .../DataNodeParameter_InvalidDataNode.csv | 6 +- .../DataNodeParameter_InvalidParameters.csv | 16 ++++++ .../DataNodeParameter_MissingParameters.csv | 16 ++++++ .../Test/MapTemplateAndImportTest.ipynb | 56 ++++++++++++++++++- ifrs17/Import/Importers.ipynb | 19 +++++-- 5 files changed, 102 insertions(+), 11 deletions(-) create mode 100644 ifrs17-template/Test/Data/DataNodeParameter_InvalidParameters.csv create mode 100644 ifrs17-template/Test/Data/DataNodeParameter_MissingParameters.csv diff --git a/ifrs17-template/Test/Data/DataNodeParameter_InvalidDataNode.csv b/ifrs17-template/Test/Data/DataNodeParameter_InvalidDataNode.csv index 681a63c5..f20a6621 100644 --- a/ifrs17-template/Test/Data/DataNodeParameter_InvalidDataNode.csv +++ b/ifrs17-template/Test/Data/DataNodeParameter_InvalidDataNode.csv @@ -3,9 +3,9 @@ ReportingNode,Year,Month CH,2020,12 @@SingleDataNodeParameter -DataNode,PremiumAllocation -DT1.1,0.9 -DataNodeInvalid0,0.85 +DataNode,PremiumAllocation,CashFlowPeriodicity,InterpolationMethod +DT1.1,0.9,Monthly,Uniform +DataNodeInvalid0,0.85,Monthly,Uniform @@InterDataNodeParameter DataNode,LinkedDataNode,ReinsuranceCoverage diff --git a/ifrs17-template/Test/Data/DataNodeParameter_InvalidParameters.csv b/ifrs17-template/Test/Data/DataNodeParameter_InvalidParameters.csv new file mode 100644 index 00000000..e08441f8 --- /dev/null +++ b/ifrs17-template/Test/Data/DataNodeParameter_InvalidParameters.csv @@ -0,0 +1,16 @@ +@@Main +ReportingNode,Year,Month +CH,2020,12 + +@@SingleDataNodeParameter +DataNode,PremiumAllocation,CashFlowPeriodicity,InterpolationMethod +DT1.1,0.9,Monthly,InvalidEntry +DT1.1,0.85,InvalidEntry,Uniform +DT1.1,0.9,,Uniform +DT1.1,0.85,Monthly, + +@@InterDataNodeParameter +DataNode,LinkedDataNode,ReinsuranceCoverage +DTR1.1,DT1.1,1 +DTR1.2,DT1.2,1 +DTR1.3,DT1.3,1 diff --git a/ifrs17-template/Test/Data/DataNodeParameter_MissingParameters.csv b/ifrs17-template/Test/Data/DataNodeParameter_MissingParameters.csv new file mode 100644 index 00000000..4e6eee83 --- /dev/null +++ b/ifrs17-template/Test/Data/DataNodeParameter_MissingParameters.csv @@ -0,0 +1,16 @@ +@@Main +ReportingNode,Year,Month +CH,2020,12 + +@@SingleDataNodeParameter +DataNode,PremiumAllocation +DT1.1,0.9 +DT1.1,0.85 +DT1.1,0.9 +DT1.1,0.85 + +@@InterDataNodeParameter +DataNode,LinkedDataNode,ReinsuranceCoverage +DTR1.1,DT1.1,1 +DTR1.2,DT1.2,1 +DTR1.3,DT1.3,1 diff --git a/ifrs17-template/Test/MapTemplateAndImportTest.ipynb b/ifrs17-template/Test/MapTemplateAndImportTest.ipynb index 60ac6284..8c2b7837 100644 --- a/ifrs17-template/Test/MapTemplateAndImportTest.ipynb +++ b/ifrs17-template/Test/MapTemplateAndImportTest.ipynb @@ -616,7 +616,46 @@ "source": [ "var inputFileName = \"Data/DataNodeParameter_InvalidReinsCov.csv\";", "\nvar errorsBm = new List(){Get(Error.ReinsuranceCoverageDataNode, \"DT1.1\",\"DT1.1\")};", - "\nvar activity = await CheckErrors(inputFileName, errorsBm, ws3);", + "\nvar activity = await CheckErrors(inputFileName, errorsBm, ws3);" + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "await Import.FromFile(inputFileName).WithFormat(ImportFormats.DataNodeParameter).WithTarget(ws3).ExecuteAsync()" + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "Workspace.Query()" + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "var ws4 = Workspace.CreateNew();", + "\nws4.InitializeFrom(DataSource);" + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "var inputFileName = \"Data/DataNodeParameter_MissingParameters.csv\";", + "\nvar errorsBm = new List(){};", + "\nvar activity = await CheckErrors(inputFileName, errorsBm, ws4);", "\nactivity" ], "metadata": {}, @@ -626,7 +665,20 @@ { "cell_type": "code", "source": [ - "" + "var ws5 = Workspace.CreateNew();", + "\nws4.InitializeFrom(DataSource);" + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "var inputFileName = \"Data/DataNodeParameter_InvalidParameters.csv\";", + "\nvar errorsBm = new List(){};", + "\nvar activity = await CheckErrors(inputFileName, errorsBm, ws5);", + "\nactivity" ], "metadata": {}, "execution_count": 0, diff --git a/ifrs17/Import/Importers.ipynb b/ifrs17/Import/Importers.ipynb index 6f64f52c..f854e9e3 100644 --- a/ifrs17/Import/Importers.ipynb +++ b/ifrs17/Import/Importers.ipynb @@ -191,14 +191,14 @@ "\n public bool IsValidDataNode(string goc) => DataNodeDataBySystemName.ContainsKey(goc);", "\n", "\n public CashFlowPeriodicity GetCashFlowPeriodicity(string goc) {", - "\n if(!SingleDataNodeParametersByGoc.TryGetValue(goc, out var inner))", - "\n ApplicationMessage.Log(Error.MissingDataNodeParameter, goc);", + "\n if(!SingleDataNodeParametersByGoc.TryGetValue(goc, out var inner)) ", + "\n return CashFlowPeriodicity.Monthly;", "\n return inner[CurrentPeriod].CashFlowPeriodicity; ", "\n }", "\n", "\n public InterpolationMethod GetInterpolationMethod(string goc) {", "\n if(!SingleDataNodeParametersByGoc.TryGetValue(goc, out var inner))", - "\n ApplicationMessage.Log(Error.MissingDataNodeParameter, goc);", + "\n return InterpolationMethod.Uniform;", "\n return inner[CurrentPeriod].InterpolationMethod; ", "\n }", "\n", @@ -1118,7 +1118,9 @@ "\n if(Activity.HasErrors()) return Activity.Finish();", "\n var singleDataNode = new List();", "\n var interDataNode = new List<(string,string)>();", - "\n ", + "\n var hasCashFlowPeriodicityColumn = dataSet.Tables[ImportFormats.DataNodeParameter].Columns.Any(x => x.ColumnName == nameof(SingleDataNodeParameter.CashFlowPeriodicity));", + "\n var hasInterpolationMethodColumn = dataSet.Tables[ImportFormats.DataNodeParameter].Columns.Any(x => x.ColumnName == nameof(SingleDataNodeParameter.InterpolationMethod));", + "\n", "\n var importLog = await Import.FromDataSet(dataSet)", "\n .WithType( (dataset, datarow) => {", "\n", @@ -1137,8 +1139,12 @@ "\n Scenario = args.Scenario,", "\n Partition = storage.TargetPartitionByReportingNode.Id,", "\n DataNode = dataNode,", - "\n CashFlowPeriodicity = (CashFlowPeriodicity)Enum.Parse(typeof(CashFlowPeriodicity), datarow.Field(nameof(SingleDataNodeParameter.CashFlowPeriodicity))),", - "\n InterpolationMethod = (InterpolationMethod)Enum.Parse(typeof(InterpolationMethod), datarow.Field(nameof(SingleDataNodeParameter.InterpolationMethod))),", + "\n CashFlowPeriodicity = hasCashFlowPeriodicityColumn && Enum.TryParse(datarow.Field(nameof(SingleDataNodeParameter.CashFlowPeriodicity)), out CashFlowPeriodicity cfp) ", + "\n ? cfp", + "\n : CashFlowPeriodicity.Monthly,", + "\n InterpolationMethod = hasInterpolationMethodColumn && Enum.TryParse(datarow.Field(nameof(SingleDataNodeParameter.InterpolationMethod)), out InterpolationMethod im) ", + "\n ? im", + "\n : InterpolationMethod.Uniform,", "\n PremiumAllocation = (datarow.Field(nameof(SingleDataNodeParameter.PremiumAllocation)))", "\n .ToString().CheckStringForExponentialAndConvertToDouble(),", "\n };", @@ -1274,6 +1280,7 @@ "\n if(Activity.HasErrors()) return Activity.Finish();", "\n ", "\n var hasAccidentYearColumn = dataSet.Tables[ImportFormats.Cashflow].Columns.Any(x => x.ColumnName == nameof(RawVariable.AccidentYear));", + "\n ", "\n var importLog = await Import.FromDataSet(dataSet)", "\n .WithType ( (dataset, datarow) => {", "\n var aocType = datarow.Field(nameof(RawVariable.AocType));", From 2e55325604141d247dcc4cad65021142d18505ba Mon Sep 17 00:00:00 2001 From: Slavomir Batka Date: Wed, 5 Apr 2023 17:08:57 +0200 Subject: [PATCH 6/9] fix mapping --- ifrs17/Import/Importers.ipynb | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/ifrs17/Import/Importers.ipynb b/ifrs17/Import/Importers.ipynb index f854e9e3..5f1ed52c 100644 --- a/ifrs17/Import/Importers.ipynb +++ b/ifrs17/Import/Importers.ipynb @@ -1118,8 +1118,9 @@ "\n if(Activity.HasErrors()) return Activity.Finish();", "\n var singleDataNode = new List();", "\n var interDataNode = new List<(string,string)>();", - "\n var hasCashFlowPeriodicityColumn = dataSet.Tables[ImportFormats.DataNodeParameter].Columns.Any(x => x.ColumnName == nameof(SingleDataNodeParameter.CashFlowPeriodicity));", - "\n var hasInterpolationMethodColumn = dataSet.Tables[ImportFormats.DataNodeParameter].Columns.Any(x => x.ColumnName == nameof(SingleDataNodeParameter.InterpolationMethod));", + "\n", + "\n var hasCashFlowPeriodicityColumn = dataSet.Tables[nameof(SingleDataNodeParameter)].Columns.Any(x => x.ColumnName == nameof(SingleDataNodeParameter.CashFlowPeriodicity));", + "\n var hasInterpolationMethodColumn = dataSet.Tables[nameof(SingleDataNodeParameter)].Columns.Any(x => x.ColumnName == nameof(SingleDataNodeParameter.InterpolationMethod));", "\n", "\n var importLog = await Import.FromDataSet(dataSet)", "\n .WithType( (dataset, datarow) => {", @@ -1139,7 +1140,7 @@ "\n Scenario = args.Scenario,", "\n Partition = storage.TargetPartitionByReportingNode.Id,", "\n DataNode = dataNode,", - "\n CashFlowPeriodicity = hasCashFlowPeriodicityColumn && Enum.TryParse(datarow.Field(nameof(SingleDataNodeParameter.CashFlowPeriodicity)), out CashFlowPeriodicity cfp) ", + "\n CashFlowPeriodicity = hasCashFlowPeriodicityColumn && Enum.TryParse(datarow.Field(nameof(SingleDataNodeParameter.CashFlowPeriodicity)), out CashFlowPeriodicity cfp)", "\n ? cfp", "\n : CashFlowPeriodicity.Monthly,", "\n InterpolationMethod = hasInterpolationMethodColumn && Enum.TryParse(datarow.Field(nameof(SingleDataNodeParameter.InterpolationMethod)), out InterpolationMethod im) ", From d37ce38ff7f38445c29a894c2b49ac91fc6f6775 Mon Sep 17 00:00:00 2001 From: Slavomir Batka Date: Thu, 6 Apr 2023 15:48:56 +0200 Subject: [PATCH 7/9] improving importer + validations + tests (still not working) --- .../DataNodeParameter_InvalidParameters.csv | 6 ++-- .../Test/MapTemplateAndImportTest.ipynb | 32 ++++++++----------- ifrs17/Constants/Validations.ipynb | 5 +-- ifrs17/Import/Importers.ipynb | 6 ++++ 4 files changed, 25 insertions(+), 24 deletions(-) diff --git a/ifrs17-template/Test/Data/DataNodeParameter_InvalidParameters.csv b/ifrs17-template/Test/Data/DataNodeParameter_InvalidParameters.csv index e08441f8..69cfa777 100644 --- a/ifrs17-template/Test/Data/DataNodeParameter_InvalidParameters.csv +++ b/ifrs17-template/Test/Data/DataNodeParameter_InvalidParameters.csv @@ -5,9 +5,9 @@ CH,2020,12 @@SingleDataNodeParameter DataNode,PremiumAllocation,CashFlowPeriodicity,InterpolationMethod DT1.1,0.9,Monthly,InvalidEntry -DT1.1,0.85,InvalidEntry,Uniform -DT1.1,0.9,,Uniform -DT1.1,0.85,Monthly, +DT1.2,0.85,InvalidEntry,Uniform +DT1.3,0.9,,Uniform +DT1.4,0.85,Monthly, @@InterDataNodeParameter DataNode,LinkedDataNode,ReinsuranceCoverage diff --git a/ifrs17-template/Test/MapTemplateAndImportTest.ipynb b/ifrs17-template/Test/MapTemplateAndImportTest.ipynb index 8c2b7837..502b2029 100644 --- a/ifrs17-template/Test/MapTemplateAndImportTest.ipynb +++ b/ifrs17-template/Test/MapTemplateAndImportTest.ipynb @@ -625,16 +625,8 @@ { "cell_type": "code", "source": [ - "await Import.FromFile(inputFileName).WithFormat(ImportFormats.DataNodeParameter).WithTarget(ws3).ExecuteAsync()" - ], - "metadata": {}, - "execution_count": 0, - "outputs": [] - }, - { - "cell_type": "code", - "source": [ - "Workspace.Query()" + "var ws4 = Workspace.CreateNew();", + "\nws4.InitializeFrom(DataSource);" ], "metadata": {}, "execution_count": 0, @@ -643,8 +635,10 @@ { "cell_type": "code", "source": [ - "var ws4 = Workspace.CreateNew();", - "\nws4.InitializeFrom(DataSource);" + "var inputFileName = \"Data/DataNodeParameter_MissingParameters.csv\";", + "\nvar errorsBm = new List(){};", + "\nvar activity = await CheckErrors(inputFileName, errorsBm, ws4);", + "\nactivity" ], "metadata": {}, "execution_count": 0, @@ -653,10 +647,8 @@ { "cell_type": "code", "source": [ - "var inputFileName = \"Data/DataNodeParameter_MissingParameters.csv\";", - "\nvar errorsBm = new List(){};", - "\nvar activity = await CheckErrors(inputFileName, errorsBm, ws4);", - "\nactivity" + "var ws5 = Workspace.CreateNew();", + "\nws5.InitializeFrom(DataSource);" ], "metadata": {}, "execution_count": 0, @@ -665,8 +657,7 @@ { "cell_type": "code", "source": [ - "var ws5 = Workspace.CreateNew();", - "\nws4.InitializeFrom(DataSource);" + "//Import.FromFile(\"Data/DataNodeParameter_InvalidParameters.csv\").WithFormat(ImportFormats.DataNodeParameter).WithTarget(Workspace)" ], "metadata": {}, "execution_count": 0, @@ -676,7 +667,10 @@ "cell_type": "code", "source": [ "var inputFileName = \"Data/DataNodeParameter_InvalidParameters.csv\";", - "\nvar errorsBm = new List(){};", + "\nvar errorsBm = new List(){Get(Error.InvalidCashFlowPeriodicity, \"DT1.1\"), ", + "\n Get(Error.InvalidCashFlowPeriodicity, \"DT1.3\"),", + "\n Get(Error.InvalidCashFlowPeriodicity, \"DT1.2\"), ", + "\n Get(Error.InvalidCashFlowPeriodicity, \"DT1.4\")};", "\nvar activity = await CheckErrors(inputFileName, errorsBm, ws5);", "\nactivity" ], diff --git a/ifrs17/Constants/Validations.ipynb b/ifrs17/Constants/Validations.ipynb index 7205c8c0..b2684e17 100644 --- a/ifrs17/Constants/Validations.ipynb +++ b/ifrs17/Constants/Validations.ipynb @@ -76,7 +76,7 @@ "\n // Data Note State", "\n ChangeDataNodeState, InactiveDataNodeState,", "\n // Parameters", - "\n ReinsuranceCoverageDataNode, DuplicateInterDataNode, DuplicateSingleDataNode, InvalidDataNode, InvalidDataNodeForOpening, MissingDataNodeParameter,", + "\n ReinsuranceCoverageDataNode, DuplicateInterDataNode, DuplicateSingleDataNode, InvalidDataNode, InvalidDataNodeForOpening, InvalidCashFlowPeriodicity, InvalidInterpolationMethod,", "\n // Storage", "\n DataNodeNotFound, PartnerNotFound, RatingNotFound, CreditDefaultRateNotFound, MissingPremiumAllocation, ReinsuranceCoverage, ", "\n YieldCurveNotFound, YieldCurvePeriodNotApplicable, EconomicBasisNotFound, AccountingVariableTypeNotFound,", @@ -151,7 +151,8 @@ "\n (Error.DuplicateSingleDataNode , 1) => $\"Duplicated Single-DataNode parameter for {s[0]} is found.\",", "\n (Error.InvalidDataNode , 1) => $\"Data imported for invalid Data Node {s[0]}.\",", "\n (Error.InvalidDataNodeForOpening , 1) => $\"Data imported for invalid Data Node or for a Data Node after its inception year {s[0]}.\",", - "\n (Error.MissingDataNodeParameter , 1) => $\"Single Data Node Parameter for Data Node {s[0]} is missing.\",", + "\n (Error.InvalidCashFlowPeriodicity, 1) => $\"Single Data Node Parameter CashFlowPeriodicity for Data Node {s[0]} is invalid.\",", + "\n (Error.InvalidInterpolationMethod, 1) => $\"Single Data Node Parameter InterpolationMethod for Data Node {s[0]} is invalid.\",", "\n // Storage", "\n (Error.DataNodeNotFound , 1) => $\"DataNode {s[0]} not found.\",", "\n (Error.PartnerNotFound , 1) => $\"Partner not found for DataNode {s[0]}.\",", diff --git a/ifrs17/Import/Importers.ipynb b/ifrs17/Import/Importers.ipynb index 5f1ed52c..061e3526 100644 --- a/ifrs17/Import/Importers.ipynb +++ b/ifrs17/Import/Importers.ipynb @@ -1133,6 +1133,12 @@ "\n if(singleDataNode.Contains(dataNode)) { ApplicationMessage.Log(Error.DuplicateSingleDataNode, dataNode); return null; }", "\n singleDataNode.Add(dataNode);", "\n ", + "\n if(hasCashFlowPeriodicityColumn && !Enum.IsDefined(typeof(CashFlowPeriodicity), datarow.Field(nameof(SingleDataNodeParameter.CashFlowPeriodicity))))", + "\n { ApplicationMessage.Log(Error.InvalidCashFlowPeriodicity, dataNode); return null; };", + "\n", + "\n if(hasInterpolationMethodColumn && !Enum.IsDefined(typeof(InterpolationMethod), datarow.Field(nameof(SingleDataNodeParameter.InterpolationMethod))))", + "\n { ApplicationMessage.Log(Error.InvalidInterpolationMethod, dataNode); return null; };", + "\n", "\n //Instantiate SingleDataNodeParameter", "\n return new SingleDataNodeParameter {", "\n Year = args.Year,", From b4abc9a19d6ed496475bdbb88728ac276a0e31f2 Mon Sep 17 00:00:00 2001 From: Davide Colleoni Date: Thu, 6 Apr 2023 18:49:39 +0200 Subject: [PATCH 8/9] improvements in ifrs17ce --- ifrs17/DataModel/DataStructure.ipynb | 8 +++++ ifrs17/Import/Importers.ipynb | 36 +++++++++++---------- ifrs17/Test/AggregateInterpolateTest.ipynb | 8 ++--- ifrs17/Utils/ImportCalculationMethods.ipynb | 6 ++-- 4 files changed, 34 insertions(+), 24 deletions(-) diff --git a/ifrs17/DataModel/DataStructure.ipynb b/ifrs17/DataModel/DataStructure.ipynb index da1ad5ad..8800c837 100644 --- a/ifrs17/DataModel/DataStructure.ipynb +++ b/ifrs17/DataModel/DataStructure.ipynb @@ -1541,6 +1541,8 @@ "\n", "\nData Node Parameters are used to keep track of other parameters pertaining to each Data Node, and their movements in time (year and month).", "\n
PremiumAllocation : defines the weight of Premium to be included in the Experience Adjustement AoC Type of the Technical Margin and is valid only for Group of Insurance Contract with LiabilityType : Liability for Remaining Coverage.", + "\n
CashFlowPeriodicity : defines the periodicity of the provided cash flows, it is not a mandatory input. Supported values can be found [here](../Constants/Enums#cashflowperiodicity). When the column *CashFlowPeriodicity* is missing from the input file it is assumed a monthly periodicity (default value). When the *CashFlowPeriodicity* column is present, a valid value must be entered. ", + "\n
InterpolationMethod : defines the interpolation method to be applied to interpolate the cash flow to the monthly granularity, it is not a mandatory input. Supported values can be found [here](../Constants/Enums#interpolation-method). When the *InterpolationMethod* is not present in the input file or the *CashFlowPeriodicity* has the default value, then the default value for the *InterpolationMethod* is applied. The default value is Not Applicable. ", "\n
ReinsuranceCoverage : defines the weight of the underlying gross business to be considered in the computation of the allocation of the Technical Margin in a Reinsurance case. In other words, it represents the percentage to which claims in the underlying GICs are expected to be reinboursed by the Reinsurance Contracts belonging to the GRIC. For proportional contracts, this factor is given by the cession while for other contracts it should be estimated. ", "\n", "\nThe latest Data Node Parameters available in the system with Year and Month earlier or equal to Year and Month of the closing period will be used as the current value during calculation." @@ -1576,6 +1578,7 @@ "\n [Required]", "\n [IdentityProperty]", "\n [Dimension(typeof(GroupOfContract))]", + "\n [Display(Order = 1)]", "\n public string DataNode { get; init; }", "\n", "\n [IdentityProperty]", @@ -1593,14 +1596,17 @@ "public record SingleDataNodeParameter : DataNodeParameter {", "\n [DefaultValue(DefaultPremiumExperienceAdjustmentFactor)]", "\n [Range(0, 1, ErrorMessage = \"Value for {0} must be between {1} and {2}.\")]", + "\n [Display(Order = 20)]", "\n public double PremiumAllocation { get; init; } = DefaultPremiumExperienceAdjustmentFactor;", "\n", "\n [IdentityProperty]", "\n [Dimension(typeof(CashFlowPeriodicity))]", + "\n [Display(Order = 30)]", "\n public CashFlowPeriodicity CashFlowPeriodicity { get; init; }", "\n ", "\n [IdentityProperty]", "\n [Dimension(typeof(InterpolationMethod))]", + "\n [Display(Order = 40)]", "\n public InterpolationMethod InterpolationMethod { get; init; }", "\n ", "\n}", @@ -1609,9 +1615,11 @@ "\n [Required]", "\n [IdentityProperty]", "\n [Dimension(typeof(GroupOfContract))]", + "\n [Display(Order = 10)]", "\n public string LinkedDataNode { get; init; }", "\n ", "\n [Range(0, 1, ErrorMessage = \"Value for {0} must be between {1} and {2}.\")]", + "\n [Display(Order = 20)]", "\n public double ReinsuranceCoverage { get; init; }", "\n}" ], diff --git a/ifrs17/Import/Importers.ipynb b/ifrs17/Import/Importers.ipynb index 061e3526..95664866 100644 --- a/ifrs17/Import/Importers.ipynb +++ b/ifrs17/Import/Importers.ipynb @@ -198,7 +198,7 @@ "\n", "\n public InterpolationMethod GetInterpolationMethod(string goc) {", "\n if(!SingleDataNodeParametersByGoc.TryGetValue(goc, out var inner))", - "\n return InterpolationMethod.Uniform;", + "\n return InterpolationMethod.NotApplicable;", "\n return inner[CurrentPeriod].InterpolationMethod; ", "\n }", "\n", @@ -1133,11 +1133,20 @@ "\n if(singleDataNode.Contains(dataNode)) { ApplicationMessage.Log(Error.DuplicateSingleDataNode, dataNode); return null; }", "\n singleDataNode.Add(dataNode);", "\n ", - "\n if(hasCashFlowPeriodicityColumn && !Enum.IsDefined(typeof(CashFlowPeriodicity), datarow.Field(nameof(SingleDataNodeParameter.CashFlowPeriodicity))))", - "\n { ApplicationMessage.Log(Error.InvalidCashFlowPeriodicity, dataNode); return null; };", - "\n", - "\n if(hasInterpolationMethodColumn && !Enum.IsDefined(typeof(InterpolationMethod), datarow.Field(nameof(SingleDataNodeParameter.InterpolationMethod))))", - "\n { ApplicationMessage.Log(Error.InvalidInterpolationMethod, dataNode); return null; };", + "\n CashFlowPeriodicity periodicity = default;", + "\n if (hasCashFlowPeriodicityColumn)", + "\n if ( Enum.TryParse(datarow.Field(nameof(SingleDataNodeParameter.CashFlowPeriodicity)), out CashFlowPeriodicity cfp))", + "\n periodicity = cfp;", + "\n else { ApplicationMessage.Log(Error.InvalidCashFlowPeriodicity, dataNode); return null; }", + "\n", + "\n InterpolationMethod interpolationMethod = default;", + "\n if(hasInterpolationMethodColumn)", + "\n {", + "\n var interpolationMethodInput = datarow.Field(nameof(SingleDataNodeParameter.InterpolationMethod));", + "\n if ( Enum.TryParse(interpolationMethodInput, out InterpolationMethod ipm)) ", + "\n interpolationMethod = ipm;", + "\n else if ( !(periodicity == (CashFlowPeriodicity)default && string.IsNullOrEmpty(interpolationMethodInput)) ) { ApplicationMessage.Log(Error.InvalidInterpolationMethod, dataNode); return null; }", + "\n }", "\n", "\n //Instantiate SingleDataNodeParameter", "\n return new SingleDataNodeParameter {", @@ -1146,12 +1155,8 @@ "\n Scenario = args.Scenario,", "\n Partition = storage.TargetPartitionByReportingNode.Id,", "\n DataNode = dataNode,", - "\n CashFlowPeriodicity = hasCashFlowPeriodicityColumn && Enum.TryParse(datarow.Field(nameof(SingleDataNodeParameter.CashFlowPeriodicity)), out CashFlowPeriodicity cfp)", - "\n ? cfp", - "\n : CashFlowPeriodicity.Monthly,", - "\n InterpolationMethod = hasInterpolationMethodColumn && Enum.TryParse(datarow.Field(nameof(SingleDataNodeParameter.InterpolationMethod)), out InterpolationMethod im) ", - "\n ? im", - "\n : InterpolationMethod.Uniform,", + "\n CashFlowPeriodicity = periodicity,", + "\n InterpolationMethod = interpolationMethod,", "\n PremiumAllocation = (datarow.Field(nameof(SingleDataNodeParameter.PremiumAllocation)))", "\n .ToString().CheckStringForExponentialAndConvertToDouble(),", "\n };", @@ -1321,10 +1326,6 @@ "\n if(values.Length == 0 && !parsingStorage.MandatoryAocSteps.Contains(new AocStep(aocType, novelty))) return null;", "\n }", "\n ", - "\n var cashFlowPeriodicity = parsingStorage.GetCashFlowPeriodicity(dataNode);", - "\n var interpolationMethod = parsingStorage.GetInterpolationMethod(dataNode); ", - "\n var valuesInterpolated = Interpolate(cashFlowPeriodicity, interpolationMethod, values);", - "\n", "\n var item = new RawVariable {", "\n DataNode = dataNode,", "\n AocType = aocType,", @@ -1335,7 +1336,8 @@ "\n ? accidentYear", "\n : (int?)null,", "\n Partition = parsingStorage.TargetPartitionByReportingNodeAndPeriod.Id,", - "\n Values = Multiply(GetSign(ImportFormats.Cashflow, (aocType, valueType.AmountType, valueType.EstimateType, dataNodeData.IsReinsurance), parsingStorage.HierarchyCache), valuesInterpolated)", + "\n Values = Multiply(GetSign(ImportFormats.Cashflow, (aocType, valueType.AmountType, valueType.EstimateType, dataNodeData.IsReinsurance), parsingStorage.HierarchyCache), values)", + "\n .Interpolate(parsingStorage.GetCashFlowPeriodicity(dataNode), parsingStorage.GetInterpolationMethod(dataNode))", "\n };", "\n return item;", "\n }, ImportFormats.Cashflow", diff --git a/ifrs17/Test/AggregateInterpolateTest.ipynb b/ifrs17/Test/AggregateInterpolateTest.ipynb index c3de6c30..7b659c85 100644 --- a/ifrs17/Test/AggregateInterpolateTest.ipynb +++ b/ifrs17/Test/AggregateInterpolateTest.ipynb @@ -141,7 +141,7 @@ "cell_type": "code", "source": [ "var cashflow = new double [] {120, 180} ;", - "\nvar yearly = Interpolate(CashFlowPeriodicity.Yearly, InterpolationMethod.Uniform, cashflow);", + "\nvar yearly = cashflow.Interpolate(CashFlowPeriodicity.Yearly, InterpolationMethod.Uniform);", "\n(yearly[0], yearly[11], yearly[12], yearly[23]).Should().Be((10, 10, 15, 15));" ], "metadata": {}, @@ -151,7 +151,7 @@ { "cell_type": "code", "source": [ - "var quarterly = Interpolate(CashFlowPeriodicity.Quarterly, InterpolationMethod.Uniform, cashflow);", + "var quarterly = cashflow.Interpolate(CashFlowPeriodicity.Quarterly, InterpolationMethod.Uniform);", "\n(quarterly[0], quarterly[3], quarterly[4], quarterly[6]).Should().Be((30, 30, 45, 45));" ], "metadata": {}, @@ -161,7 +161,7 @@ { "cell_type": "code", "source": [ - "var monthly = Interpolate(CashFlowPeriodicity.Monthly, InterpolationMethod.Uniform, cashflow);", + "var monthly = cashflow.Interpolate(CashFlowPeriodicity.Monthly, InterpolationMethod.Uniform);", "\n(monthly[0], monthly[1]).Should().Be((120,180));" ], "metadata": {}, @@ -171,7 +171,7 @@ { "cell_type": "code", "source": [ - "var yearly = Interpolate(CashFlowPeriodicity.Yearly, InterpolationMethod.NotApplicable, cashflow);", + "var yearly = cashflow.Interpolate(CashFlowPeriodicity.Yearly, InterpolationMethod.NotApplicable);", "\n(yearly[0], yearly[11], yearly[12], yearly[23]).Should().Be((10, 10, 15, 15));" ], "metadata": {}, diff --git a/ifrs17/Utils/ImportCalculationMethods.ipynb b/ifrs17/Utils/ImportCalculationMethods.ipynb index b1641d05..7f04345b 100644 --- a/ifrs17/Utils/ImportCalculationMethods.ipynb +++ b/ifrs17/Utils/ImportCalculationMethods.ipynb @@ -218,9 +218,9 @@ { "cell_type": "code", "source": [ - "public static double[] Interpolate(CashFlowPeriodicity periodicity, InterpolationMethod interpolationMethod, double[] cashflowValues)", + "public static double[] Interpolate(this double[] cashflowValues, CashFlowPeriodicity periodicity, InterpolationMethod interpolationMethod)", "\n{ ", - "\n if (periodicity == CashFlowPeriodicity.Monthly || periodicity == null)", + "\n if (periodicity == CashFlowPeriodicity.Monthly)", "\n return cashflowValues;", "\n ", "\n var frequency = periodicity switch {", @@ -230,7 +230,7 @@ "\n };", "\n ", "\n return interpolationMethod switch {", - "\n InterpolationMethod.Uniform or _ => cashflowValues.SelectMany(v => Enumerable.Range(0, frequency).Select( (y,i) => v / (double)frequency)).ToArray()", + "\n InterpolationMethod.Uniform or _ => cashflowValues.SelectMany(v => Enumerable.Range(0, frequency).Select( _ => v / (double)frequency)).ToArray()", "\n };", "\n", "\n}" From 548640839799c5f6fbc2f57fe0e0bd56763a0fc3 Mon Sep 17 00:00:00 2001 From: Davide Colleoni Date: Thu, 6 Apr 2023 18:53:12 +0200 Subject: [PATCH 9/9] test and test data --- .../DataNodeParameter_InvalidParameters.csv | 1 + ...deParameter_MissingNonRequiredColumns.csv} | 6 +- .../Test/MapTemplateAndImportTest.ipynb | 60 +++++++++++++++---- 3 files changed, 54 insertions(+), 13 deletions(-) rename ifrs17-template/Test/Data/{DataNodeParameter_MissingParameters.csv => DataNodeParameter_MissingNonRequiredColumns.csv} (87%) diff --git a/ifrs17-template/Test/Data/DataNodeParameter_InvalidParameters.csv b/ifrs17-template/Test/Data/DataNodeParameter_InvalidParameters.csv index 69cfa777..00108a5f 100644 --- a/ifrs17-template/Test/Data/DataNodeParameter_InvalidParameters.csv +++ b/ifrs17-template/Test/Data/DataNodeParameter_InvalidParameters.csv @@ -8,6 +8,7 @@ DT1.1,0.9,Monthly,InvalidEntry DT1.2,0.85,InvalidEntry,Uniform DT1.3,0.9,,Uniform DT1.4,0.85,Monthly, +DT1.5,0.9,Yearly, @@InterDataNodeParameter DataNode,LinkedDataNode,ReinsuranceCoverage diff --git a/ifrs17-template/Test/Data/DataNodeParameter_MissingParameters.csv b/ifrs17-template/Test/Data/DataNodeParameter_MissingNonRequiredColumns.csv similarity index 87% rename from ifrs17-template/Test/Data/DataNodeParameter_MissingParameters.csv rename to ifrs17-template/Test/Data/DataNodeParameter_MissingNonRequiredColumns.csv index 4e6eee83..068b8fa4 100644 --- a/ifrs17-template/Test/Data/DataNodeParameter_MissingParameters.csv +++ b/ifrs17-template/Test/Data/DataNodeParameter_MissingNonRequiredColumns.csv @@ -5,9 +5,9 @@ CH,2020,12 @@SingleDataNodeParameter DataNode,PremiumAllocation DT1.1,0.9 -DT1.1,0.85 -DT1.1,0.9 -DT1.1,0.85 +DT1.2,0.85 +DT1.3,0.9 +DT1.4,0.85 @@InterDataNodeParameter DataNode,LinkedDataNode,ReinsuranceCoverage diff --git a/ifrs17-template/Test/MapTemplateAndImportTest.ipynb b/ifrs17-template/Test/MapTemplateAndImportTest.ipynb index 502b2029..4702c3dd 100644 --- a/ifrs17-template/Test/MapTemplateAndImportTest.ipynb +++ b/ifrs17-template/Test/MapTemplateAndImportTest.ipynb @@ -124,6 +124,42 @@ "execution_count": 0, "outputs": [] }, + { + "cell_type": "markdown", + "source": [ + "# Test Data Node Parameter" + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "var singleParam = (await DataSource.Query().Where(x => x.DataNode == \"DT1.1\").ToArrayAsync()).Single();" + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "singleParam.CashFlowPeriodicity.Should().Be((CashFlowPeriodicity)default);" + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "singleParam.InterpolationMethod.Should().Be((InterpolationMethod)default);" + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, { "cell_type": "markdown", "source": [ @@ -397,7 +433,10 @@ "\n nameof(PartitionByReportingNodeAndPeriod.Month),", "\n nameof(PartitionByReportingNodeAndPeriod.Scenario)};", "\nvar singleDataNodeParamCols = new[]{nameof(DataNode),", - "\n nameof(SingleDataNodeParameter.PremiumAllocation)};", + "\n nameof(SingleDataNodeParameter.PremiumAllocation),", + "\n nameof(SingleDataNodeParameter.CashFlowPeriodicity),", + "\n nameof(SingleDataNodeParameter.InterpolationMethod),", + "\n };", "\nvar interDataNodeParamCols = new[]{nameof(DataNodeParameter.DataNode),", "\n nameof(InterDataNodeParameter.LinkedDataNode),", "\n nameof(InterDataNodeParameter.ReinsuranceCoverage)};", @@ -546,6 +585,7 @@ "\n{", "\n Activity.Start();", "\n var log = await Import.FromFile(inputFileName).WithFormat(ImportFormats.DataNodeParameter).WithTarget(workspace).ExecuteAsync();", + "\n log.Errors.Count().Should().Be(errorBms.Count());", "\n errorBms.Intersect(log.Errors.Select(x => x.ToString().Substring(0,x.ToString().Length-2).Substring(40)).ToArray()).Count().Should().Be(errorBms.Count());", "\n return Activity.Finish();", "\n}" @@ -635,7 +675,7 @@ { "cell_type": "code", "source": [ - "var inputFileName = \"Data/DataNodeParameter_MissingParameters.csv\";", + "var inputFileName = \"Data/DataNodeParameter_MissingNonRequiredColumns.csv\";", "\nvar errorsBm = new List(){};", "\nvar activity = await CheckErrors(inputFileName, errorsBm, ws4);", "\nactivity" @@ -657,7 +697,13 @@ { "cell_type": "code", "source": [ - "//Import.FromFile(\"Data/DataNodeParameter_InvalidParameters.csv\").WithFormat(ImportFormats.DataNodeParameter).WithTarget(Workspace)" + "var inputFileName = \"Data/DataNodeParameter_InvalidParameters.csv\";", + "\nvar errorsBm = new List(){Get(Error.InvalidInterpolationMethod, \"DT1.1\"), ", + "\n Get(Error.InvalidCashFlowPeriodicity, \"DT1.2\"),", + "\n Get(Error.InvalidCashFlowPeriodicity, \"DT1.3\"),", + "\n Get(Error.InvalidInterpolationMethod, \"DT1.5\")};", + "\nvar activity = await CheckErrors(inputFileName, errorsBm, ws5);", + "\nactivity" ], "metadata": {}, "execution_count": 0, @@ -666,13 +712,7 @@ { "cell_type": "code", "source": [ - "var inputFileName = \"Data/DataNodeParameter_InvalidParameters.csv\";", - "\nvar errorsBm = new List(){Get(Error.InvalidCashFlowPeriodicity, \"DT1.1\"), ", - "\n Get(Error.InvalidCashFlowPeriodicity, \"DT1.3\"),", - "\n Get(Error.InvalidCashFlowPeriodicity, \"DT1.2\"), ", - "\n Get(Error.InvalidCashFlowPeriodicity, \"DT1.4\")};", - "\nvar activity = await CheckErrors(inputFileName, errorsBm, ws5);", - "\nactivity" + "" ], "metadata": {}, "execution_count": 0,