You are here in the market-data-to-CVA chain A horizontal rail of eleven markers, one per chapter: IR-01 to IR-08 on the left, XVA-01 to XVA-03 on the right. IR-05 to IR-08 are drawn hollow under a bracket reading "written, not yet published". The chapter being read is ringed in crimson and named above the rail, and the object it consumes and the object it produces are printed below it. Market data to CVA · the whole chain, IR-01 to XVA-03 IR-01 · Bootstrap the SOFR curve IR-02 · Multi-curve bootstrapping IR-03 · Swaptions and the vol surface IR-04 · Why we model rates as random XVA-01 · Exposure XVA-02 · Netting, CSA and collateral XVA-03 · Credit Valuation Adjustment written, not yet published IR XVA 0102 0304 0506 0708 0102 03 INmarket quotes IN14 SOFR par quotes INESTR + EURIBOR INP(0,T), ATM vol grid INP(0,T) INV(t,ω), 5000 paths INEE(t) per trade INEEnet(t), dPD(t) OUTCVA OUTP(0,T), 14 pillars OUTtwo curves, a basis OUTσN, swaption prices OUTr(t,ω) under Q OUTEE(t), PFE(t,q) OUTEEnet(t) OUTCVA
You are here · XVA-02 This chapter takes one EE$(t)$ per trade and hands on a single $\text{EE}_{\text{net}}(t)$ for the whole netting set.
Prerequisites

This chapter requires XVA-01: EE$(t)$ for a single trade, computed from simulated mark-to-market paths.

This chapter introduces netting sets and CSA (Credit Support Annex), the legal structures that reduce exposure. No prior knowledge of ISDA agreements or collateral mechanics is assumed.

By the end, you can collapse a portfolio into a single netted exposure profile and apply a CSA to reduce it further.

The input is a set of mark-to-market paths $V_k(t, \omega)$: one value per trade $k$, monitoring date $t$, and simulated scenario $\omega$.

From single trades to portfolios

A bank does not compute CVA trade by trade. It manages netting sets: collections of trades governed by a single ISDA Master Agreement with one counterparty. On default the bankruptcy trustee does not pay out a thousand individual claims; it nets them and pays the single net amount.

Netting: why it matters

Netting at two dates: what the offset is worth, and when it disappears Two panels of horizontal bars, both measuring expected exposure of the same three-trade netting set in US dollar thousands. Top panel, at three years, with all three trades alive: trade A, a ten-year payer swap, 305.0; trade B, a five-year payer swap, 126.3; trade C, a seven-year receiver swap, 225.2. Gross EE, which takes the positive part of each trade and only then adds, is 656.5. Netted EE, which adds first and only then takes the positive part, is 180.0. The difference is drawn as a dashed gold segment that completes the netted bar to exactly the length of the gross bar: the netting benefit of 476.5, which is 73 per cent of gross. Bottom panel, at seven and a quarter years: trades B and C have matured and contribute nothing, so gross EE and netted EE are both 232.6 and the netting benefit is zero. Footnote: for n similar trades at average pairwise correlation rho, the netting factor is the square root of n plus n times n minus one times rho, all divided by n; at rho equal to zero and n equal to twenty the factor is 0.22, a 78 per cent cut. EE, USD thousands t = 3 years all three trades alive A · 10Y payer swap 305.0 B · 5Y payer swap 126.3 C · 7Y receiver swap 225.2 Gross EE · max first, then add 656.5 Netted EE · add first, then max 180.0 netting benefit 476.5 73% of gross EE t = 7.25 years the 7Y receiver has matured A · 10Y payer swap 232.6 B, C · matured 0 Gross EE · max first, then add 232.6 Netted EE · add first, then max 232.6 netting benefit 0 · nothing left to offset n similar trades, average correlation ρ: netting factor = √(n + n(n−1)ρ) / n ρ = 0, n = 20: factor 0.22, a 78% cut
Figure 1 · XVA-02 Netting is worth 73% of gross exposure while the receiver is alive, and nothing at all once it matures. Below each rule the same trades are aggregated two ways: take the positive part of each and add, or add and then take the positive part. Source: xvafoundations.xva.NettingSet, seed 42, 5000 paths. Netting factor: Pykhtin & Zhu (2007).

