"""Tests for point-in-time signal context snapshots.""" from __future__ import annotations import json from datetime import date, datetime, timezone import pytest from app.models.fundamental import FundamentalData from app.models.score import CompositeScore, DimensionScore from app.models.sentiment import SentimentScore from app.models.signal_context_snapshot import SignalContextSnapshot from app.models.ticker import Ticker from app.models.trade_setup import TradeSetup from app.services import rr_scanner_service as rr from tests.conftest import _test_session_factory # type: ignore @pytest.fixture async def session(): async with _test_session_factory() as s: yield s async def test_create_signal_context_snapshot_captures_latest_context(session): now = datetime(2026, 7, 2, 12, tzinfo=timezone.utc) ticker = Ticker(symbol="CTX") session.add(ticker) await session.flush() session.add_all([ DimensionScore( ticker_id=ticker.id, dimension="technical", score=71.0, is_stale=False, computed_at=now, ), DimensionScore( ticker_id=ticker.id, dimension="momentum", score=82.0, is_stale=False, computed_at=now, ), CompositeScore( ticker_id=ticker.id, score=76.5, is_stale=False, weights_json='{"technical": 0.25}', computed_at=now, ), SentimentScore( ticker_id=ticker.id, classification="BULLISH", confidence=78, source="test", timestamp=now, reasoning="", citations_json="[]", recommendation="BUY", ), FundamentalData( ticker_id=ticker.id, pe_ratio=25.0, revenue_growth=0.18, earnings_surprise=0.05, market_cap=1_000_000_000.0, next_earnings_date=date(2026, 8, 1), fetched_at=now, unavailable_fields_json="{}", ), ]) setup = TradeSetup( ticker_id=ticker.id, direction="long", entry_price=100.0, stop_loss=95.0, target=120.0, rr_ratio=4.0, composite_score=76.5, detected_at=now, confidence_score=64.0, momentum_percentile=88.0, recommended_action="LONG_HIGH", risk_level="Low", ) session.add(setup) await session.flush() await rr._create_signal_context_snapshots(session, [setup]) await session.commit() row = (await session.get(SignalContextSnapshot, 1)) assert row is not None assert row.trade_setup_id == setup.id assert row.strategy_version == rr.STRATEGY_VERSION assert row.momentum_percentile == 88.0 score = json.loads(row.score_context_json) sentiment = json.loads(row.sentiment_context_json) fundamental = json.loads(row.fundamental_context_json) assert score["composite_score"] == 76.5 assert score["dimensions"]["technical"]["score"] == 71.0 assert sentiment["classification"] == "BULLISH" assert sentiment["confidence"] == 78 assert fundamental["pe_ratio"] == 25.0 assert fundamental["next_earnings_date"] == "2026-08-01"