SigmaField

Practice Risk

Generate correlated market scenarios

Medium+25 pointsAbout 35 minutesRisk

The brief

A market-risk desk revalues its book under thousands of simulated days. Each day is a joint move in four risk factors: the 2-year and 10-year yields, an equity index and the EUR/USD exchange rate. If the moves have the wrong volatilities or correlations, the risk figure is wrong.

The factors come in different units: yield changes in basis points, the others in percent. A plain simulation matches the target correlations only roughly. For reports that must reproduce the model's risk figure, the desk also wants scenarios that match the targets exactly.

Your task

  1. Write simulate_moves(vols, corr, n, seed): an array of daily moves with one row per scenario and one column per factor. Draw independent standard normals with np.random.default_rng(seed), correlate them with the Cholesky factor of corr, and scale each column by its volatility.
  2. Write matched_moves(vols, corr, n, seed): n scenarios whose sample mean is exactly 0 and whose sample covariance matrix is exactly Σ=DRD\Sigma = DRD. Here DD is the diagonal matrix of the volatilities, RR is corr, and the sample covariance divides by n−1n - 1, as np.cov does. Raise ValueError unless n is larger than the number of factors.
  3. Write pnl_volatility(vols, corr, sensitivities): the standard deviation of the book's daily P&L under the model. The P&L of a move x\mathbf{x} is s⊤x\mathbf{s}^\top\mathbf{x}, where s\mathbf{s} holds the dollars made for a move of one unit in each factor.

All three raise ValueError unless corr is square and symmetric, with 1 on its diagonal, and positive definite. They need one volatility per factor, none negative, and pnl_volatility needs one sensitivity per factor.

The data

FACTORS names the four factors with their units. VOLS holds their daily volatilities, CORR the target correlation matrix, and SENSITIVITIES the book's P&L for a move of one unit.

Hint: Where to start

Case study 3.7.4 turns a table ZZ of independent draws into correlated ones with Z @ L.T, where LL⊤LL^\top is the target. Lesson 5.5.3 gives the rule behind it: Cov⁡(AX)=AΣA⊤\operatorname{Cov}(A\mathbf{X}) = A\Sigma A^\top.

Hint: Matching exactly

For any sample, the sample covariance of ZL⊤ZL^\top is exactly LSZL⊤LS_ZL^\top (case study 3.7.4). So centre ZZ, then turn it into a table WW whose sample covariance is exactly II. If SZ=MM⊤S_Z = MM^\top (lesson 3.7.2), take W=Z(M⊤)−1W = Z(M^\top)^{-1}, found with triangular solves instead of an inverse.

Hint: The P&L

The P&L is one linear combination of jointly normal moves. Lesson 5.5.3 gives its variance, s⊤Σ s\mathbf{s}^\top\Sigma\,\mathbf{s}, and case study 5.5.5 uses the same rule for a fund.