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¶
| Collateral Type | Residual Maturity | Haircut (H_c) |
|---|---|---|
| Cash | Any | 0% |
| Government/PSE CQS1 | ≤1 year | 0.5% |
| 1-5 years | 2% | |
| >5 years | 4% | |
| Government/PSE CQS2-3 | ≤1 year | 1% |
| 1-5 years | 3% | |
| >5 years | 6% | |
| Corporate CQS1 | ≤1 year | 1% |
| 1-5 years | 4% | |
| >5 years | 8% | |
| Corporate CQS2-3 | ≤1 year | 2% |
| 1-5 years | 6% | |
| >5 years | 12% | |
| Main Index Equity | Any | 15% |
| Other Listed Equity | Any | 25% |
| Gold | Any | 15% |
Currency Mismatch (H_fx):
# Add 8% if collateral currency ≠ exposure currency
if collateral_currency != exposure_currency:
H_fx = 0.08
else:
H_fx = 0.00
Exposure Haircut (H_e)¶
For repos and similar transactions:
| Exposure Type | Haircut (H_e) |
|---|---|
| Government bonds CQS1 | Same as H_c table |
| Corporate bonds | Same as H_c table |
| Equity | 0% (exposure side) |
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:
| Collateral Type | CRR F-IRB LGD | Basel 3.1 F-IRB LGD |
|---|---|---|
| Residential Real Estate | 35% | 20% |
| Commercial Real Estate | 35% | 20% |
| Receivables | 35% | 20% |
| Other Physical | 40% | 25% |
| Unsecured | 45% | 40% |
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 |
Guarantee Requirements¶
- Direct claim on guarantor
- Unconditional - no conditions to payment
- Irrevocable - cannot be cancelled
- Legally enforceable in relevant jurisdictions
Double Default (CRR)¶
For qualifying guarantees, the double default treatment may apply:
# Probability both obligor AND guarantor default
PD_joint = PD_obligor × PD_guarantor × (1 + correlation)
# Typically results in lower RWA
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¶
When protection maturity < exposure maturity:
# Minimum protection maturity: 3 months (0.25 years)
t = max(0.25, protection_residual_maturity)
T = min(max(0.25, exposure_residual_maturity), 5.0) # Capped at 5 years
# Adjustment factor
if t >= T:
adjustment = 1.0
elif t < 0.25:
adjustment = 0.0 # Below minimum — no protection
else:
adjustment = (t - 0.25) / (T - 0.25)
# Adjusted protection
Adjusted_Protection = Protection × adjustment
Example: - Exposure maturity: 5 years - Guarantee maturity: 3 years
adjustment = (3 - 0.25) / (5 - 0.25) = 2.75 / 4.75 = 0.579
# £4m guarantee provides £2.32m effective protection
On-Balance Sheet Netting (CRR Art. 195)¶
When a legally enforceable netting agreement exists, mutual claims between the firm and the counterparty can be netted. In practice, this means a negative drawn amount (credit balance / deposit) on one loan can reduce sibling exposures within the same facility.
How It Works¶
The calculator implements netting as synthetic cash collateral:
- Loans with
has_netting_agreement = Trueanddrawn_amount < 0contribute their absolute drawn amount to a netting pool per(netting_facility, currency), where the netting facility is determined by priority:netting_facility_reference→root_facility_reference→parent_facility_reference - The pool is allocated pro-rata by
ead_grossto all positive-drawn siblings in the same netting facility — siblings benefit regardless of their ownhas_netting_agreementflag - 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 has_netting_agreement = True on the negative-drawn loan record to enable netting. The loan must be under a facility (parent_facility_reference is not null) for netting to apply.
Optionally set netting_facility_reference to explicitly control which facility defines the netting group. If omitted, the calculator uses root_facility_reference (top-level facility in the hierarchy) or falls back to parent_facility_reference.
Example¶
# Facility FAC_01 with two loans:
# Loan A: drawn = -200 (credit balance), has_netting_agreement = True
# Loan B: drawn = 1000, has_netting_agreement = True
# Result (SA):
# Loan A EAD = 0 (floored)
# Loan B EAD = 1000 - 200 = 800 (reduced by synthetic cash collateral)
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(2) 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(2) 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
processor = CRMProcessor(is_basel_3_1=config.is_basel_3_1)
# Process exposures through CRM pipeline — returns CRMAdjustedBundle
result = processor.get_crm_adjusted_bundle(
data=classified_exposures_bundle,
config=config,
)
# Access adjusted exposures (split by approach)
adjusted = result.exposures # All exposures with CRM adjustments
sa_adjusted = result.sa_exposures
irb_adjusted = result.irb_exposures
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
apply_crm(data, config)
¶
Apply credit risk mitigation to exposures.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
data
|
ClassifiedExposuresBundle
|
Classified exposures from classifier |
required |
config
|
CalculationConfig
|
Calculation configuration |
required |
Returns:
| Type | Description |
|---|---|
LazyFrameResult
|
LazyFrameResult with CRM-adjusted exposures and any errors |
get_crm_adjusted_bundle(data, config)
¶
Apply CRM and return as a bundle.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
data
|
ClassifiedExposuresBundle
|
Classified exposures from classifier |
required |
config
|
CalculationConfig
|
Calculation configuration |
required |
Returns:
| Type | Description |
|---|---|
CRMAdjustedBundle
|
CRMAdjustedBundle with adjusted exposures |
resolve_provisions(exposures, provisions, config)
¶
Resolve provisions with multi-level beneficiary and drawn-first deduction.
apply_collateral(exposures, collateral, config)
¶
Apply collateral to reduce EAD (SA) or LGD (IRB).
apply_guarantees(exposures, guarantees, counterparty_lookup, config, rating_inheritance=None)
¶
Apply guarantee substitution.
CRM Processor Implementation (processor.py)
See CRMProcessor.apply_crm() and CRMProcessor.get_crm_adjusted_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. 238-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