Regulatory Capital

Compute SA-CVA Capital for a Netting Set

CVA sensitivities from one AAD sweep on a real netting set, cross-checked against the regulation's own prescribed bump-and-revalue method.

Netting set NS-CPTY-A
Trade IDTypeSideNotionalRate / StrikeMaturity
IR swap, payer%y
IR swap, receiver%y
FX forward, buy foreigny

Counterparty CPTY-A — BBB, financial sector, 40% recovery, 150bp flat hazard spread.

Rates & credit market
FX marketOptional
SimulationOptional
Java source
SaCvaRiskStudio.java

This exact source runs in TeaVM. Form changes update its Java literals and reset manual edits.

import com.nablatensor.cva.CreditName;
import com.nablatensor.cva.CvaMarket;
import com.nablatensor.cva.CvaResult;
import com.nablatensor.cva.CvaRiskFactors;
import com.nablatensor.cva.ExposureSimulation;
import com.nablatensor.cva.FxForward;
import com.nablatensor.cva.HazardCurve;
import com.nablatensor.cva.InterestRateSwap;
import com.nablatensor.cva.NettingSet;
import com.nablatensor.cva.SaCva;
import com.nablatensor.cva.SaCvaParameters;
import com.nablatensor.cva.SaCvaResult;
import com.nablatensor.cva.SaCvaSensitivities;
import com.nablatensor.risk.RiskFactor;
import com.nablatensor.risk.Sensitivities;
import java.util.List;

public final class SaCvaRiskStudio {
  public static void main(String[] args) {
    double r0 = 0.0300000000000, a = 0.0300000000000, sigma = 0.0100000000000, hs = 0.0120000000000,
        hm = 0.0150000000000, hl = 0.0175000000000, recovery = 0.400000000000, fxSpot = 1.10000000000,
        fxVol = 0.120000000000, fxForeign = 0.0250000000000;
    int steps = 20;
    long paths = 2500L, seed = 20260902L;
    CreditName cp = CreditName.of()
        .id("CPTY-A")
        .curve(HazardCurve.fromFlatSpread(150.0, recovery, 10.0))
        .recovery(recovery)
        .rating(CreditName.RatingEnum.BBB)
        .sector(CreditName.SectorEnum.FINANCIAL)
        .build();
    NettingSet ns = NettingSet.of()
        .id("NS-CPTY-A")
        .counterparty(cp)
        .trades(List.of(InterestRateSwap.of()
        .id("SWAP-PAY")
        .side(InterestRateSwap.SideEnum.PAY_FIXED)
        .notional(100000000.000)
        .fixedRate(0.0320000000000)
        .startYears(0)
        .maturityYears(5.00000000000)
        .accrualYears(.5)
        .build(), InterestRateSwap.of()
        .id("SWAP-REC")
        .side(InterestRateSwap.SideEnum.RECEIVE_FIXED)
        .notional(40000000.0000)
        .fixedRate(0.0280000000000)
        .startYears(0)
        .maturityYears(5.00000000000)
        .accrualYears(.5)
        .build(), FxForward.of()
        .id("FX-FWD")
        .side(FxForward.SideEnum.BUY_FOREIGN)
        .foreignNotional(30000000.0000)
        .strike(1.10000000000)
        .settlementYears(3.00000000000)
        .build()))
        .collateral(com.nablatensor.cva.CollateralAgreement.uncollateralised())
        .build();
    CvaRiskFactors keys = new CvaRiskFactors("USD", cp, "EURUSD");
    CvaMarket market = CvaMarket.of()
        .r0(r0)
        .hwLevel(r0)
        .hwMeanReversion(a)
        .hwSigma(sigma)
        .hazardShort(hs)
        .hazardMid(hm)
        .hazardLong(hl)
        .recovery(recovery)
        .fxSpot(fxSpot)
        .fxVol(fxVol)
        .fxForeignRate(fxForeign)
        .build();
    ExposureSimulation sim = ExposureSimulation.of(ns, steps)
        .on("cpu")
        .fp64(true);
    CvaResult result = sim.run(market, paths, seed);
    Sensitivities adj = SaCvaSensitivities.adjoint(result, keys);
    SaCvaSensitivities.BumpResult bump = SaCvaSensitivities.bumpAndRevalue(sim, market, paths, seed,
        keys);
    SaCva calculator = new SaCva(SaCvaParameters.demo());
    SaCvaResult ca = calculator.charge(adj), cb = calculator.charge(bump.sensitivities());
    System.out.println("RESULT|" + result.value() + "|" + result.standardError() + "|" + result.sweepSeconds()
        + "|" + bump.seconds() + "|" + bump.revaluations() + "|" + ca.total() + "|" + cb.total());
    for (RiskFactor factor : bump.sensitivities()
        .asMap()
        .keySet()) System.out.println("ROW|" + factor.riskClass() + " " + factor.measure() + " @"
        + factor.tenor() + "y|" + adj.get(factor) + "|" + bump.sensitivities()
        .get(factor));
  }
}
TeaVM compiles and runs the Java source above in this browser.
Implementation guide

SA-CVA connects pricing risk to capital

SA-CVA uses prescribed aggregation of CVA sensitivities rather than treating the headline CVA as the capital number.

Core mechanism

The calculation starts from simulated exposure and counterparty credit inputs, then uses CVA market sensitivities in the regulatory risk-weight and correlation framework. The page contrasts an adjoint extraction with prescribed revaluation checks.

Practical workflow

Build and govern the netting set, exposure model, collateral terms, credit curves and hedge representation. Extract sensitivities in consistent units, reconcile selected factors, then aggregate under the current local rule set.

Key details

Analysis note — where the heaviest computation in CVA risk capital sits and whether NablaTensor helps. Date: 2026-09-02. §4 is implemented in the nablatensor-cva module and the demo/cva-capital.sh walk-through; the parameter tables are still indicative. Verdict: Strong fit — the widest adjoint-AD margin of any regime covered in these notes. Calculators, not sign-off. This note describes where the computation sits and what NablaTensor could compute — the numbers the rules ask for. Model validation, parameter attestation and regulatory submission stay with the user.

Capital for the risk of mark-to-market losses on the credit valuation adjustment of a derivative portfolio. Two approaches:

Binding dates. With FRTB in each jurisdiction: 🇪🇺 1 Jan 2027 (inside the same CRR3 targeted-relief delegated act), 🇺🇸 2027 phase-in, 🇬🇧 1 Jan 2027. UK Basel 3.1 eliminates all CVA internal models and replaces them with three risk-sensitive standardised methods, so every UK bank with material CVA needs a sensitivities engine — not a Monte-Carlo IMM-CVA model — for capital.

where each exposure path requires a full revaluation of every trade in the netting set at every simulation time step. The cost shape is:

The SA-CVA capital charge then needs CVA delta and vega to every prescribed risk factor — dozens to a few hundred credit-spread, rates, FX, equity and commodity factors. Computed by bump-and-revalue, that is the entire exposure simulation re-run once per risk factor.

The bottleneck is the per-risk-factor re-simulation of the netting-set exposure paths for the SA-CVA sensitivity vector.

Yes — this is where bump-and-revalue is most expensive and adjoint AD wins by the widest margin of any regime covered in these notes.

Scope and review point

This compact netting set omits many contractual, legal and wrong-way-risk details required for a production CVA desk calculation.