131 lines
4.0 KiB
Python
131 lines
4.0 KiB
Python
"""Test all Pydantic models and enums."""
|
|
import pytest
|
|
from datetime import date
|
|
from models import (
|
|
MarketRegime, OIState, BreadthBucket, VolRegime,
|
|
MarketStateVector, FactorScore, RegimeResult,
|
|
SignalFeatureRecord, ExpectancyReport, DailyOutput,
|
|
FactorContribution, SufficiencyLevel, SignalGrade,
|
|
)
|
|
|
|
|
|
class TestEnums:
|
|
def test_regime_values(self):
|
|
assert MarketRegime.TREND.value == "TREND"
|
|
assert MarketRegime.RANGE.value == "RANGE"
|
|
assert MarketRegime.PANIC.value == "PANIC"
|
|
|
|
def test_oi_state_has_neutral(self):
|
|
assert OIState.NEUTRAL.value == "Neutral"
|
|
assert len(OIState) == 5
|
|
|
|
def test_breadth_bucket_values(self):
|
|
assert BreadthBucket.EXTREME.value == "EXTREME"
|
|
assert len(BreadthBucket) == 5
|
|
|
|
def test_vol_regime_values(self):
|
|
assert VolRegime.LOW_VOL.value == "LOW_VOL"
|
|
assert VolRegime.EXPLOSIVE_VOL.value == "EXPLOSIVE_VOL"
|
|
|
|
|
|
class TestMarketStateVector:
|
|
def test_minimal_construction(self):
|
|
sv = MarketStateVector(
|
|
date="2026-06-24",
|
|
regime=MarketRegime.TREND,
|
|
regime_confidence=0.82,
|
|
regime_version="v1_price_breadth_vol",
|
|
)
|
|
assert sv.date == date(2026, 6, 24)
|
|
assert sv.regime == MarketRegime.TREND
|
|
assert sv.breadth_top50 == 50.0 # default
|
|
|
|
def test_date_string_parsing(self):
|
|
sv = MarketStateVector(
|
|
date="2026-01-15",
|
|
regime=MarketRegime.RANGE,
|
|
regime_confidence=0.55,
|
|
regime_version="v1_price_breadth_vol",
|
|
)
|
|
assert sv.date == date(2026, 1, 15)
|
|
|
|
def test_compute_hash(self):
|
|
sv = MarketStateVector(
|
|
date="2026-06-24",
|
|
regime=MarketRegime.TREND,
|
|
regime_confidence=0.82,
|
|
regime_version="v1_price_breadth_vol",
|
|
breadth_bucket=BreadthBucket.EXTREME,
|
|
oi_state=OIState.NEW_LONGS,
|
|
volatility_regime=VolRegime.NORMAL_VOL,
|
|
)
|
|
h = sv.compute_hash()
|
|
assert len(h) == 12
|
|
# Same state = same hash
|
|
sv2 = MarketStateVector(
|
|
date="2026-06-25",
|
|
regime=MarketRegime.TREND,
|
|
regime_confidence=0.80,
|
|
regime_version="v1_price_breadth_vol",
|
|
breadth_bucket=BreadthBucket.EXTREME,
|
|
oi_state=OIState.NEW_LONGS,
|
|
volatility_regime=VolRegime.NORMAL_VOL,
|
|
)
|
|
assert sv2.compute_hash() == h
|
|
|
|
def test_state_embedding(self):
|
|
sv = MarketStateVector(
|
|
date="2026-06-24",
|
|
regime=MarketRegime.TREND,
|
|
regime_confidence=0.82,
|
|
regime_version="v1_price_breadth_vol",
|
|
breadth_top20=80.0,
|
|
breadth_top30=75.0,
|
|
breadth_top50=70.0,
|
|
regime_maturity_score=60.0,
|
|
)
|
|
emb = sv.state_embedding()
|
|
assert len(emb) == 5
|
|
assert emb[0] == 80.0
|
|
assert emb[3] == 60.0
|
|
|
|
|
|
class TestRegimeResult:
|
|
def test_construction(self):
|
|
r = RegimeResult(
|
|
date="2026-06-24",
|
|
regime=MarketRegime.TREND,
|
|
confidence=0.82,
|
|
regime_version="v1_price_breadth_vol",
|
|
maturity_score=55.0,
|
|
all_scores={"TREND": 82.0, "RANGE": 45.0, "PANIC": 20.0},
|
|
confirmation_days=5,
|
|
)
|
|
assert r.regime == MarketRegime.TREND
|
|
assert r.confirmation_days == 5
|
|
|
|
|
|
class TestExpectancyReport:
|
|
def test_insufficient(self):
|
|
r = ExpectancyReport(
|
|
signal_type="B3",
|
|
date="2026-06-24",
|
|
final_estimate=0.0,
|
|
sufficiency=SufficiencyLevel.INSUFFICIENT,
|
|
source="insufficient",
|
|
)
|
|
assert r.final_estimate == 0.0
|
|
assert r.sufficiency == SufficiencyLevel.INSUFFICIENT
|
|
|
|
|
|
class TestFactorContribution:
|
|
def test_construction(self):
|
|
fc = FactorContribution(
|
|
factor="ETF Flow",
|
|
raw_score=85.0,
|
|
weight=0.1925,
|
|
impact=6.7,
|
|
direction="bullish",
|
|
)
|
|
assert fc.impact > 0
|