Offline Solvency II components in R

Select rules explicitly

The same input can belong to different dated regimes. Select the profile and information date explicitly; the package does not look up today’s rules online.

ctx <- Context("2025-01-17", "2026-09-23", "EUR",
               "EU-S2-DOCUMENTS-2024-2025-v0.1")
names(rule_profiles()$profiles)
#> [1] "EU-S2-DOCUMENTS-2024-2025-v0.1" "EU-S2-DOCUMENTS-2027-v0.1"
result <- intangible_risk(100, context = ctx)
result
#> intangible_risk: 80 EUR [REFERENCE_COMPONENT]
result$sources
#> [[1]]
#> [1] "DR:article-203"

The result is an ordinary list with an S3 class. Inspect details for assumptions, scope and external qualification flags. input_hash and profile_hash identify the R calculation inputs and profile, not regulatory approval.

Use an individual formula or an integration graph

aggregate_risk(list(premium_reserve = 3, lapse = 4),
               matrix_id = "health_nslt", context = ctx)$value
#> [1] 5
nodes <- list(
  intangible = list("function" = "intangible_risk", inputs = list(amount = 100))
)
# Reference cases provide the exact input names for any formula:
case <- Filter(function(x) x[["function"]] == "intangible_risk" &&
                 is.null(x$expected_error), reference_cases()$cases)[[1]]
nodes$intangible$inputs <- case$kwargs
runner <- Engine()
runner$run(nodes, context = ctx)$results$intangible$value
#> [1] 0
runner$run(nodes, context = ctx)$cache_hits
#> [[1]]
#> [1] "intangible"

Use list("$ref" = "node_id") in a downstream input to refer to another node’s value. Missing dependencies and cycles are errors. Combined results retain PARTIAL status; a graph does not certify that every obligation of an undertaking has been represented.

Local curves and explicit cashflows

curve <- DiscountCurve("synthetic-one-year", "2025-01-17", "EUR", "custom",
                       "invented example", list(list("2026-01-17", 0.97)))
discount_curve_factor(curve, "2026-01-17")
#> [1] 0.97
cashflows <- list("2026-01-17" = list(expected_inflows = 10,
                                     expected_outflows = 100))
best_estimate_with_curve(cashflows, curve, runoff_complete = TRUE,
                        cashflow_reference = "synthetic complete runoff",
                        context = ctx)$value
#> [1] 87.3

The CSV adapter expects exactly date,discount_factor; JSON carries explicit curve identity, date, currency, kind and provenance. Every payment date must have a supplied factor. Obtain market inputs separately: no adapter downloads data or silently invents interpolation or compounding conventions.

Analyst scenarios without changing the baseline

scenario <- ctx
scenario$overrides <- list(NumericOverride(
  "profile.json", list("scalars", "intangible", "value"), 0.70,
  "Synthetic analyst sensitivity"
))
intangible_risk(100, context = scenario)$status
#> [1] "ANALYST_SCENARIO"
parameter("scalars/intangible", scenario)$analyst_overrides
#> [[1]]
#> [[1]]$resource
#> [1] "profile.json"
#> 
#> [[1]]$path
#> [[1]]$path[[1]]
#> [1] "scalars"
#> 
#> [[1]]$path[[2]]
#> [1] "intangible"
#> 
#> [[1]]$path[[3]]
#> [1] "value"
#> 
#> 
#> [[1]]$original
#> [1] 0.8
#> 
#> [[1]]$value
#> [1] 0.7
#> 
#> [[1]]$reason
#> [1] "Synthetic analyst sensitivity"
intangible_risk(100, context = ctx)$value
#> [1] 80

Matrix paths use the source JSON’s zero-based indices. Overrides have explicit reasons and applicability guards. Editing a returned parameter list does not change either the installed resource or a later calculation.

Reporting is a separate technical choice

bindings <- list(v1 = list(value = 1005, decimals = 0),
                 v2 = list(values = list(list(value = 1000, decimals = 0))))
reporting_bound_rule_check("BV1053-1", bindings, "2.8.2", "synthetic selection")$value
#> [1] FALSE
reporting_bound_rule_check("BV1053-1", bindings, "2.10.0", "synthetic selection")$value
#> [1] TRUE

Reporting technical releases are not inferred from the regulatory Context. Tagged numbers, text, dates, QNames, Boolean values and absence have distinct meanings. Exact rational arithmetic preserves declared reporting precision. Archived activation evidence and filing preconditions are separate from the rule’s numeric result. reporting_instance() assembles a source-bound XML draft and explicit findings, never a submission-ready filing certificate.

Handle failures and reproduce examples

tryCatch(intangible_risk(Inf, context = ctx), CalculationError = function(error) {
  list(code = error$code, field = error$field)
})
#> $code
#> [1] "INVALID_INPUT"
#> 
#> $field
#> [1] "recognised_value"
length(reference_cases()$cases)
#> [1] 12382
length(reference_portfolios()$portfolios)
#> [1] 227
reference_datasets()
#>  [1] "reference_reporting_balanced_scope.json"    
#>  [2] "reference_reporting_capital_cases.json"     
#>  [3] "reference_reporting_cases.json"             
#>  [4] "reference_reporting_fact_context_cases.json"
#>  [5] "reference_reporting_metric_cases.json"      
#>  [6] "reference_reporting_portfolios.json"        
#>  [7] "reference_reporting_scope_cases.json"       
#>  [8] "reference_reporting_string_cases.json"      
#>  [9] "reference_reporting_typed_cases.json"       
#> [10] "reference_reporting_validation_status.json"

Fixed references include deliberately invalid inputs as well as successful examples. Regulatory tables retain source references; company inputs and market demonstrations are synthetic. Review the selected function’s help page and the machine-readable coverage() before interpreting a component result.