Faster Algorithm for FRTB SBM Risk Aggregation
Faster Algorithm for FRTB SBM Risk Aggregation

Building regulatory risk application with python and atoti

In this post, I want to discuss a faster approach to compute the variance-covariance formulae present by regulatory capital models — FRTB SBM and CVA Risk Framework — as well as ISDA SIMM and internal sensitivity-based VaR-type models, and illustrate this approach with a sample implementation of SBM Equity Delta aggregation in atoti. I would like to thank Robert Mouat for sharing his ideas on multi-threading in the FRTB Accelerator and on the matrix formula optimization.

All of the above-mentioned methodologies use a series of nested variance-covariance formulae — see an example below — to compute a VaR-like risk measure. For the justification of the nested variance-covariance formulae please refer to “From Principles to Model Specification” document by ISDA SIMM, March 3, 2016.

One of the roll-up steps involves a high-cardinality operation — aggregating risk factors into buckets — since there might be thousands of risk factors in certain risk classes, for instance, in credit spreads and equities, brute-force application of the formula is expensive. Since we want to be able to recompute SBM dynamically, explore portfolios and apply simulations, the efficiency of the calculation is critical.

The naïve approach to the bucket-level aggregation has O(N2) time complexity:

The trick is to leverage the fact that many of the risk factor pairs use the same value of the correlation 𝞺kl — so that it can be taken out of the double sum and the formulae can be rearranged.

Equity Delta Bucket-Level Rollup Optimisation

We’ll group the pairs of equity delta risk factors sharing the same correlation value. The Equity Delta risk factor correlations are set in paragraph [MAR21.78] of the Consolidated Basel Framework and allow us to break the pairs as follows:

Group 1: same name, different type (spot/repo): constant value 0.999 per [MAR21.78]

Group 2: different name, same type: a single value depending on the bucket, for example, 0.15

Group 3: different name, different type: value depending on the bucket and multiplied by 0.999, for example, 0.15 x 0.999

Now let’s look at how the formulae can be rearranged for groups of risk factor pairs having the same risk factor correlation.

Let’s start with the pairs where both risk factors are either spot or repo — cases 1. and 2. above. Since for any 𝑘 and 𝑙 the correlation 𝜌𝑘𝑙 will be equal to the correlation defined per bucket 𝜌𝑛𝑎𝑚𝑒𝑠, their contribution can be rewritten — “reduced formula”:

This calculation is O(N) complexity.

Python implementation

I used python and atoti to implement this formula as follows:

The contribution of the risk factors where one risk factor belongs to “SPOT” and the other belongs to “REPO” — case 3 above — can be rearranged as follows and computed with O(N) time complexity:

where:

- J — is a matrix of ones,

- first term in the above formula performs aggregation of all sensitivities as if they all are correlated at 𝜌𝑛𝑎𝑚𝑒𝑠,

- the second term is to correct the first term and to account for the fact that risk factors, where spot and repo risk factors have the same equity name, must be correlated at 0.999.

This is my code snippet implementing the contribution of pairs having spot and repo risk factors — called “cross repo spot contribution”:

Combining the spot, repo and cross spot/repo paris into Kb measure and checking whether the bucket is 11 or not (see Kb formula for bucket 11 in [MAR21.79]):

Dynamic aggregation in atoti

I used the above rearranged formulae to implement measures for the on-the-fly aggregation with python and atoti, you can download my example here: Notebook example for Equity Delta SBM.

My sample data has about 1000 different names, and most of them sit in bucket #2,

and the whole SBM chain from sensitivities to weighted sensitivities to bucket level charges and equity delta risk charge is re-aggregated interactively:

Let’s look at how the chain of SBM measures can be implemented.

I’m using atoti “where” function to check whether I should use the basic or formula for the Delta margin as prescribed in [MAR21.4(5)(b)(ii)]:

When Sb is equal to the net weighted sensitivity — as per the basic formula in MAR21.4(5)(a) — I’m using square_sum and sum aggregation functions in atoti:

To implement the alternative formula from [MAR21.4(5)(b)], I’m first computing the Sb and Sc and then aggregating them.

We’ve discussed the bucket-level calculation — “Kb” — in details in the previous section, so the only measure that we haven’t discussed so far is the weighted sensitivity calculation which is trivial:

Please refer to the notebook example if you wish to learn more about input data and model that I used.

Conclusion

In this post, we discussed how to rearrange the variance-covariance formula so that it can be computed more efficiently. Two additional notes on that:
['Anastasia V Polyakova']
['Fintech', 'Technology', 'Regulation', 'Analytics', 'Risk Management']