Research / Numerics

Where a capital number comes from

A capital charge is a square root, so it does not add up by position. How the engine splits it exactly, and what the page does when it rounds the pieces.

A risk manager looks at a capital number and asks which positions made it. For the standardised approach the question is harder than it sounds, because the number is not a sum. It is a square root.

The problem with a square root

The charge for a bucket of interest rate risk is the square root of a sum over pairs of tenors. Each term is the correlation between two tenors times the weighted sensitivities at both, where a weighted sensitivity is the net PV01 at a tenor times its risk weight.

Take two positions with weighted sensitivities of 100 and −60, at two tenors whose correlation is 0.8. Alone, they would carry charges of 100 and 60. Together the charge is the square root of 4,000, which is 63.25. It is not 40, the net. It is not 160, the sum of the two charges alone. Diversification took 96.75 off the sum, and the question is whose 96.75 it is.

Splitting it in half would be arbitrary. Splitting the charge in proportion to the charges alone would ignore that the second position is a hedge for the first.

The split that adds up

Write c for the list of weighted sensitivities and R for the matrix of correlations. Then R c is the matrix times the list. The charge is K, the square root of the dot product of c with R c, and the share of each position is its own term of that dot product, divided by K.

K = sqrt( c · (R c) )        share of position i = c_i × (R c)_i / K

The program below works out both for the two positions, using only the standard library. It also bumps each position by a millionth and measures how far K moves.

Python
from math import sqrt

# Two weighted sensitivities, and the correlation between the two tenors.
c = (100.0, -60.0)
rho = 0.8


def charge(c):
    return sqrt(c[0] ** 2 + c[1] ** 2 + 2 * rho * c[0] * c[1])


k = charge(c)
print(round(k, 4))

# The correlation matrix times c, then each position's share: c_i (R c)_i / K.
rc = (c[0] + rho * c[1], rho * c[0] + c[1])
shares = [c[i] * rc[i] / k for i in (0, 1)]
print(*[round(s, 3) for s in shares])
print(round(sum(shares), 3))

# Scale one position by 1 + e and see how far K moves, per unit of e.
e = 1e-6
for i in (0, 1):
    bumped = list(c)
    bumped[i] *= 1 + e
    print(round((charge(bumped) - k) / e, 3))

It prints this. The first line is the charge, the second is the two shares, the third is their sum, and the last two are the movements of the charge.

63.2456
82.219 -18.974
63.246
82.219
-18.974

The shares are 82.2 and −19.0, and they add up to the charge. The second is negative because the second position is a hedge.

Why it adds up

The charge is homogeneous of degree one. Double every position and it doubles. A function like that obeys Euler’s theorem, which says that it equals the sum over positions of each position times the derivative of the function with respect to it. For this charge the derivative with respect to c_i is (R c)_i / K, so the terms of the sum are exactly the shares above. They add up to K by algebra. No share is adjusted to make it so.

The last two lines of the program show that the shares are also derivatives. Grow the first position by one percent and the charge moves by about one percent of 82.2, which is 0.82. Grow the hedge by one percent and the charge falls by about 0.19. The statement holds to first order, so it is a good guide for a small change in a position and a poor one for a large change. For a large change, recompute.

This is not the only way to split a number like this. It is the one that adds up and is also a derivative.

A real book

The example book on this site is illustrative. It has two currencies with ten tenors each, and its capital charge is 36.58 million US dollars. The standard takes the largest of three charges, one for each correlation scenario.

Scenario Charge, millions
High 32.15
Medium 34.44
Low 36.58

The low scenario binds. A book that is hedged across tenors relies on the hedges moving together. When the low scenario cuts the correlations, the hedges work less well and the charge rises.

The same split runs through two layers. The first layer is the ten tenors within a currency, and the second is the two currencies, which the text combines with a prescribed correlation. The share of a tenor includes its part of the second layer. The twenty shares add up to the charge under each scenario.

Rounding what the page shows

