Changelog¶
All notable changes to the RWA Calculator are documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
[Unreleased]¶
Added¶
- UI: Add template workbench — duplicate read-only template workbooks into editable user workspace with full Python and SQL support via
marimo edit - UI: Add workspace management REST API (
/api/templates,/api/workbooks,/api/workbooks/duplicate,/api/workbooks/{name}) - UI: Add "Workbench" link to sidebar navigation in all template apps
Changed¶
- API: Replace
RWAService+CalculationRequest+quick_calculate+create_servicewith singleCreditRiskCalcclass. Usage:CreditRiskCalc(data_path=..., framework=..., reporting_date=...).calculate(). All response models (CalculationResponse,SummaryStatistics, etc.) are unchanged. - Config: Replace granular
IRBPermissionsconfig (withsa_only(),full_irb(),firb_only(), etc.) with a simple two-modePermissionModeenum (STANDARDISED/IRB). Thepermission_modeparameter onCalculationConfig.crr()and.basel_3_1()replaces the oldirb_permissionsparameter. In IRB mode,model_permissionsinput data drives all approach routing (AIRB, FIRB, slotting); without it, the pipeline falls back to SA with a warning.IRBPermissionsremains as an internal implementation detail but is no longer part of the public API. - Classifier: Add
model_slotting_permittedflag to model permissions resolution, enabling slotting to be driven by per-model permissions alongside AIRB and FIRB - Model Permissions: Add
"slotting"as a validapproachvalue (alongside"foundation_irb"and"advanced_irb") - Comparison:
TransitionalScheduleRunner.run()now acceptspermission_modeinstead ofirb_permissions
Added¶
- Engine: Add
materialise.pymodule with strategy-aware materialization barriers — supports disk-spill (sink_parquet→scan_parquet) for out-of-core datasets and in-memory (collect().lazy()) for backward compatibility, controlled byconfig.collect_engine - Config: Add
spill_dirfield toCalculationConfigfor configuring temp file directory during streaming materialization - Tests: Add unit tests for
materialise_barrier,materialise_branches, andcleanup_spill_files
Changed¶
- Data Tables: Consolidate slotting risk weights —
engine/slotting/namespace.pynow sources all risk weights fromdata/tables/instead of defining them inline, consistent with SA/IRB/Equity engines - Data Tables: Export all 4 CRR slotting weight dicts and convenience functions from
data/tables/__init__.py(previously only 2 of 4 were exported)
Added¶
- Data Tables: Add
b31_slotting.pywith Basel 3.1 slotting risk weights (base, pre-operational, HVCRE) per BCBS CRE33 - Tests: Add unit tests for Basel 3.1 slotting tables and extend CRR slotting short-maturity test coverage
Removed¶
- Engine: Remove unused
calculate_unified()fromSlottingCalculator,IRBCalculator, and their protocols — only SA uses this method (for the output floor). Simplifies the slotting and IRB calculator interfaces. - Engine: Remove unused
calculate()fromSlottingCalculatorand its protocol — the pipeline usescalculate_branch()directly. Also remove dead_run_slotting_calculator()from pipeline.
Added¶
- Docs: Add OF 02.00 and OF 02.01 output floor reporting documentation — master own funds requirements template with new SA-only and output floor columns, dedicated output floor comparison template (U-TREA vs S-TREA), flow diagram showing how IRB output floor columns feed into total capital, Pillar III cross-reference (UKB OV1/KM1)
- Docs: Add CIU exposure treatment to key-differences — three approaches (look-through, mandate-based, 1250% fallback), impact of IRB equity removal on CIU underlyings, and CIU transitional (Art. 4.7–4.8)
- Docs: Add IRB equity transitional to key-differences — floor-based transition for firms with existing IRB permission (Art. 4.4–4.6), irrevocable opt-out (Art. 4.9–4.10)
- Docs: Add post-model adjustments (PMAs) section to key-differences — new Basel 3.1 concept (Art. 146(3)) with no CRR equivalent
- Docs: Add retail-specific A-IRB LGD floor table to key-differences — 5% mortgage, 50% QRRE, 30% other unsecured, 30% LGDU
- Docs: Add "Why Basel 3.1?" section to framework comparison index — explains the rationale for transitioning from CRR (risk-weight variability, inadequate capital, IRB complexity) and how Basel 3.1 responds
Fixed¶
- Docs: Add missing sovereign (central govts, central banks, quasi-sovereigns) SA-only restriction to IRB approach tables — Art. 147A(1)(a) mandates SA for all sovereign exposures under Basel 3.1, removing F-IRB and A-IRB
- Docs: Add missing IPRE/HVCRE specialised lending Slotting-only restriction — Art. 147A(1)(c); replaces misleading "Specialised Lending (no PD)" row which conflated all SL sub-types
- Docs: Correct large corporate revenue threshold in
basel31.mdfrom >£500m to >£440m (Art. 147(4C)) - Docs: Correct equity transitional schedule — 2027 starts at 160%/220% (not 130%/160%) after implementation date shifted to 2027
- Docs: Split F-IRB senior LGD into financial entities (45%, unchanged) and other corporates (40%) — previously shown as single 40% row
- Docs: Correct large corporate threshold from >£500m to >£440m (Art. 147(4C))
- Docs: Correct correlation multiplier scope — 1.25x applies to financial sector entities (Art. 153(2)), not all large corporates
- Docs: Correct PD floor for retail mortgage from 0.05% to 0.10% (PRA Art. 163(1)(b))
- Docs: Correct PD floor for QRRE transactor from 0.03% to 0.05% (falls under "all other retail")
- Docs: Correct unfunded credit protection terminology — "cancel or change" (Art. 213(1)(c)(i)), not "change of control"
- Docs: Add Pillar III disclosure documentation covering 9 quantitative credit risk templates (OV1, CR4, CR5, CR6, CR6-A, CR7, CR7-A, CR8, CR10) with CRR and Basel 3.1 column/row definitions
- Docs: Add CRR vs Basel 3.1 disclosure differences page — template naming (UK→UKB), output floor rows, expanded risk weight columns, post-model adjustments, slotting CRM, equity transitional treatment
- Docs: Expand COREP template comparison documentation to cover all 9 key credit risk templates (C 07.00, C 08.01–08.07, C 09.01–09.02) — previously only C 07.00, C 08.01, C 08.02 were documented
- Docs: Add full CRR vs Basel 3.1 column/row reference for C 08.03 (PD ranges), C 08.04 (RWEA flow), C 08.06 (slotting), C 08.07 (scope of use), C 09.01 (geo SA), C 09.02 (geo IRB)
Fixed¶
- Docs: Correct Template Overview in reporting-differences.md — C 08.03 exists in CRR (PD ranges breakdown), not a new Basel 3.1 slotting template
Changed¶
- Engine: Simplify IRB engine module structure — extract
adjustments.py(defaulted treatment, post-model adjustments, EL shortfall) andguarantee.py(guarantee substitution) fromnamespace.py, deduplicate correlation/K/maturity-adjustment formulas informulas.py, remove dead code (_norm_cdf,_norm_ppf,IRBCalculationError)
Removed¶
- Engine: Remove unused
HierarchyLazyFramenamespace (hierarchy_namespace.py) — duplicated logic fromhierarchy.pyand was not used in production code - Engine: Remove unused
CRMLazyFramenamespace (crm/namespace.py) andHaircutsLazyFrame/HaircutsExprnamespaces (crm/haircuts_namespace.py) — independent reimplementations not used in production pipeline (CRMProcessor is the sole production API) - Engine: Remove unused
SALazyFrame/SAExprnamespaces (sa/namespace.py) — SACalculator uses private methods directly
Added¶
- Docs: New top-level "CRR vs Basel 3.1" section consolidating all framework comparison content — key differences, reporting differences, impact analysis, and technical reference
- Docs: New reporting differences page documenting COREP template changes between C-prefix (CRR) and OF-prefix (Basel 3.1) templates
- Docs: Add retail transactor (45%) and payroll/pension (35%) risk weights to framework comparison and Basel 3.1 guide
- Docs: Add equity risk weight section with 250%/400% structure and 2027-2029 transitional phase-in schedule
- Docs: Add currency mismatch 1.5x risk weight multiplier for unhedged FX retail/residential RE exposures
- Docs: Add SA specialised lending risk weights (Art. 122A-122B: object/commodities/project finance)
- Docs: Add CRM structural changes — Foundation Collateral Method, Parameter Substitution Method, overcollateralisation thresholds, change of control provisions
- Docs: Add exposure class priority waterfall restructuring (real estate as standalone class)
- Docs: Add institution ECRA/SCRA risk weight detail with short-term exposure weights
- Docs: Add financial sector entities to IRB A-IRB restrictions table
- Docs: Add IRB 10% RW floor for UK residential mortgages (PRA-specific)
- Docs: Add regional government/local authority and covered bond risk weight changes
- Docs: Add output floor OF-ADJ formula detail to technical reference
- Docs: Add full supervisory haircut comparison tables (CRR 3-band vs Basel 3.1 5-band)
- Docs: Add IRB maturity calculation changes (revolving: M = max contractual termination date)
- Docs: Add slotting subgrade detail (Strong A/B, Good C/D for residual maturity)
Changed¶
- Regulatory: Update all Basel 3.1 references from PRA PS9/24 (near-final) to PRA PS1/26 (final rules) across source code, documentation, tests, and workbooks
- Regulatory: Replace old PS9/24 and CP16/22 URLs with PS1/26 final rules links (policy statement, Appendix 1, Appendix 17)
- Regulatory: Mark CP16/22 consultation paper as superseded where retained for historical context
- CI: Add version consistency validation step to publish workflow
- CI: Add step to generate test fixtures in CI pipeline
- CI: Replace mypy with ty for type checking
- Docs: Migrate documentation from mkdocs to zensical (
zensical.tomlreplacesmkdocs.yml)
Removed¶
- Docs: Remove completed development roadmap (
docs/plans/roadmap.md) to reduce maintenance burden
Fixed¶
- Regulatory: Replace incorrect BCBS whole-loan LTV-band approach for general residential RE with PRA-mandated loan-splitting (Art. 124F) — secured portion (up to 55% of property value) at 20%, residual at counterparty RW
- Regulatory: Fix income-producing residential RE 60-70% LTV band risk weight from 45% to 40% per PRA Table 6B (Art. 124G)
- Docs: Fix incorrect Basel 3.1 haircut table in
basel31.md— equity haircuts are 25%/35% (not 15%/25%), long-dated bond haircuts also increased - Docs: Fix defaulted exposure comparison table to show residential RE flat 100% under Basel 3.1
- Docs: Fix residential RE tables to describe PRA loan-splitting instead of BCBS whole-loan table
- Docs: Fix mermaid diagrams not rendering by adding
custom_fencesconfiguration forpymdownx.superfences - Style: Update theme color palette to orange
Refactored¶
- Improve risk weight dictionary creation in test helpers
- Clean up code formatting and assertions in tests
[0.1.50] - 2026-04-01¶
Changed¶
- Version bump for PyPI release
[0.1.49] - 2026-03-30¶
Changed¶
- Version bump for PyPI release
[0.1.48] - 2026-03-29¶
Changed¶
- Version bump for PyPI release
[0.1.47] - 2026-03-28¶
Changed¶
- Version bump for PyPI release
[0.1.46] - 2026-03-28¶
Changed¶
- Version bump for PyPI release
[0.1.45] - 2026-03-27¶
Added¶
CCP Guarantor Risk Weight Support (CRR Art. 306 / CRE54.14-15)¶
CCP guarantors now receive the prescribed QCCP risk weight (2% proprietary / 4% client-cleared) instead of being treated as generic unrated institutions (40% RW). The guarantee substitution when/then chain in both the SA calculator and IRB namespace checks guarantor_entity_type == "ccp" before the institution/MDB branch, applying QCCP_PROPRIETARY_RW (2%) or QCCP_CLIENT_CLEARED_RW (4%) based on guarantor_is_ccp_client_cleared.
- CRM processor and namespace propagate
is_ccp_client_clearedfrom guarantor counterparty data - Entity type normalization (
.str.to_lowercase()) applied to guarantor entity type joins
[0.1.44] - 2026-03-25¶
Added¶
Article 114(4) EU domestic currency 0% risk weight for EU sovereigns¶
EU member state central government and central bank exposures denominated in that member state's domestic currency now receive 0% risk weight regardless of CQS, per CRR Art. 114(4). Covers all 27 EU member states: eurozone members (EUR) and non-euro members in their national currencies (PLN, SEK, CZK, DKK, HUF, BGN, RON). EU domestic sovereign exposures are also forced to the Standardised Approach, preventing internal models from overriding the regulatory 0% treatment. Applies to both direct exposures and guarantor risk weight substitution (SA and IRB).
is_ccp_client_clearedfield added to data generators
Fixed¶
- CCP exposures now forced to SA approach with correct risk weights (was falling through to generic corporate treatment)
[0.1.43] - 2026-03-24¶
Fixed¶
Guarantee application expanded to facility and counterparty levels¶
Guarantee application previously only matched at direct (loan/exposure/contingent) level. Guarantees linked at facility or counterparty level were silently ignored. Now supports multi-level beneficiary matching: direct, facility (pro-rata across facility's exposures), and counterparty (pro-rata across all counterparty exposures).
[0.1.42] - 2026-03-22¶
Fixed¶
Slotting maturity not derived from maturity_date¶
The is_short_maturity flag for CRR Art. 153(5) specialised lending was never calculated from exposure maturity_date. It defaulted to False, causing all exposures to receive the >= 2.5yr risk weights regardless of actual remaining maturity. Strong category exposures with <2.5yr maturity now correctly receive 50% RW (was 70%), Good receives 70% (was 90%), HVCRE Strong receives 70% (was 95%), and HVCRE Good receives 95% (was 120%).
prepare_columns()now acceptsCalculationConfigand derivesis_short_maturityfrommaturity_dateandreporting_date- Extracted
exact_fractional_years_exprto sharedengine/utils.py(reused by IRB and slotting) - Added
remaining_maturity_yearscolumn to slotting audit trail - Added CRR-E5 through CRR-E8 acceptance scenarios for short-maturity slotting
UK govt guarantee exposure marked "not beneficial" for non-sovereign entity types¶
Guarantor risk weight lookup used regex matching on guarantor_entity_type (e.g., contains("SOVEREIGN")), which only matched sovereign but not central_bank, bank, company, or mdb. These entity types produced null guarantor RW, causing beneficial guarantees to be incorrectly skipped. The lookup now uses guarantor_exposure_class (derived from the existing ENTITY_TYPE_TO_SA_CLASS mapping), ensuring all valid entity types resolve to the correct SA risk weight. Also adds Art. 114(3) domestic sovereign treatment: UK CGCB guarantors in GBP receive 0% RW regardless of CQS. Both SA calculator and IRB namespace are fixed. CRM processor and namespace now propagate guarantor_country_code from counterparty data.
[0.1.41] - 2026-03-22¶
Added¶
Article 114(3) domestic currency 0% risk weight for UK sovereign¶
UK central government and central bank exposures denominated in GBP now receive 0% risk weight regardless of CQS, per CRR Art. 114(3). Previously, 0% was only assigned via CQS 1 external rating lookup. The override applies in both CRR and Basel 3.1 SA risk weight chains. Foreign-currency UK sovereign exposures continue to use the standard CQS-based risk weight table.
[0.1.40] - 2026-03-22¶
Changed¶
Specialised lending now input-driven via counterparty_reference¶
Specialised lending metadata (sl_type, slotting_category, is_hvcre) is now supplied as an input file (exposures/specialised_lending.parquet) keyed by counterparty_reference, rather than being derived from counterparty reference naming conventions. This allows a corporate counterparty to have both SL and non-SL exposures, aligning with CRR Art. 147(8) and BCBS CRE30.6.
- New input file:
ratings/specialised_lending.parquet - Schema change:
exposure_referencereplaced withcounterparty_reference;remaining_maturity_yearsremoved (sourced from loan/facility data) - Removed dead code:
_build_slotting_category_expr(),_build_sl_type_expr(), and counterparty reference naming convention logic in the classifier
Fixed¶
FI scalar (apply_fi_scalar) not applied to IRB correlation¶
The apply_fi_scalar counterparty flag was gated on is_financial_sector_entity, which required the entity_type to be an institution-like value. Counterparties with entity_type="corporate" and apply_fi_scalar=True silently received no 1.25x correlation multiplier. The classifier now derives requires_fi_scalar directly from the user-supplied apply_fi_scalar flag.
Removed dead code: FINANCIAL_SECTOR_ENTITY_TYPES, is_financial_sector_entity, and is_large_financial_sector_entity — set in the classifier but never consumed by any calculation engine.
[0.1.39] - 2026-03-21¶
Fixed¶
- SME managed-as-retail 75% RW now correctly gated on EUR 1m turnover threshold check (was applying 75% RW without verifying threshold)
Changed¶
- Documentation aligned with current codebase state
[0.1.38] - 2026-03-20¶
Fixed¶
- Null
slotting_categoryandsl_typefor non-slotting exposures (was leaving stale values from classification) - Defaulted exposure treatment for SA risk weights now correctly implemented
- Case-insensitive column value validation (lowercase valid values set before comparison)
country_codesandexcluded_book_codescolumns inmodel_permissionsinput are now truly optional — when absent, treated as null (all geographies permitted, no book code exclusions). Previously causedColumnNotFoundError- Documentation aligned with code schemas across 13 files
[0.1.37] - 2026-03-17¶
Fixed¶
- Validation error messages now correctly convert file paths to string (was raising
TypeErrorforPathobjects)
[0.1.36] - 2026-03-15¶
Changed¶
Model ID moved from counterparty to ratings level (Breaking)¶
model_id has been moved from COUNTERPARTY_SCHEMA to RATINGS_SCHEMA. The rating inheritance pipeline now carries model_id alongside internal_pd through parent-child inheritance, eliminating the redundant counterparty-to-exposure propagation path.
- Removed:
model_idfromCOUNTERPARTY_SCHEMA - Added:
model_idtoRATINGS_SCHEMA - Updated: Rating inheritance pipeline carries
internal_model_idthrough coalesce (own → parent) - Updated:
_unify_exposures()sourcesmodel_idfrom rating inheritance instead of counterparty join - Updated: Fixture generators, integration tests, benchmark data generators, and documentation
- Counterparty data handling consolidated
[0.1.35] - 2026-03-11¶
Added¶
Integration Test Infrastructure¶
Comprehensive integration test suite covering the full pipeline from loader to output:
- Phase 1: Hierarchy → Classifier flow tests
- Phase 2: Classifier → CRM and CRM → Calculators flow tests
- Phase 3: Loader → Hierarchy, model permissions, and output floor tests
- Phase 4: Equity flow integration tests
- Integration test strategy document and shared infrastructure
Changed¶
model_idadded to counterparty-level schema (subsequently moved to ratings in 0.1.36)
[0.1.34] - 2026-03-10¶
Added¶
Model-Level IRB Permissions¶
Per-model IRB approach gating replaces the org-wide IRBPermissions config when a model_permissions input file is provided:
- New schema:
MODEL_PERMISSIONS_SCHEMAwithmodel_id,exposure_class,approach,country_codes,excluded_book_codes - New column:
model_idonFACILITY_SCHEMA,LOAN_SCHEMA,CONTINGENTS_SCHEMA— links exposures to their IRB model - Classifier:
_resolve_model_permissions()joins exposures with model permissions, filters by geography and book code, gates approach on both permission and data availability (AIRB requiresinternal_pd+lgd; FIRB requires onlyinternal_pd) - Backward compatible: When no
model_permissionsfile is present, org-wideIRBPermissionsfallback applies - Validation:
model_permissionsincluded invalidate_raw_data_bundle()andvalidate_bundle_values()for schema and value validation model_permissionsfixtures andmodel_idadded to exposure generators- API documentation updated
- 10 unit tests covering AIRB/FIRB gating, geography filters, book code exclusions, and backward compatibility
Rename is_regulated → apply_fi_scalar¶
Simplified FI scalar control on COUNTERPARTY_SCHEMA:
- Schema:
is_regulatedrenamed toapply_fi_scalar— direct user-controlled flag replacing the intermediate boolean - Classifier:
requires_fi_scalarnow derives fromis_financial_sector_entity AND cp_apply_fi_scalar(simpler than the previous two-condition inference fromis_regulated) - Documentation: All references updated across input schemas, architecture, and classification docs
[0.1.33] - 2026-03-09¶
Added¶
Dual Per-Type Rating Resolution¶
Rating inheritance now resolves best internal and best external rating per counterparty independently. CQS is an external-only concept; internal ratings carry PD values without internal CQS.
- Per-type columns:
internal_pd,internal_rating_value,external_cqs,external_rating_value - Per-type inheritance: own internal → parent internal, own external → parent external (independent chains)
- Removed internal CQS references throughout the codebase
Changed¶
- Enhanced netting facility handling in loan data
[0.1.32] - 2026-03-08¶
Added¶
netting_facility_referencefield added toLOAN_SCHEMAand loan data for explicit netting group assignment
[0.1.31] - 2026-03-07¶
Added¶
- Enhanced netting logic for facility siblings (pro-rata allocation within netting groups)
interest_for_eadfunction in CCF module to handle negative interest values
[0.1.30] - 2026-03-06¶
Added¶
Basel 3.1 Engine¶
Full Basel 3.1 framework implementation alongside existing CRR support:
- Revised SA risk weight tables (CRE20.7-26) with LTV-band risk weights for residential and commercial real estate
- Basel 3.1 supervisory haircuts and F-IRB LGD framework dispatch
- Output floor: SA-equivalent RWA calculation on all IRB rows with phase-in schedule
- Basel 3.1 acceptance tests: B31-B (F-IRB), B31-C (A-IRB), B31-D (CRM), B31-E (slotting), B31-G (provisions), B31-H (complex scenarios) — 116 tests total
- IRB: A-IRB LGD floors gated on
is_airbcolumn (CRE30.41) - IRB: QRRE transactor/revolver PD floor distinction (CRR Art. 147(5), CRE30.55)
Dual-Framework Comparison and Analysis¶
- M3.1: CRR vs Basel 3.1 side-by-side comparison with per-exposure RWA delta
- M3.2: Capital impact analysis with driver attribution
- M3.3: Transitional floor schedule modelling with year-by-year phase-in
- M3.4: Enhanced Marimo workbook for interactive impact analysis
EL Shortfall/Excess (CRR Art. 158-159)¶
Expected loss shortfall/excess computation for IRB portfolios, with portfolio-level Tier 2 credit cap per CRR Art. 62(d).
COREP Template Generation (FR-4.6 / M4.1)¶
Regulatory reporting templates for CRR firms following EBA/PRA COREP structure (Regulation (EU) 2021/451):
- C 07.00 — SA credit risk: original exposure, SA EAD, RWA by exposure class, plus risk weight band breakdown
- C 08.01 — IRB totals: original exposure, IRB EAD, RWA, expected loss, weighted-average PD/LGD/maturity by exposure class
- C 08.02 — IRB PD grade breakdown: obligor-grade-level detail with standard PD bands and exposure-weighted averages
COREPGeneratorclass withgenerate()andexport_to_excel()methodsResultExporter.export_to_corep()for multi-sheet Excel exportCalculationResponse.to_corep()convenience method
Programmatic Export API (FR-4.7)¶
Export calculation results to Parquet, CSV, and Excel formats programmatically.
On-Balance Sheet Netting (CRR Article 195)¶
Support for on-balance sheet netting of mutual claims when a legally enforceable netting agreement exists:
- New fields:
has_netting_agreementandnetting_facility_referenceonLOAN_SCHEMAandLoanfixture - Synthetic cash collateral: Negative-drawn netting-eligible loans generate cash collateral that reduces all positive-drawn sibling exposures pro-rata within the same netting facility
- Netting facility resolution: Priority chain — explicit
netting_facility_reference→root_facility_reference→parent_facility_reference - SA: EAD reduced by netting pool (cash = 0% haircut)
- F-IRB: LGD reduced via cash collateral path (0% LGD)
- FX mismatch: 8% haircut applied when currencies differ
Service API Documentation¶
Restructured user-facing documentation to promote the high-level Service API (quick_calculate, RWAService) as the primary entry point:
- Quick Start rewritten with 3-tier progression:
quick_calculateone-liner,RWAServicewith more control, full example with validation/export - New page:
docs/api/service.md— complete Service API reference - API Reference index features Service API as first module
Basel 3.1 Parameter Substitution for IRB Guarantors (CRE22.70-85)¶
IRB guarantee substitution parameters updated for Basel 3.1 framework.
CI/CD Pipeline¶
GitHub Actions workflow with lint, typecheck, and test jobs.
Changed¶
- Replaced
EnumwithStrEnumandIntEnumthroughout the codebase - Centralised data source configuration with
DataSourceRegistryreplacingRequiredFiles - Introduced
BaseRequestclass to reduce duplication in request models - Error factory functions updated to support
Pathtypes alongsidestr - Tests migrated to use
Pathfor file paths
Fixed¶
- Corporate bond haircut CQS grouping corrected per CRR Art. 224
- PD floors and transitional schedule corrected to PRA PS1/26
- Output floor
sa_rwacomputation fixed for acceptance tests - Benchmark data generators now include all schema columns (
is_buy_to_let,interest,bs_type,pledge_percentage,is_qrre_transactor) - Benchmark tests updated for current API:
_unify_exposuressignature (addedfacilitiesarg),CRMProcessor.get_crm_adjusted_bundle - Protocol test stubs updated to include
calculate_branchmethod
[0.1.29] - 2026-02-28¶
Added¶
- F-IRB acceptance tests and expected outputs (CRR-B1 through B7)
Changed¶
- Pipeline refactored to single-pass calculation for unified frame (filter-process-merge pattern)
- Classifier exposure classification logic optimized
- Hierarchy collateral allocation logic simplified
- RWA calculations simplified with filter-process-merge approach
Performance¶
- Pipeline optimizations: pre-computed classifier intermediates, deferred audit string, slimmed counterparty join, eliminated unnecessary
collect_schema()calls - Full CRR pipeline at 100K: ~1.7s mean (SA-only ~1.7s, CRR ~1.9s)
[0.1.28] - 2026-02-24¶
Added¶
- Benchmarking module for RWA Calculator performance testing
Performance¶
- Optimized aggregation data collection and processing
- Optimized hierarchy graph traversal methods
- Optimized exposure enrichment methods
- Optimized pledge resolution and validation in pipeline
[0.1.27] - 2026-02-22¶
Added¶
- Results caching with lazy loading for improved pipeline performance
Changed¶
- Replaced custom validation methods with shared utility functions across hierarchy, loader, pipeline, and processor
- Replaced
enable_irbboolean config withirb_approachenum for clearer IRB permission modelling - Optimized data materialization to reduce redundant
.collect()calls - Multiple speed optimization PRs merged (aggregator, formatters, validation)
[0.1.26] - 2026-02-21¶
Performance¶
- Optimized aggregator processing for large result sets
- Optimized formatter output generation
- Streamlined validation data processing to reduce overhead
- UI speed improvements for interactive calculator
[0.1.25] - 2026-02-20¶
Added¶
IRB Defaulted Exposure Treatment (CRR Art. 153(1)(ii), 154(1)(i))¶
- Defaulted exposures (PD=1.0) receive K=0 under F-IRB and K=max(0, LGD-BEEL) under A-IRB
- Expected loss = LGD × EAD for defaulted exposures
- CRR 1.06 scaling factor correctly applied to defaulted corporate exposures
- New CRR-I acceptance test group with 9 tests (I1 F-IRB corporate, I2 A-IRB retail, I3 A-IRB corporate with CRR scaling)
Fixed¶
- SME supporting factor now correctly uses drawn amount (not EAD) for tier threshold calculation
[0.1.24] - 2026-02-19¶
Added¶
Multi-Level SA Collateral Allocation¶
- Multi-level collateral allocation for SA EAD reduction with overcollateralisation compliance
- Haircut calculator enhancements for multi-level processing
[0.1.23] - 2026-02-17¶
Added¶
SA Provision Handling — Art. 111(2) Compliance¶
Provisions are now resolved before CCF application using a drawn-first deduction approach, compliant with CRR Art. 111(2):
Pipeline reorder:
New method: resolve_provisions() with multi-level beneficiary resolution:
- Direct (loan/exposure/contingent): provision matched to specific exposure
- Facility: distributed pro-rata across facility's exposures
- Counterparty: distributed pro-rata across all counterparty exposures
SA drawn-first deduction:
- provision_on_drawn = min(provision, max(0, drawn)) — absorbs provision against drawn first
- Remainder → provision_on_nominal — reduces nominal before CCF
- nominal_after_provision = nominal_amount - provision_on_nominal feeds into CCF
IRB/Slotting: Provisions tracked (provision_allocated) but NOT deducted from EAD (feeds EL shortfall/excess comparison)
New columns:
| Column | Type | Description |
|--------|------|-------------|
| provision_on_drawn | Float64 | Provision absorbed by drawn (SA only) |
| provision_on_nominal | Float64 | Provision reducing nominal before CCF (SA only) |
| nominal_after_provision | Float64 | nominal_amount - provision_on_nominal |
| provision_deducted | Float64 | Total = provision_on_drawn + provision_on_nominal |
| provision_allocated | Float64 | Total provision matched to this exposure |
Other changes:
- finalize_ead() no longer subtracts provisions (already baked into ead_pre_crm)
- _initialize_ead() preserves existing provision columns if set by resolve_provisions
- 14 unit tests in tests/unit/crm/test_provisions.py
- CCF test suite expanded to 57 tests
[0.1.22] - 2026-02-16¶
Changed¶
- Slotting risk weights updated for remaining maturity splits (CRR Art. 153(5))
- Config enhancements for slotting maturity bands
[0.1.21] - 2026-02-16¶
Added¶
Pledge Percentage for Collateral Valuation¶
- Introduced
pledge_percentagefield to allow collateral to be specified as a percentage of the beneficiary's EAD - Collateral processing resolves
pledge_percentageto absolute market values based on beneficiary type (loan, facility, or counterparty level) - Updated input schemas and CRM methodology documentation to reflect the new field
- 403 lines of new tests covering pledge percentage resolution across different beneficiary levels
[0.1.20] - 2026-02-14¶
Added¶
Equity Exposure FX Conversion¶
- New
convert_equity_exposures()method in FX converter for converting equity exposure values to reporting currency - Updated classifier and hierarchy to support equity exposures in FX conversion pipeline
- Enhanced FX rate configuration with equity-specific handling
- Comprehensive tests for equity exposure conversion and currency handling
[0.1.19] - 2026-02-11¶
Added¶
Buy-to-Let Flag¶
- New
is_buy_to_letboolean flag in hierarchy and schemas for identifying BTL exposures - BTL exposures excluded from SME supporting factor discount
- Unit tests verifying BTL flag behaviour in supporting factor calculations
On-Balance EAD Helper¶
- New
on_balance_ead()helper function in CCF module calculating EAD asmax(0, drawn) + interest - Updated CRM processor and namespace to use the new helper
- Comprehensive tests covering various on-balance EAD scenarios
Changed¶
- Updated implementation plan and roadmap documentation with current test results and fixture completion status
[0.1.18] - 2026-02-10¶
Added¶
Facility Hierarchy Enhancements¶
- Facility root lookup and undrawn calculations for full facility hierarchy resolution
- Include contingent liabilities in facility undrawn calculations
- Enhanced facility hierarchy resolution logic
[0.1.17] - 2026-02-10¶
Added¶
- CCF: handle negative drawn amounts in EAD calculations
Fixed¶
- Hierarchy: resolve duplicate mapping issues in facility calculations
[0.1.16] - 2026-02-09¶
Added¶
Cross-Approach CCF Substitution¶
- SA CCF expression and cross-approach substitution for guaranteed IRB exposures
- When an IRB exposure is guaranteed by an SA counterparty, the guaranteed portion uses SA CCFs
- New columns:
ccf_original,ccf_guaranteed,ccf_unguaranteed,guarantee_ratio,guarantor_approach,guarantor_rating_type
Aggregator Enhancements¶
- Updated summaries for post-CRM reporting
- Enhanced approach handling for IRB results
[0.1.15] - 2026-02-08¶
Added¶
- Correlation: rename sovereign exposure class to central govt/central bank
- CI: add GitHub Actions workflow for documentation deployment
[0.1.14] - 2026-02-07¶
Added¶
Overcollateralisation Requirements (CRR Art. 230 / CRE32.9-12)¶
Non-financial collateral now requires overcollateralisation to receive CRM benefit:
| Collateral Type | Overcollateralisation Ratio | Minimum Threshold |
|---|---|---|
| Financial | 1.0x | No minimum |
| Receivables | 1.25x | No minimum |
| Real estate | 1.4x | 30% of EAD |
| Other physical | 1.4x | 30% of EAD |
effectively_secured = adjusted_value / overcollateralisation_ratio- Financial vs non-financial collateral tracked separately for threshold checks
- Multi-level allocation respects overcollateralisation at each level
Changed¶
- Standardized
collateral_typecasing and descriptions across codebase
[0.1.13] - 2026-02-07¶
Added¶
Input Value Validation¶
validate_bundle_values()validates all categorical columns againstCOLUMN_VALUE_CONSTRAINTS- Error code
DQ006for invalid column values - Pipeline calls
_validate_input_data()as non-blocking step (errors collected, not raised)
Fixed¶
- Prevented row duplication in exposure joins when
facility_reference = loan_reference(#71)
[0.1.12] - 2026-02-02¶
Added¶
Equity Exposure Calculator¶
Complete equity exposure RWA calculation supporting two regulatory approaches:
Article 133 - Standardised Approach (SA): | Equity Type | Risk Weight | |-------------|-------------| | Central bank | 0% | | Listed/Exchange-traded/Government-supported | 100% | | Unlisted/Private equity | 250% | | Speculative | 400% |
Article 155 - IRB Simple Risk Weight Method: | Equity Type | Risk Weight | |-------------|-------------| | Central bank | 0% | | Private equity (diversified portfolio) | 190% | | Government-supported | 190% | | Exchange-traded/Listed | 290% | | Other equity | 370% |
New Components:
- EquityCalculator class (src/rwa_calc/engine/equity/calculator.py)
- EquityLazyFrame namespace (lf.equity) for fluent calculations
- EquityExpr namespace (expr.equity) for column-level operations
- EquityResultBundle for equity calculation results
- crr_equity_rw.py lookup tables
Features: - Automatic approach determination based on IRB permissions - Diversified portfolio treatment for private equity (190% vs 370%) - Full audit trail generation - Single exposure calculation convenience method
Pre/Post CRM Tracking for Guarantees¶
Enhanced guarantee processing with full tracking of exposure amounts before and after CRM application:
- rwa_pre_crm: RWA calculated on original exposure before guarantee
- rwa_post_crm: RWA calculated after guarantee substitution
- guarantee_rwa_benefit: Reduction in RWA from guarantee protection
- Supports both covered and uncovered portion tracking
Changed¶
- Pipeline now includes equity calculator between CRM and aggregator
CRMAdjustedBundleextended withequity_exposuresfield
[0.1.11] - 2026-01-28¶
Added¶
- Namespace: add exact fractional years calculation
- Config: add MCP server configuration
[0.1.10] - 2026-01-28¶
Added¶
- CCF: include interest in EAD calculations
[0.1.8] - 2026-01-28¶
Added¶
- Data: add script to generate sample data in parquet format
- Correlation: add SME adjustment with EUR/GBP conversion
- Orgs: make org_mappings optional in data loaders
Fixed¶
- Config: update EUR to GBP exchange rate
[0.1.7] - 2026-01-27¶
Added¶
- Tests: add unit tests for API error handling and validation
- Protocols: update aggregation method with new bundles
- Loader: enhance data loading with validation checks
- BDD: add specifications for CRR provisions, risk weights, and supporting factors
Changed¶
- Loans: update loan schema and documentation
[0.1.6] - 2026-01-25¶
Added¶
- Stats: implement backend detection for statistical functions
- Documentation: add detailed implementation plan and project roadmap
Changed¶
- Stats: remove dual stats backend implementation
- Documentation: update optional dependencies and installation instructions
[0.1.5] - 2026-01-25¶
Added¶
- Counterparties: enhance counterparty schema and classification
- Documentation: add logo to documentation theme
Changed¶
- CCF: remove unused CCF module and tests
- Contingents: remove ccf_category and update risk_type
Performance¶
- Benchmark: update results with improved metrics
[0.1.4] - 2026-01-25¶
Added¶
- Deploy: add automated deployment script
Performance¶
- Benchmark: transition to pure Polars expressions
[0.1.3] - 2025-01-24¶
Added¶
Documentation Code Linking¶
- Updated documentation to link code examples to actual source implementations
- Added
pymdownx.snippetsfor embedding real code from source files - Added
mkdocstringsauto-generated API documentation - New
docs/development/documentation-conventions.mdguide for contributors - Source code references with GitHub line number links throughout docs
Mandatory risk_type Column for CCF Determination¶
The risk_type column is now the authoritative source for CCF (Credit Conversion Factor) determination across all facility inputs:
New Columns:
- risk_type (mandatory) - Off-balance sheet risk category: FR, MR, MLR, LR
- ccf_modelled (optional) - A-IRB modelled CCF estimate (0.0-1.5, Retail IRB can exceed 100%)
- is_short_term_trade_lc (optional) - CRR Art. 166(9) exception flag
Risk Type Values (CRR Art. 111):
| Code | SA CCF | F-IRB CCF | Description |
|---|---|---|---|
| FR | 100% | 100% | Full risk - guarantees, credit substitutes |
| MR | 50% | 75% | Medium risk - NIFs, RUFs, committed undrawn |
| MLR | 20% | 75% | Medium-low risk - documentary credits, trade |
| LR | 0% | 0% | Low risk - unconditionally cancellable |
F-IRB Rules:
- CRR Art. 166(8): MR and MLR both become 75% CCF under F-IRB
- CRR Art. 166(9): Short-term trade LCs for goods movement retain 20% (set is_short_term_trade_lc=True)
A-IRB Support:
- When ccf_modelled is provided and approach is A-IRB, this value takes precedence
Removed¶
commitment_type Column and Legacy CCF Functions¶
The following have been removed as risk_type is now the authoritative CCF source:
Removed from schemas:
- commitment_type column from FACILITY_SCHEMA and all intermediate schemas
Removed from crr_ccf.py:
- lookup_ccf() function
- lookup_firb_ccf() function
- calculate_ead_off_balance_sheet() function
- create_ccf_type_mapping_df() function
Removed from ccf.py:
- calculate_single_ccf() method
- CCFResult dataclass
Migration: Replace commitment_type with risk_type:
- unconditionally_cancellable → LR (low_risk)
- committed_other → MR (medium_risk) or MLR (medium_low_risk)
FX Conversion Support (14 new tests)¶
Multi-currency portfolio support with configurable FX conversion:
FXConverter Module (src/rwa_calc/engine/fx_converter.py)
- convert_exposures() - Converts drawn, undrawn, and nominal amounts
- convert_collateral() - Converts market and nominal values
- convert_guarantees() - Converts covered amounts
- convert_provisions() - Converts provision amounts
- Factory function create_fx_converter()
Features:
- Configurable target currency via CalculationConfig.base_currency
- Enable/disable via CalculationConfig.apply_fx_conversion
- Full audit trail: original_currency, original_amount, fx_rate_applied
- Graceful handling of missing FX rates (values unchanged, rate = null)
- Early pipeline integration (HierarchyResolver) for consistent threshold calculations
Data Support:
- New FX_RATES_SCHEMA in src/rwa_calc/data/schemas.py
- fx_rates field added to RawDataBundle
- fx_rates_file config in DataSourceConfig
- Test fixtures in tests/fixtures/fx_rates/
Tests: - 14 unit tests covering all conversion scenarios - Tests for exposure, collateral, guarantee, and provision conversion - Multi-currency batch conversion tests - Alternative base currency tests (EUR, USD)
Polars Namespace Extensions (8 namespaces, 139 new tests)¶
The calculator now provides comprehensive Polars namespace extensions for fluent, chainable calculations across all approaches:
SA Namespace (lf.sa, expr.sa)
- SALazyFrame namespace for Standardised Approach calculations
- Methods: prepare_columns, apply_risk_weights, apply_residential_mortgage_rw, apply_cqs_based_rw, calculate_rwa, apply_supporting_factors, apply_all
- UK deviation handling for institution CQS 2 (30% vs 50%)
- 29 unit tests
IRB Namespace (lf.irb, expr.irb)
- IRBLazyFrame namespace for IRB calculations
- Methods: classify_approach, apply_firb_lgd, prepare_columns, apply_pd_floor, apply_lgd_floor, calculate_correlation, calculate_k, calculate_maturity_adjustment, calculate_rwa, calculate_expected_loss, apply_all_formulas
- Expression methods: floor_pd, floor_lgd, clip_maturity
- 33 unit tests
CRM Namespace (lf.crm)
- CRMLazyFrame namespace for EAD waterfall processing
- Methods: initialize_ead_waterfall, apply_collateral, apply_guarantees, apply_provisions, finalize_ead, apply_all_crm
- SA vs IRB treatment differences handled automatically
- 20 unit tests
Haircuts Namespace (lf.haircuts)
- HaircutsLazyFrame namespace for collateral haircut calculations
- Methods: classify_maturity_band, apply_collateral_haircuts, apply_fx_haircut, apply_maturity_mismatch, calculate_adjusted_value, apply_all_haircuts
- CRR Article 224 supervisory haircuts
- 24 unit tests
Slotting Namespace (lf.slotting, expr.slotting)
- SlottingLazyFrame namespace for specialised lending
- Methods: prepare_columns, apply_slotting_weights, calculate_rwa, apply_all
- CRR vs Basel 3.1 risk weight differences
- HVCRE treatment
- 26 unit tests
Hierarchy Namespace (lf.hierarchy)
- HierarchyLazyFrame namespace for hierarchy resolution
- Methods: resolve_ultimate_parent, calculate_hierarchy_depth, inherit_ratings, coalesce_ratings, calculate_lending_group_totals, add_lending_group_reference, add_collateral_ltv
- Pure LazyFrame join-based traversal (no Python recursion)
- 13 unit tests
Aggregator Namespace (lf.aggregator)
- AggregatorLazyFrame namespace for result combination
- Methods: combine_approach_results, apply_output_floor, calculate_floor_impact, generate_summary_by_class, generate_summary_by_approach, generate_supporting_factor_impact
- Basel 3.1 output floor support
- 12 unit tests
Audit Namespace (lf.audit, expr.audit)
- AuditLazyFrame namespace for audit trail generation
- Methods: build_sa_calculation, build_irb_calculation, build_slotting_calculation, build_crm_calculation, build_haircut_calculation, build_floor_calculation
- AuditExpr namespace for column formatting: format_currency, format_percent, format_ratio, format_bps
- 15 unit tests
Changed¶
- All calculators can now use namespace-based fluent APIs
- Improved code readability with chainable method calls
- Test count increased from 635 to 826 (139 namespace tests + 14 FX converter tests + 38 other tests)
[0.1.2] - 2025-01-24¶
Added¶
Interactive UI Console Command¶
- New
rwa-calc-uiconsole script for starting the UI server when installed from PyPI main()function added toserver.pyfor entry point
Documentation Improvements¶
- New
docs/user-guide/interactive-ui.md- comprehensive UI guide with prerequisites, all three apps, troubleshooting - Updated quickstart with "Choose Your Approach" section (UI vs Python API)
- Added Interactive UI to user guide navigation and recommendations
- Updated all server startup commands to show both PyPI and source installation methods
Changed¶
- Installation instructions clarified for PyPI vs source installations
- UI documentation moved from Development section to User Guide for better discoverability
[0.1.1] - 2025-01-22¶
Added¶
- FX conversion support for multi-currency portfolios
- Polars namespace extensions (8 namespaces)
- Retail classification flag (
cp_is_managed_as_retail)
[0.1.0] - 2025-01-18¶
Added¶
Core Framework¶
- Dual-framework support (CRR and Basel 3.1 configuration)
- Pipeline architecture with discrete processing stages
- Protocol-based component interfaces
- Immutable data contracts (bundles)
Data Loading¶
- Parquet file loader
- Schema validation
- Optional file handling
- Metadata tracking
Hierarchy Resolution¶
- Counterparty hierarchy resolution (up to 10 levels)
- Rating inheritance from parent
- Lending group aggregation
- LazyFrame-based join optimization
Classification¶
- All exposure classes supported
- Approach determination (SA/F-IRB/A-IRB/Slotting)
- SME identification
- Retail eligibility checking
- EAD calculation with CCFs
Standardised Approach¶
- Complete risk weight tables
- Sovereign, Institution, Corporate, Retail classes
- Real estate treatments
- Defaulted exposure handling
IRB Approach¶
- K formula implementation
- Asset correlation with SME adjustment
- Maturity adjustment
- PD and LGD floors
- Expected loss calculation
- 1.06 scaling factor (CRR)
Slotting Approach¶
- All specialised lending types
- Category-based risk weights
- HVCRE treatment
- Pre-operational project finance
Credit Risk Mitigation¶
- Financial collateral (comprehensive method)
- Supervisory haircuts
- Currency mismatch handling
- Guarantees (substitution approach)
- Maturity mismatch adjustment
- Provision allocation
Supporting Factors (CRR)¶
- SME supporting factor (tiered calculation)
- Infrastructure factor
Output¶
- Aggregated results
- Breakdown by approach/class/counterparty
- Export to Parquet/CSV/JSON
- Error accumulation and reporting
Configuration¶
- Factory methods (crr/basel_3_1)
- EUR/GBP rate configuration
- Configurable supporting factors
- PD floor configuration
Testing¶
- 468+ test cases
- Unit tests for all components
- Contract tests for interfaces
- Acceptance test framework
- Test fixtures generation
Documentation¶
- MkDocs with Material theme
- User guide for all audiences
- API reference
- Architecture documentation
- Development guide
Technical¶
- Python 3.13+ support
- Polars LazyFrame optimization
- Pydantic validation
- Type hints throughout
- Ruff formatting/linting
Version History¶
| Version | Date | Status |
|---|---|---|
| 0.1.50 | 2026-04-01 | Current |
| 0.1.49 | 2026-04-01 | Previous |
| 0.1.48 | 2026-03-30 | - |
| 0.1.47 | 2026-03-29 | - |
| 0.1.46 | 2026-03-28 | - |
| 0.1.45 | 2026-03-28 | - |
| 0.1.44 | 2026-03-25 | - |
| 0.1.43 | 2026-03-24 | - |
| 0.1.42 | 2026-03-22 | - |
| 0.1.41 | 2026-03-22 | - |
| 0.1.40 | 2026-03-22 | - |
| 0.1.39 | 2026-03-21 | - |
| 0.1.38 | 2026-03-20 | - |
| 0.1.37 | 2026-03-17 | - |
| 0.1.36 | 2026-03-15 | - |
| 0.1.35 | 2026-03-11 | - |
| 0.1.34 | 2026-03-10 | - |
| 0.1.33 | 2026-03-09 | - |
| 0.1.32 | 2026-03-08 | - |
| 0.1.31 | 2026-03-07 | - |
| 0.1.30 | 2026-03-06 | - |
| 0.1.29 | 2026-02-28 | - |
| 0.1.28 | 2026-02-24 | - |
| 0.1.27 | 2026-02-22 | - |
| 0.1.26 | 2026-02-21 | - |
| 0.1.25 | 2026-02-20 | - |
| 0.1.24 | 2026-02-19 | - |
| 0.1.23 | 2026-02-17 | - |
| 0.1.22 | 2026-02-16 | - |
| 0.1.21 | 2026-02-16 | - |
| 0.1.20 | 2026-02-14 | - |
| 0.1.19 | 2026-02-11 | - |
| 0.1.18 | 2026-02-10 | - |
| 0.1.17 | 2026-02-10 | - |
| 0.1.16 | 2026-02-09 | - |
| 0.1.15 | 2026-02-08 | - |
| 0.1.14 | 2026-02-07 | - |
| 0.1.13 | 2026-02-07 | - |
| 0.1.12 | 2026-02-02 | - |
| 0.1.11 | 2026-01-28 | - |
| 0.1.10 | 2026-01-28 | - |
| 0.1.8 | 2026-01-28 | - |
| 0.1.7 | 2026-01-27 | - |
| 0.1.6 | 2026-01-25 | - |
| 0.1.5 | 2026-01-25 | - |
| 0.1.4 | 2026-01-25 | - |
| 0.1.3 | 2025-01-24 | - |
| 0.1.2 | 2025-01-24 | - |
| 0.1.1 | 2025-01-22 | - |
| 0.1.0 | 2025-01-18 | Initial |
Migration Notes¶
From Previous Versions¶
This is the initial release. No migration required.
CRR to Basel 3.1¶
When transitioning calculations from CRR to Basel 3.1:
-
Update configuration:
-
Review impacted exposures:
- SME exposures (factor removal)
- Infrastructure exposures (factor removal)
-
Low-risk IRB portfolios (output floor)
-
Update data requirements:
- LTV data for Basel 3.1 real estate weights
- Transactor/revolver flags for QRRE
Deprecation Notices¶
CRR-Specific Features (End of 2026)¶
The following CRR-specific features will be removed from active use after December 2026:
- SME supporting factor
- Infrastructure supporting factor
- 1.06 scaling factor
These will remain available for historical calculations and comparison.
Contributing¶
See Development Guide for contribution guidelines.
Support¶
For issues and feature requests, please use the project's issue tracker.