SA-CCR — FX treatment¶
This page covers FX derivatives end-to-end through the SA-CCR pipeline: input schema, hedging-set partition, asset-class add-on aggregation, and the worked CCR-A2 acceptance scenario.
Part of the SA-CCR specification set; see also adjusted-notional.md, supervisory-delta.md, maturity-factor.md, hedging-sets.md, ead-composition.md, rc-calculation.md, pfe-multiplier.md, legal-enforceability.md, wrong-way-risk.md, and ccp-exposures.md.
Input — two-leg trade schema¶
FX forwards / FX swaps / cross-currency basis swaps carry two currency legs.
TRADE_SCHEMA (src/rwa_calc/data/schemas.py) captures the two legs as:
| Column | Dtype | Required for FX | Description |
|---|---|---|---|
notional |
Float64 |
yes | Leg 1 notional in currency |
currency |
String |
yes | Leg 1 ISO-4217 currency |
notional_leg2 |
Float64 |
yes | Leg 2 notional in currency_leg2 |
currency_leg2 |
String |
yes | Leg 2 ISO-4217 currency |
For non-FX trades (asset_class != "fx"), the two *_leg2 columns are null.
Sign convention: notional and notional_leg2 are absolute amounts;
direction lives on is_long and flows through supervisory_delta.
The leg ordering is conventional — the engine treats both legs symmetrically. A typical convention is leg 1 = bought currency, leg 2 = sold currency.
Hedging set — Art. 277(3)(a)¶
Each FX trade belongs to one hedging set, keyed on the currency pair:
The min/max ordering makes the key order-independent so EUR/USD and USD/EUR
trades collapse into a single hedging set within the same netting set. FX has
no maturity sub-buckets (unlike IR) — every FX trade in a given pair
shares one hedging set regardless of tenor.
Engine: src/rwa_calc/engine/ccr/hedging_sets.py::assign_hedging_set.
Adjusted notional — Art. 279b(1)(b)¶
See adjusted-notional.md for the formula. In short:
- If one leg is the reporting currency, take the other leg converted to the reporting currency at spot.
- If both legs are non-reporting currencies, take the larger of the two converted notionals.
Asset-class add-on — Art. 277a(2) + BCBS CRE52.55¶
For each FX hedging set:
D_HS = Σ_i ( supervisory_delta_i × adjusted_notional_i × maturity_factor_i ) (signed)
AddOn_HS = SF_FX × |D_HS| (SF_FX = 0.04, Art. 280 Table 1)
For each netting set:
Unlike equity / commodity asset classes (Art. 277a(3) carries a ρ = 0.5 cross-hedging-set correlation), FX is a plain sum across hedging sets per BCBS CRE52.55. Within a hedging set, opposite-direction trades net perfectly via the signed sum of effective notionals.
Engine: src/rwa_calc/engine/ccr/pfe.py::_compute_addon_fx, dispatched from
compute_addon_per_asset_class.
CCR-A2 worked example¶
Input fixture (tests/fixtures/ccr/golden_ccr_a2.py):
- Trade
T_FX_001: 1-year GBP/USD outright forward, buy USD 100m / sell GBP 80m (implies forward rate 1.25 USD/GBP). At-par (MtM = 0),delta = 1.0. - Netting set
NS_FX_001: counterparty CP_001 (institution, CQS 2, GB), legally enforceable, unmargined. - FX rates:
USD → GBP = 0.80(spot). - Reporting date: 2026-01-15. Reporting currency: GBP.
Hand-calc:
adjusted_notional = |100m USD| × 0.80 = 80,000,000 GBP (Art. 279b(1)(b)(i))
business_days_to_maturity (2026-01-15 → 2027-01-15) ≈ 261 BD (Mon-Fri)
MF = sqrt(min(261, 250) / 250) = 1.0 (Art. 279c(1), ≥ 250 BD)
effective_notional = 1.0 × 80,000,000 × 1.0 = 80,000,000
AddOn_HS = 0.04 × 80,000,000 = 3,200,000 (Art. 277a(2))
AddOn_FX = 3,200,000 (single HS)
RC = max(0 − 0, 0) = 0 (Art. 275(1))
PFE_multiplier = min(1, 0.05 + 0.95 × exp(0)) = 1.0 (Art. 278(3))
PFE_addon = 1.0 × 3,200,000 = 3,200,000 (Art. 278(1))
EAD = 1.4 × (0 + 3,200,000) = 4,480,000 (Art. 274(2))
RW = 0.50 (Art. 120(1) Table 3, CQS 2)
RWA = 4,480,000 × 0.50 = 2,240,000 GBP
Pinned by tests/expected_outputs/ccr/CCR-A2.json and the six assertions in
tests/acceptance/ccr/test_ccr_a2_unmargined_fx_forward.py.
Out-of-scope / future work¶
- FX options: the existing
option_strike/option_type/option_underlying_pricecolumns plusσ_FX = 15%(Art. 279a(2)) already support FX options once leg2 columns are populated. No dedicated FX-option acceptance scenario yet — flagged for a future batch. - Cross-rate triangulation: the engine requires direct quotes
(
foreign → base); non-major-pair FX trades (e.g. NOK/SEK with base GBP) will fail the join. Firms supply every required pair, matching the precedent from the EUR/GBP auto-sync atengine/fx_rate_sync.py. - Specific WWR + FX: the WWR break-out (
engine/ccr/wwr.py) treats FX trades identically to IR — ais_specific_wwr=TrueFX trade lands in its own single-trade synthetic netting set withwwr_lgd_override = 1.0.
References¶
- CRR Art. 274(2) — EAD = α × (RC + PFE).
- CRR Art. 275(1) — unmargined RC = max(V − C, 0).
- CRR Art. 277(3)(a) — FX hedging set = currency pair.
- CRR Art. 277a(2) — hedging-set add-on = SF × |D_HS|.
- CRR Art. 278(1)–(3) — PFE multiplier and PFE composition.
- CRR Art. 279b(1)(b) — FX adjusted notional.
- CRR Art. 279c(1) — unmargined maturity factor.
- CRR Art. 280 Table 1 — SF_FX = 0.04.
- BCBS CRE52.34, CRE52.55 — FX hedging-set partition and add-on aggregation.
- PRA Rulebook — Counterparty Credit Risk (CRR) Part Chapter 3 §§3–5.