import sys import os import pytest import numpy as np import pandas as pd _this_dir = os.path.dirname(os.path.abspath(__file__)) sys.path.insert(0, _this_dir) from risk_attribution import cvar_attribution, stress_correlation def test_cvar_fallback_branch(): rng = np.random.default_rng(42) # Generate an artificially small dataset with very low variance # to trigger the "Empirical tail too thin (<3 obs)" fallback branch tickers = ["AAPL", "TLT"] dates = pd.date_range("2023-01-01", periods=10, freq="B") # Only 10 observations, tail at 95% will have 0.5 obs < 3 returns_df = pd.DataFrame({ "AAPL": rng.normal(0, 0.01, 10), "TLT": rng.normal(0, 0.01, 10) }, index=dates) weights = pd.Series({"AAPL": 0.6, "TLT": 0.4}) # This should trigger the parametric fallback component_cvar, total_cvar = cvar_attribution(weights, returns_df, alpha=0.95) assert total_cvar > 0 assert len(component_cvar) == 2 assert "AAPL" in component_cvar def test_stress_correlation_bounds(): rng = np.random.default_rng(42) tickers = ["A", "B", "C"] # Base covariance matrix with some positive correlation cov = np.array([ [0.04, 0.01, 0.01], [0.01, 0.04, 0.01], [0.01, 0.01, 0.04] ]) cov_df = pd.DataFrame(cov, index=tickers, columns=tickers) weights = pd.Series({"A": 0.4, "B": 0.4, "C": 0.2}) # Apply a massive shock to trigger clipping stressed_cov_df, stressed_vol = stress_correlation(weights, cov_df, shock_corr=0.9) # Check that correlations don't exceed 1.0 (implied by variance and covariance) vols = np.sqrt(np.diag(stressed_cov_df.values)) outer_vols = np.outer(vols, vols) corr_mat = stressed_cov_df.values / outer_vols # Max correlation off-diagonal should be <= 1.0 np.testing.assert_array_less(corr_mat - 1e-5, 1.0) # Stressed vol should be higher than normal vol normal_vol = np.sqrt(weights.values.T @ cov_df.values @ weights.values) assert stressed_vol > normal_vol