import json from pathlib import Path import httpx import pytest from app.bars.models import Timeframe from app.market.yahoo import MAX_1M_WINDOW_SECONDS, YahooSource, parse_chart FIXTURE = Path(__file__).parent / "fixtures" / "yahoo_es_1h.json" def test_parser_filters_null_ohlc_rows(): payload = json.loads(FIXTURE.read_text()) raw_count = len(payload["chart"]["result"][0]["timestamp"]) bars = parse_chart(payload, Timeframe.H1) assert len(bars) == raw_count - 1 assert all(None not in (bar.o, bar.h, bar.l, bar.c) for bar in bars) assert all(bar.source == "yahoo" and bar.symbol == "ES=F" for bar in bars) @pytest.mark.asyncio async def test_one_minute_history_is_windowed_and_deduplicated(): payload = json.loads(FIXTURE.read_text()) calls = [] async def handler(request: httpx.Request): calls.append(request) return httpx.Response(200, json=payload) async with httpx.AsyncClient(transport=httpx.MockTransport(handler)) as client: source = YahooSource(client=client) bars = await source.history( "ES=F", Timeframe.M1, 0, MAX_1M_WINDOW_SECONDS * 2 + 1 ) assert len(calls) == 3 assert len(bars) == len({bar.t for bar in parse_chart(payload, Timeframe.M1)}) @pytest.mark.asyncio async def test_thirty_minute_history_uses_yahoos_native_interval(): payload = json.loads(FIXTURE.read_text()) calls = [] async def handler(request: httpx.Request): calls.append(request) return httpx.Response(200, json=payload) async with httpx.AsyncClient(transport=httpx.MockTransport(handler)) as client: bars = await YahooSource(client=client).history( "ES=F", Timeframe.M30, range_="60d" ) assert len(calls) == 1 assert calls[0].url.params["interval"] == "30m" assert calls[0].url.params["range"] == "60d" assert bars and all(bar.tf is Timeframe.M30 for bar in bars)