A payer swap gains when rates rise; a receiver swap loses on the same move. Trade C is the receiver, so it is a liability exactly where A and B are assets.

Let $V_k(t)$ be the mark-to-market of trade $k$ at time $t$ on one scenario:

Netting set value $$V_{\text{net}}(t) = \sum_{k=1}^{K} V_k(t)$$
K: number of trades governed by the one ISDA Master Agreement $V_{\text{net}}(t)$ is the only value the bankruptcy trustee recognises; it is used unchanged for the rest of the chapter

There are two ways to aggregate it, and an inequality between them:

Gross, netted, and the inequality $$\text{EE}_{\text{gross}}(t) = \sum_k \mathbb{E}^{\mathbb{Q}}\!\left[\max(V_k(t),\, 0)\right]$$ $$\text{EE}_{\text{netted}}(t) = \mathbb{E}^{\mathbb{Q}}\!\left[\max\left(V_{\text{net}}(t),\, 0\right)\right]$$ $$\text{EE}_{\text{netted}}(t) \leq \text{EE}_{\text{gross}}(t)$$
The inequality is subadditivity of the positive part, $\max(\sum_k x_k,\, 0) \leq \sum_k \max(x_k,\, 0)$ for all real $x_k$, with the expectation taken on both sides. Nothing about it is asymptotic or approximate: it holds scenario by scenario.

Per the convention from XVA Chapter 01, $\text{EE}(t)$ is the time-varying expected positive exposure and EPE is its scalar time-average $\text{EPE} = \tfrac{1}{T}\int_0^T \text{EE}(t)\,dt$.

Collateral and the Credit Support Annex

Most derivative trades between investment-grade counterparties are governed by a Credit Support Annex (CSA): an agreement to post collateral against the net mark-to-market at regular intervals.

The CSA ladder and the margin period of risk Two panels. The upper panel plots the collateral balance C against the net mark-to-market, both in millions of US dollars, for illustrative CSA terms: threshold H of 20 million, minimum transfer amount of 5 million, independent amount of 5 million. The line is a staircase. Inside the shaded threshold band, from minus H to plus H, it is flat at plus 5 million: the independent amount is held whatever the mark-to-market does, and no call is made. The flat section extends a further 5 million on each side of the band, because a required transfer smaller than the minimum transfer amount produces no call. Beyond that the line rises in five-million steps in both directions: to the right the counterparty posts to you, to the left you post to them. The library implements only the right-hand branch. The lower panel is a timeline in business days across a single scenario. The net mark-to-market climbs steadily from about 22 to about 72. The collateral held is a step function that tracks it, but stops: the last margin call that settles is at marker 1, ten business days before close-out, and freezes the balance at 19. Marker 2 is the counterparty ceasing to post, marker 3 is close-out. The shaded gold region between the frozen collateral line and the still-rising mark-to-market is the residual exposure, and at close-out it measures 53, against a threshold of 15. A double-headed arrow spans markers 1 to 3 and is labelled margin period of risk, ten business days. In the library run on this page the margin period of risk is two quarterly grid steps, half a year; at three years that takes expected exposure from 180.3 thousand to 40.7 thousand. The CSA ladder collateral C as a function of net MTM threshold ±H no call inside IA = 5m MTA = 5m −50 −H 0 +H +50 net MTM (USD m) +20 0 −20 collateral C (USD m) H = 20m, MTA = 5m, IA = 5m: illustrative CSA terms. The left branch is collateral you post; the library implements only the right. The margin period of risk one scenario, schematic net MTM collateral held H: no collateral moves inside residual exposure 1 2 3 MPR = 10 business days 1 last margin call that settles 2 counterparty stops posting 3 close-out and replacement In the run below MPR = 2 grid steps = 0.5y. At t = 3y that takes EE from 180.3k to 40.7k.
Figure 2 · XVA-02 Collateral does not remove exposure. It truncates it to whatever the mark-to-market moves between the last settled margin call and close-out. The ladder gives the levels, the timeline the lag: $C(t)$ freezes at marker 1, $V_{\text{net}}(t)$ keeps moving, and the gold gap is what survives. Both panels illustrative; not library output. The two EE figures are xvafoundations.xva.NettingSet, seed 42, 5000 paths.

$C(t)$ is the balance called on the net MTM one margin period earlier, at $t - \text{MPR}$, not this period's flow:

