You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
157 lines
4.5 KiB
Python
157 lines
4.5 KiB
Python
from __future__ import annotations
|
|
|
|
import pytest
|
|
|
|
import libs.intraday.catalyst as catalyst_mod
|
|
from libs.intraday.catalyst import (
|
|
AttentionEventCache,
|
|
FilingEventCache,
|
|
fetch_attention_features_bulk,
|
|
fetch_filing_event_features_bulk,
|
|
)
|
|
from libs.oracle_client.models import (
|
|
EntityInfo,
|
|
EventAttentionResponse,
|
|
FilingEventEntry,
|
|
FilingEventsResponse,
|
|
NewsFeatures,
|
|
WikiFeatures,
|
|
)
|
|
|
|
|
|
def test_filing_event_cache_roundtrip(tmp_path) -> None:
|
|
cache = FilingEventCache(str(tmp_path))
|
|
cache.put(
|
|
"ABC",
|
|
"2026-01-01",
|
|
"2026-03-31",
|
|
[
|
|
{
|
|
"ticker": "ABC",
|
|
"filing_date": "2026-02-10",
|
|
"accession_number": "1",
|
|
"event_type": "other_material_event",
|
|
"item_number": "8.01",
|
|
"form_type": "8-K",
|
|
"title": "Material event",
|
|
}
|
|
],
|
|
)
|
|
|
|
hit = cache.get("ABC", "2026-01-02", "2026-03-01")
|
|
miss = cache.get("ABC", "2025-12-31", "2026-03-01")
|
|
|
|
assert hit is not None and hit[0]["event_type"] == "other_material_event"
|
|
assert miss is None
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_fetch_filing_event_features_bulk_uses_cache_after_first_hit(tmp_path, monkeypatch) -> None:
|
|
cache = FilingEventCache(str(tmp_path))
|
|
calls = {"count": 0}
|
|
|
|
async def fake_get_events(self, ticker, start_date=None, end_date=None):
|
|
calls["count"] += 1
|
|
return FilingEventsResponse(
|
|
ticker=ticker,
|
|
events=[
|
|
FilingEventEntry(
|
|
id="evt-1",
|
|
ticker=ticker,
|
|
accession_number="acc-1",
|
|
form_type="8-K",
|
|
filing_date="2026-02-10",
|
|
item_number="8.01",
|
|
event_type="other_material_event",
|
|
title="Material event",
|
|
)
|
|
],
|
|
total_count=1,
|
|
)
|
|
|
|
monkeypatch.setattr(catalyst_mod.FilingsService, "get_filing_events", fake_get_events)
|
|
|
|
first = await fetch_filing_event_features_bulk(
|
|
["ABC"],
|
|
"2026-01-01",
|
|
"2026-03-31",
|
|
client=object(), # patched method ignores the client
|
|
cache=cache,
|
|
concurrency=1,
|
|
)
|
|
second = await fetch_filing_event_features_bulk(
|
|
["ABC"],
|
|
"2026-01-01",
|
|
"2026-03-31",
|
|
client=object(),
|
|
cache=cache,
|
|
concurrency=1,
|
|
)
|
|
|
|
assert first["ABC"]["2026-02-10"]["event_flag"] is True
|
|
assert first["ABC"]["2026-02-10"]["event_score"] >= 1.0
|
|
assert second == first
|
|
assert calls["count"] == 1
|
|
|
|
|
|
def test_attention_event_cache_roundtrip(tmp_path) -> None:
|
|
cache = AttentionEventCache(str(tmp_path))
|
|
cache.put(
|
|
"ABC",
|
|
"2026-02-10",
|
|
{
|
|
"attention_wiki_spike_10d": 2.3,
|
|
"attention_wiki_zscore_20d": 3.1,
|
|
"attention_article_count_3d": 5,
|
|
"attention_us_article_count_3d": 3,
|
|
"attention_resolver_confidence": 0.95,
|
|
},
|
|
)
|
|
|
|
hit = cache.get("ABC", "2026-02-10")
|
|
miss = cache.get("ABC", "2026-02-11")
|
|
|
|
assert hit is not None and hit["attention_article_count_3d"] == 5
|
|
assert miss is None
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_fetch_attention_features_bulk_uses_cache_after_first_hit(tmp_path, monkeypatch) -> None:
|
|
cache = AttentionEventCache(str(tmp_path))
|
|
calls = {"count": 0}
|
|
|
|
async def fake_get_attention(self, ticker, event_date):
|
|
calls["count"] += 1
|
|
return EventAttentionResponse(
|
|
ticker=ticker,
|
|
event_date=event_date,
|
|
entity=EntityInfo(
|
|
ticker=ticker,
|
|
canonical_name=ticker,
|
|
resolver_confidence=0.91,
|
|
),
|
|
wiki=WikiFeatures(spike_10d=2.8, zscore_20d=3.4),
|
|
news=NewsFeatures(article_count_3d=6, us_article_count_3d=4),
|
|
metadata={},
|
|
)
|
|
|
|
monkeypatch.setattr(catalyst_mod.AttentionService, "get_event_attention", fake_get_attention)
|
|
|
|
first = await fetch_attention_features_bulk(
|
|
[("ABC", "2026-02-10")],
|
|
client=object(),
|
|
cache=cache,
|
|
concurrency=1,
|
|
)
|
|
second = await fetch_attention_features_bulk(
|
|
[("ABC", "2026-02-10")],
|
|
client=object(),
|
|
cache=cache,
|
|
concurrency=1,
|
|
)
|
|
|
|
assert first["ABC"]["2026-02-10"]["attention_wiki_spike_10d"] == 2.8
|
|
assert first["ABC"]["2026-02-10"]["attention_us_article_count_3d"] == 4
|
|
assert second == first
|
|
assert calls["count"] == 1
|