"""Test regime detector and validation.""" import pytest from datetime import date import pandas as pd import numpy as np class TestRegimeDetector: def test_detects_trend(self): from regime_detector import RegimeDetector from models import MarketRegime d = RegimeDetector() r = d.detect(75.0, 80.0, "NORMAL_VOL", date(2026, 6, 24)) assert r.regime == MarketRegime.TREND assert r.confidence > 0.5 def test_detects_range(self): from regime_detector import RegimeDetector from models import MarketRegime d = RegimeDetector() r = d.detect(50.0, 50.0, "LOW_VOL", date(2026, 6, 24)) assert r.regime in (MarketRegime.RANGE, MarketRegime.TREND) def test_detects_panic(self): from regime_detector import RegimeDetector from models import MarketRegime d = RegimeDetector() r = d.detect(15.0, 10.0, "EXPLOSIVE_VOL", date(2026, 6, 24)) assert r.regime == MarketRegime.PANIC def test_2day_confirmation(self): from regime_detector import RegimeDetector from models import MarketRegime d = RegimeDetector() # Day 1: RANGE r1 = d.detect(50.0, 50.0, "LOW_VOL", date(2026, 6, 24)) assert r1.regime == MarketRegime.RANGE # first run, no confirmation needed # Day 2: still RANGE r2 = d.detect(50.0, 50.0, "LOW_VOL", date(2026, 6, 25)) assert r2.regime == MarketRegime.RANGE assert r2.confirmation_days == 2 def test_transition_needs_confirmation(self): from regime_detector import RegimeDetector from models import MarketRegime d = RegimeDetector() # Establish TREND d.detect(75.0, 80.0, "NORMAL_VOL", date(2026, 6, 24)) d.detect(75.0, 80.0, "NORMAL_VOL", date(2026, 6, 25)) # Day 3: weak scores → raw best = RANGE, but TREND should persist r3 = d.detect(35.0, 40.0, "NORMAL_VOL", date(2026, 6, 26)) # First day of pending transition — should still be TREND assert r3.regime == MarketRegime.TREND assert d.pending_regime is not None def test_version_is_stored(self): from regime_detector import RegimeDetector d = RegimeDetector(regime_version="v1_price_breadth_vol") r = d.detect(75.0, 80.0, "NORMAL_VOL", date(2026, 6, 24)) assert r.regime_version == "v1_price_breadth_vol" def test_load_state(self, db_path): from regime_detector import RegimeDetector from models import MarketRegime d = RegimeDetector() d.load_state(db_path) # DB has TREND for first 100 days, so most recent should load assert d.current_regime is not None def test_confidence_for_confirmed_regime(self): """Confidence should be for the confirmed regime, not raw best.""" from regime_detector import RegimeDetector from models import MarketRegime d = RegimeDetector() # Establish TREND d.detect(75.0, 80.0, "NORMAL_VOL", date(2026, 6, 24)) d.detect(75.0, 80.0, "NORMAL_VOL", date(2026, 6, 25)) # Now feed weak scores → raw best would be PANIC or RANGE r = d.detect(15.0, 10.0, "EXPLOSIVE_VOL", date(2026, 6, 26)) # Should still report TREND (need 2 confirmations to switch) assert r.regime == MarketRegime.TREND class TestTransitionValidator: def test_stable_regime_passes(self): from validation.transition_validator import TransitionValidator # Create stable regime sequence: long periods seq = pd.Series( ["TREND"] * 50 + ["RANGE"] * 50 + ["PANIC"] * 40, index=pd.date_range("2026-01-01", periods=140), ) tv = TransitionValidator() report = tv.validate(seq) assert report.is_stable assert report.avg_duration > 20 assert report.flip_rate < 0.05 def test_unstable_regime_fails(self): from validation.transition_validator import TransitionValidator # Create unstable sequence: flips every 2 days seq = pd.Series( ["TREND", "TREND", "RANGE", "RANGE", "TREND", "TREND", "PANIC", "PANIC", "RANGE", "RANGE"] * 5, index=pd.date_range("2026-01-01", periods=50), ) tv = TransitionValidator() report = tv.validate(seq) assert not report.is_stable assert report.flip_rate > 0.15