Core mechanism
Counterparty exposures are weighted and aggregated according to the prescribed formula, with a defined treatment of eligible hedges. It deliberately does not depend on a bank's full CVA sensitivity model.
The basic approach charge, with and without CDS hedge recognition, alongside SA-CVA on the same two netting sets.
The full charge applies the regulation’s hedge recognition to CPTY-A; the reduced charge does not recognise the CDS hedge.
This exact source runs in TeaVM. Form changes update its Java literals and reset manual edits.
import com.nablatensor.cva.BaCva;
import com.nablatensor.cva.BaCvaParameters;
import com.nablatensor.cva.BaCvaResult;
import com.nablatensor.cva.CollateralAgreement;
import com.nablatensor.cva.CreditName;
import com.nablatensor.cva.CvaHedge;
import com.nablatensor.cva.CvaMarket;
import com.nablatensor.cva.CvaResult;
import com.nablatensor.cva.CvaRiskFactors;
import com.nablatensor.cva.ExposureSimulation;
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.SaCvaSensitivities;
import com.nablatensor.risk.Sensitivities;
import java.util.List;
public final class BaCvaRiskStudio {
public static void main(String[] args) {
double r0 = 0.0200000000000, hazardA = 150 / 10000.0, hazardB = 110 / 10000.0, recovery = 40 / 100.0,
hedgeNotional = 1500000.00000;
long paths = 3000L, seed = 20260902L;
int steps = 20;
CreditName a = CreditName.of()
.id("CPTY-A")
.curve(HazardCurve.fromFlatSpread(hazardA * 10000.0, recovery, 10.0))
.recovery(recovery)
.rating(CreditName.RatingEnum.BBB)
.sector(CreditName.SectorEnum.FINANCIAL)
.build();
NettingSet nsA = NettingSet.of()
.id("NS-CPTY-A")
.counterparty(a)
.trades(List.of(InterestRateSwap.of()
.id("A-SWAP-PAY")
.side(InterestRateSwap.SideEnum.PAY_FIXED)
.notional(100000000.0)
.fixedRate(0.02)
.startYears(0.0)
.maturityYears(7.0)
.accrualYears(0.5)
.build(), InterestRateSwap.of()
.id("A-SWAP-REC")
.side(InterestRateSwap.SideEnum.RECEIVE_FIXED)
.notional(40000000.0)
.fixedRate(0.036)
.startYears(0.0)
.maturityYears(5.0)
.accrualYears(0.5)
.build()))
.collateral(CollateralAgreement.uncollateralised())
.build();
CreditName b = CreditName.of()
.id("CPTY-B")
.curve(HazardCurve.fromFlatSpread(hazardB * 10000.0, recovery, 10.0))
.recovery(recovery)
.rating(CreditName.RatingEnum.A)
.sector(CreditName.SectorEnum.CORPORATE)
.build();
NettingSet nsB = NettingSet.of()
.id("NS-CPTY-B")
.counterparty(b)
.trades(List.of(InterestRateSwap.of()
.id("B-SWAP-PAY")
.side(InterestRateSwap.SideEnum.PAY_FIXED)
.notional(75000000.0)
.fixedRate(0.022)
.startYears(0.0)
.maturityYears(7.0)
.accrualYears(0.5)
.build()))
.collateral(CollateralAgreement.dailyMargined(2000000.0))
.build();
CvaMarket market = CvaMarket.of()
.r0(r0)
.hwLevel(r0)
.hwMeanReversion(0.03)
.hwSigma(0.01)
.hazardShort(hazardA)
.hazardMid(hazardA)
.hazardLong(hazardA)
.recovery(recovery)
.fxSpot(1.1)
.fxVol(0.12)
.fxForeignRate(0.024)
.build();
ExposureSimulation simA = ExposureSimulation.of(nsA, steps)
.on("cpu")
.fp64(true);
CvaResult resultA = simA.run(market, paths, seed);
CvaMarket marketB = CvaMarket.of()
.r0(r0)
.hwLevel(r0)
.hwMeanReversion(0.03)
.hwSigma(0.01)
.hazardShort(hazardB)
.hazardMid(hazardB)
.hazardLong(hazardB)
.recovery(recovery)
.fxSpot(1.1)
.fxVol(0.12)
.fxForeignRate(0.024)
.build();
ExposureSimulation simB = ExposureSimulation.of(nsB, steps)
.on("cpu")
.fp64(true);
CvaResult resultB = simB.run(marketB, paths, seed + 1);
BaCvaParameters bp = BaCvaParameters.standard();
double alpha = bp.alpha();
BaCva calc = new BaCva(bp);
BaCva.Exposure ea = new BaCva.Exposure(a, nsA.effectiveMaturityYears(), alpha * resultA.expectedPositiveExposure());
BaCva.Exposure eb = new BaCva.Exposure(b, nsB.effectiveMaturityYears(), alpha * resultB.expectedPositiveExposure());
BaCvaResult reduced = calc.charge(List.of(ea, eb), List.of());
CvaHedge hedge = CvaHedge.of()
.kind(CvaHedge.KindEnum.SINGLE_NAME_CDS)
.referenceId("CPTY-A")
.notional(hedgeNotional)
.maturityYears(7.0)
.riskWeight(0.05)
.correlation(1.0)
.build();
BaCvaResult full = calc.charge(List.of(ea, eb), hedgeNotional > 0 ? List.of(hedge) : List.of());
CvaRiskFactors ka = new CvaRiskFactors("USD", a, "EURUSD"), kb = new CvaRiskFactors("USD", b,
"EURUSD");
Sensitivities sens = SaCvaSensitivities.adjoint(resultA, ka)
.plus(SaCvaSensitivities.adjoint(resultB, kb));
double sa = new SaCva(SaCvaParameters.demo())
.charge(sens)
.total();
System.out.println("RESULT|" + resultA.value() + "|" + resultB.value() + "|" + reduced.reduced()
+ "|" + full.full() + "|" + sa + "|" + resultA.sweepSeconds() + "|" + resultB.sweepSeconds()
+ "|" + reduced.scvaByCounterparty()
.get("CPTY-A") + "|" + reduced.scvaByCounterparty()
.get("CPTY-B"));
}
}
The Basic Approach uses supervisory parameters and exposure measures to provide a simpler CVA-capital result than SA-CVA.
Counterparty exposures are weighted and aggregated according to the prescribed formula, with a defined treatment of eligible hedges. It deliberately does not depend on a bank's full CVA sensitivity model.
Identify the applicable regulatory approach, map counterparties and maturities correctly, apply the current supervisory parameters, and reconcile scope with the SA-CVA population.
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.
A simple formula is still regulatory reporting: eligibility, legal scope, parameter version and audit trail are essential.