76 lines
2.8 KiB
Python
76 lines
2.8 KiB
Python
from __future__ import annotations
|
|
|
|
from datetime import datetime
|
|
|
|
import pandas as pd
|
|
|
|
from web_core import data as data_module
|
|
|
|
|
|
def _make_intraday_df(days: list[str]) -> pd.DataFrame:
|
|
index_values: list[pd.Timestamp] = []
|
|
for day in days:
|
|
index_values.append(pd.Timestamp(f"{day} 14:30:00", tz="UTC"))
|
|
index_values.append(pd.Timestamp(f"{day} 15:30:00", tz="UTC"))
|
|
|
|
index = pd.DatetimeIndex(index_values)
|
|
return pd.DataFrame(
|
|
{
|
|
"Open": [100.0 + i for i in range(len(index))],
|
|
"High": [101.0 + i for i in range(len(index))],
|
|
"Low": [99.0 + i for i in range(len(index))],
|
|
"Close": [100.5 + i for i in range(len(index))],
|
|
"Volume": [1000 + i for i in range(len(index))],
|
|
},
|
|
index=index,
|
|
)
|
|
|
|
|
|
def test_fetch_ohlc_day_period_backfills_until_target_trading_days(monkeypatch) -> None:
|
|
fixed_now = datetime(2026, 2, 17, 20, 0, 0)
|
|
four_day_df = _make_intraday_df(["2026-02-12", "2026-02-13", "2026-02-14", "2026-02-17"])
|
|
five_day_df = _make_intraday_df(["2026-02-11", "2026-02-12", "2026-02-13", "2026-02-14", "2026-02-17"])
|
|
calls: list[dict[str, object]] = []
|
|
|
|
class FakeTicker:
|
|
def history(self, **kwargs: object) -> pd.DataFrame:
|
|
calls.append(kwargs)
|
|
start = kwargs.get("start")
|
|
if start is None:
|
|
return four_day_df.copy()
|
|
lookback_days = (fixed_now - pd.Timestamp(start).to_pydatetime()).days
|
|
return five_day_df.copy() if lookback_days >= 12 else four_day_df.copy()
|
|
|
|
monkeypatch.setattr(data_module.yf, "Ticker", lambda symbol: FakeTicker())
|
|
monkeypatch.setattr(data_module, "_utc_now", lambda: fixed_now)
|
|
data_module.fetch_ohlc.clear()
|
|
|
|
out = data_module.fetch_ohlc(symbol="TSLA", interval="2m", period="5d")
|
|
session_days = pd.DatetimeIndex(out.index).normalize().unique()
|
|
|
|
assert len(session_days) == 5
|
|
assert pd.Timestamp("2026-02-11", tz="UTC") in session_days
|
|
assert len(calls) >= 2
|
|
assert all("start" in call and "end" in call for call in calls)
|
|
|
|
|
|
def test_fetch_ohlc_non_day_period_uses_period_request(monkeypatch) -> None:
|
|
calls: list[dict[str, object]] = []
|
|
month_df = _make_intraday_df(["2026-01-05", "2026-01-06", "2026-01-07"])
|
|
|
|
class FakeTicker:
|
|
def history(self, **kwargs: object) -> pd.DataFrame:
|
|
calls.append(kwargs)
|
|
return month_df.copy()
|
|
|
|
monkeypatch.setattr(data_module.yf, "Ticker", lambda symbol: FakeTicker())
|
|
data_module.fetch_ohlc.clear()
|
|
|
|
out = data_module.fetch_ohlc(symbol="AAPL", interval="1h", period="1mo")
|
|
|
|
assert len(out) == len(month_df)
|
|
assert len(calls) == 1
|
|
assert calls[0].get("period") == "1mo"
|
|
assert "start" not in calls[0]
|
|
assert "end" not in calls[0]
|