Collateral balance held at t $$C(t) = \max\!\left(V_{\text{net}}(t - \text{MPR}) - H,\, 0\right)$$
C(t) ≥ 0: collateral the bank has received, the right-hand branch of the ladder above and the only branch xvafoundations.xva.netting implements. The left-hand branch, $\max(-V_{\text{net}}(t - \text{MPR}) - H,\, 0)$, can only lower $C$, so the one-way profile below is a lower bound on two-way residual exposure at every date.

Residual exposure is the positive part of the net MTM after deducting that balance, so it carries $E$ from XVA-01, not $V$:

Collateralised exposure $$E_{\text{coll}}(t) = \max\!\left(V_{\text{net}}(t) - C(t),\, 0\right)$$
With no CSA, $C(t) \equiv 0$ and $E_{\text{coll}}(t) = \max(V_{\text{net}}(t),\, 0)$, the netted exposure
Modelling caveat

The formula above and the library implementation both use a one-snapshot proxy: the balance at $t$ is computed from the lagged net MTM rather than from a running collateral account tracking every call, partial release and unposting in between. For monitoring grids coarse relative to the MPR this is adequate; for daily or intraday margining, a path-by-path balance simulation is closer to the true CSA mechanics. See Gregory (2020) Ch. 11 for the bilateral convention with thresholds, minimum transfer amounts, and independent amount.

The library takes the MPR in grid steps, not days. The run below is quarterly with mpr=2: a six-month lag against the 10 business days of a real CSA, so the collateralised profile is conservative. A genuine 10-day MPR needs a daily grid, which is a simulation cost, not a modelling change.

Portfolio-level CVA

Nothing about the CVA formula changes. Substitute the netting set's EE$(t)$ for the single-trade EE$(t)$ and the integral is the one XVA-03 derives, under the same assumption that the exposure and the default time $\tau$ are independent. The hazard rate and the recovery rate are the counterparty's, not any single trade's.

With the inputs XVA-03 uses, a flat 120 bp CDS spread and 40% recovery, the three profiles below give CVA of USD 37,602 gross, USD 14,227 netted and USD 3,303 collateralised. Netting removes 62.2% of the gross number, and the CSA removes a further 76.8% of what netting left.

Computing portfolio exposure in code

Part 1: the netting set

The aggregation lives in the library, so import it rather than retype it. All three methods return the profile EE$(t)$ of shape (num_times,).

Python · PyTorch
from xvafoundations.xva.netting import NettingSet

# NettingSet takes a list of (num_paths, num_times) MTM tensors, one per
# trade -- the paths-first convention used throughout xvafoundations.
#
#   gross_ee()                 sum_k  mean_i max(V_k(t), 0)
#   netted_ee()                mean_i max(sum_k V_k(t), 0)
#   collateralised_ee(H, mpr)  mean_i max(V_net(t) - C(t), 0)
#
# with C(t) = max(V_net(t - mpr) - H, 0) and mpr counted in GRID STEPS.

Part 2: Example with a 3-trade netting set

Python · PyTorch
from datetime import date

import torch
torch.set_default_dtype(torch.float64)   # the library is float64 throughout

from xvafoundations.calibration import Stripper
from xvafoundations.conventions import DayCount, year_fraction
from xvafoundations.data.sofr import INSTRUMENTS, VALUATION_DATE
from xvafoundations.instruments import (build_instruments,
                                        pillar_maturities, initial_rates)
from xvafoundations.models import HullWhite1F
from xvafoundations.pricing import SwapSpec, reprice_swap_paths
from xvafoundations.xva.netting import NettingSet

t0 = torch.tensor(0.0)

# The SOFR OIS curve of IR-01, rebuilt here so this block runs alone.
pillars = torch.tensor(pillar_maturities(INSTRUMENTS, VALUATION_DATE))
rates = torch.tensor(initial_rates(INSTRUMENTS))
stripper = Stripper(pillars, rates, instrument_factory=lambda c:
                    build_instruments(INSTRUMENTS, VALUATION_DATE, c))
stripper.calibrate()
curve = stripper.get_curve()

# ACT/360 year fractions of an annual 15-January schedule, so 10Y
# matures at 10.144444, not 10.0.
def annual_schedule(years):
    v0 = VALUATION_DATE
    return tuple(year_fraction(v0, date(v0.year + 1 + k, v0.month, v0.day),
                               DayCount.ACT360)
                 for k in range(years))

