Credit & Counterparty Risk

Build CVA From Exposure, PD and LGD

TeaVM runs the actual netting-set exposure simulation, then assembles the flat-discount textbook CVA from Java EPE, marginal default probability and LGD for comparison.

Book
Rates & credit market
SimulationOptional

Three trades net in one uncollateralised USD set: the editable payer swap, a fixed offsetting receiver, and a bought EUR forward. Credit hazard is piecewise flat across the three displayed buckets.

Java source
CvaFirstPrinciplesRiskStudio.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.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.CollateralAgreement;
import java.util.List;

public final class CvaFirstPrinciplesRiskStudio {
  public static void main(String[] args) {
    double r0 = 0.020000000000, a = 0.030000000000, sigma = 0.010000000000, hs = 0.0090000000000,
        hm = 0.015000000000, hl = 0.017000000000, recovery = 0.40000000000, notional = 100000000.00;
    int steps = 20;
    long paths = 3000L, seed = 20260902L;
    CreditName cpty = 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(cpty)
        .trades(List.of(InterestRateSwap.of()
        .id("A-SWAP-PAY")
        .side(InterestRateSwap.SideEnum.PAY_FIXED)
        .notional(notional)
        .fixedRate(.02)
        .startYears(0)
        .maturityYears(7)
        .accrualYears(.5)
        .build(), InterestRateSwap.of()
        .id("A-SWAP-REC")
        .side(InterestRateSwap.SideEnum.RECEIVE_FIXED)
        .notional(40000000)
        .fixedRate(.036)
        .startYears(0)
        .maturityYears(5)
        .accrualYears(.5)
        .build(), FxForward.of()
        .id("A-FX-FWD")
        .side(FxForward.SideEnum.BUY_FOREIGN)
        .foreignNotional(20000000)
        .strike(1.05)
        .settlementYears(4)
        .build()))
        .collateral(CollateralAgreement.uncollateralised())
        .build();
    CvaMarket market = CvaMarket.of()
        .r0(r0)
        .hwLevel(r0)
        .hwMeanReversion(a)
        .hwSigma(sigma)
        .hazardShort(hs)
        .hazardMid(hm)
        .hazardLong(hl)
        .recovery(recovery)
        .fxSpot(1.1)
        .fxVol(.12)
        .fxForeignRate(.024)
        .build();
    ExposureSimulation sim = ExposureSimulation.of(ns, steps)
        .on("cpu")
        .fp64(true);
    CvaResult result = sim.run(market, paths, seed);
    double[] times = result.epeProfile()
        .times(), epe = result.epeProfile()
        .values();
    double dt = sim.stepYears(), survival = 1, previous = 0, approx = 0, mean = 0;
    for (int k = 1; k <= steps; k++) {
      double t = k * dt, from = previous, to = t;
      double dh = hs * Math.max(0, Math.min(to, 2) - Math.max(from, 0)) + hm * Math.max(0, Math.min(to,
          5) - Math.max(from, 2)) + hl * Math.max(0, to - Math.max(from, 5));
      double marginal = survival * (1 - Math.exp(-dh)), discount = Math.exp(-r0 * t), contribution = epe[k - 1] * discount * marginal * (1 - recovery);
      approx += contribution;
      mean += epe[k - 1];
      System.out.println("STEP|" + t + "|" + epe[k - 1] + "|" + discount + "|" + marginal + "|" + contribution);
      survival *= Math.exp(-dh);
      previous = t;
    }
    System.out.println("RESULT|" + result.value() + "|" + result.standardError() + "|" + (mean / steps)
        + "|" + approx + "|" + times.length + "|" + result.buildSeconds() + "|" + result.sweepSeconds());
  }
}
TeaVM compiles and runs the Java source above in this browser.
Implementation guide

CVA as discounted expected loss

Unilateral CVA combines exposure, counterparty default probability and loss given default on a common time grid.

Core mechanism

At each future date the model estimates positive exposure, weights it by incremental default probability and loss given default, then discounts the contribution. Summing dates gives the counterparty-credit adjustment.

Practical workflow

Model legal netting and collateral first, generate market scenarios, price future exposure consistently, calibrate the credit curve and retain contribution-by-date diagnostics.

Key details

At each exposure date, unilateral CVA combines discounted expected positive exposure with the counterparty’s incremental default probability and loss given default. The time profile matters: a trade with the same terminal exposure can have a different CVA when its exposure is concentrated early rather than late.

Expected exposure is not simply today’s mark. Future market states are simulated, each trade in the netting set is revalued at each grid date, and legally enforceable netting is applied before positive exposure is taken. Collateral then changes the remaining exposure according to threshold, call timing and margin-period assumptions.

The computational shape is paths multiplied by future dates multiplied by trades. A full bump of one market factor repeats that exposure simulation, which is why adjoint extraction is useful: recording the connected CVA valuation once can return the vector of sensitivities in one reverse sweep rather than one resimulation per factor.

The page’s contribution-by-date output is a diagnostic, not just presentation. It lets a reviewer see whether the result is driven by early exposure, a credit-curve interval, a collateral gap or discounting. That decomposition should be reconciled before relying on a headline CVA.

Important omitted effects include bilateral credit effects, funding adjustments, disputes, close-out conventions and explicit wrong-way risk. Those omissions should be understood as scope boundaries, not hidden approximations.

Scope and review point

A teaching grid omits many real effects, including disputes, margin period of risk, wrong-way risk, funding and close-out conventions.