refactor(dataflows): group the vendors under dataflows/vendors

- vendors/yahoo: ohlcv (loader and cache), market (prices, indicators), fundamentals (profile, statements, insider), news, snapshot
- vendors/alpha_vantage is a package; sec_edgar, fred, polymarket, reddit and stocktwits sit beside it
- the one-method StockstatsUtils class is a function; the duplicate Yahoo host constant is gone
- tests are named after the modules they cover: test_ohlcv_date_column, test_yahoo_snapshot, and the ohlcv and snapshot aliases
This commit is contained in:
Yijia-Xiao
2026-09-24 04:37:40 +00:00
parent c42a2f2c61
commit 6097b582d9
45 changed files with 417 additions and 389 deletions
+70
View File
@@ -0,0 +1,70 @@
"""Tests for tolerating a non-`Date` index column in the Yahoo OHLCV loader (#890).
Guards against a download frame whose date column is `index` or `Datetime`
instead of `Date`, which would otherwise silently drop every indicator.
"""
from __future__ import annotations
import pandas as pd
import pytest
from tradingagents.dataflows.vendors.yahoo import ohlcv
def _ohlcv(date_col: str) -> pd.DataFrame:
"""OHLCV frame whose date column is named `date_col`."""
dates = pd.bdate_range("2026-04-01", periods=10)
return pd.DataFrame({
date_col: dates,
"Open": [100.0 + i for i in range(10)],
"High": [101.0 + i for i in range(10)],
"Low": [99.0 + i for i in range(10)],
"Close": [100.5 + i for i in range(10)],
"Volume": [1_000_000 + i for i in range(10)],
})
@pytest.mark.unit
class TestEnsureDateColumn:
def test_renames_index_column(self):
out = ohlcv._ensure_date_column(_ohlcv("index"))
assert "Date" in out.columns and "index" not in out.columns
def test_renames_datetime_and_date_variants(self):
assert "Date" in ohlcv._ensure_date_column(_ohlcv("Datetime")).columns
assert "Date" in ohlcv._ensure_date_column(_ohlcv("date")).columns
def test_leaves_existing_date_untouched(self):
df = _ohlcv("Date")
assert ohlcv._ensure_date_column(df) is df # no-op short-circuit
def test_no_datelike_column_is_left_alone(self):
df = pd.DataFrame({"Close": [1, 2, 3]})
out = ohlcv._ensure_date_column(df)
assert "Date" not in out.columns # nothing to rename; caller handles
@pytest.mark.unit
class TestCleanDataframeAcrossVersions:
def test_clean_handles_index_column(self):
"""A frame with `index` instead of `Date` must still clean to a
usable, date-parsed frame (was KeyError: 'Date')."""
cleaned = ohlcv._clean_dataframe(_ohlcv("index"))
assert "Date" in cleaned.columns
assert pd.api.types.is_datetime64_any_dtype(cleaned["Date"])
assert len(cleaned) == 10
def test_clean_handles_legacy_date_column(self):
cleaned = ohlcv._clean_dataframe(_ohlcv("Date"))
assert len(cleaned) == 10
def test_indicators_compute_after_index_rename(self):
"""stockstats must compute indicators on a frame whose date column
arrived as `index`, instead of erroring per indicator."""
from stockstats import wrap
cleaned = ohlcv._clean_dataframe(_ohlcv("index"))
df = wrap(cleaned)
df["close_5_sma"] # triggers calculation
assert "close_5_sma" in df.columns
assert df["close_5_sma"].notna().any()