Disclosure: AI assistance was used in preparing this article. The code is an illustrative research example, not a production risk engine or investment recommendation.
A portfolio can appear diversified under normal market conditions and still become highly exposed when several risk factors deteriorate together.
For example, a digital-asset portfolio may face:
- Falling BTC and ETH prices.
- Rising implied volatility.
- Higher cross-asset correlation.
- Reduced order-book depth.
- Wider execution spreads.
Testing these conditions independently may miss the combined effect.
A more useful approach is to define coherent scenarios, apply their shocks to portfolio positions, and separately account for stressed execution costs.
1. Define the portfolio
Start with a simple portfolio containing two linear positions.
import pandas as pd
portfolio = pd.DataFrame({
"asset": ["BTC", "ETH"],
"notional_usd": [500_000, 300_000]
})
print(portfolio)
The notional values represent the portfolio's exposure before applying the scenario.
This example deliberately excludes options and other nonlinear instruments. Those require instrument-specific valuation models.
2. Define joint market scenarios
Instead of changing one asset at a time, define scenarios that describe a consistent set of market conditions.
scenarios = {
"moderate_stress": {
"BTC": -0.10,
"ETH": -0.15,
"execution_cost_bps": 20
},
"severe_stress": {
"BTC": -0.20,
"ETH": -0.25,
"execution_cost_bps": 75
},
"extreme_stress": {
"BTC": -0.30,
"ETH": -0.40,
"execution_cost_bps": 150
}
}
These values are illustrative assumptions, not calibrated historical estimates or forecasts.
The execution-cost assumptions are also simplified. In a production model, costs should depend on order size, market depth, spread, volatility, and execution horizon.
3. Calculate stressed portfolio losses
For a linear position:
[
P&L_i=N_i \times r_i
]
Where:
- (N_i) is the position's signed USD notional.
- (r_i) is the scenario return.
Execution costs can then be estimated separately.
def run_stress_test(portfolio, scenarios):
results = []
for scenario_name, shocks in scenarios.items():
market_pnl = 0.0
gross_notional = 0.0
for _, position in portfolio.iterrows():
asset = position["asset"]
notional = position["notional_usd"]
market_pnl += (
notional * shocks[asset]
)
gross_notional += abs(notional)
execution_cost = (
gross_notional
* shocks["execution_cost_bps"]
/ 10_000
)
total_pnl = market_pnl - execution_cost
results.append({
"scenario": scenario_name,
"market_pnl_usd": market_pnl,
"execution_cost_usd": execution_cost,
"total_pnl_usd": total_pnl
})
return pd.DataFrame(results)
results = run_stress_test(
portfolio,
scenarios
)
print(results)
This produces a scenario-by-scenario comparison of market losses and estimated execution costs.
Importantly, this is not a full liquidity model. The cost assumption is applied to the entire gross notional as a simplified illustration.
4. Separate market losses from execution costs
The distinction matters.
A portfolio may experience a substantial mark-to-market loss even if it can be liquidated efficiently.
Alternatively, market losses may be relatively moderate while poor liquidity makes reducing the position expensive.
These are different sources of risk.
Combining them into one unexplained number makes it harder to identify which control needs improvement.
A more developed framework should track:
- Market valuation changes.
- Bid-ask spread changes.
- Market impact.
- Position liquidation time.
- Financing and margin changes.
- Counterparty exposure.
5. Extend the model beyond linear assets
The simple example above is not sufficient for portfolios containing options.
An option's stressed value depends on more than the underlying asset's return.
A fuller scenario engine should update the relevant pricing inputs, including:
- Underlying asset prices.
- Implied volatility surfaces.
- Interest rates and financing assumptions.
- Time to expiration.
- Relevant correlation or dependence assumptions.
For sufficiently large shocks, full repricing is preferable to simply applying the current Delta.
The same principle applies to portfolios with nonlinear hedges or path-dependent instruments.
6. Add reverse stress testing
A further extension is to start with a predefined loss threshold.
For example:
LOSS_LIMIT = -150_000
results["breach"] = (
results["total_pnl_usd"] < LOSS_LIMIT
)
print(
results[
["scenario", "total_pnl_usd", "breach"]
]
)
This identifies which of the specified scenarios breaches the illustrative loss threshold.
It is not yet a complete reverse stress test.
A genuine reverse stress analysis must search for combinations of risk-factor changes that produce the specified adverse outcome, subject to documented constraints and economically meaningful assumptions.
7. From scenario results to risk controls
For KAEL AI's quantitative research, the value of scenario analysis is not simply producing a larger collection of loss estimates.
It is understanding which combinations of market conditions can undermine a strategy's risk assumptions and execution capabilities.
A practical framework should connect the results to position limits, liquidity buffers, hedge requirements, and restrictions on additional risk.
Stress testing does not guarantee that a strategy will withstand every market event.
It provides a structured way to identify vulnerabilities before those conditions become operational problems.
Conclusion
Joint market shocks can reveal risks that isolated sensitivity tests overlook.
Python provides a straightforward starting point for scenario construction and portfolio-level calculations, but realistic stress testing requires more than a few price shocks.
Liquidity, nonlinear valuation, financing, model assumptions, and execution constraints must also be considered.
The objective is to understand not only how much a portfolio might lose, but also whether the strategy can still operate within its risk limits when market conditions deteriorate.
References
Federal Reserve — Scenario Design Framework
https://www.federalreserve.gov/frrs/regulations/appendix-a-policy-statement-on-the-scenario-design-framework-for-stress-testing.htm
Federal Reserve — 2026 Stress Test Scenarios
https://www.federalreserve.gov/publications/2026-stress-test-scenarios.htm
Basel Committee — Stress Testing
https://www.bis.org/committees/bcbs/basel-consolidated-guidelines/module/rma/30
Top comments (0)