# a and sigma are ASSERTED, not calibrated: IR-05 and IR-06 are
# unwritten. They are in the range a USD desk would see, and the shapes
# below do not depend on the third decimal of either.
model = HullWhite1F(a=0.05, sigma=0.007, curve=curve)

# Three trades under one ISDA, each struck at its own par rate, so
# V(0) = 0 for every trade and therefore for the netting set:
#   A  10Y payer     10,000,000 USD   c = 4.1200%
#   B   5Y payer     10,000,000 USD   c = 3.9200%
#   C   7Y receiver  12,000,000 USD   c = 4.0200%
definitions = [("A", 10, 1.0e7, True),
               ("B", 5, 1.0e7, True),
               ("C", 7, 1.2e7, False)]

specs = {}
for key, years, notional, pay_fixed in definitions:
    schedule = annual_schedule(years)
    par = curve.par_swap_rate(t0, torch.tensor(schedule)).item()
    specs[key] = SwapSpec(
        notional=notional,
        fixed_rate=par,
        fixed_payment_times=schedule,
        pay_fixed=pay_fixed,
    )

# 41 steps to 10.25y is dt = 0.25 exactly, and 10.25 covers the longest
# maturity. One short-rate simulation drives all three trades.
short_rates, times = model.simulate(5_000, 41, 10.25, seed=42)
mtm = {key: reprice_swap_paths(model, spec, short_rates, times)
       for key, spec in specs.items()}

netting_set = NettingSet([mtm["A"], mtm["B"], mtm["C"]])

# EE profiles: the per-time function EE(t), not the scalar EPE
gross = netting_set.gross_ee()
netted = netting_set.netted_ee()
coll = netting_set.collateralised_ee(threshold=0.0, mpr=2)  # 2 steps = 0.5y

print(f"gross peak       {gross.max():>12,.2f}")          # 656,516.37
print(f"collateralised   {coll.max():>12,.2f}"
      f" at {times[coll.argmax()]:.2f}y")                 # 87,833.51 at 0.50y
What this run does and does not model

The mark-to-market paths are repriced swaps, not scaled noise, so the net MTM is serially persistent: consecutive quarterly dates correlate 0.920 at 1.25y rising to 0.976 at 7y, and 0.919 across a full two-step margin period. That persistence is what makes collateral work at all: a margin call only protects you if today's MTM resembles the MTM one margin period ago.

What is asserted rather than calibrated is the pair $a = 0.05$ and $\sigma = 0.007$. IR-05 and IR-06 are unwritten, so nothing on this page claims these are the market's Hull-White parameters. They set the scale of every number in this chapter; they do not set its shape.

Gross vs. netted vs. collateralised EE profiles

Three-trade netting set: gross, netted and collateralised EE$(t)$
Netting cuts the exposure profile to 27% of gross at the gross peak, collateral cuts it again, and the netting benefit disappears entirely once the offsetting receiver matures.
Collateral leaves a peak of 88k against a gross peak of 657k, and after 7.25y netting is worth nothing. Source: xvafoundations.xva.NettingSet on xvafoundations.pricing.reprice_swap_paths output, seed 42, 5000 paths, quarterly grid, threshold 0, mpr = 2 steps. Hull-White $a = 0.05$, $\sigma = 0.007$, asserted not calibrated.

References

  1. Brigo, D. & Mercurio, F. (2006). Interest Rate Models: Theory and Practice (2nd ed.). Springer. The canonical reference on rates models underlying XVA computations.
  2. Gregory, J. (2020). The xVA Challenge (4th ed.). Wiley. Comprehensive treatment of CVA, DVA, FVA, and counterparty risk in practice.
  3. Crépey, S. (2015). Counterparty Risk and Funding: A Tale of Two Puzzles. Chapman & Hall/CRC. Rigorous mathematical treatment of counterparty risk and funding costs.
  4. Pykhtin, M. & Zhu, S. (2007). "A Guide to Modelling Counterparty Credit Risk." GARP Risk Review. Excellent overview of EPE, netting, and collateral modelling.

XVA-03 takes this profile, adds default probabilities stripped from CDS spreads, and prices the credit risk.