Credit Risk Mitigation¶
Credit Risk Mitigation (CRM) techniques reduce the capital requirement for exposures by providing protection against default losses. The calculator supports collateral, guarantees, and provisions.
Overview¶
flowchart TD
A[Gross Exposure] --> B{CRM Available?}
B -->|Yes| C{CRM Type}
B -->|No| D[Calculate RWA on Gross]
C -->|Collateral| E[Apply Haircuts]
C -->|Guarantee| F[Substitution Approach]
C -->|Provision| G[Reduce EAD/EL]
E --> H[Net Exposure]
F --> I[Split Exposure]
G --> J[Adjusted Exposure]
H --> K[Calculate RWA]
I --> K
J --> K
D --> K
Collateral¶
Pledge Percentage¶
Collateral can be specified as a percentage of the beneficiary's EAD instead of an absolute market_value. Set pledge_percentage (decimal fraction, e.g. 0.5 = 50%) and leave market_value null or zero. The system resolves it to an absolute value before haircuts:
- Direct (loan/contingent):
market_value = pledge_percentage × exposure ead_gross - Facility:
market_value = pledge_percentage × sum(ead_gross)across all facility exposures - Counterparty:
market_value = pledge_percentage × sum(ead_gross)across all counterparty exposures
When market_value is provided (non-null, non-zero), it takes priority and pledge_percentage is ignored.
Financial Collateral¶
Financial collateral (cash, bonds, equity) directly reduces exposure.
Simple Method (SA Only)¶
The collateral's risk weight substitutes for the exposure's risk weight:
# Protected portion uses collateral issuer's RW
RWA_protected = Protected_Amount × Collateral_RW
# Unprotected portion uses counterparty RW
RWA_unprotected = Unprotected_Amount × Counterparty_RW
# Total
RWA = RWA_protected + RWA_unprotected
Comprehensive Method¶
Applies haircuts to both exposure and collateral. See crm/haircuts.py for the implementation.
Conceptual Formula
Supervisory Haircuts¶
Haircuts depend on collateral type, credit quality, and residual maturity. Cash has 0% haircut; government bonds range from 0.5% to 4% (CQS 1); equities are 15%-25%. A currency mismatch adds 8%.
Details: See CRM Specification for the complete haircut tables including Basel 3.1 changes (expanded maturity bands, increased equity haircuts).
Collateral Calculation Example¶
Exposure: - Corporate loan, £10m - Counterparty RW: 100%
Collateral: - Government bonds (CQS1), £8m - Residual maturity: 3 years - Same currency
Calculation (Comprehensive Method):
# Haircuts
H_e = 0% # Loan exposure
H_c = 2% # Govt bond 1-5yr
H_fx = 0% # Same currency
# Adjusted values
E_adjusted = 10,000,000 × (1 + 0.00) = 10,000,000
C_adjusted = 8,000,000 × (1 - 0.02 - 0.00) = 7,840,000
# Net exposure
E_star = max(0, 10,000,000 - 7,840,000) = 2,160,000
# RWA
RWA = 2,160,000 × 100% = £2,160,000
# vs. Gross RWA
Gross_RWA = 10,000,000 × 100% = £10,000,000
# Benefit: 78.4% reduction
Physical Collateral¶
Physical collateral (real estate, equipment) provides CRM for IRB by reducing the supervisory LGD. Basel 3.1 significantly reduces F-IRB supervisory LGD values (e.g. CRE/RRE from 35% to 20%).
Details: See Key Differences — F-IRB Supervisory LGD for the complete CRR vs Basel 3.1 comparison.
Eligibility Requirements: - Legal certainty of enforcement - Regular revaluation - Proper documentation - Insurance where appropriate
Overcollateralisation (CRR Art. 230)¶
Non-financial collateral must meet overcollateralisation requirements before it can provide CRM benefit. This ensures sufficient excess coverage to absorb valuation uncertainty.
Overcollateralisation Ratios¶
| Collateral Type | Required Ratio | Effectively Secured |
|---|---|---|
| Financial | 1.0x | Full adjusted value |
| Receivables | 1.25x | Adjusted value / 1.25 |
| Real estate | 1.4x | Adjusted value / 1.4 |
| Other physical | 1.4x | Adjusted value / 1.4 |
# Example: £1.4m of real estate collateral (after haircuts)
overcoll_ratio = 1.4
effectively_secured = 1_400_000 / 1.4 # = £1,000,000 of CRM benefit
Minimum Coverage Thresholds¶
Physical collateral must cover a minimum portion of EAD to provide any benefit:
| Collateral Type | Minimum Coverage |
|---|---|
| Financial | No minimum |
| Receivables | No minimum |
| Real estate | 30% of EAD |
| Other physical | 30% of EAD |
If the minimum threshold is not met, the non-financial collateral value is zeroed (no CRM benefit at all).
# Example: EAD = £1,000,000, RE collateral adjusted value = £200,000
# Coverage = 200,000 / 1,000,000 = 20% < 30% threshold
# Result: collateral value set to £0 (threshold not met)
Multi-Level Treatment¶
Financial and non-financial collateral are tracked separately through the multi-level allocation process (exposure, facility, counterparty levels). This ensures:
- Overcollateralisation ratios are applied per collateral type
- Minimum thresholds are checked against the total non-financial coverage
- Financial collateral is unaffected by the overcollateralisation requirements
Guarantees¶
Substitution Approach¶
The guaranteed portion is treated as an exposure to the guarantor:
flowchart LR
A[£10m Exposure] --> B{Guaranteed?}
B -->|£6m| C[Guarantor RW]
B -->|£4m| D[Counterparty RW]
C --> E[£6m × 20%]
D --> F[£4m × 100%]
E --> G[Total RWA = £5.2m]
F --> G
Eligible Guarantors¶
| Guarantor Type | Eligibility |
|---|---|
| Sovereigns | CQS1-3 |
| Institutions | CQS1-3 |
| Corporates | Rated corporates with lower RW |
| Parent Companies | Under certain conditions |
Qualifying CCP (QCCP) Guarantor Override (CRR Art. 306)¶
When the guarantor is a qualifying central counterparty (QCCP), the substituted risk weight on the guaranteed portion is overridden by the Art. 306 trade-exposure weights. This bypasses the normal institution CQS-keyed lookup and applies under both CRR and Basel 3.1 (Art. 306 is carried forward unchanged by PRA PS1/26):
| Trade Type | RW | Trigger | Reference |
|---|---|---|---|
| Proprietary trade exposure (own / clearing-member trades) | 2% | guarantor_entity_type == "ccp" and guarantor_is_ccp_client_cleared is False / null |
CRR Art. 306(1)(a); BCBS CRE54.14 |
| Client-cleared trade exposure | 4% | guarantor_entity_type == "ccp" and guarantor_is_ccp_client_cleared = True |
CRR Art. 306(1)(b); BCBS CRE54.15 |
The override fires inside the IRB guarantee SA-RW substitution path
(_compute_guarantor_rw_sa in
engine/irb/guarantee.py)
and the parallel SA path. It takes precedence over the institution
CQS-driven RW that would otherwise apply to a guarantor_exposure_class of
institution, and the guarantee-beneficiality test (guarantor RW < borrower
IRB RW) is then evaluated against the 2%/4% weight rather than the institution
CQS weight.
Scope: trade exposures only
Art. 306 covers trade exposures (initial margin, mark-to-market, cleared derivative positions). Default-fund contributions to a QCCP follow the separate Art. 308 / CRE54.16 risk-sensitive calculation and are not part of the guarantee substitution path. See the COREP CR-SA template mapping at Output Reporting Specification — Row 0150 / 0160 for how each is tagged.
Non-QCCPs do not get the override
If the guarantor is a CCP that is not qualifying (i.e. is_qccp = False),
Art. 306 does not apply: the guarantor falls back to the bilateral institution
treatment (CQS-keyed institution RW) for trade exposures, and default-fund
contributions attract the punitive 1250% / deduction treatment. The calculator
only fires the 2%/4% override when the entity is flagged as a CCP at the input
layer; QCCP qualification is a precondition the user data must already reflect.
Worked Example — QCCP-Guaranteed Bank Exposure¶
Exposure:
- Corporate loan, £10m, IRB obligor
- Pre-CRM IRB RW: 80%
Guarantee:
- Qualifying CCP, proprietary trade exposure
guarantor_entity_type = "ccp",guarantor_is_ccp_client_cleared = False- Guaranteed amount: £6m
Calculation:
# Guarantor RW from Art. 306(1)(a) override -- not the institution CQS table
guarantor_rw = 0.02 # 2% QCCP proprietary
# Beneficiality check: 2% < 80% -> guarantee is beneficial, applied
RWA_guaranteed = 6_000_000 * 0.02 = 120_000
RWA_unguaranteed = 4_000_000 * 0.80 = 3_200_000
RWA = 120_000 + 3_200_000 = 3_320_000
# vs. pre-CRM RWA = 10,000,000 * 0.80 = 8,000,000
# Benefit: 58.5% reduction
If the same guarantee had been a client-cleared trade exposure instead, the
override would yield 4% on the guaranteed portion (6_000_000 × 0.04 =
£240,000) — still substantially below any institution CQS RW.
See also: Institution Exposure Class — Central Counterparties for the SA direct-exposure side of the same Art. 306 mechanic.
Guarantee Requirements¶
- Direct claim on guarantor
- Unconditional - no conditions to payment
- Irrevocable - cannot be cancelled
- Legally enforceable in relevant jurisdictions
Double Default (CRR Only)¶
For qualifying guarantees under CRR, the double default treatment (Art. 153(3)) adjusts the risk-weighted exposure amount by a factor that reflects the guarantor's creditworthiness:
Where RW is calculated using the obligor's PD combined with the LGD of a comparable
direct exposure to the protection provider (per Art. 161(4)), PD_pp is the protection
provider's probability of default, and the maturity factor b is calculated using the lower
of the guarantor and obligor PDs. The scaling factor (0.15 + 160 × PD_pp) is less than 1
for investment-grade guarantors, providing meaningful capital relief.
Eligibility — protection provider (Art. 202):
- Must be an institution, investment firm, insurance/reinsurance undertaking, or export credit agency
- Must be regulated equivalently to the CRR, or had an ECAI assessment ≥ CQS 3 at the time the protection was provided (Art. 202(b))
- Must have had, at the time the protection was provided (or any period thereafter), an internal rating with PD equivalent to CQS 2 or better (Art. 202(c))
- Must currently have an internal rating with PD equivalent to CQS 3 or better (Art. 202(d))
- Export credit agency protection must not benefit from any explicit central government counter-guarantee
Eligibility — exposure & operational (Art. 153(3), Art. 154(2), Art. 217):
- Underlying exposure must be corporate, institution, central government/central bank, or retail SME (the latter via Art. 154(2) cross-reference to Art. 153(3))
- Obligor and protection provider must not be in the same group
- Risk weight on the underlying exposure must not already factor in any aspect of the credit protection
- The institution must hold A-IRB own-LGD permission for the relevant exposure class: Art. 153(3) requires the LGD of a comparable direct exposure to the protection provider (Art. 161(4)), which in turn presupposes the own-LGD recognition framework of Art. 161(3). Foundation-IRB firms (supervisory LGD per Art. 161(1)) cannot use the double-default formula and must fall back to Art. 235 risk weight substitution or Art. 236 parameter substitution.
The general Art. 161(3) floor still applies: the adjusted risk weight from the double-default treatment must not be lower than that of a comparable direct exposure to the guarantor.
Formal definition and full eligibility text: CRR Credit Risk Mitigation Specification.
Removed under Basel 3.1
PRA PS1/26 blanks Art. 153(3), Art. 202, and Art. 217 — the double default treatment is removed entirely. Guaranteed exposures must use parameter substitution (Art. 236) or risk weight substitution (Art. 235) instead. See A-IRB Specification for details.
Guarantee Example¶
Exposure: - SME loan, £5m - Counterparty RW: 100%
Guarantee: - UK Government (0% RW) - Guaranteed amount: £4m
Calculation:
# Guaranteed portion (G10 sovereign)
RWA_guaranteed = 4,000,000 × 0% = £0
# Unguaranteed portion
RWA_unguaranteed = 1,000,000 × 100% = £1,000,000
# Total RWA
RWA = £0 + £1,000,000 = £1,000,000
# vs. Gross RWA
Gross_RWA = £5,000,000
# Benefit: 80% reduction
Maturity Mismatch (CRR Art. 237–239)¶
When protection residual maturity < exposure residual maturity, the credit protection is either disallowed entirely (Art. 237 eligibility gates) or its value is scaled down by the Art. 239 adjustment factor.
# Maturity inputs (CRR Art. 238 — measurement of T and t):
# t = residual maturity of the credit protection (years)
# T = min(residual exposure maturity, 5) # 5-year cap per Art. 238
# The 5-year cap on T is the rule that distinguishes the maturity-mismatch
# treatment from the IRB maturity adjustment in Art. 162.
t = max(0.25, protection_residual_maturity)
T = min(max(0.25, exposure_residual_maturity), 5.0) # Art. 238: cap T at 5 years
# Adjustment factor (CRR Art. 239(2) for funded, Art. 239(3) for unfunded):
# funded: CVAM = CVA × (t − 0.25) / (T − 0.25)
# unfunded: GA = G* × (t − 0.25) / (T − 0.25)
# Note: the multiplier is identical between Art. 239(2) and (3); only the
# protection input (CVA vs G*) differs.
if t >= T:
adjustment = 1.0
elif t < 0.25:
adjustment = 0.0 # Art. 237(1) — below 3-month floor, protection ineligible
else:
adjustment = (t - 0.25) / (T - 0.25)
# Adjusted protection
Adjusted_Protection = Protection × adjustment
Example: - Exposure residual maturity: 5 years (so T = min(5, 5) = 5) - Guarantee residual maturity: 3 years (so t = 3)
adjustment = (3 - 0.25) / (5 - 0.25) = 2.75 / 4.75 = 0.579
# £4m guarantee provides £2.32m effective protection (Art. 239(3) GA)
Cap matters when exposure maturity > 5 years
For an exposure with residual maturity of 7 years and a guarantee with
residual maturity of 5 years, T is capped at 5 (not 7), so
adjustment = (5 − 0.25) / (5 − 0.25) = 1.0 — i.e. the guarantee is
treated as fully matched. Without the Art. 238 cap the same case
would scale the guarantee down to (5 − 0.25) / (7 − 0.25) ≈ 0.704.
Spec: see CRR CRM Specification — Maturity Mismatch (Art. 237–239) for the full eligibility gates, the Art. 238(1A) list of in-scope CRM methods, and the Basel 3.1 (PS1/26) carry-forward note.
On-Balance Sheet Netting (CRR Art. 195 / Art. 219)¶
When a legally enforceable netting agreement exists, mutual claims covered by that agreement can be netted. In practice, this means a negative drawn amount (credit balance / deposit) on one loan can reduce other exposures covered by the same netting agreement. Netting is driven solely by a shared netting_agreement_reference — the agreement is the legal right-of-set-off boundary, so netting follows the reference rather than facility hierarchy or counterparty. A deposit booked against one counterparty can net a loan to a different counterparty (and under a different facility) when both carry the same reference.
CRR Art. 219 limits on-balance-sheet netting to drawn loans and deposits — it is a cash-on-cash mechanism. Off-balance-sheet items (contingent exposures and synthetic facility-undrawn rows representing unused commitment headroom) are not eligible to receive the netting benefit.
How It Works¶
The calculator implements netting as synthetic cash collateral:
- Loans with a non-null
netting_agreement_referenceanddrawn_amount < 0contribute their absolute drawn amount to a netting pool per(netting_agreement_reference, currency) - The pool is allocated pro-rata by drawn portion (
on_bs_for_ead) to positive-drawn loan siblings carrying the same reference — contingents and facility-undrawn rows are excluded per Art. 219; facility hierarchy and counterparty are irrelevant to the match - Each allocation becomes a synthetic cash collateral row fed into the existing collateral pipeline
This reuses the full collateral mechanics:
- SA: Cash collateral (0% haircut) directly reduces EAD
- F-IRB: Cash collateral has 0% LGD → weighted LGD reduction
- FX mismatch: 8% haircut if the negative-drawn loan's currency differs from the positive sibling's
No Double-Counting¶
- The negative-drawn loan's own EAD is already floored to 0 by
drawn_for_ead()— it never self-reduces - The synthetic collateral only benefits positive-drawn siblings — distinct mechanism
Input Data¶
Set netting_agreement_reference to the same value on every exposure covered by one netting agreement — both the negative-drawn deposit and the loans it offsets. Exposures with no reference are never netted. No facility or counterparty linkage is required: the reference alone defines the netting set.
Example¶
# Two loans (any facility / counterparty) sharing netting_agreement_reference = "AGR1":
# Loan A: drawn = -200 (credit balance), netting_agreement_reference = "AGR1"
# Loan B: drawn = 1000, netting_agreement_reference = "AGR1"
# Result (SA):
# Loan A EAD = 0 (floored)
# Loan B EAD = 1000 - 200 = 800 (reduced by synthetic cash collateral)
A mixed facility containing a drawn loan, a contingent guarantee, and an undrawn commitment receives the full netting benefit on the drawn loan only:
# Exposures sharing netting_agreement_reference = "AGR1":
# Loan A: drawn = -300 (deposit), netting_agreement_reference = "AGR1"
# Loan B: drawn = 500 (drawn loan), netting_agreement_reference = "AGR1"
# Contingent C: nominal = 1000 (off-balance-sheet guarantee)
# Facility undrawn: undrawn = 2000 (synthetic row for unused headroom)
# Result (SA): the full 300 nets against Loan B only.
# Loan B EAD = 500 - 300 = 200
# Contingent C EAD = unchanged from its CCF-based value
# Facility undrawn EAD = unchanged from its CCF-based value
Cross-Approach CCF Substitution¶
When an IRB exposure is guaranteed by a counterparty that falls under the Standardised Approach, the guaranteed portion uses SA CCFs instead of the IRB supervisory CCFs. This reflects the principle that the risk of the guaranteed portion should be treated consistently with the guarantor's approach.
When It Applies¶
Cross-approach CCF substitution triggers when:
- The exposure is under F-IRB or A-IRB
- The guarantor's approach is determined to be SA — either because:
- The firm does not have IRB permission for the guarantor's exposure class, OR
- The guarantor only has an external rating (no internal PD estimate)
Guarantor Approach Determination¶
The guarantor's approach depends on three factors:
| Condition | Guarantor Approach |
|---|---|
| Firm has IRB permission for guarantor's class AND guarantor has internal rating (PD) | IRB |
| Firm lacks IRB permission for guarantor's class | SA |
| Guarantor has external rating only (no PD) | SA |
For example, a sovereign guarantor rated CQS 1 with no internal PD will always be treated as SA, even if the firm has F-IRB permission for sovereign exposures.
EAD Recalculation¶
When the guarantor approach is SA, the exposure's EAD is recalculated with a split:
# Original EAD uses IRB CCF
ead_original = drawn + undrawn × ccf_irb
# Guaranteed portion recalculated with SA CCF
ead_guaranteed = guarantee_ratio × (drawn + undrawn × ccf_sa)
# Unguaranteed portion retains IRB CCF
ead_unguaranteed = (1 - guarantee_ratio) × (drawn + undrawn × ccf_irb)
Output Columns¶
The cross-approach CCF process adds these columns:
| Column | Description |
|---|---|
ccf_original |
Original IRB CCF |
ccf_guaranteed |
CCF for guaranteed portion (SA if cross-approach) |
ccf_unguaranteed |
CCF for unguaranteed portion (IRB) |
guarantee_ratio |
Proportion guaranteed |
guarantor_approach |
"sa" or "irb" |
guarantor_rating_type |
"internal" or "external" |
Regulatory Reference¶
CRR Article 153(3) and CRE31.4 — when a guarantee provides credit protection, the CCF applicable to the protected portion should be consistent with the guarantor's treatment.
Provisions¶
SA Treatment (Art. 111(1)(a)-(b) Compliant)¶
Provisions are resolved before CCF application using a drawn-first deduction approach:
# Step 1: Drawn-first deduction
provision_on_drawn = min(provision_allocated, max(0, drawn_amount))
# Step 2: Remainder reduces nominal before CCF
provision_on_nominal = provision_allocated - provision_on_drawn
nominal_after_provision = nominal_amount - provision_on_nominal
# Step 3: CCF applied to adjusted nominal
ead_from_ccf = nominal_after_provision × CCF
# Step 4: Final EAD
EAD = (max(0, drawn_amount) - provision_on_drawn) + interest + ead_from_ccf
RWA = EAD × Risk_Weight
Provisions are allocated via multi-level beneficiary resolution:
- Direct (loan/exposure/contingent): provision matched to specific exposure
- Facility: provision distributed pro-rata across facility's exposures
- Counterparty: provision distributed pro-rata across all counterparty exposures
IRB Treatment¶
Under IRB, provisions are tracked (provision_allocated) but not deducted from EAD. Instead, the calculator computes Expected Loss for comparison:
# Provisions NOT deducted from EAD (provision_deducted = 0)
# provision_on_drawn = 0, provision_on_nominal = 0
EL = PD × LGD × EAD
if Provisions >= EL:
# Excess provisions can be added to Tier 2 (limited)
Excess = Provisions - EL
else:
# Shortfall deducted from CET1
Shortfall = EL - Provisions
SCRA and GCRA Provisions¶
| Type | Description | Treatment |
|---|---|---|
| SCRA | Specific Credit Risk Adjustments | Reduce EAD directly |
| GCRA | General Credit Risk Adjustments | May be included in Tier 2 |
Provision Allocation¶
Provisions can be allocated at different levels:
| Level | Application |
|---|---|
| Counterparty | Applies to all exposures |
| Facility | Applies to facility and sub-loans |
| Loan | Applies to specific loan |
CRM Hierarchy¶
When multiple CRM types are available, provisions are resolved first (before CCF), then the remaining CRM is applied after EAD initialization:
# Order of application (Art. 111(1)(a)-(b) compliant)
1. Resolve provisions (before CCF) — drawn-first deduction, adjusts nominal
2. Apply CCFs (uses nominal_after_provision for off-balance sheet conversion)
3. Initialize EAD waterfall
4. Apply collateral (reduce net exposure with haircuts)
5. Apply guarantees (substitution on remainder)
6. Finalize EAD (no further provision subtraction)
Example with Multiple CRM¶
Exposure: - Corporate loan, £10m - Counterparty RW: 100%
CRM: - Specific provision: £1m - Cash collateral: £3m - Bank guarantee (20% RW): £4m
Calculation:
# Step 1: Apply provision
Net_1 = 10,000,000 - 1,000,000 = 9,000,000
# Step 2: Apply collateral (no haircut for cash)
Net_2 = 9,000,000 - 3,000,000 = 6,000,000
# Step 3: Apply guarantee (substitution)
Guaranteed = min(4,000,000, 6,000,000) = 4,000,000
Unguaranteed = 6,000,000 - 4,000,000 = 2,000,000
# Calculate RWA
RWA_guaranteed = 4,000,000 × 20% = 800,000
RWA_unguaranteed = 2,000,000 × 100% = 2,000,000
Total_RWA = £2,800,000
# vs. Gross RWA = £10,000,000
# Benefit: 72% reduction
Implementation¶
The CRM processing is implemented in crm/processor.py and crm/haircuts.py.
CRM Processor¶
from rwa_calc.engine.crm.processor import CRMProcessor
from rwa_calc.contracts.config import CalculationConfig
from datetime import date
config = CalculationConfig.crr(reporting_date=date(2026, 12, 31))
# Create processor (regime behaviour reads from the resolved rulepack
# threaded through the pipeline, not a constructor flag)
processor = CRMProcessor()
# Process exposures through CRM pipeline — returns CRMAdjustedBundle
result = processor.get_crm_unified_bundle(
data=classified_exposures_bundle,
config=config,
)
# Access adjusted exposures (unified frame; filter on `approach` if needed)
adjusted = result.exposures # All exposures with CRM adjustments
sa_adjusted = adjusted.filter(pl.col("approach") == "standardised")
rwa_calc.engine.crm.processor.CRMProcessor
¶
Apply credit risk mitigation to exposures.
Implements CRMProcessorProtocol for: - CCF application for off-balance sheet items (CRR Art. 111) - Collateral haircuts and allocation (CRR Art. 223-224) - Guarantee substitution (CRR Art. 213-215) - Provision deduction (CRR Art. 110)
The CRM process follows this order: 1. Apply CCF to calculate base EAD for contingents 2. Apply collateral (reduce EAD for SA, reduce LGD for IRB) 3. Apply guarantees (substitution approach) 4. Deduct provisions from EAD
get_crm_unified_bundle(data, config, *, pack=None)
¶
Apply CRM on the unified exposure frame (single-pass pipeline).
Runs the full CRM chain — look-through, provisions, CCF, collateral
(Comprehensive, plus FCSM precompute under a Simple Method election),
life insurance, guarantees — and returns the unified LazyFrame for
the calculators' approach split. Laziness is strictly intra-stage:
the two sanctioned checkpoints (crm_post_ead,
crm_pre_guarantee_unified) and the crm_exit stage edge keep
the plan shallow.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
data
|
ClassifiedExposuresBundle
|
Classified exposures from classifier |
required |
config
|
CalculationConfig
|
Calculation configuration |
required |
pack
|
ResolvedRulepack | None
|
Resolved rulepack for the run's regime/date (Phase 5 — the
source of regulatory values, e.g. the Art. 222 FCSM floors).
Production passes the orchestrator's pack; direct callers may
omit it, in which case sub-steps resolve one from |
None
|
Returns:
| Type | Description |
|---|---|
CRMAdjustedBundle
|
CRMAdjustedBundle with all exposures in the unified frame |
resolve_provisions(exposures, provisions, config, *, pack=None)
¶
Resolve provisions with multi-level beneficiary and drawn-first deduction.
apply_collateral(exposures, collateral, config, *, pack=None)
¶
Apply collateral to reduce EAD (SA) or LGD (IRB).
apply_guarantees(exposures, guarantees, counterparty_lookup, config, rating_inheritance=None, *, pack=None)
¶
Apply guarantee substitution.
CRM Processor Implementation (processor.py)
See CRMProcessor.get_crm_unified_bundle() in
src/rwa_calc/engine/crm/processor.py for the full pipeline implementation.
Haircut Calculator¶
from rwa_calc.engine.crm.haircuts import HaircutCalculator
from decimal import Decimal
calculator = HaircutCalculator()
# Calculate haircut for a single collateral item
result = calculator.calculate_single_haircut(
collateral_type="govt_bond",
market_value=Decimal("8000000"),
collateral_currency="GBP",
exposure_currency="GBP",
cqs=1,
residual_maturity_years=3.0,
)
print(f"Collateral haircut: {result.collateral_haircut:.1%}")
print(f"Adjusted value: {result.adjusted_value:,.0f}")
Haircut Application (haircuts.py)
See HaircutCalculator.apply_collateral_haircuts() in src/rwa_calc/engine/crm/haircuts.py
for the Polars expression implementation of supervisory haircuts.
CRM Data Structure¶
The calculator accepts CRM data at multiple levels. The beneficiary_reference column links CRM items to exposures at the appropriate level (direct exposure, facility, or counterparty):
# Collateral data
collateral = {
"collateral_reference": "COL001",
"beneficiary_reference": "CP001", # Links to exposure/facility/counterparty
"collateral_type": "cash",
"market_value": 1_000_000,
"collateral_currency": "GBP",
"issuer_cqs": None, # For bonds
"residual_maturity": None, # For bonds
}
# Guarantee data
guarantee = {
"guarantee_reference": "GAR001",
"beneficiary_reference": "CP001", # Protected party
"guarantor": "GP001",
"amount_covered": 5_000_000,
"guarantor_type": "SOVEREIGN",
"guarantor_cqs": 1,
"maturity_date": date(2028, 12, 31),
}
# Provision data
provision = {
"provision_reference": "PRV001",
"beneficiary_reference": "CP001", # Links to exposure/facility/counterparty
"provision_type": "SCRA",
"amount": 500_000,
"ifrs_stage": "STAGE_3",
}
Regulatory References¶
| Topic | CRR Article | BCBS CRE |
|---|---|---|
| On-balance sheet netting | Art. 195 | CRE22.11-14 |
| CRM overview | Art. 192-194 | CRE22.1-10 |
| Financial collateral | Art. 197-200 | CRE22.35-70 |
| Haircuts | Art. 224-227 | CRE22.50-55 |
| Guarantees | Art. 213-216 | CRE22.71-85 |
| Maturity mismatch | Art. 237–239 | CRE22.90-95 |
| Physical collateral | Art. 199 | CRE22.100-120 |
| Overcollateralisation | Art. 230 | CRE32.9-12 |
Next Steps¶
- Supporting Factors - SME and infrastructure factors
- Standardised Approach - SA with CRM
- IRB Approach - IRB with CRM