The ledger on the home page shows every share in whole dollars, and a line under it says whether the shares add up to the charge. Rounded one by one, the twenty shares of the low scenario add up to 36,584,377, which is a dollar short of the charge of 36,584,378. The other two scenarios miss by a dollar as well, over in the high scenario and under in the medium.

A dollar is nothing to a bank. A column that does not add up is still a defect, and the first one a reader finds. The gap is easier to see with coarser figures. Here are the ten US dollar tenors of the low scenario in millions, to one decimal place.

Tenor, years Share, millions Rounded alone Shown
0.25 0.6377 0.6 0.6
0.5 1.8677 1.9 1.8
1 5.7764 5.8 5.8
2 11.6105 11.6 11.6
3 6.9817 7.0 7.0
5 23.9075 23.9 23.9
10 −12.3258 −12.3 −12.3
15 −3.2277 −3.2 −3.2
20 −1.9983 −2.0 −2.0
30 0.6735 0.7 0.7
Total 33.9031 34.0 33.9

Round each share on its own and the column adds up to 34.0. The currency’s own figure rounds to 33.9. A reader who adds up the column finds a gap that is only rounding, and then has to wonder what else is.

The ledger uses the largest remainder method, the one used to share out seats in a parliament. Round every share down to the digit that is shown. Count the units that are missing from the rounded total. Give one unit each to the shares with the largest remainders. Here five units were missing. The five largest remainders belonged to the three, one, ten, thirty and fifteen year tenors. The half year tenor, at 0.68 of a unit, was sixth, so it stays at 1.8 although it would round to 1.9 on its own.

Each share moves by at most one unit in the last place, and the column adds up to the rounded total exactly. Ties go to the earlier row, so the same input gives the same table on every engine.

The ledger applies the method at each layer. It rounds the charge to whole dollars, shares that between the two currencies so that their rounded figures add up to it, and then shares each currency’s rounded figure between its ten tenors.

Where the digits go

The shares are worked out in doubles, so their sum differs from the charge in the last digits. A test checks that for 500 generated books and all three scenarios the shares add up to the charge to within 1e-14 of the gross, which is the sum of the absolute shares plus the charge. The tolerance follows the gross and not the charge, because a book with two nearly offsetting positions has a charge far smaller than its gross, and the rounding error in each share is as large as the gross allows.

A second test sets each share against a finite difference of the charge. Together the two are statement FR-01 on the verification page. It is labelled tested, because a test samples books and says nothing about the rest.

The ledger shows whole dollars, which is far fewer digits than the shares hold.

What we have not checked

  • The test that sets each share against a finite difference of the charge covers 60 generated books. It skips a book whose weighted exposures or shares run to more than thirty times its charge, because a difference quotient cannot be trusted there. For those books the exact sum is checked, and the derivative property is not.
  • The receipt for a calculation covers the book, the three charges and the binding scenario. It does not cover the shares, so a match says nothing about how the charge was split.
  • The engine behind this site’s preview covers the interest rate delta charge only. The other risk classes, vega and curvature are not in the preview, and we have not examined how the split behaves for them.
  • We read the January 2019 text, BCBS d457. Later consolidations were not checked.
  • We have not compared our split with what other systems report. Other allocations exist, and a bank that uses one will see different pieces and the same total.

Research

Keep reading

  1. Numerics

    One sum, five engines, one answer

    Five JavaScript engines disagree about the last bit of exp, log, sin and tan. We built the kernel from operations they cannot disagree about, and run all five.

    Tomasz Wierzbicki6 min read

  2. Regulation

    Three numbers that cannot all be true

    The prescribed correlations between interest rate tenors are not a valid correlation matrix. Three entries show it by hand, and the standard says what to do.

    Dr Anneliese Okafor and Marcus Teller5 min read

The next step

Bring us
one book

A scoping call, a sample book and a parallel run on your data. Most teams have the first reconciled number inside two weeks, and a receipt for it on the day.

Book a demo Work out a price