Scenario Gates
Forward-looking tail-risk checks: what if X happens?
ScenarioGuard runs forward-looking risk checks. Instead of watching current drawdown (which is reactive), scenarios ask “what if the market drops 10% right now?” and compute the hypothetical P&L against the current portfolio.
Available scenarios
python
from horizon.risk import Scenario
Scenario.MarketDrop(pct=-0.10)
Scenario.VolSpike(vix_to=40)
Scenario.CryptoCrash(pct=-0.30)
Scenario.PredictionMarketBinary(asset="ELECTION_YES", outcome="NO")
Scenario.CorrelationToOne()
Each scenario is a dataclass that knows how to apply its shock to a portfolio position and compute P&L impact.
ScenarioGuard
python
from horizon.risk import Scenario, ScenarioGuard
scenarios = ScenarioGuard(
enabled_scenarios=[
Scenario.MarketDrop(pct=-0.10),
Scenario.VolSpike(vix_to=40),
Scenario.CryptoCrash(pct=-0.30),
Scenario.CorrelationToOne(),
],
max_scenario_drawdown_pct=0.15,
check_frequency="daily",
block_orders_if_worsens=True,
alert_on_breach=True,
)
enabled_scenarioslist[Scenario]Scenarios to evaluate.
max_scenario_drawdown_pctfloatThreshold for "this scenario would hurt us too much". When any scenario implies a drawdown beyond this, fire.
check_frequencystrHow often to run the full scenario suite. Too frequent is wasteful; too infrequent and you miss a buildup.
block_orders_if_worsensboolWhen True, pre-trade checks reject orders that would make any scenario worse.
alert_on_breachboolFire alerts when any scenario crosses the threshold.
Scenario types
How it works
Snapshot current portfolio
Read all open positions and their current P&L.
Apply each scenario
For each enabled scenario, compute the hypothetical P&L impact on the current portfolio.
Compute implied drawdown
For each scenario, implied drawdown = scenario_pnl_impact / current_equity.
Check threshold
If any scenario's drawdown >
max_scenario_drawdown_pct, the scenario is "breached."Act on breach
- Alert the operator (if
alert_on_breach=True)
- Block orders that would worsen the breach (if block_orders_if_worsens=True)Usage
python
from horizon.risk import RiskConfig, Scenario, ScenarioGuard
risk = RiskConfig(
scenarios=ScenarioGuard(
enabled_scenarios=[
Scenario.MarketDrop(-0.10),
Scenario.VolSpike(vix_to=40),
Scenario.CorrelationToOne(),
],
max_scenario_drawdown_pct=0.20,
check_frequency="daily",
),
)
Why it matters
Traditional risk (drawdown guards, stops) is reactive: it only fires after losses have already occurred. Scenario gates are proactive: they catch portfolios that look fine today but have hidden tail risk.
A portfolio can:
- Be at a new equity peak (drawdown = 0%)
- Have no positions near stop levels
- Have perfect margin utilization
…and still implode if one specific scenario plays out. The scenario guard is the layer that catches this before it happens.