Skip to content

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

# Exposure with volatility adjustment
E_adjusted = E × (1 + H_e)

# Collateral with haircuts
C_adjusted = C × (1 - H_c - H_fx)

# Net exposure
E_star = max(0, E_adjusted - C_adjusted)

# RWA on net exposure
RWA = E_star × Risk_Weight

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

  1. Direct claim on guarantor
  2. Unconditional - no conditions to payment
  3. Irrevocable - cannot be cancelled
  4. 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:

  1. Loans with has_netting_agreement = True and drawn_amount < 0 contribute their absolute drawn amount to a netting pool per (netting_facility, currency), where the netting facility is determined by priority: netting_facility_referenceroot_facility_referenceparent_facility_reference
  2. The pool is allocated pro-rata by ead_gross to all positive-drawn siblings in the same netting facility — siblings benefit regardless of their own has_netting_agreement flag
  3. 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:

  1. The exposure is under F-IRB or A-IRB
  2. The guarantor's approach is determined to be SA — either because:
  3. The firm does not have IRB permission for the guarantor's exposure class, OR
  4. 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