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-template/Test/ScenarioDataImportTest.ipynb b/ifrs17-template/Test/ScenarioDataImportTest.ipynb index 12cfeca0..f943b73e 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/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/Constants/Validations.ipynb b/ifrs17/Constants/Validations.ipynb index b2684e17..0152a7e0 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, NoScenarioOpening,", "\n // Exchange Rate", "\n ExchangeRateNotFound, ExchangeRateCurrency,", "\n // Data Note State", @@ -137,6 +137,9 @@ "\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) => $\"Column {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.\",", "\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 ecf6058a..dbab9748 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 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();", + "\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.ValidateArgsForPeriodAsync(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,", @@ -508,7 +511,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)." ], @@ -833,30 +836,36 @@ "Import.DefineFormat(ImportFormats.YieldCurve, async (options, dataSet) => {", "\n Activity.Start();", "\n var primaryArgs = GetArgsFromMain(dataSet) with {ImportFormat = ImportFormats.YieldCurve};", - "\n primaryArgs.ValidateArgsForPeriod();", + "\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 (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 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();", + "\n if (!values.Any()) 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", - "\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);", @@ -864,32 +873,31 @@ "\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 ", "\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(importLog);", + "\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 // 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 // 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": {}, @@ -1214,7 +1222,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.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());", @@ -1243,9 +1251,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(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 // 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()) 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) && ", @@ -1631,6 +1638,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);", diff --git a/ifrs17/OverviewCalculationEngine.ipynb b/ifrs17/OverviewCalculationEngine.ipynb index 27e70a33..46e44c4c 100644 --- a/ifrs17/OverviewCalculationEngine.ipynb +++ b/ifrs17/OverviewCalculationEngine.ipynb @@ -213,9 +213,10 @@ "\n- Financial Performance (FP) and Other Comprehensive Income (OCI)", "\n- Scenario and Sensitivity analysis", "\n- Run-off Projections (coming soon)", - "\n ", "\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." + "\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, diff --git a/ifrs17/Test/EqualityComparerTest.ipynb b/ifrs17/Test/EqualityComparerTest.ipynb index 02466a84..e372e0cf 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 3f922761..6d56de42 100644 --- a/ifrs17/Utils/EqualityComparers.ipynb +++ b/ifrs17/Utils/EqualityComparers.ipynb @@ -174,7 +174,7 @@ "\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); ",