Skip to main content
Pro Feature. Requires a Pro or Ultra subscription. Get started at api.mathematicalcompany.com
Stress test your portfolio with Monte Carlo simulation, built-in crisis scenarios, and custom shocks. Compute prediction greeks and Cornish-Fisher VaR for a complete risk picture.

Full Code

"""Portfolio stress testing with Monte Carlo and scenario analysis."""

import horizon as hz

# ── Build portfolio ──
positions = [
    hz.SimPosition(market_id="election-winner", side=hz.Side.Yes, size=100.0, entry_price=0.55),
    hz.SimPosition(market_id="btc-100k", side=hz.Side.Yes, size=80.0, entry_price=0.60),
    hz.SimPosition(market_id="fed-rate-cut", side=hz.Side.No, size=50.0, entry_price=0.40),
    hz.SimPosition(market_id="gop-senate", side=hz.Side.Yes, size=60.0, entry_price=0.52),
    hz.SimPosition(market_id="eth-10k", side=hz.Side.Yes, size=40.0, entry_price=0.15),
]

# ── Run stress test ──
result = hz.stress_test(
    positions=positions,
    num_simulations=10_000,
    scenarios=[
        hz.CORRELATION_SPIKE,     # all correlations go to 1
        hz.ALL_RESOLVE_NO,        # every market resolves No
        hz.LIQUIDITY_SHOCK,       # bid-ask spreads widen 5x
        hz.TAIL_RISK,             # 3-sigma adverse move
    ],
    confidence=0.95,
)

print("Stress Test Results")
print(f"  Portfolio value:     ${result.portfolio_value:,.2f}")
print(f"  Monte Carlo VaR:    ${result.mc_var:,.2f}")
print(f"  Monte Carlo CVaR:   ${result.mc_cvar:,.2f}")
print(f"  Worst simulation:   ${result.worst_case:,.2f}")
print(f"  Best simulation:    ${result.best_case:,.2f}")

print(f"\nScenario Results:")
for scenario in result.scenarios:
    print(f"  {scenario.name}:")
    print(f"    PnL impact:  ${scenario.pnl_impact:,.2f}")
    print(f"    Drawdown:    {scenario.drawdown_pct:.1%}")

# ── Custom scenario ──
election_shock = hz.StressScenario(
    name="Election Surprise",
    description="Unexpected candidate wins, all election markets move 30 cents",
    price_shocks={
        "election-winner": -0.30,
        "gop-senate": -0.25,
    },
    correlation_override=0.9,
)

custom_result = hz.stress_test(
    positions=positions,
    num_simulations=5_000,
    scenarios=[election_shock],
)

shock = custom_result.scenarios[0]
print(f"\nElection Shock:")
print(f"  PnL impact:  ${shock.pnl_impact:,.2f}")
print(f"  Drawdown:    {shock.drawdown_pct:.1%}")

Prediction Greeks

Compute the sensitivity of each position to price and time changes:
"""Prediction greeks for the portfolio."""

import horizon as hz

greeks = hz.prediction_greeks(
    prob=0.55,
    market_price=0.55,
    days_to_expiry=30.0,
    size=100.0,
)

print(f"Prediction Greeks:")
print(f"  Delta:  {greeks.delta:.4f}   (PnL per 1-cent move)")
print(f"  Gamma:  {greeks.gamma:.4f}   (delta change per 1-cent move)")
print(f"  Theta:  {greeks.theta:.4f}   (daily time decay)")
print(f"  Vega:   {greeks.vega:.4f}    (sensitivity to vol)")

Cornish-Fisher VaR

For portfolios with skewed return distributions, Cornish-Fisher adjusts for non-normality:
import horizon as hz

returns = [-0.02, 0.01, -0.05, 0.02, -0.01, 0.03, -0.04, 0.01, -0.08, 0.02]

var = hz.cornish_fisher_var(returns, confidence=0.99)
cvar = hz.cornish_fisher_cvar(returns, confidence=0.99)

print(f"99% VaR:  {var:.4f}")
print(f"99% CVaR: {cvar:.4f}")

Run It

python examples/stress_test_portfolio.py
See Simulation for Monte Carlo details and Sentinel for live risk monitoring.