Risk Management¶
qufin provides comprehensive risk analytics including VaR, CVaR, stress testing, and counterparty risk.
Value at Risk (VaR)¶
Three estimation methods, all returning VaRResult with dollar amounts:
from qufin.risk.classical_var import historical_var, parametric_var, monte_carlo_var
returns = ... # (T,) array of portfolio returns
# Historical (empirical percentile)
result = historical_var(returns, confidence=0.95, portfolio_value=10_000_000)
print(f"95% VaR: ${result.var_dollar:,.0f}")
print(f"ES: ${result.es_dollar:,.0f}")
# Parametric (Gaussian assumption)
result = parametric_var(returns, confidence=0.99)
# Monte Carlo (simulated)
result = monte_carlo_var(returns, confidence=0.99, n_simulations=1_000_000, horizon=10)
Portfolio VaR¶
Convenience function that combines weights with asset returns:
from qufin.risk.classical_var import portfolio_var
result = portfolio_var(
asset_returns, # (T, N) matrix
weights, # (N,) vector
confidence=0.95,
method="historical", # or "parametric", "monte_carlo"
)
Conditional VaR (CVaR / Expected Shortfall)¶
from qufin.risk.cvar import cvar_from_samples, portfolio_cvar, CVaRObjective
# Simple CVaR
cvar = cvar_from_samples(portfolio_returns, alpha=0.05)
# Portfolio CVaR
cvar = portfolio_cvar(asset_returns, weights, alpha=0.05)
# CVaR as optimization objective (for QAOA/VQE)
obj = CVaRObjective(alpha=0.5)
value = obj.evaluate(costs, counts)
Ascending CVaR Schedule¶
Progressively shift from tail to mean during optimization:
from qufin.risk.cvar import AscendingCVaR
schedule = AscendingCVaR(alpha_start=0.1, alpha_end=1.0, n_steps=100)
for step in range(100):
objective = schedule.get_objective()
# ... use in optimizer ...
schedule.step()
Stress Testing¶
Pre-built scenarios based on historical crises:
from qufin.risk.stress import stress_test_suite, SCENARIO_LIBRARY
# Run all scenarios
results = stress_test_suite(
portfolio_value=50_000_000,
weights=[0.6, 0.2, 0.1, 0.1], # equity, rates, vol, spreads
)
for name, res in results.items():
print(f"{name}: ${res['total_pnl']:,.0f} ({res['pct_loss']:.1%})")
Built-in scenarios:
| Scenario | Equity Shock | Rates Shock | Vol Shock |
|---|---|---|---|
| Black Monday 1987 | -22.6% | -50 bps | +150% |
| GFC 2008 | -38.0% | -200 bps | +200% |
| COVID 2020 | -34.0% | -150 bps | +400% |
| Rate Hiking 2022 | -19.0% | +300 bps | +50% |
Custom scenarios:
from qufin.risk.stress import StressScenario, apply_stress
custom = StressScenario(
name="Tail Event",
date="custom",
equity_shock=-0.50,
rates_shock=-300,
vol_shock=5.0,
spread_shock=500,
)
result = apply_stress(portfolio_value, weights, custom)
Counterparty Risk (CVA)¶
from qufin.risk.counterparty import (
CounterpartyExposure, compute_cva, compute_ead_sa_ccr, portfolio_cva,
)
exposure = CounterpartyExposure(
name="JPMorgan IRS",
notional=100_000_000,
pd=0.001,
lgd=0.45,
exposure_profile=np.array([...]), # time series of expected exposure
)
cva = compute_cva(exposure, risk_free_rate=0.03)
ead = compute_ead_sa_ccr(notional=1e8, mtm=5e6, add_on_factor=0.01)
Credit Risk¶
Gaussian Copula (Vasicek)¶
from qufin.risk.credit.gaussian_copula import vasicek_analytical
result = vasicek_analytical(pd=0.02, rho=0.15, lgd=0.45, confidence=0.999)
print(f"Expected Loss: {result['expected_loss']:.4f}")
print(f"VaR 99.9%: {result['var']:.4f}")
Quantum Stress Testing¶
Run quantum-enhanced stress tests with predefined crisis scenarios:
from qufin.risk.quantum_stress import QuantumStressTester, classical_stress_test
tester = QuantumStressTester(backend=backend)
results = tester.run_scenarios(portfolio_weights, portfolio_value=1_000_000)
# Classical alternative
results = classical_stress_test(portfolio_weights, portfolio_value=1_000_000)
Predefined scenarios: GFC 2008, COVID 2020, Rate Hike 2022.