From d1c3a0c5db11f71d199e2b1be83d59e5f90ae6f6 Mon Sep 17 00:00:00 2001 From: Danilo Calderini Date: Tue, 18 Apr 2023 17:38:54 +0200 Subject: [PATCH 01/13] importers, yield curve comparer and docu improved --- ifrs17/Import/Importers.ipynb | 26 +++++++-------- ifrs17/OverviewCalculationEngine.ipynb | 45 +++++++++++++++++++++++++- ifrs17/Utils/EqualityComparers.ipynb | 26 ++++----------- 3 files changed, 63 insertions(+), 34 deletions(-) diff --git a/ifrs17/Import/Importers.ipynb b/ifrs17/Import/Importers.ipynb index 5633d094..1aaa081f 100644 --- a/ifrs17/Import/Importers.ipynb +++ b/ifrs17/Import/Importers.ipynb @@ -508,7 +508,7 @@ "\n", "\nThe following methods are used in the different importers to compute the [IfrsVariables](../DataModel/DataStructure#ifrs-variable).", "\n", - "\nGetAllArgsAsync retrieves the partitions or Args that require computation. They are the union of the primary args (the one read from the main tab of the imported file) with the secondary args (senarios which depends on the best estimate data).", + "\nGetAllArgsAsync retrieves the partitions or Args that require computation. They are the union of the primary args (the one read from the main tab of the imported file) with the secondary args (scenarios which depends on the best estimate data).", "\n", "\nComputeAsync computes the IfrsVariables for a given partition (identified by its ImportArgs) and stores the results in a disposable workspace. This then serves as DataSource in the calculation of the secondary partitions (identified by the secondary args)." ], @@ -862,25 +862,25 @@ "\n var updatedCurrencies = toCommitYieldCurves.Select(x => x.Currency).Distinct();", "\n var dataNodesToUpdate = await workspace.Query().Where(x => updatedCurrencies.Contains(x.ContractualCurrency)).Select(x => x.SystemName).ToArrayAsync();", "\n var workspaceToCompute = Workspace.CreateNew();", - "\n workspaceToCompute.Initialize(x => x.FromSource(options.TargetDataSource));", + "\n workspaceToCompute.Initialize(x => x.FromSource(options.TargetDataSource).DisableInitialization().DisableInitialization());", "\n ", "\n foreach (var args in allArgs) {", "\n await CommitPartitionAsync(args, workspace, workspaceToCompute);", "\n var targetPartition = (Guid)(await options.TargetDataSource.Partition.GetKeyForInstanceAsync(args));", "\n var defaultPartition = (Guid)(await options.TargetDataSource.Partition.GetKeyForInstanceAsync(args with {Scenario = null}));", + "\n var previousPartition = (Guid)(await options.TargetDataSource.Partition.GetKeyForInstanceAsync(args with {Scenario = null, Year = args.Year-1, Month = 12}));", + "\n await options.TargetDataSource.Partition.SetAsync(null);", "\n if(ApplicationMessage.HasErrors()) return Activity.Finish().Merge(importLog);", "\n ", "\n // Avoid starting the computation if no best estimate cash flow has ever been imported ", - "\n if(args.Scenario == null) {", - "\n await options.TargetDataSource.Partition.SetAsync(null);", - "\n if(!(await options.TargetDataSource.Query().Where(x => x.Partition == targetPartition).Take(1).ToArrayAsync()).Any()) continue;", - "\n }", + "\n if(!(await options.TargetDataSource.Query().Where(x => x.Partition == defaultPartition).Take(1).ToArrayAsync()).Any() &&", + "\n !(await options.TargetDataSource.Query().Where(x => x.Partition == defaultPartition).Take(1).ToArrayAsync()).Any()) continue;", + "\n ", + "\n // Only nominals corresponding to the target data nodes are added to the workspace", + "\n var nominals = await options.TargetDataSource.Query().Where(x => dataNodesToUpdate.Contains(x.DataNode) && ", + "\n (x.Partition == targetPartition || x.Partition == defaultPartition || x.Partition == previousPartition)).ToArrayAsync();", + "\n if(nominals.Any()) await workspaceToCompute.UpdateAsync(nominals);", "\n", - "\n // Remove data nodes which are unaffected by the updated yield curves", - "\n // TODO : Reintroduce this functionality. Note all UpdateAsync/DeleteAsync performed to the workspaceToCompute are then trasferred to the DataSource.", - "\n // This is way this functionality should be written in a different way. ", - "\n // await workspaceToCompute.DeleteAsync( await workspaceToCompute.Query()", - "\n // .Where(x => !(dataNodesToUpdate.Contains(x.DataNode) && (x.Partition == targetPartition || x.Partition == defaultPartition))).ToArrayAsync() );", "\n", "\n importLog = importLog.Merge(await ComputeAsync(args, workspace, workspaceToCompute, false));", "\n if(importLog.Errors.Any()) return Activity.Finish().Merge(importLog);", @@ -1243,8 +1243,8 @@ "\n if(ApplicationMessage.HasErrors()) return Activity.Finish().Merge(log);", "\n ", "\n // Avoid starting the computation if no best estimate cash flow and actuals has ever been imported ", - "\n if(args.Scenario == null && !(await options.TargetDataSource.Query().Where(x => x.Partition == targetPartition).Take(1).ToArrayAsync()).Any() &&", - "\n !(await options.TargetDataSource.Query().Where(x => x.Partition == targetPartition).Take(1).ToArrayAsync()).Any()) continue;", + "\n if(!(await options.TargetDataSource.Query().Where(x => x.Partition == defaultPartition).Take(1).ToArrayAsync()).Any() &&", + "\n !(await options.TargetDataSource.Query().Where(x => x.Partition == defaultPartition).Take(1).ToArrayAsync()).Any()) continue;", "\n", "\n // Only nominals corresponding to the target data nodes are added to the workspace", "\n var nominals = await options.TargetDataSource.Query().Where(x => targetDataNodes.Contains(x.DataNode) && ", diff --git a/ifrs17/OverviewCalculationEngine.ipynb b/ifrs17/OverviewCalculationEngine.ipynb index 27e70a33..3535d7eb 100644 --- a/ifrs17/OverviewCalculationEngine.ipynb +++ b/ifrs17/OverviewCalculationEngine.ipynb @@ -214,8 +214,51 @@ "\n- Scenario and Sensitivity analysis", "\n- Run-off Projections (coming soon)", "\n ", + "\n" + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "## Scenario", + "\n", + "\nSensitivity Analysis (SA) is based on the comparison of different IFRS17 results, each of them labeled by a unique string called Scenario. ", + "\n", + "\nScenario is a Dimension and has to be known by the Platform in order to successfully import a file for that specific Scenario. See [DataModel](./DataModel/DataStructure#data-structure) for an overview of other types of Dimension and the [Initialization](../Ifrs17-template/Initialization/InitSystemorphRefDataToMemory#import-dimensions) to see how to import them.", + "\n", + "\nThe Best Estimate (BE) is the comparison base, and it does not need a column Scenario in the Main section. Alternatevely, the Scenario column can be left empty. ", "\n", - "\n For more information on the latest developments, please refer to our [GitHub](https://github.com/Systemorph/IFRS17CalculationEngine) project page. From there, you can get to know about future releases, place requests, track the current work and report issues." + "\n", + "\nScenarios and BE are stored in distinct Partitions to avoid Data contamination and only non redundant informations are saved." + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "", + "\n## Fall Back Principle", + "\n", + "\nUsually, only a subset of information changes for a given Scenario. Partial Scenario data is enriched with corresponding BE, called Fall Back Principle (FBP).", + "\nCombining FBP with optimization of latency time, memory usage and business standards inspired the features of the IFRS17 CalculationEngine:", + "\n- Minimun Interaction: importing one single file (Cashflow, Actual, YieldCurve, Data Node Parameter or Exchange Rate) for a specific Scenario creates automatically the corresponding Partition and data without any other action needed from the User.", + "\n- No Artifacts: if BE Transactional Data is not present, importing Scenario does not trigger IFRS17 calculations. Data is saved for succeeding calculations.", + "\n- No Memory Leak: if BE Transactional Data is imported or re-imported, all Scenario dependant Partitions will be updated as well. In order to avoid instability, IFRS17 CalculationEngine does not re-calculate Partitions that belong to subsequent years or months. " + ], + "metadata": {}, + "execution_count": 0, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "For more information on the latest developments, please refer to our [GitHub](https://github.com/Systemorph/IFRS17CalculationEngine) project page. From there, you can get to know about future releases, place requests, track the current work and report issues.", + "\n " ], "metadata": {}, "execution_count": 0, diff --git a/ifrs17/Utils/EqualityComparers.ipynb b/ifrs17/Utils/EqualityComparers.ipynb index 7323fce0..376537a3 100644 --- a/ifrs17/Utils/EqualityComparers.ipynb +++ b/ifrs17/Utils/EqualityComparers.ipynb @@ -88,35 +88,21 @@ { "cell_type": "code", "source": [ - "using System.Reflection;", - "\nclass IfrsVariableComparer: IEqualityComparer", + "class IfrsVariableComparer: IEqualityComparer", "\n{", "\n private bool IgnoreValue;", - "\n private double precision;", - "\n private IfrsVariableComparer(bool ignoreValue, double precision)", + "\n private IfrsVariableComparer(bool ignoreValue)", "\n {", "\n IgnoreValue = ignoreValue;", - "\n this.precision = precision;", - "\n }", - "\n", - "\n // At this point it is cumbersome and invokes reflections. Will be simplified when we switch to the arrays - A.K.", - "\n private bool CompareValues(IfrsVariable x, IfrsVariable y){", - "\n var values = Enumerable.Range(0, 12).Select(x => x == 0 ? \"Value\" : \"Value\" + x.ToString());", - "\n foreach (var v in values){", - "\n var val1 = (double)x.GetType().GetProperty(v).GetValue(x, null);", - "\n var val2 = (double)y.GetType().GetProperty(v).GetValue(y, null);", - "\n if (Math.Abs(val1 - val2) > precision) return false;", - "\n }", - "\n return true;", "\n }", "\n", "\n public bool Equals(IfrsVariable x, IfrsVariable y) =>", "\n x.AccidentYear == y.AccidentYear && x.AmountType == y.AmountType && x.DataNode == y.DataNode && x.AocType == y.AocType && ", - "\n x.Novelty == y.Novelty && x.EstimateType == y.EstimateType && x.EconomicBasis == y.EconomicBasis && (IgnoreValue ? true : CompareValues(x, y)); ", + "\n x.Novelty == y.Novelty && x.EstimateType == y.EstimateType && x.EconomicBasis == y.EconomicBasis && (IgnoreValue ? true : Math.Abs(x.Value - y.Value) < Precision); ", "\n", "\n public int GetHashCode(IfrsVariable v) => 0;", "\n", - "\n public static IfrsVariableComparer Instance(bool ignoreValue = false, double precision = Precision) => new IfrsVariableComparer(ignoreValue, precision);", + "\n public static IfrsVariableComparer Instance(bool ignoreValue = false) => new IfrsVariableComparer(ignoreValue);", "\n}" ], "metadata": {}, @@ -136,11 +122,11 @@ "\n return true; ", "\n if (x == null || y == null)", "\n return false; ", - "\n if (!(x.Month == y.Month && x.Scenario == y.Scenario && x.Currency == y.Currency && x.Id == y.Id && x.Name == y.Name))", + "\n if (!(x.Scenario == y.Scenario && x.Currency == y.Currency && x.Name == y.Name))", "\n return false; ", "\n if (x.Year == y.Year)", "\n return x.Values.SequenceEqual(y.Values, YieldCurvePrecision); ", - "\n return x.Year > y.Year", + "\n return x.Year > y.Year", "\n ? x.Values.SequenceEqual(y.Values.Skip(x.Year - y.Year).ToArray(), YieldCurvePrecision)", "\n : x.Values.Skip(y.Year - x.Year).ToArray().SequenceEqual(y.Values, YieldCurvePrecision);", "\n }", From 649d62d78f1b148f90d12a4ee3ecd509955cf7f7 Mon Sep 17 00:00:00 2001 From: Danilo Calderini Date: Wed, 19 Apr 2023 16:06:58 +0200 Subject: [PATCH 02/13] bug for scenario cashflow and actuals --- .../Test/ScenarioDataImportTest.ipynb | 18 +++++++++--------- ifrs17/Constants/Validations.ipynb | 4 +++- ifrs17/Import/Importers.ipynb | 11 +++++++---- 3 files changed, 19 insertions(+), 14 deletions(-) diff --git a/ifrs17-template/Test/ScenarioDataImportTest.ipynb b/ifrs17-template/Test/ScenarioDataImportTest.ipynb index b0419970..96086175 100644 --- a/ifrs17-template/Test/ScenarioDataImportTest.ipynb +++ b/ifrs17-template/Test/ScenarioDataImportTest.ipynb @@ -74,7 +74,7 @@ "cell_type": "code", "source": [ "var argsBestEstimate = new ImportArgs (\"CH\", 2020, 12, Periodicity.Quarterly, null, ImportFormats.Cashflow);", - "\nvar argsScenario = new ImportArgs (\"CH\", 2020, 12, Periodicity.Quarterly, \"Test\", ImportFormats.Cashflow);" + "\nvar argsScenario = new ImportArgs (\"CH\", 2020, 12, Periodicity.Quarterly, \"MTUP10pct\", ImportFormats.Cashflow);" ], "metadata": {}, "execution_count": 0, @@ -187,7 +187,7 @@ "var cashflowsScenario = @\"", "\n@@Main", "\nReportingNode,Year,Month,Scenario", - "\nCH,2020,12,Test", + "\nCH,2020,12,MTUP10pct", "\n@@Cashflow", "\nDataNode,AmountType,EstimateType,AocType,Novelty,AccidentYear,Values0,Values1,Values2,Values3,Values4,Values5,Values6,Values7,Values8,Values9,Values10,Values11,Values12,Values13,Values14,Values15,Values16,Values17,Values18,Values19,Values20,Values21,Values22,Values23", "\nDT1.1,PR,BE,CL,C,,110,0,0,110,0,0,110,0,0,110,0,0,0,110,0,0,110,0,0,110,0,0,110,0", @@ -248,7 +248,7 @@ "var actualsScenario = @\"", "\n@@Main", "\nReportingNode,Year,Month,Scenario", - "\nCH,2020,12,Test", + "\nCH,2020,12,MTUP10pct", "\n@@Actual", "\nDataNode,AocType,AmountType,EstimateType,AccidentYear,Value", "\nDT1.1,CF,NIC,A,,-308\";" @@ -315,7 +315,7 @@ "var cashflowsScenarioUpdateCU = @\"", "\n@@Main", "\nReportingNode,Year,Month,Scenario", - "\nCH,2020,12,Test", + "\nCH,2020,12,MTUP10pct", "\n@@Cashflow", "\nDataNode,AmountType,EstimateType,AocType,Novelty,AccidentYear,Values0,Values1,Values2,Values3,Values4,Values5,Values6,Values7,Values8,Values9,Values10,Values11,Values12,Values13,Values14,Values15,Values16,Values17,Values18,Values19,Values20,Values21,Values22,Values23", "\nDT1.1,,CU,CL,C,,-17,-17,-17,-17,-17,-17,-17,-17,-17,-17,-17,-17,-17,-6.5,-6.5,-6.5,-6.5,-6.5,-6.5,-6.5,-6.5,-6.5,-7.5,-8.5\";" @@ -375,7 +375,7 @@ "var actualsScenarioUpdateACAAEA = @\"", "\n@@Main", "\nReportingNode,Year,Month,Scenario", - "\nCH,2020,12,Test", + "\nCH,2020,12,MTUP10pct", "\n@@Actual", "\nDataNode,AocType,AmountType,EstimateType,AccidentYear,Value", "\nDT1.1,CF,ACA,A,,-555", @@ -444,7 +444,7 @@ "var actualsScenarioNoACAAEA = @\"", "\n@@Main", "\nReportingNode,Year,Month,Scenario", - "\nCH,2020,12,Test", + "\nCH,2020,12,MTUP10pct", "\n@@Actual", "\nDataNode,AocType,AmountType,EstimateType,AccidentYear,Value", "\nDT1.1,CF,ACA,A,,0", @@ -500,7 +500,7 @@ "var cashflowsScenarioEqualToBestEstimate = @\"", "\n@@Main", "\nReportingNode,Year,Month,Scenario", - "\nCH,2020,12,Test", + "\nCH,2020,12,MTUP10pct", "\n@@Cashflow", "\nDataNode,AmountType,EstimateType,AocType,Novelty,AccidentYear,Values0,Values1,Values2,Values3,Values4,Values5,Values6,Values7,Values8,Values9,Values10,Values11,Values12,Values13,Values14,Values15,Values16,Values17,Values18,Values19,Values20,Values21,Values22,Values23", "\nDT1.1,PR,BE,CL,C,,100,0,0,100,0,0,100,0,0,100,0,0,0,100,0,0,100,0,0,100,0,0,100,0", @@ -518,7 +518,7 @@ "var actualsScenarioEqualToBestEstimate = @\"", "\n@@Main", "\nReportingNode,Year,Month,Scenario", - "\nCH,2020,12,Test", + "\nCH,2020,12,MTUP10pct", "\n@@Actual", "\nDataNode,AocType,AmountType,EstimateType,AccidentYear,Value", "\nDT1.1,CF,ACA,A,,-10", @@ -850,7 +850,7 @@ "var cashflowsScenarioNoCU = @\"", "\n@@Main", "\nReportingNode,Year,Month,Scenario", - "\nCH,2020,12,Test", + "\nCH,2020,12,MTUP10pct", "\n@@Cashflow", "\nDataNode,AmountType,EstimateType,AocType,Novelty,AccidentYear,Values0,Values1,Values2,Values3,Values4,Values5,Values6,Values7,Values8,Values9,Values10,Values11,Values12,Values13,Values14,Values15,Values16,Values17,Values18,Values19,Values20,Values21,Values22,Values23", "\nDT1.1,PR,BE,CL,C,,110,0,0,110,0,0,110,0,0,110,0,0,0,110,0,0,110,0,0,110,0,0,110,0", diff --git a/ifrs17/Constants/Validations.ipynb b/ifrs17/Constants/Validations.ipynb index b2684e17..bae2493e 100644 --- a/ifrs17/Constants/Validations.ipynb +++ b/ifrs17/Constants/Validations.ipynb @@ -70,7 +70,7 @@ "\n PartitionNotFound, ParsedPartitionNotFound, PartititionNameNotFound, PartitionTypeNotFound,", "\n // Dimensions", "\n AmountTypeNotFound, EstimateTypeNotFound, ReportingNodeNotFound, AocTypeMapNotFound, AocTypeNotFound, PortfolioGicNotFound, PortfolioGricNotFound, ", - "\n InvalidAmountTypeEstimateType, MultipleTechnicalMarginOpening,", + "\n InvalidAmountTypeEstimateType, MultipleTechnicalMarginOpening, DimensionNotFound, ", "\n // Exchange Rate", "\n ExchangeRateNotFound, ExchangeRateCurrency,", "\n // Data Note State", @@ -137,6 +137,8 @@ "\n (Error.PortfolioGricNotFound , 2) => $\"Portfolio {s[0]} assigned to Group of Reinsurance Contract {s[1]} does not exist.\",", "\n (Error.InvalidAmountTypeEstimateType , 2) => $\"Invalid combination of EstimateType {s[0]} and AmountType {s[1]}.\",", "\n (Error.MultipleTechnicalMarginOpening , 1) => $\"Multiple opening for techincal margin are not allowed for DataNode {s[0]}.\",", + "\n (Error.DimensionNotFound , 2) => $\"Property {0} has unknown value {1}.\",", + "\n ", "\n // Exchange Rate", "\n (Error.ExchangeRateNotFound , 2) => $\"Exchange Rate for {s[0]} {s[1]} is not present.\",", "\n (Error.ExchangeRateCurrency , 1) => $\"{s[0]} does not have any Exchange Rate defined.\", ", diff --git a/ifrs17/Import/Importers.ipynb b/ifrs17/Import/Importers.ipynb index 1aaa081f..b5986f2c 100644 --- a/ifrs17/Import/Importers.ipynb +++ b/ifrs17/Import/Importers.ipynb @@ -367,9 +367,11 @@ { "cell_type": "code", "source": [ - "public static void ValidateArgsForPeriod(this ImportArgs args) {", + "public async static void ValidateArgsForPeriod(this ImportArgs args, IDataSource targetDataSource) {", "\n if(args.Year == default(int)) ApplicationMessage.Log(Error.YearInMainNotFound);", "\n if(args.Month == default(int)) ApplicationMessage.Log(Error.MonthInMainNotFound);", + "\n var availableScenarios = await targetDataSource.Query().Select(x => x.SystemName).ToArrayAsync();", + "\n if(!(args.Scenario == default(string) || availableScenarios.Contains(args.Scenario))) ApplicationMessage.Log(Error.DimensionNotFound, \"Scenario\", args.Scenario);", "\n}" ], "metadata": {}, @@ -401,8 +403,9 @@ "\n break;", "\n }", "\n case nameof(PartitionByReportingNodeAndPeriod) : {", - "\n args.ValidateArgsForPeriod();", + "\n args.ValidateArgsForPeriod(dataSource);", "\n if(ApplicationMessage.HasErrors()) return;", + "\n", "\n await dataSource.UpdateAsync( new[]{ new PartitionByReportingNodeAndPeriod { ", "\n Id = (Guid)(await DataSource.Partition.GetKeyForInstanceAsync(args)),", "\n Year = args.Year,", @@ -832,7 +835,7 @@ "Import.DefineFormat(ImportFormats.YieldCurve, async (options, dataSet) => {", "\n Activity.Start();", "\n var primaryArgs = GetArgsFromMain(dataSet) with {ImportFormat = ImportFormats.YieldCurve};", - "\n primaryArgs.ValidateArgsForPeriod();", + "\n primaryArgs.ValidateArgsForPeriod(options.TargetDataSource);", "\n if(ApplicationMessage.HasErrors()) return Activity.Finish();", "\n var workspace = Workspace.CreateNew();", "\n workspace.Initialize(x => x.FromSource(options.TargetDataSource).DisableInitialization().DisableInitialization());", @@ -1213,7 +1216,7 @@ "Import.DefineFormat(ImportFormats.DataNodeParameter, async (options, dataSet) => {", "\n Activity.Start();", "\n var primaryArgs = GetArgsFromMain(dataSet) with {ImportFormat = ImportFormats.DataNodeParameter};", - "\n primaryArgs.ValidateArgsForPeriod();", + "\n primaryArgs.ValidateArgsForPeriod(options.TargetDataSource);", "\n if(ApplicationMessage.HasErrors()) return Activity.Finish();", "\n var workspace = Workspace.CreateNew();", "\n workspace.Initialize(x => x.FromSource(options.TargetDataSource).DisableInitialization().DisableInitialization());", From 8bc79d6e2366121bd254b50c490c54c34d22ea90 Mon Sep 17 00:00:00 2001 From: Danilo Calderini Date: Mon, 24 Apr 2023 17:38:29 +0200 Subject: [PATCH 03/13] clean up --- ifrs17/OverviewCalculationEngine.ipynb | 34 -------------------------- 1 file changed, 34 deletions(-) diff --git a/ifrs17/OverviewCalculationEngine.ipynb b/ifrs17/OverviewCalculationEngine.ipynb index 3535d7eb..2d687361 100644 --- a/ifrs17/OverviewCalculationEngine.ipynb +++ b/ifrs17/OverviewCalculationEngine.ipynb @@ -220,40 +220,6 @@ "execution_count": 0, "outputs": [] }, - { - "cell_type": "markdown", - "source": [ - "## Scenario", - "\n", - "\nSensitivity Analysis (SA) is based on the comparison of different IFRS17 results, each of them labeled by a unique string called Scenario. ", - "\n", - "\nScenario is a Dimension and has to be known by the Platform in order to successfully import a file for that specific Scenario. See [DataModel](./DataModel/DataStructure#data-structure) for an overview of other types of Dimension and the [Initialization](../Ifrs17-template/Initialization/InitSystemorphRefDataToMemory#import-dimensions) to see how to import them.", - "\n", - "\nThe Best Estimate (BE) is the comparison base, and it does not need a column Scenario in the Main section. Alternatevely, the Scenario column can be left empty. ", - "\n", - "\n", - "\nScenarios and BE are stored in distinct Partitions to avoid Data contamination and only non redundant informations are saved." - ], - "metadata": {}, - "execution_count": 0, - "outputs": [] - }, - { - "cell_type": "markdown", - "source": [ - "", - "\n## Fall Back Principle", - "\n", - "\nUsually, only a subset of information changes for a given Scenario. Partial Scenario data is enriched with corresponding BE, called Fall Back Principle (FBP).", - "\nCombining FBP with optimization of latency time, memory usage and business standards inspired the features of the IFRS17 CalculationEngine:", - "\n- Minimun Interaction: importing one single file (Cashflow, Actual, YieldCurve, Data Node Parameter or Exchange Rate) for a specific Scenario creates automatically the corresponding Partition and data without any other action needed from the User.", - "\n- No Artifacts: if BE Transactional Data is not present, importing Scenario does not trigger IFRS17 calculations. Data is saved for succeeding calculations.", - "\n- No Memory Leak: if BE Transactional Data is imported or re-imported, all Scenario dependant Partitions will be updated as well. In order to avoid instability, IFRS17 CalculationEngine does not re-calculate Partitions that belong to subsequent years or months. " - ], - "metadata": {}, - "execution_count": 0, - "outputs": [] - }, { "cell_type": "markdown", "source": [ From c01acd264f2d3a1bf82dc0e11831021b89fe1c24 Mon Sep 17 00:00:00 2001 From: Danilo Calderini Date: Mon, 24 Apr 2023 21:10:35 +0200 Subject: [PATCH 04/13] test updated --- ifrs17/Test/EqualityComparerTest.ipynb | 2 +- ifrs17/Utils/EqualityComparers.ipynb | 25 +++++++++++++++++++------ 2 files changed, 20 insertions(+), 7 deletions(-) diff --git a/ifrs17/Test/EqualityComparerTest.ipynb b/ifrs17/Test/EqualityComparerTest.ipynb index 1faccfb1..4a200561 100644 --- a/ifrs17/Test/EqualityComparerTest.ipynb +++ b/ifrs17/Test/EqualityComparerTest.ipynb @@ -97,7 +97,7 @@ { "cell_type": "code", "source": [ - "comparer.Equals(yc,yc with { Month = 19}).Should().BeFalse()" + "comparer.Equals(yc,yc with { Month = 19}).Should().BeTrue()" ], "metadata": {}, "execution_count": 0, diff --git a/ifrs17/Utils/EqualityComparers.ipynb b/ifrs17/Utils/EqualityComparers.ipynb index 376537a3..e814bf23 100644 --- a/ifrs17/Utils/EqualityComparers.ipynb +++ b/ifrs17/Utils/EqualityComparers.ipynb @@ -91,18 +91,31 @@ "class IfrsVariableComparer: IEqualityComparer", "\n{", "\n private bool IgnoreValue;", - "\n private IfrsVariableComparer(bool ignoreValue)", - "\n {", - "\n IgnoreValue = ignoreValue;", - "\n }", + "\n private double precision;", + "\n", + "\n private IfrsVariableComparer(bool ignoreValue, double precision)", + "\n {", + "\n IgnoreValue = ignoreValue;", + "\n this.precision = precision;", + "\n }", + "\n ", + "\n // At this point it is cumbersome and invokes reflections. Will be simplified when we switch to the arrays - A.K.", + "\n private bool CompareValues(IfrsVariable x, IfrsVariable y){", + "\n var values = Enumerable.Range(0, 12).Select(x => x == 0 ? Value : Value + x.ToString());", + "\n foreach (var v in values){", + "\n var val1 = (double)x.GetType().GetProperty(v).GetValue(x, null);", + "\n var val2 = (double)y.GetType().GetProperty(v).GetValue(y, null);", + "\n if (Math.Abs(val1 - val2) > precision) return false;", + "\n }", + "\n return true;", "\n", "\n public bool Equals(IfrsVariable x, IfrsVariable y) =>", "\n x.AccidentYear == y.AccidentYear && x.AmountType == y.AmountType && x.DataNode == y.DataNode && x.AocType == y.AocType && ", - "\n x.Novelty == y.Novelty && x.EstimateType == y.EstimateType && x.EconomicBasis == y.EconomicBasis && (IgnoreValue ? true : Math.Abs(x.Value - y.Value) < Precision); ", + "\n x.Novelty == y.Novelty && x.EstimateType == y.EstimateType && x.EconomicBasis == y.EconomicBasis && (IgnoreValue ? true : CompareValues(x, y)); ", "\n", "\n public int GetHashCode(IfrsVariable v) => 0;", "\n", - "\n public static IfrsVariableComparer Instance(bool ignoreValue = false) => new IfrsVariableComparer(ignoreValue);", + "\n public static IfrsVariableComparer Instance(bool ignoreValue = false, double precision = Precision) => new IfrsVariableComparer(ignoreValue, precision);", "\n}" ], "metadata": {}, From 1f41275a89d03a72f432d5a87ae56aa3d1a1d95d Mon Sep 17 00:00:00 2001 From: Danilo Calderini Date: Mon, 24 Apr 2023 21:17:38 +0200 Subject: [PATCH 05/13] bug fix --- ifrs17/Utils/EqualityComparers.ipynb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ifrs17/Utils/EqualityComparers.ipynb b/ifrs17/Utils/EqualityComparers.ipynb index e814bf23..731e3725 100644 --- a/ifrs17/Utils/EqualityComparers.ipynb +++ b/ifrs17/Utils/EqualityComparers.ipynb @@ -92,7 +92,6 @@ "\n{", "\n private bool IgnoreValue;", "\n private double precision;", - "\n", "\n private IfrsVariableComparer(bool ignoreValue, double precision)", "\n {", "\n IgnoreValue = ignoreValue;", @@ -101,13 +100,14 @@ "\n ", "\n // At this point it is cumbersome and invokes reflections. Will be simplified when we switch to the arrays - A.K.", "\n private bool CompareValues(IfrsVariable x, IfrsVariable y){", - "\n var values = Enumerable.Range(0, 12).Select(x => x == 0 ? Value : Value + x.ToString());", + "\n var values = Enumerable.Range(0, 12).Select(x => x == 0 ? \"Value\" : \"Value\" + x.ToString());", "\n foreach (var v in values){", "\n var val1 = (double)x.GetType().GetProperty(v).GetValue(x, null);", "\n var val2 = (double)y.GetType().GetProperty(v).GetValue(y, null);", "\n if (Math.Abs(val1 - val2) > precision) return false;", "\n }", "\n return true;", + "\n }", "\n", "\n public bool Equals(IfrsVariable x, IfrsVariable y) =>", "\n x.AccidentYear == y.AccidentYear && x.AmountType == y.AmountType && x.DataNode == y.DataNode && x.AocType == y.AocType && ", From 9a77fad3013bd9eddc04c5ac82d7d4a8da19c14b Mon Sep 17 00:00:00 2001 From: Danilo Calderini Date: Mon, 24 Apr 2023 21:25:25 +0200 Subject: [PATCH 06/13] cleanup --- ifrs17/Utils/EqualityComparers.ipynb | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/ifrs17/Utils/EqualityComparers.ipynb b/ifrs17/Utils/EqualityComparers.ipynb index 731e3725..f0b30986 100644 --- a/ifrs17/Utils/EqualityComparers.ipynb +++ b/ifrs17/Utils/EqualityComparers.ipynb @@ -93,11 +93,11 @@ "\n private bool IgnoreValue;", "\n private double precision;", "\n private IfrsVariableComparer(bool ignoreValue, double precision)", - "\n {", - "\n IgnoreValue = ignoreValue;", - "\n this.precision = precision;", - "\n }", - "\n ", + "\n {", + "\n IgnoreValue = ignoreValue;", + "\n this.precision = precision;", + "\n }", + "\n", "\n // At this point it is cumbersome and invokes reflections. Will be simplified when we switch to the arrays - A.K.", "\n private bool CompareValues(IfrsVariable x, IfrsVariable y){", "\n var values = Enumerable.Range(0, 12).Select(x => x == 0 ? \"Value\" : \"Value\" + x.ToString());", @@ -106,7 +106,7 @@ "\n var val2 = (double)y.GetType().GetProperty(v).GetValue(y, null);", "\n if (Math.Abs(val1 - val2) > precision) return false;", "\n }", - "\n return true;", + "\n return true;", "\n }", "\n", "\n public bool Equals(IfrsVariable x, IfrsVariable y) =>", From 093db6a7adab563e392e0850d9c7f0050868c0e9 Mon Sep 17 00:00:00 2001 From: Danilo Calderini Date: Tue, 25 Apr 2023 10:57:21 +0200 Subject: [PATCH 07/13] bug yield curve importer --- ifrs17/Constants/Validations.ipynb | 3 ++- ifrs17/Import/Importers.ipynb | 21 +++++++++++++-------- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/ifrs17/Constants/Validations.ipynb b/ifrs17/Constants/Validations.ipynb index bae2493e..048efc1d 100644 --- a/ifrs17/Constants/Validations.ipynb +++ b/ifrs17/Constants/Validations.ipynb @@ -70,7 +70,7 @@ "\n PartitionNotFound, ParsedPartitionNotFound, PartititionNameNotFound, PartitionTypeNotFound,", "\n // Dimensions", "\n AmountTypeNotFound, EstimateTypeNotFound, ReportingNodeNotFound, AocTypeMapNotFound, AocTypeNotFound, PortfolioGicNotFound, PortfolioGricNotFound, ", - "\n InvalidAmountTypeEstimateType, MultipleTechnicalMarginOpening, DimensionNotFound, ", + "\n InvalidAmountTypeEstimateType, MultipleTechnicalMarginOpening, DimensionNotFound, NoScenarioOpening,", "\n // Exchange Rate", "\n ExchangeRateNotFound, ExchangeRateCurrency,", "\n // Data Note State", @@ -138,6 +138,7 @@ "\n (Error.InvalidAmountTypeEstimateType , 2) => $\"Invalid combination of EstimateType {s[0]} and AmountType {s[1]}.\",", "\n (Error.MultipleTechnicalMarginOpening , 1) => $\"Multiple opening for techincal margin are not allowed for DataNode {s[0]}.\",", "\n (Error.DimensionNotFound , 2) => $\"Property {0} has unknown value {1}.\",", + "\n (Error.NoScenarioOpening , 0) => \"Only Best Estimate is valid Scenario for Openings\",", "\n ", "\n // Exchange Rate", "\n (Error.ExchangeRateNotFound , 2) => $\"Exchange Rate for {s[0]} {s[1]} is not present.\",", diff --git a/ifrs17/Import/Importers.ipynb b/ifrs17/Import/Importers.ipynb index d03f7b54..9753cfb8 100644 --- a/ifrs17/Import/Importers.ipynb +++ b/ifrs17/Import/Importers.ipynb @@ -843,14 +843,18 @@ "\n var committedYieldCurves = await options.TargetDataSource.Query().ToArrayAsync();", "\n var hasNameColumn = dataSet.Tables[ImportFormats.YieldCurve].Columns.Any(x => x.ColumnName == nameof(YieldCurve.Name));", "\n var importLog = await Import.FromDataSet(dataSet).WithType(", - "\n (dataset, datarow) => new YieldCurve {", - "\n Currency = datarow.Field(nameof(YieldCurve.Currency)),", - "\n Year = primaryArgs.Year,", - "\n Month = primaryArgs.Month, ", - "\n Scenario = primaryArgs.Scenario,", - "\n Values = datarow.Table.Columns.Where(c => c.ColumnName.StartsWith(nameof(YieldCurve.Values))).OrderBy(c => c.ColumnName.Length).ThenBy(c => c.ColumnName)", - "\n .Select(x => datarow.Field(x.ColumnName).CheckStringForExponentialAndConvertToDouble()).ToArray(),", - "\n Name = hasNameColumn ? datarow.Field(nameof(YieldCurve.Name)) : default(string)", + "\n (dataset, datarow) => {", + "\n var values = datarow.Table.Columns.Where(c => c.ColumnName.StartsWith(nameof(YieldCurve.Values))).OrderBy(c => c.ColumnName.Length).ThenBy(c => c.ColumnName)", + "\n .Select(x => datarow.Field(x.ColumnName).CheckStringForExponentialAndConvertToDouble()).ToArray().Prune();", + "\n if (values.Length == 0 ) return null;", + "\n return new YieldCurve {", + "\n Currency = datarow.Field(nameof(YieldCurve.Currency)),", + "\n Year = primaryArgs.Year,", + "\n Month = primaryArgs.Month, ", + "\n Scenario = primaryArgs.Scenario,", + "\n Values = values,", + "\n Name = hasNameColumn ? datarow.Field(nameof(YieldCurve.Name)) : default(string)", + "\n };", "\n }", "\n ).WithTarget(workspace).ExecuteAsync(); ", "\n", @@ -1619,6 +1623,7 @@ "Import.DefineFormat(ImportFormats.Opening, async (options, dataSet) => {", "\n Activity.Start();", "\n var primaryArgs = await GetArgsAndCommitPartitionAsync(dataSet, options.TargetDataSource) with {ImportFormat = ImportFormats.Opening};", + "\n if(primaryArgs.Scenario != default(string)) ApplicationMessage.Log(Error.NoScenarioOpening);", "\n if(Activity.HasErrors()) return Activity.Finish();", "\n", "\n var allArgs = await GetAllArgsAsync(primaryArgs, options.TargetDataSource, ImportFormats.Opening);", From e0608d8dc142e8d1a02c19dcdeb110f561d0d734 Mon Sep 17 00:00:00 2001 From: Danilo Calderini Date: Tue, 25 Apr 2023 11:16:52 +0200 Subject: [PATCH 08/13] code clean up --- ifrs17/OverviewCalculationEngine.ipynb | 12 ++---------- ifrs17/Utils/EqualityComparers.ipynb | 2 +- 2 files changed, 3 insertions(+), 11 deletions(-) diff --git a/ifrs17/OverviewCalculationEngine.ipynb b/ifrs17/OverviewCalculationEngine.ipynb index 2d687361..46e44c4c 100644 --- a/ifrs17/OverviewCalculationEngine.ipynb +++ b/ifrs17/OverviewCalculationEngine.ipynb @@ -213,22 +213,14 @@ "\n- Financial Performance (FP) and Other Comprehensive Income (OCI)", "\n- Scenario and Sensitivity analysis", "\n- Run-off Projections (coming soon)", + "\n", + "\nFor more information on the latest developments, please refer to our [GitHub](https://github.com/Systemorph/IFRS17CalculationEngine) project page. From there, you can get to know about future releases, place requests, track the current work and report issues.", "\n ", "\n" ], "metadata": {}, "execution_count": 0, "outputs": [] - }, - { - "cell_type": "markdown", - "source": [ - "For more information on the latest developments, please refer to our [GitHub](https://github.com/Systemorph/IFRS17CalculationEngine) project page. From there, you can get to know about future releases, place requests, track the current work and report issues.", - "\n " - ], - "metadata": {}, - "execution_count": 0, - "outputs": [] } ] } \ No newline at end of file diff --git a/ifrs17/Utils/EqualityComparers.ipynb b/ifrs17/Utils/EqualityComparers.ipynb index f0b30986..31c4359f 100644 --- a/ifrs17/Utils/EqualityComparers.ipynb +++ b/ifrs17/Utils/EqualityComparers.ipynb @@ -139,7 +139,7 @@ "\n return false; ", "\n if (x.Year == y.Year)", "\n return x.Values.SequenceEqual(y.Values, YieldCurvePrecision); ", - "\n return x.Year > y.Year", + "\n return x.Year > y.Year", "\n ? x.Values.SequenceEqual(y.Values.Skip(x.Year - y.Year).ToArray(), YieldCurvePrecision)", "\n : x.Values.Skip(y.Year - x.Year).ToArray().SequenceEqual(y.Values, YieldCurvePrecision);", "\n }", From 81c130c224b2cae51eb4ca0b383ab0ecbdc8f755 Mon Sep 17 00:00:00 2001 From: Danilo Calderini Date: Tue, 25 Apr 2023 14:22:39 +0200 Subject: [PATCH 09/13] comments resolved --- .../TransactionalData/Actuals_CH_2020_12.csv | 2 +- ifrs17/Constants/Validations.ipynb | 2 +- ifrs17/Import/Importers.ipynb | 19 +++++++++++-------- 3 files changed, 13 insertions(+), 10 deletions(-) diff --git a/ifrs17-template/Files/TransactionalData/Actuals_CH_2020_12.csv b/ifrs17-template/Files/TransactionalData/Actuals_CH_2020_12.csv index a7900401..a8d71374 100644 --- a/ifrs17-template/Files/TransactionalData/Actuals_CH_2020_12.csv +++ b/ifrs17-template/Files/TransactionalData/Actuals_CH_2020_12.csv @@ -1,5 +1,5 @@ @@Main,,,,, -ReportingNode,Year,Month,Scenario ,, +ReportingNode,Year,Month,Scenario CH,2020,12,,, @@Actual,,,,, DataNode,AocType,AmountType,EstimateType,AccidentYear,Value diff --git a/ifrs17/Constants/Validations.ipynb b/ifrs17/Constants/Validations.ipynb index 048efc1d..0152a7e0 100644 --- a/ifrs17/Constants/Validations.ipynb +++ b/ifrs17/Constants/Validations.ipynb @@ -137,7 +137,7 @@ "\n (Error.PortfolioGricNotFound , 2) => $\"Portfolio {s[0]} assigned to Group of Reinsurance Contract {s[1]} does not exist.\",", "\n (Error.InvalidAmountTypeEstimateType , 2) => $\"Invalid combination of EstimateType {s[0]} and AmountType {s[1]}.\",", "\n (Error.MultipleTechnicalMarginOpening , 1) => $\"Multiple opening for techincal margin are not allowed for DataNode {s[0]}.\",", - "\n (Error.DimensionNotFound , 2) => $\"Property {0} has unknown value {1}.\",", + "\n (Error.DimensionNotFound , 2) => $\"Column {0} has unknown value {1}.\",", "\n (Error.NoScenarioOpening , 0) => \"Only Best Estimate is valid Scenario for Openings\",", "\n ", "\n // Exchange Rate", diff --git a/ifrs17/Import/Importers.ipynb b/ifrs17/Import/Importers.ipynb index 9753cfb8..0687c90e 100644 --- a/ifrs17/Import/Importers.ipynb +++ b/ifrs17/Import/Importers.ipynb @@ -367,7 +367,7 @@ { "cell_type": "code", "source": [ - "public async static void ValidateArgsForPeriod(this ImportArgs args, IDataSource targetDataSource) {", + "public async static void ValidateArgsForPeriodAsync(this ImportArgs args, IDataSource targetDataSource) {", "\n if(args.Year == default(int)) ApplicationMessage.Log(Error.YearInMainNotFound);", "\n if(args.Month == default(int)) ApplicationMessage.Log(Error.MonthInMainNotFound);", "\n var availableScenarios = await targetDataSource.Query().Select(x => x.SystemName).ToArrayAsync();", @@ -403,7 +403,7 @@ "\n break;", "\n }", "\n case nameof(PartitionByReportingNodeAndPeriod) : {", - "\n args.ValidateArgsForPeriod(dataSource);", + "\n args.ValidateArgsForPeriodAsync(dataSource);", "\n if(ApplicationMessage.HasErrors()) return;", "\n", "\n await dataSource.UpdateAsync( new[]{ new PartitionByReportingNodeAndPeriod { ", @@ -835,7 +835,7 @@ "Import.DefineFormat(ImportFormats.YieldCurve, async (options, dataSet) => {", "\n Activity.Start();", "\n var primaryArgs = GetArgsFromMain(dataSet) with {ImportFormat = ImportFormats.YieldCurve};", - "\n primaryArgs.ValidateArgsForPeriod(options.TargetDataSource);", + "\n primaryArgs.ValidateArgsForPeriodAsync(options.TargetDataSource);", "\n if(ApplicationMessage.HasErrors()) return Activity.Finish();", "\n var workspace = Workspace.CreateNew();", "\n workspace.Initialize(x => x.FromSource(options.TargetDataSource).DisableInitialization().DisableInitialization());", @@ -879,14 +879,17 @@ "\n await options.TargetDataSource.Partition.SetAsync(null);", "\n if(ApplicationMessage.HasErrors()) return Activity.Finish().Merge(importLog);", "\n ", - "\n // Avoid starting the computation if no best estimate cash flow has ever been imported ", + "\n // Avoid starting the computation if no best estimate cash flow or actual has ever been imported ", "\n if(!(await options.TargetDataSource.Query().Where(x => x.Partition == defaultPartition).Take(1).ToArrayAsync()).Any() &&", "\n !(await options.TargetDataSource.Query().Where(x => x.Partition == defaultPartition).Take(1).ToArrayAsync()).Any()) continue;", "\n ", - "\n // Only nominals corresponding to the target data nodes are added to the workspace", - "\n var nominals = await options.TargetDataSource.Query().Where(x => dataNodesToUpdate.Contains(x.DataNode) && ", + "\n // Only rawvariables and ifrsvariables corresponding to the target data nodes are added to the workspace", + "\n var rawvariables = await options.TargetDataSource.Query().Where(x => dataNodesToUpdate.Contains(x.DataNode) && ", "\n (x.Partition == targetPartition || x.Partition == defaultPartition || x.Partition == previousPartition)).ToArrayAsync();", - "\n if(nominals.Any()) await workspaceToCompute.UpdateAsync(nominals);", + "\n if(rawvariables.Any()) await workspaceToCompute.UpdateAsync(rawvariables);", + "\n var ifrsvariables = await options.TargetDataSource.Query().Where(x => dataNodesToUpdate.Contains(x.DataNode) && ", + "\n (x.Partition == targetPartition || x.Partition == defaultPartition || x.Partition == previousPartition)).ToArrayAsync();", + "\n if(ifrsvariables.Any()) await workspaceToCompute.UpdateAsync(ifrsvariables);", "\n", "\n", "\n importLog = importLog.Merge(await ComputeAsync(args, workspace, workspaceToCompute, false));", @@ -1220,7 +1223,7 @@ "Import.DefineFormat(ImportFormats.DataNodeParameter, async (options, dataSet) => {", "\n Activity.Start();", "\n var primaryArgs = GetArgsFromMain(dataSet) with {ImportFormat = ImportFormats.DataNodeParameter};", - "\n primaryArgs.ValidateArgsForPeriod(options.TargetDataSource);", + "\n primaryArgs.ValidateArgsForPeriodAsync(options.TargetDataSource);", "\n if(ApplicationMessage.HasErrors()) return Activity.Finish();", "\n var workspace = Workspace.CreateNew();", "\n workspace.Initialize(x => x.FromSource(options.TargetDataSource).DisableInitialization().DisableInitialization());", From 421c9298584d500040c5e4c1392ecd1e64e08295 Mon Sep 17 00:00:00 2001 From: Danilo Calderini Date: Tue, 25 Apr 2023 15:58:40 +0200 Subject: [PATCH 10/13] revert to previous implementation --- ifrs17/Import/Importers.ipynb | 46 ++++++++++++++++------------------- 1 file changed, 21 insertions(+), 25 deletions(-) diff --git a/ifrs17/Import/Importers.ipynb b/ifrs17/Import/Importers.ipynb index 0687c90e..73557a44 100644 --- a/ifrs17/Import/Importers.ipynb +++ b/ifrs17/Import/Importers.ipynb @@ -838,11 +838,13 @@ "\n primaryArgs.ValidateArgsForPeriodAsync(options.TargetDataSource);", "\n if(ApplicationMessage.HasErrors()) return Activity.Finish();", "\n var workspace = Workspace.CreateNew();", - "\n workspace.Initialize(x => x.FromSource(options.TargetDataSource).DisableInitialization().DisableInitialization());", + "\n workspace.Initialize(x => x.FromSource(options.TargetDataSource))", + "\n .DisableInitialization()", + "\n .DisableInitialization());", "\n", "\n var committedYieldCurves = await options.TargetDataSource.Query().ToArrayAsync();", "\n var hasNameColumn = dataSet.Tables[ImportFormats.YieldCurve].Columns.Any(x => x.ColumnName == nameof(YieldCurve.Name));", - "\n var importLog = await Import.FromDataSet(dataSet).WithType(", + "\n var log = await Import.FromDataSet(dataSet).WithType(", "\n (dataset, datarow) => {", "\n var values = datarow.Table.Columns.Where(c => c.ColumnName.StartsWith(nameof(YieldCurve.Values))).OrderBy(c => c.ColumnName.Length).ThenBy(c => c.ColumnName)", "\n .Select(x => datarow.Field(x.ColumnName).CheckStringForExponentialAndConvertToDouble()).ToArray().Prune();", @@ -858,47 +860,41 @@ "\n }", "\n ).WithTarget(workspace).ExecuteAsync(); ", "\n", - "\n if(importLog.Errors.Any()) return Activity.Finish().Merge(importLog); ", + "\n if(log.Errors.Any()) return Activity.Finish().Merge(log); ", "\n var toCommitYieldCurves = (await workspace.Query().ToArrayAsync()).Except(committedYieldCurves, YieldCurveComparer.Instance());", "\n if (!toCommitYieldCurves.Any()) {", "\n ApplicationMessage.Log(Warning.VariablesAlreadyImported); ", - "\n return Activity.Finish().Merge(importLog);", + "\n return Activity.Finish().Merge(log);", "\n }", "\n", "\n var allArgs = await GetAllArgsAsync(primaryArgs, options.TargetDataSource, ImportFormats.YieldCurve);", "\n var updatedCurrencies = toCommitYieldCurves.Select(x => x.Currency).Distinct();", "\n var dataNodesToUpdate = await workspace.Query().Where(x => updatedCurrencies.Contains(x.ContractualCurrency)).Select(x => x.SystemName).ToArrayAsync();", "\n var workspaceToCompute = Workspace.CreateNew();", - "\n workspaceToCompute.Initialize(x => x.FromSource(options.TargetDataSource).DisableInitialization().DisableInitialization());", - "\n ", + "\n workspaceToCompute.Initialize(x => x.FromSource(options.TargetDataSource));", + "\n ApplicationMessage.Log(Warning.Generic, String.Join(\", \", dataNodesToUpdate));", "\n foreach (var args in allArgs) {", "\n await CommitPartitionAsync(args, workspace, workspaceToCompute);", "\n var targetPartition = (Guid)(await options.TargetDataSource.Partition.GetKeyForInstanceAsync(args));", "\n var defaultPartition = (Guid)(await options.TargetDataSource.Partition.GetKeyForInstanceAsync(args with {Scenario = null}));", - "\n var previousPartition = (Guid)(await options.TargetDataSource.Partition.GetKeyForInstanceAsync(args with {Scenario = null, Year = args.Year-1, Month = 12}));", - "\n await options.TargetDataSource.Partition.SetAsync(null);", - "\n if(ApplicationMessage.HasErrors()) return Activity.Finish().Merge(importLog);", + "\n if(ApplicationMessage.HasErrors()) return Activity.Finish().Merge(log);", "\n ", - "\n // Avoid starting the computation if no best estimate cash flow or actual has ever been imported ", - "\n if(!(await options.TargetDataSource.Query().Where(x => x.Partition == defaultPartition).Take(1).ToArrayAsync()).Any() &&", - "\n !(await options.TargetDataSource.Query().Where(x => x.Partition == defaultPartition).Take(1).ToArrayAsync()).Any()) continue;", + "\n // Avoid starting the computation if no best estimate cash flow has ever been imported ", + "\n if(!(await options.TargetDataSource.Query().Where(x => x.Partition == defaultPartition).Take(1).ToArrayAsync()).Any()) continue;", "\n ", - "\n // Only rawvariables and ifrsvariables corresponding to the target data nodes are added to the workspace", - "\n var rawvariables = await options.TargetDataSource.Query().Where(x => dataNodesToUpdate.Contains(x.DataNode) && ", - "\n (x.Partition == targetPartition || x.Partition == defaultPartition || x.Partition == previousPartition)).ToArrayAsync();", - "\n if(rawvariables.Any()) await workspaceToCompute.UpdateAsync(rawvariables);", - "\n var ifrsvariables = await options.TargetDataSource.Query().Where(x => dataNodesToUpdate.Contains(x.DataNode) && ", - "\n (x.Partition == targetPartition || x.Partition == defaultPartition || x.Partition == previousPartition)).ToArrayAsync();", - "\n if(ifrsvariables.Any()) await workspaceToCompute.UpdateAsync(ifrsvariables);", - "\n", + "\n // Remove data nodes which are unaffected by the updated yield curves\",", + "\n // TODO : Reintroduce this functionality. Note all UpdateAsync/DeleteAsync performed to the workspaceToCompute are then trasferred to the DataSource.\",", + "\n // This is way this functionality should be written in a different way. \",", + "\n // await workspaceToCompute.DeleteAsync( await workspaceToCompute.Query()\",", + "\n // .Where(x => !(dataNodesToUpdate.Contains(x.DataNode) && (x.Partition == targetPartition || x.Partition == defaultPartition))).ToArrayAsync() );\",", "\n", - "\n importLog = importLog.Merge(await ComputeAsync(args, workspace, workspaceToCompute, false));", - "\n if(importLog.Errors.Any()) return Activity.Finish().Merge(importLog);", + "\n log = log.Merge(await ComputeAsync(args, workspace, workspaceToCompute, false));", + "\n if(log.Errors.Any()) return Activity.Finish().Merge(log);", "\n }", "\n", "\n await workspaceToCompute.UpdateAsync(toCommitYieldCurves);", "\n await workspaceToCompute.CommitToTargetAsync(options.TargetDataSource);", - "\n return Activity.Finish().Merge(importLog);", + "\n return Activity.Finish().Merge(log);", "\n});" ], "metadata": {}, @@ -1252,8 +1248,8 @@ "\n await options.TargetDataSource.Partition.SetAsync(null);", "\n if(ApplicationMessage.HasErrors()) return Activity.Finish().Merge(log);", "\n ", - "\n // Avoid starting the computation if no best estimate cash flow and actuals has ever been imported ", - "\n if(!(await options.TargetDataSource.Query().Where(x => x.Partition == defaultPartition).Take(1).ToArrayAsync()).Any() &&", + "\n // Avoid starting the computation if no best estimate cash flow or actuals has ever been imported ", + "\n if(!(await options.TargetDataSource.Query().Where(x => x.Partition == defaultPartition).Take(1).ToArrayAsync()).Any() ||", "\n !(await options.TargetDataSource.Query().Where(x => x.Partition == defaultPartition).Take(1).ToArrayAsync()).Any()) continue;", "\n", "\n // Only nominals corresponding to the target data nodes are added to the workspace", From af955a8c7ecc5ffd19d68e745557b5377388c42c Mon Sep 17 00:00:00 2001 From: Danilo Calderini Date: Tue, 25 Apr 2023 16:13:10 +0200 Subject: [PATCH 11/13] more reverting --- ifrs17/Import/Importers.ipynb | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/ifrs17/Import/Importers.ipynb b/ifrs17/Import/Importers.ipynb index 73557a44..656ce2fa 100644 --- a/ifrs17/Import/Importers.ipynb +++ b/ifrs17/Import/Importers.ipynb @@ -838,7 +838,7 @@ "\n primaryArgs.ValidateArgsForPeriodAsync(options.TargetDataSource);", "\n if(ApplicationMessage.HasErrors()) return Activity.Finish();", "\n var workspace = Workspace.CreateNew();", - "\n workspace.Initialize(x => x.FromSource(options.TargetDataSource))", + "\n workspace.Initialize(x => x.FromSource(options.TargetDataSource)", "\n .DisableInitialization()", "\n .DisableInitialization());", "\n", @@ -872,12 +872,15 @@ "\n var dataNodesToUpdate = await workspace.Query().Where(x => updatedCurrencies.Contains(x.ContractualCurrency)).Select(x => x.SystemName).ToArrayAsync();", "\n var workspaceToCompute = Workspace.CreateNew();", "\n workspaceToCompute.Initialize(x => x.FromSource(options.TargetDataSource));", - "\n ApplicationMessage.Log(Warning.Generic, String.Join(\", \", dataNodesToUpdate));", "\n foreach (var args in allArgs) {", "\n await CommitPartitionAsync(args, workspace, workspaceToCompute);", "\n var targetPartition = (Guid)(await options.TargetDataSource.Partition.GetKeyForInstanceAsync(args));", "\n var defaultPartition = (Guid)(await options.TargetDataSource.Partition.GetKeyForInstanceAsync(args with {Scenario = null}));", "\n if(ApplicationMessage.HasErrors()) return Activity.Finish().Merge(log);", + "\n if(args.Scenario == null) {", + "\n await options.TargetDataSource.Partition.SetAsync(null);", + "\n if(!(await options.TargetDataSource.Query().Where(x => x.Partition == targetPartition).Take(1).ToArrayAsync()).Any()) continue;", + "\n }", "\n ", "\n // Avoid starting the computation if no best estimate cash flow has ever been imported ", "\n if(!(await options.TargetDataSource.Query().Where(x => x.Partition == defaultPartition).Take(1).ToArrayAsync()).Any()) continue;", From fb5d85b1b0371bf02762489500ad031cdd36e307 Mon Sep 17 00:00:00 2001 From: Danilo Calderini Date: Tue, 25 Apr 2023 16:17:31 +0200 Subject: [PATCH 12/13] code clean up --- ifrs17/Import/Importers.ipynb | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/ifrs17/Import/Importers.ipynb b/ifrs17/Import/Importers.ipynb index 656ce2fa..34732fe6 100644 --- a/ifrs17/Import/Importers.ipynb +++ b/ifrs17/Import/Importers.ipynb @@ -877,14 +877,13 @@ "\n var targetPartition = (Guid)(await options.TargetDataSource.Partition.GetKeyForInstanceAsync(args));", "\n var defaultPartition = (Guid)(await options.TargetDataSource.Partition.GetKeyForInstanceAsync(args with {Scenario = null}));", "\n if(ApplicationMessage.HasErrors()) return Activity.Finish().Merge(log);", + "\n ", + "\n // Avoid starting the computation if no best estimate cash flow has ever been imported ", "\n if(args.Scenario == null) {", "\n await options.TargetDataSource.Partition.SetAsync(null);", "\n if(!(await options.TargetDataSource.Query().Where(x => x.Partition == targetPartition).Take(1).ToArrayAsync()).Any()) continue;", "\n }", "\n ", - "\n // Avoid starting the computation if no best estimate cash flow has ever been imported ", - "\n if(!(await options.TargetDataSource.Query().Where(x => x.Partition == defaultPartition).Take(1).ToArrayAsync()).Any()) continue;", - "\n ", "\n // Remove data nodes which are unaffected by the updated yield curves\",", "\n // TODO : Reintroduce this functionality. Note all UpdateAsync/DeleteAsync performed to the workspaceToCompute are then trasferred to the DataSource.\",", "\n // This is way this functionality should be written in a different way. \",", From d35c5c421014cbec630b066912a99338a043259b Mon Sep 17 00:00:00 2001 From: Danilo Calderini Date: Wed, 26 Apr 2023 11:46:51 +0200 Subject: [PATCH 13/13] comments resolved --- ifrs17/Constants/Consts.ipynb | 2 +- ifrs17/Import/Importers.ipynb | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/ifrs17/Constants/Consts.ipynb b/ifrs17/Constants/Consts.ipynb index 4beeab84..24be6fab 100644 --- a/ifrs17/Constants/Consts.ipynb +++ b/ifrs17/Constants/Consts.ipynb @@ -416,7 +416,7 @@ "cell_type": "code", "source": [ "public static class Scenarios{", - "\n public static bool EnableScenario = false;", + "\n public static bool EnableScenario = true;", "\n public const string Default = \"Best Estimate\";", "\n public const string All = nameof(All);", "\n public const string Delta = nameof(Delta);", diff --git a/ifrs17/Import/Importers.ipynb b/ifrs17/Import/Importers.ipynb index 2f844e69..dbab9748 100644 --- a/ifrs17/Import/Importers.ipynb +++ b/ifrs17/Import/Importers.ipynb @@ -849,7 +849,7 @@ "\n (dataset, datarow) => {", "\n var values = datarow.Table.Columns.Where(c => c.ColumnName.StartsWith(nameof(YieldCurve.Values))).OrderBy(c => c.ColumnName.Length).ThenBy(c => c.ColumnName)", "\n .Select(x => datarow.Field(x.ColumnName).CheckStringForExponentialAndConvertToDouble()).ToArray().Prune();", - "\n if (values.Length == 0 ) return null;", + "\n if (!values.Any()) return null;", "\n return new YieldCurve {", "\n Currency = datarow.Field(nameof(YieldCurve.Currency)),", "\n Year = primaryArgs.Year,", @@ -1252,8 +1252,7 @@ "\n if(ApplicationMessage.HasErrors()) return Activity.Finish().Merge(log);", "\n ", "\n // Avoid starting the computation if no best estimate cash flow or actuals has ever been imported ", - "\n if(!(await options.TargetDataSource.Query().Where(x => x.Partition == defaultPartition).Take(1).ToArrayAsync()).Any() ||", - "\n !(await options.TargetDataSource.Query().Where(x => x.Partition == defaultPartition).Take(1).ToArrayAsync()).Any()) continue;", + "\n if(!(await options.TargetDataSource.Query().Where(x => x.Partition == defaultPartition).Take(1).ToArrayAsync()).Any()) continue;", "\n", "\n // Only nominals corresponding to the target data nodes are added to the workspace", "\n var nominals = await options.TargetDataSource.Query().Where(x => targetDataNodes.Contains(x.DataNode) && ",