Scenario methodology: how Portfolio Lab runs stress tests
The Scenarios tab on the Risk page is a stress test for today's portfolio: it calculates what a shock to equities, interest rates, the dollar, crude oil, gold or credit spreads would do, how historical crises carry over to this portfolio and which move in a factor would trigger a given loss. It is based on a linear factor model estimated from monthly returns. This page describes what the code in core/scenarios.py actually calculates.
Data and factors
The basis is the same data as on the rest of the Risk page: monthly returns of completed months in the base currency from the settings, for all positions over their common period, at the target weights of the selected portfolio (positive weights only, scaled to 100%). Positions with a short history are extended by their proxy from the grid. In addition, there are seven factors as monthly series that the app already uses elsewhere. The code loads each series individually over its full available history, so that one short factor does not cut off the others.
| Factor | Monthly value | Series |
|---|---|---|
| Global equities | return in % | asset class Equities world (developed markets) |
| Euro rates | change in percentage points | yield on ten-year German Bunds at month-end, earlier the monthly average |
| US rates | change in percentage points | yield on ten-year US Treasuries at month-end, earlier the monthly average |
| US dollar | return in % | US dollar exchange rate in the base currency at month-end |
| Crude oil | return in % | asset class WTI crude oil (future) |
| Gold | return in % | asset class Gold |
| Credit | excess return in % | USD corporate bonds (investment grade) minus US Treasuries 10y |
The asset class returns are calculated in the base currency; for euro investors, Global equities therefore also includes exchange rate movements, and the regression separates out the dollar through its own factor. For the credit factor, the exchange rates cancel out except for a small cross term, because both asset classes are quoted in the same currency. With the US dollar as base currency, the dollar factor is dropped. If a series is missing when the data is retrieved, the page calculates without this factor and names it in a note. The interest rate series come from central bank statistics; where only monthly averages are available, they fill in only the period before the month-end values begin.
Deliberately left out of the model are euro credit spreads (the euro corporate bond series only starts in 2009), the slope of the yield curve, other currencies such as the pound, yen or Swiss franc, volatility and inflation. For these risks, either there is no long monthly series in the app, or they would overload the model at 60 months. You can recognise positions that depend mainly on them by their low R².
Regression per position
For each position, the code estimates a least squares regression of the monthly returns on all selected factors with an intercept, over the last 36, 60 or 120 common months or the entire common history; the default is 60 months, as on the rest of the page. At least 36 months are required, and at least three times as many months as there are coefficients. With all seven factors, that makes 24, so the minimum stays at 36. A factor whose series ends before the last month or is too short within the period is dropped, with a note.
rᵢₜ = αᵢ + Σₖ βᵢₖ fₖₜ + εᵢₜ
R²ᵢ = 1 − SSEᵢ / SSTᵢ, residual volatility = √(SSEᵢ / (T − K − 1)) × √12
β_p,k = Σᵢ wᵢ βᵢₖ- rᵢₜ
- monthly return of position i in month t
- fₖₜ
- value of factor k: return or change in interest rates in percentage points
- βᵢₖ
- beta: return per unit of the factor, for interest rates per percentage point
- T, K
- number of months and of factors
- wᵢ
- target weight of the position
The portfolio betas are the weighted sum of the betas. They match exactly a regression of the portfolio return, whose R² the page also shows. For each beta there is a t-statistic based on the classical standard errors. If the factors explain less than 50% of the variation of a position or of the portfolio, a note appears: in that case, every scenario captures only part of the risk. Closely related factors such as equities and credit, or euro and dollar interest rates, share the effect between them (multicollinearity). Individual betas then fluctuate strongly, but their sum in the scenario is well determined. If you want more stable betas, choose fewer factors.
Hypothetical scenarios
A scenario consists of shocks to one or more factors, such as equities −30% or euro rates +2 percentage points. For the remaining factors, there are two modes. Isolated, they stay at zero. With correlations (default), they take their conditional expectation, as proposed by Kupiec (1998) for stress tests: for jointly normally distributed factors with zero mean, this is the move you would expect on average if the shocked factors take exactly the specified values. The covariance matrix Σ is the sample covariance of the factors over the regression period.
f_S = s, f_U = Σ_US Σ_SS⁻¹ s
ΔV / V = Σₖ β_p,k fₖ = Σᵢ wᵢ Σₖ βᵢₖ fₖ
d = √(fᵀ Σ⁻¹ f)- S, U
- shocked and remaining factors
- s
- shocks to the shocked factors
- β_p,k fₖ
- contribution of factor k; the contributions per factor and per position add up exactly to the impact
- d
- Mahalanobis distance of the whole factor vector from normal conditions, in monthly standard deviations
Alphas are not included: a shock is a deviation from normal conditions, not a month with the usual return; the code also sets the factor means to zero. Each factor value comes with its z-score fₖ/σₖ in monthly standard deviations, and the scenario as a whole with its Mahalanobis distance. According to Breuer et al. (2009), the conditional expectation is the most plausible of all possible completions of the remaining factors: its Mahalanobis distance is the smallest. Kritzman and Li (2010) use the same distance as a measure of financial turbulence. If you want to model the causes and consequences of a scenario explicitly, you can use Bayesian networks (Rebonato 2010); Portfolio Lab sticks with the simpler conditional expectation.
If a portfolio value is entered, all impacts are also shown as amounts. As a measure of uncertainty, the page shows the portfolio's residual volatility for one month. Five templates set typical shocks: Equity crash (equities −30%), Rate shock (euro rates +2 percentage points), Stagflation (equities −20%, euro rates +1.5 percentage points, crude oil +50%), Dollar weakness (US dollar −10%) and Credit crisis (credit −6%). Shocks of down to −95% are allowed for equities and crude oil, and of up to ±5 percentage points for interest rates.
Historical crises
For each stored crisis window, the code measures the move of each factor from the end of the month before the first month to the end of the last month: returns compounded as Π(1 + fₜ) − 1, interest rate changes summed. These moves act on today's portfolio through today's betas, exactly like a hypothetical scenario that specifies all factors. This means that even a fund without prices from that period can be run through the crisis. If a factor is missing even a single month in the window (crude oil goes back less far as a monthly series than the other factors), its conditional expectation given the available factors is used instead. Windows without any factor series or with months after the last completed month are dropped. Supervisory principles call for scenarios that are severe but plausible (Basel Committee on Banking Supervision 2018). Twelve windows are stored, from Black Monday to the 2025 tariff shock:
| Crisis | Window | Characteristics |
|---|---|---|
| Black Monday | 10/1987 | Market crash in October 1987 |
| Russian crisis | 08/1998 | Russian default, near-collapse of the hedge fund LTCM |
| Dotcom crash | 04/2000–09/2002 | Bursting of the tech bubble, bear market until autumn 2002 |
| Financial crisis | 11/2007–02/2009 | Mortgage and banking crisis from the 2007 peak to the 2009 trough |
| Lehman collapse | 09/2008–10/2008 | The two sharpest months of the financial crisis |
| Euro debt crisis | 05/2011–09/2011 | Euro area debt crisis and US downgrade |
| Taper tantrum | 05/2013–06/2013 | Jump in bond yields after the Fed hinted at fewer bond purchases |
| Oil price slump and China | 08/2015–02/2016 | Yuan devaluation, falling oil price, growth worries |
| Late-2018 sell-off | 10/2018–12/2018 | Rate hikes and trade dispute in the fourth quarter of 2018 |
| Covid crash | 02/2020–03/2020 | Slump at the start of the pandemic |
| Rate reversal and inflation | 01/2022–09/2022 | Inflation surge, equities and bonds fall together |
| 2025 tariff shock | 03/2025–04/2025 | US tariffs, market slide and weak US dollar |
If all positions have returns for every month of the window, the actual replay is shown alongside: Π(1 + Σ wᵢ rᵢₜ) − 1, reset to the target weights every month as in the risk decomposition, with proxies as in the grid. The difference between model and replay comes from the positions' residual risk, the alphas, compounding over several months (the model applies the betas to the whole move over the window) and the fact that the betas come from today's estimation period. For long windows such as the dotcom crash, it is therefore usually larger.
Reverse stress test
For a chosen factor j, the reverse stress test looks for the shock that moves the portfolio by a specified loss L; the default is 20%, the permitted range 0.5% to 90%. Because the model is linear, there is a closed-form solution. With correlations, the whole factor vector moves in direction c, i.e. per unit of factor j, each remaining factor moves by its regression slope on factor j; isolated, only the factor itself moves.
s = L / (β_pᵀ c), f = s × c
with correlations cₖ = Σₖⱼ / Σⱼⱼ (so cⱼ = 1), isolated c = eⱼ- L
- target impact, negative for a loss
- c
- direction of the scenario per unit of factor j
- eⱼ
- unit vector: only factor j moves
The page calculates this for all factors and marks as reachable whatever lies within the factor's permitted range. If the portfolio does not react at all in a given direction, there is no solution. A linear reverse stress test only finds the size of the shock along a fixed direction; Glasserman et al. (2015) show how to determine instead the most likely combination of factor moves behind a large loss.
Limitations
- Linear: the model has no convexity. For large interest rate moves, a bond loses less and gains more than the linear calculation suggests (see Scenario analysis); options, leveraged products and portfolio insurance strategies react quite differently from what their beta implies.
- Estimation period: betas and correlations come from the selected months. Correlations often rise in crises Longin and Solnik (2001); Kim and Finger (2000) therefore estimate separate correlations for stress periods. Correlations from calm years make scenarios too mild.
- Signs can flip: whether interest rates fall or rise in an equity crash depends on the period. In years with inflation shocks, equities and interest rates move together differently than in years with growth shocks.
- Monthly data: the model does not see slumps within a month that recover by the end of the month. Historical windows measure from month-end to month-end.
- No probability: a scenario states a loss, but not how likely it is Berkowitz (2000). The Mahalanobis distance only ranks scenarios by plausibility; probabilities come from value at risk.
- Choice of factors: risks outside the seven factors, such as individual stocks, sectors or emerging market currencies, end up in the residual risk. A low R² indicates this.
Frequently asked questions
What does “with correlations” mean?
The factors that are not shocked move as their correlations with the shocked factors in the estimation period would lead you to expect on average: f_U = Σ_US Σ_SS⁻¹ s. In isolated mode, they stay at zero.
Why does the model differ from the actual replay for historical crises?
The model applies today's betas to the factor moves. The positions' residual risk, alphas, compounding over several months and betas that have changed since the crisis explain the difference.
How many months does the regression need?
At least 36 common months, and at least three times as many as there are coefficients. The default is the last 60 months.
Why is the actual replay missing for some crises?
It needs returns for all positions for every month of the window. Funds launched later can be extended with a proxy in the grid; the model calculates even without one.
How is the reverse stress test solved?
Linearly and in closed form: shock = target loss / (portfolio betas times the direction of the scenario). With correlations, the remaining factors move along, by covariance divided by variance per unit.
Literature
- Basel Committee on Banking Supervision (2018): Stress testing principles. Bank für Internationalen Zahlungsausgleich, 17.10.2018; abgerufen am 25.10.2026. Source
- Berkowitz, Jeremy (2000): A coherent framework for stress testing. The Journal of Risk 2 (2), pp. 5–15. doi:10.21314/jor.2000.021
- Breuer, Thomas; Jandačka, Martin; Rheinberger, Klaus; Summer, Martin (2009): How to Find Plausible, Severe, and Useful Stress Scenarios. International Journal of Central Banking 5 (3), pp. 205–224. Source
- Glasserman, Paul; Kang, Chulmin; Kang, Wanmo (2015): Stress scenario selection by empirical likelihood. Quantitative Finance 15 (1), pp. 25–41. doi:10.1080/14697688.2014.926019
- Kim, Jongwoo; Finger, Christopher (2000): A stress test to incorporate correlation breakdown. The Journal of Risk 2 (3), pp. 5–19. doi:10.21314/jor.2000.026
- Kritzman, Mark; Li, Yuanzhen (2010): Skulls, Financial Turbulence, and Risk Management. Financial Analysts Journal 66 (5), pp. 30–41. doi:10.2469/faj.v66.n5.3
- Kupiec, Paul H. (1998): Stress Testing in a Value at Risk Framework. The Journal of Derivatives 6 (1), pp. 7–24. doi:10.3905/jod.1998.408008
- Longin, François; Solnik, Bruno (2001): Extreme Correlation of International Equity Markets. The Journal of Finance 56 (2), pp. 649–676. doi:10.1111/0022-1082.00340
- Rebonato, Riccardo (2010): Coherent Stress Testing: A Bayesian Approach to the Analysis of Financial Stress. Wiley. doi:10.1002/9781118374719
This page describes how Portfolio Lab calculates; past results are not a forecast. All terms in the glossary.