IRB Approach¶
The Internal Ratings-Based (IRB) approach allows banks with regulatory approval to use their own risk estimates for calculating RWA. This provides greater risk sensitivity than the Standardised Approach.
Overview¶
Two IRB variants are available:
| Approach | PD | LGD | EAD | CCF |
|---|---|---|---|---|
| Foundation IRB (F-IRB) | Bank | Supervisory | Supervisory | Supervisory |
| Advanced IRB (A-IRB) | Bank | Bank | Bank | Bank |
Basel 3.1 Restrictions
Under Basel 3.1, A-IRB is no longer permitted for: - Large corporates (revenue > £440m) - Banks/Financial Institutions - Equity exposures
IRB Formula¶
The core IRB formula calculates the capital requirement (K). See irb/formulas.py for the pure Polars implementation.
Where: - N() = Standard normal cumulative distribution function - G() = Inverse standard normal distribution function - R = Asset correlation - PD = Probability of Default - LGD = Loss Given Default - MA = Maturity Adjustment (for non-retail)
Then:
Stats Backend¶
The IRB formulas require statistical functions (normal CDF and inverse CDF). The calculator uses polars-normal-stats for native Polars CDF/PPF expressions.
Capital K Formula Implementation (formulas.py)
See the _polars_capital_k_expr() function in src/rwa_calc/engine/irb/formulas.py
for the full Polars expression implementation.
Risk Parameters¶
Probability of Default (PD)¶
PD is the likelihood of default within one year. CRR uses a uniform 0.03% floor; Basel 3.1 introduces differentiated floors (0.03%–0.10%) by exposure class.
Loss Given Default (LGD)¶
LGD is the percentage of exposure lost after recoveries. F-IRB uses supervisory values (0%–75% depending on collateral); A-IRB uses bank estimates subject to floors under Basel 3.1.
Under Basel 3.1, A-IRB firms have two methods for incorporating collateral into LGD (Art. 191A):
- LGD Modelling Collateral Method (Art. 169A/169B) — the firm's own LGD model captures collateral-specific recovery characteristics, subject to PRA approval and annual revaluation. Must produce estimates at least as conservative as the Foundation Collateral Method.
- Foundation Collateral Method (FCM, Art. 230) — uses supervisory LGDS values by collateral type, blended with LGDU for partially secured exposures.
For unfunded credit protection (guarantees), A-IRB firms may use the LGD Adjustment Method (LGD-AM, Art. 183) or the Parameter Substitution Method (PSM, Art. 236). LGD-AM is available only for exposure classes where the firm holds A-IRB own-LGD permission under Art. 143(2A)(c); F-IRB classes and Art. 147A SA-only classes (sovereigns, institutions, large corporates, FSEs) must use PSM instead. See Credit Risk Mitigation, the B31 CRM § LGD-AM Availability Gate, and the CRM Specification for details.
Exposure at Default (EAD)¶
F-IRB uses regulatory CCFs based on risk_type (CRR Art. 166(8)–(9)):
| Risk Type | F-IRB CCF | Rule |
|---|---|---|
| FR / FRC | 100% | Full risk / certain drawdown |
| MR | 75% | Medium risk (Art. 166(8)) |
| MLR | 75% | Medium-low risk (Art. 166(8)) |
| LR | 0% | Unconditionally cancellable |
Art. 166(9) Exception: Short-term letters of credit arising from the movement of
goods retain 20% CCF under F-IRB. Flag these exposures with
is_short_term_trade_lc = True.
Basel 3.1 Art. 166C fully aligns F-IRB CCFs to SA Table A1. The separate CRR Art. 166(8) supervisory schedule (75% for MR/MLR) is eliminated — F-IRB exposures use the same CCFs as SA exposures:
| Risk Type | CRR F-IRB | B31 F-IRB | Change |
|---|---|---|---|
| FR / FRC | 100% | 100% | Unchanged |
| MR | 75% | 50% | Down from 75% |
| MLR | 75% | 20% | Down from 75% |
| OC | 75%* | 40% | New Table A1 Row 5 category |
| LR (UCC) | 0% | 10% | Up from 0% |
* Under CRR, OC had no separate category. These commitments were classified by maturity into MR/MLR, both 75% under F-IRB Art. 166(8).
Art. 166(9) Trade LC Exception Removed
CRR Art. 166(9) is blanked by PRA PS1/26. The 20% short-term trade LC
carve-out no longer applies under Basel 3.1 — these exposures receive the
standard SA CCF for their risk type. The is_short_term_trade_lc flag has
no effect under Basel 3.1.
A-IRB uses bank-estimated CCFs via the ccf_modelled column, subject to Basel 3.1
restrictions: own-estimate CCFs are limited to revolving facilities only
(Art. 166D(1)(a)), with a floor of 50% of the SA CCF (CRE32.27). Non-revolving
A-IRB exposures use SA CCFs. See A-IRB CCF Restrictions
for full details.
Details: See Key Differences for the complete CCF comparison table across CRR and Basel 3.1, and CCF Specification for the full regulatory treatment.
Maturity (M)¶
Effective maturity affects capital through the maturity adjustment (Art. 162).
- Range: 1 year (floor) to 5 years (cap)
- Retail exemption: No maturity adjustment for retail (MA = 1.0)
CRR F-IRB fixed maturities (Art. 162(1)):
| Exposure Type | M |
|---|---|
| Repo-style transactions (repos, securities/commodities lending) | 0.5 years |
| All other exposures | 2.5 years |
Basel 3.1 deletes Art. 162(1) — all IRB firms must calculate M from cash flows or contractual terms. Revolving exposures must use the maximum contractual termination date (Art. 162(2A)(k)), not the current drawing repayment date.
Exceptions to the 1-Year Floor
Art. 162(3) allows a one-day maturity floor for daily-margined repos, derivatives,
and margin lending, and for qualifying short-term exposures (FX settlement, trade finance
≤ 1yr, securities settlement). The has_one_day_maturity_floor input flag controls this.
See the F-IRB specification
for full details.
Details: See Technical Reference for the full CRR vs Basel 3.1 comparison table.
Asset Correlation¶
Asset correlation (R) determines how sensitive the exposure is to systematic risk. See _polars_correlation_expr() for the pure Polars implementation.
Corporate/Bank Correlation¶
This produces: - R = 24% for very low PD - R = 12% for high PD
SME Size Adjustment¶
For SME corporates (turnover €5m-€50m). The turnover_m column is provided in GBP millions; the calculator converts to EUR using config.eur_gbp_rate:
# Convert GBP turnover to EUR
S_eur = turnover_gbp / eur_gbp_rate # e.g. £25m / 0.8732 = €28.6m
# Clamp to range and apply adjustment
S = min(50, max(5, S_eur))
R_adjusted = R - 0.04 × (1 - (S - 5) / 45)
This reduces correlation by up to 4 percentage points for smaller firms.
Retail Correlations¶
| Retail Type | Correlation |
|---|---|
| Residential Mortgage | 15% |
| QRRE | 4% |
| Other Retail | 3-16% (PD-dependent) |
Other Retail:
Actual Correlation Implementation (formulas.py)
See _polars_correlation_expr() in src/rwa_calc/engine/irb/formulas.py
for the full Polars expression implementation including SME adjustment.
Financial Sector Entity Correlation Multiplier¶
Large financial sector entities (LFSEs) and unregulated financial sector entities receive a 1.25x multiplier on their asset correlation R (Art. 153(2) / CRE31.5). This increases capital requirements for exposures to financial institutions. The multiplier mechanism is unchanged between CRR and Basel 3.1; only the LFSE total-assets threshold differs:
- CRR: total assets ≥ EUR 70 billion (CRR Art. 142(1)(4)).
- Basel 3.1: total assets ≥ GBP 79 billion (PS1/26 Glossary p. 78, with Note "corresponds to Article 142(1)(4) of CRR").
Set apply_fi_scalar = True on the counterparty record for entities meeting these criteria. The calculator derives requires_fi_scalar directly from this flag.
Not the same as the Art. 147A large corporate threshold
The 1.25x correlation multiplier applies to financial sector entities based on the LFSE total-assets threshold (EUR 70bn CRR / GBP 79bn B31). The Art. 147A(1)(e) large corporate threshold (GBP 440m revenue) is an approach restriction (F-IRB only under Basel 3.1) — it does not trigger the correlation uplift. See the Key Differences for comparison.
Maturity Adjustment¶
For non-retail exposures. See _polars_maturity_adjustment_expr() for the pure Polars implementation.
# Maturity factor b
b = (0.11852 - 0.05478 × ln(PD))^2
# Maturity adjustment
MA = (1 + (M - 2.5) × b) / (1 - 1.5 × b)
Where M is effective maturity in years.
Actual Maturity Adjustment (formulas.py)
See _polars_maturity_adjustment_expr() in src/rwa_calc/engine/irb/formulas.py
for the full Polars expression implementation.
Example values:
| PD | M=1yr | M=2.5yr | M=5yr |
|---|---|---|---|
| 0.03% | 0.853 | 1.000 | 1.221 |
| 0.10% | 0.880 | 1.000 | 1.177 |
| 1.00% | 0.934 | 1.000 | 1.099 |
| 5.00% | 0.966 | 1.000 | 1.050 |
Scaling Factor¶
| Framework | Scaling Factor |
|---|---|
| CRR | 1.06 |
| Basel 3.1 | 1.00 (none) |
Expected Loss (EL)¶
IRB requires calculation of Expected Loss:
EL is compared to provisions: - EL > Provisions: Shortfall deducted from capital - EL < Provisions: Excess added to Tier 2 (with limits)
Detailed Calculation Example¶
Exposure: - Corporate loan, £50m - Bank-estimated PD: 0.50% - F-IRB (LGD = 45%) - Maturity: 3 years - Counterparty turnover: £25m (SME)
Step 1: Apply PD Floor
Step 2: Calculate Asset Correlation
# Base correlation
R_base = 0.12 × (1 - exp(-50 × 0.005)) / (1 - exp(-50)) +
0.24 × (1 - (1 - exp(-50 × 0.005)) / (1 - exp(-50)))
R_base = 0.12 × 0.221 + 0.24 × 0.779 = 0.214
# SME adjustment (turnover £25m, converted to EUR)
S_eur = 25 / 0.8732 = 28.63 # GBP → EUR conversion
S = min(50, max(5, 28.63)) = 28.63
adjustment = 0.04 × (1 - (28.63 - 5) / 45) = 0.04 × 0.475 = 0.019
R = 0.214 - 0.019 = 0.195
Step 3: Calculate Capital Requirement (K)
# Intermediate calculations
G_PD = norm.ppf(0.005) = -2.576
G_999 = norm.ppf(0.999) = 3.090
term1 = (1 - R)^(-0.5) × G_PD = 1.115 × (-2.576) = -2.871
term2 = (R / (1-R))^0.5 × G_999 = 0.492 × 3.090 = 1.521
K_pre = LGD × N(term1 + term2) - LGD × PD
K_pre = 0.45 × N(-1.350) - 0.45 × 0.005
K_pre = 0.45 × 0.0885 - 0.00225
K_pre = 0.0398 - 0.00225 = 0.0376
Step 4: Calculate Maturity Adjustment
b = (0.11852 - 0.05478 × ln(0.005))^2 = (0.11852 + 0.290)^2 = 0.167
MA = (1 + (3 - 2.5) × 0.167) / (1 - 1.5 × 0.167)
MA = 1.0835 / 0.7495 = 1.446
Step 5: Calculate RWA
# CRR
RWA_CRR = K × 12.5 × EAD × MA × 1.06
RWA_CRR = 0.0376 × 12.5 × 50,000,000 × 1.446 × 1.06
RWA_CRR = £36,019,860
RW_CRR = RWA / EAD = 72.0%
# Basel 3.1 (no scaling)
RWA_B31 = 0.0376 × 12.5 × 50,000,000 × 1.446 × 1.00
RWA_B31 = £33,981,000
RW_B31 = 68.0%
Step 6: Check Output Floor (Basel 3.1)
# SA equivalent RWA (assume 100% RW corporate)
RWA_SA = 50,000,000 × 100% = £50,000,000
# Output floor (72.5%)
Floor = 50,000,000 × 0.725 = £36,250,000
# Final RWA
RWA_final = max(33,981,000, 36,250,000) = £36,250,000
Implementation¶
Using the IRB Transforms (Recommended)¶
The IRB logic is plain module-level typed functions in
irb/transforms.py
and irb/formulas.py,
composed over a LazyFrame via lf.pipe(fn, config):
import polars as pl
from datetime import date
from rwa_calc.contracts.config import CalculationConfig
from rwa_calc.engine.irb.transforms import (
classify_approach, # Determine F-IRB vs A-IRB
apply_firb_lgd, # Apply supervisory LGD for F-IRB
prepare_columns, # Ensure required columns exist
apply_all_formulas, # Run full IRB calculation
)
config = CalculationConfig.crr(reporting_date=date(2026, 12, 31))
# Create sample exposure data
exposures = pl.LazyFrame({
"exposure_reference": ["EXP001"],
"pd": [0.005],
"lgd": [0.45],
"ead_final": [50_000_000.0],
"maturity": [3.0],
"exposure_class": ["CORPORATE"],
"turnover_m": [25.0], # Annual turnover in millions
})
# IRB calculation pipeline composed via lf.pipe(fn, config)
result = (
exposures
.pipe(classify_approach, config)
.pipe(apply_firb_lgd, config)
.pipe(prepare_columns, config)
.pipe(apply_all_formulas, config)
.collect()
)
# Access results
print(result.select([
"pd_floored", "correlation", "k", "maturity_adjustment", "rwa", "expected_loss"
]))
Using the IRB Calculator¶
import polars as pl
from datetime import date
from rwa_calc.engine.irb.calculator import IRBCalculator
from rwa_calc.contracts.config import CalculationConfig
# Create calculator
calculator = IRBCalculator()
# calculate_branch() takes a pre-filtered IRB LazyFrame and returns a LazyFrame
irb_lf = pl.LazyFrame({
"exposure_reference": ["EXP001"],
"pd": [0.005],
"lgd": [0.45],
"ead_final": [50_000_000.0],
"maturity": [3.0],
"exposure_class": ["CORPORATE"],
"turnover_m": [25.0],
})
result_lf = calculator.calculate_branch(
irb_lf,
CalculationConfig.crr(reporting_date=date(2026, 12, 31)),
)
irb_rwa_df = result_lf.collect()
print(irb_rwa_df.select("rwa", "expected_loss"))
Using IRB Formulas Directly¶
The IRB formulas are implemented in irb/formulas.py. Both scalar functions and pure Polars expression functions are available.
Implementation Architecture
- Vectorized expressions: Pure Polars expressions for bulk processing (used by the IRB transforms (
engine/irb/transforms.py) and the calculator vialf.pipe(...)) - Scalar wrappers: Thin wrappers around vectorized expressions for single-value calculations
from rwa_calc.engine.irb.formulas import (
calculate_k,
calculate_correlation,
calculate_maturity_adjustment,
calculate_irb_rwa, # Convenience function for single exposures
)
# Calculate components
R = calculate_correlation(
pd=0.005,
exposure_class="CORPORATE",
turnover_m=25.0, # Turnover in GBP millions (converted to EUR internally)
)
MA = calculate_maturity_adjustment(pd=0.005, maturity=3)
K = calculate_k(pd=0.005, lgd=0.45, correlation=R)
# Calculate RWA
rwa = K * 12.5 * ead * MA * scaling_factor
# Or use the convenience function for complete calculation
result = calculate_irb_rwa(
ead=50_000_000,
pd=0.005,
lgd=0.45,
correlation=R,
maturity=3.0,
apply_scaling_factor=True, # CRR 1.06 factor
)
print(f"RWA: {result['rwa']:,.0f}")
Scalar K Calculation (formulas.py)
See calculate_k() in src/rwa_calc/engine/irb/formulas.py
for the scalar wrapper around the Polars expression.
Expected Loss Calculation¶
from rwa_calc.engine.irb.formulas import calculate_expected_loss
el = calculate_expected_loss(
pd=0.005,
lgd=0.45,
ead=50_000_000
)
# el = 0.005 × 0.45 × 50,000,000 = £112,500
F-IRB vs A-IRB Comparison¶
| Parameter | F-IRB | A-IRB |
|---|---|---|
| PD | Bank estimate | Bank estimate |
| LGD | Supervisory (45%/75%) | Bank estimate (floored) |
| CRM for collateral | Foundation Collateral Method (Art. 230) | LGD modelling (Art. 169A/169B) or FCM |
| EAD | Regulatory | Bank estimate |
| CCF | Regulatory (CRR: 75% MR/MLR; B31: SA-aligned via Art. 166C) | Bank estimate (B31: revolving only, floored at 50% SA) |
| Typical RW | Higher | Lower |
| Complexity | Lower | Higher |
| Approval | Easier | Harder |
Regulatory References¶
| Topic | CRR Article | BCBS CRE |
|---|---|---|
| IRB approach overview | Art. 142-150 | CRE30 |
| K formula | Art. 153 | CRE31 |
| Default definition | Art. 178 (specification) | CRE36.67–82 |
| PD estimation | Art. 179-180 | CRE32 |
| LGD estimation | Art. 181 | CRE32 |
| Correlation | Art. 153 | CRE31 |
| Maturity adjustment | Art. 162 | CRE31 |
| Supervisory LGD | Art. 161 | CRE32 |
| F-IRB CCF | Art. 166(8)–(9) (CRR) / Art. 166C (B31) | CRE32 |
| A-IRB CCF / EAD | Art. 166 (CRR) / Art. 166D (B31) | CRE32 |
| A-IRB LGD modelling for collateral | Art. 169A/169B | CRE32 |
| CRM method taxonomy | Art. 191A | — |
Next Steps¶
- Standardised Approach - Compare with SA
- Credit Risk Mitigation - CRM under IRB, including Foundation Collateral Method (F-IRB) and LGD Modelling Collateral Method (A-IRB, Art. 169A/169B)
- Supporting Factors - SME correlation adjustment