portfolio-engine / tests /test_regime_detection.py
engineportf's picture
Initial Deployment from Local Engine
208fbf8 verified
Raw
History Blame Contribute Delete
2.42 kB
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 regime_detection import detect_volatility_regime, dynamic_risk_aversion
from config import DEFAULT_CONFIG
def test_detect_volatility_regime_sorting():
rng = np.random.default_rng(42)
# Generate 3 distinct regimes to ensure sorting logic works
# Low vol (bull), Med vol (normal), High vol (crash)
rets_low = rng.normal(0.001, 0.005, 100)
rets_med = rng.normal(0.000, 0.015, 100)
rets_high = rng.normal(-0.002, 0.040, 100)
# Combine into a single series
all_rets = np.concatenate([rets_low, rets_med, rets_high])
series = pd.Series(all_rets)
res = detect_volatility_regime(series, cfg=DEFAULT_CONFIG, silent=True)
# Verify the HMM detected the high vol regime at the end
assert bool(res["is_high_vol"]) is True
assert res["current_regime"] == "Crash / High Volatility"
assert res["severity_score"] > 1.0
# Verify the state sorting worked (variances should be strictly increasing)
regime_vols = res["details"]["regime_vols"]
assert regime_vols[0] < regime_vols[1] < regime_vols[2]
def test_dynamic_risk_aversion_vix_crisis():
"""Base inputs (Aggressive profile < 6)"""
base_input = 4
base_factor = 2.0
# Crisis VIX
vix = 40.0
adj_input, adj_factor = dynamic_risk_aversion(vix, base_input, base_factor, silent=True)
# Should clamp aggressive risk profile to conservative
assert adj_input == 7
assert adj_factor >= 7.5
def test_dynamic_risk_aversion_vix_complacent():
"""Aggressive inputs"""
base_input = 8
base_factor = 2.0
# Complacent VIX
vix = 10.0
adj_input, adj_factor = dynamic_risk_aversion(vix, base_input, base_factor, silent=True)
assert adj_input == base_input
assert adj_factor < base_factor
def test_detect_volatility_regime_zeros_boundary():
"""HMM should gracefully handle a completely flat/zero return series without crashing."""
series = pd.Series(np.zeros(200))
res = detect_volatility_regime(series, cfg=DEFAULT_CONFIG, silent=True)
# Should fallback to baseline or calm regime
assert res["severity_score"] == 1.0
assert not res["is_high_vol"]