"""Unit tests for point-in-time earnings calendar loading.""" from __future__ import annotations import datetime as dt import pyarrow as pa import pyarrow.parquet as pq from libs.backtest.earnings_calendar import ( OraclePointInTimeEarningsCalendar, load_pit_earnings_calendar, ) def test_pit_earnings_calendar_respects_as_of_revisions(tmp_path): path = tmp_path / "earnings_calendar_pit.parquet" table = pa.Table.from_pylist( [ { "symbol": "AMD", "as_of_date": "2026-01-05", "expected_reaction_date": "2026-01-09", "expected_event_date": "2026-01-08", "filing_time_bucket": "post_market", "is_cancelled": False, }, { "symbol": "AMD", "as_of_date": "2026-01-07", "expected_reaction_date": "2026-01-12", "expected_event_date": "2026-01-09", "filing_time_bucket": "post_market", "is_cancelled": False, }, { "symbol": "NVDA", "as_of_date": "2026-01-05", "expected_reaction_date": "2026-01-09", "expected_event_date": "2026-01-08", "is_cancelled": True, }, ] ) pq.write_table(table, path) load_pit_earnings_calendar.cache_clear() calendar = load_pit_earnings_calendar(str(path)) early = calendar.get_known_upcoming_reaction_dates( as_of_date=dt.date(2026, 1, 6), allowed_reaction_dates=[dt.date(2026, 1, 9), dt.date(2026, 1, 12)], ) late = calendar.get_known_upcoming_reaction_dates( as_of_date=dt.date(2026, 1, 8), allowed_reaction_dates=[dt.date(2026, 1, 9), dt.date(2026, 1, 12)], ) assert early == {"AMD": dt.date(2026, 1, 9)} assert late == {"AMD": dt.date(2026, 1, 12)} class _FakeResponse: def __init__(self, payload: dict[str, object], status_code: int = 200) -> None: self._payload = payload self.status_code = status_code def raise_for_status(self) -> None: if self.status_code >= 400: raise RuntimeError(f"http {self.status_code}") def json(self) -> dict[str, object]: return self._payload class _FakeSession: def __init__(self) -> None: self.calls: list[tuple[str, dict[str, object]]] = [] def post(self, url: str, json: dict[str, object], timeout: float) -> _FakeResponse: self.calls.append((url, json)) return _FakeResponse( { "entries": [ { "symbol": "AMD", "earnings_date": "2026-01-08T21:00:00Z", "earnings_time": "post_market", "estimated_eps": 1.09, "reported_eps": 1.11, "source": "oracle", "fetched_at": "2026-04-02T00:00:00Z", }, { "symbol": "CRM", "earnings_date": "2026-01-12T14:00:00Z", "earnings_time": "pre_market", "estimated_eps": 2.22, "reported_eps": 2.30, "source": "oracle", "fetched_at": "2026-04-02T00:00:00Z", }, ] } ) def test_oracle_pit_earnings_calendar_uses_bulk_endpoint(): session = _FakeSession() calendar = OraclePointInTimeEarningsCalendar( "http://oracle:18001", timeout=12.0, session=session, ) matches = calendar.get_known_upcoming_reaction_dates( as_of_date=dt.date(2026, 1, 6), allowed_reaction_dates=[dt.date(2026, 1, 9)], symbols=["AMD", "CRM", "NVDA"], ) assert matches == { "AMD": dt.date(2026, 1, 9), } assert len(session.calls) == 1 url, payload = session.calls[0] assert url == "http://oracle:18001/api/v1/earnings/calendar/bulk" assert payload["symbols"] == ["AMD", "CRM", "NVDA"] assert payload["as_of_date"] == "2026-01-06" assert payload["days_ahead"] == 3