Monte Carlo · Methodology
Crisis and Stress Scenarios
Scenario arms are conditional sensitivities, not frequency claims. Each one asks a bounded question: if this specific thing happened, what would it have done to this plan? None of them carries an occurrence probability, and the engine records that explicitly rather than leaving it to be inferred.
The contract every scenario obeys
Every scenario runs under common random numbersagainst the base arm. Path in the scenario is path in the base run, so the difference between them is the intervention rather than two independent draws.
The drift target is resolved once per run from the frozen panel plus the configuration, so the base run and every scenario share one drift assumption. A scenario measures the stress, never a different view of expected returns.
Every result persists the exact intervention, target, duration, execution and reinvestment rules, and sets event_probability: null with calibration_status: deterministic_counterfactual_no_event_probability on the deterministic arms. A scenario result is never a statement about how likely the scenario is.
Historical replay arms
These reweight the resampler toward a labelled historical window rather than injecting a synthetic shock. The mechanism is a fivefold weighting applied at each eligible block restart, so a path is more likely to begin drawing from the stressed window but the days it draws are still real observed days with their real cross-asset structure intact.
Both replay arms need the block_bootstrap process. That process is retired and no plan grants it, so you cannot request it. The engine skips a replay arm on any other process and reports the reason with the result. One route still reaches these arms: a panel too short for the default generator falls back to block_bootstrap, with the fallback disclosed on the run.
2008 replay 2008_repeat
Blocks starting inside the labelled 2008-09-01 to 2009-03-31 window are weighted five times at every eligible block restart. Requires block_bootstrap, which is retired and which no plan grants, so this arm is skipped with the reason on every process a customer can select.
COVID replay covid_repeat
The same fivefold window-start weighting applied to the 2020-02-01 to 2020-05-31 window. It carries the same block_bootstrap requirement, so it is skipped with the reason on every process a customer can select.
Single-name blowup single_name_blowup
One -40% single-session shock per simulated path-year, applied to a randomly selected eligible holding above 5% weight.
Bear regime start bear_regime_start
Forces the regime chain to open in the fitted high-volatility state. Requires the regime bootstrap with a successful fit.
A crisis window must contribute at least ten trading days of the frozen history before the scenario is considered runnable. A window your data cannot support, such as COVID when the calibration history starts after 2020, is reported in skipped_scenarios with the reason rather than silently dropped.
The weighting is a versioned non-probabilistic intervention rule. It is fixed by product decision and is deliberately not derived from the observed crisis arrival rate described below.
Deterministic market-mechanics stresses
Four opt-in arms cover risks that ordinary return resampling cannot express cleanly, because they are mechanical events rather than draws from a return distribution.
Permanent loss permanent_loss
The largest initial holding is written to zero on session one, then excluded from later contributions, rebalances and pathwise re-fits.
Why it exists. Return resampling can produce a large drawdown, but it always assumes the asset still exists and can recover. Fraud, delisting and capital destruction do not behave that way.
Liquidity freeze liquidity_freeze
Discretionary rebalancing is suspended for three months, and unavoidable cash-flow trades price at 500 bps per side.
Why it exists. Separates the risk of holding an asset from the risk of being unable to trade it. The SIP still has to buy and the SWP still has to sell.
Multi-session price band multi_session_price_band
Five consecutive -10% closes on the largest holding, compounded.
Why it exists. Models the Indian circuit-breaker mechanic where a name can only fall a fixed percentage per session, so a repricing takes several days to complete.
Correlation spike correlation_spike
The first 63 sessions are symmetrically whitened and recoloured to 0.90 off-diagonal correlation, retaining the calibration asset scales.
Why it exists. Diversification fails exactly when it is needed. This holds each asset's own volatility fixed and moves only the dependence structure, so the effect is attributable.
Fast crisis entry fast_crisis_entry
The slow variance layer of the regime processes has a median fitted half-life of about 414 sessions, so a simulated path reaches a stressed level over months. Across 300,000 measured paths it produced no entry to three times volatility by session 5. The 2008 and COVID episodes crossed three times within 4 and 9 sessions of their last calm window. Since mc-v1.24.0, this opt-in scenario applies a deterministic fast-entry state, fhs-stress-fast-entry-v1, to the conditional variance of every holding:
Here counts simulated sessions from zero. Every path opens at three times its conditional volatility, and the excess log variance halves every 21 sessions: the volatility multiplier is about 2.54 at session 5 and 1.73 at session 21. The state adds to the slow layer in logs where a process has one, inside the same bound, and the conditional volatility clamp still applies. It stays out of the GJR recursion, so the declared half-life is its whole persistence.
- The state uses no random numbers, so the scenario arm keeps the base arm's common random numbers and the paired delta measures the variance path alone.
- The engine accepts only points from a grid declared before any result was read: an initial multiplier of 2, 3 or 4 and a half-life of 10, 21 or 63 sessions. The preset uses 3 and 21.
- It applies to
fhs_gjr_garch_vt,fhs_gjr_garch,fhs_ewma,fhs_gjr_regimeandfhs_gjr_regime_uv_fallback. Ongbm_lognormaland the simple-return processes it is reported inskipped_scenarioswith the reason, because those processes have no variance state to raise. - The artifact records the mechanism, its version and its parameters in
scenario_assumptions.fast_entry_stress, withevent_probability: null.
It is a stress severity, not an event probability and not a calibrated forecast. The rolling-origin harness has not validated it. A run that selects no stress scenario does not change. The API and the MCP submit_monte_carlo tool accept it.
Two mechanics worth stating precisely
Price bands compound, they do not add
Five consecutive 10% down sessions is not a 50% loss. The correct arithmetic is
The engine compounds the closes rather than summing the daily percentages. The nine-percentage-point difference is not a rounding detail on a concentrated holding.
Correlation spikes are applied by whitening and recolouring
Raising a correlation matrix cannot be done by editing the off-diagonal entries: the result is usually not positive semi-definite, and it silently changes each asset's own variance. The engine instead factors the calibration correlation as , maps the simulated block to uncorrelated coordinates, then recolours it under the target:
The transform is symmetric, the target matrix is positive definite by construction for any off-diagonal value strictly below 1, and each asset's marginal scale is restored afterwards. Only the dependence structure moves.
The calibration evidence behind the named scenarios
Every run carries the digest-verified BSE SENSEX episode registry that sits behind its named stress scenarios. The frozen window runs from 1997-07-02 through 2026-07-28, contains 7,160 returns, and spans 29.0711 calendar years.
| Distinct 20% drawdown episodes | 8 |
| Observed historical rate | 0.27519 episodes per year |
| Median peak-to-trough depth | 33.64% |
| Most severe | 60.91% |
| Median duration | 243.5 sessions |
| Exact 95% Poisson interval on the rate | 0.11881 to 0.54223 per year |
Each episode publishes its start, trough and recovery dates, depth and duration. The Poisson interval is included specifically to show how little eight events identify, even under the generous assumption that crises arrive at a constant rate:
The upper bound is more than four and a half times the lower one. That width is the reason the rate is not converted into an annual crisis probability, does not enter the generator, and does not alter scenario sampling. The observed rate and empirical severity describe a frozen broad-market sample. They are not a statement about the probability, timing or severity of a future portfolio crisis.
A missing or damaged snapshot fails closed to the same non-probabilistic scenario contract rather than to a softer one.
Related pages
History governance covers what your own calibration window contains and why a long window is not the same as an informative one. Regime-switching bootstrap is the generator that bear_regime_start conditions. The variance-regime process describes the slow entry that fast_crisis_entry stresses, and output statistics defines the scenario comparison block.
References
- Garman, M. B. (1996). Improving on VaR. Risk, 9(5). On the distinction between a scenario and a probability statement.
- Kupiec, P. (1998). Stress Testing in a Value at Risk Framework. Journal of Derivatives, 6(1), 7–24.
- Basel Committee on Banking Supervision (2018). Stress testing principles. BCBS 450. The source of the separation between deterministic counterfactuals and calibrated probability models.
- Longin, F., & Solnik, B. (2001). Extreme Correlation of International Equity Markets. Journal of Finance, 56(2), 649–676. The empirical basis for treating correlation as state-dependent.