mirror of
https://github.com/TauricResearch/TradingAgents.git
synced 2026-08-01 19:34:24 +03:00
fix(dataflows): make the Yahoo news window UTC and end-exclusive
- the upper bound was inclusive, so an article stamped exactly midnight after end_date leaked into a historical run - flat epoch timestamps were parsed in host-local time and offset-aware stamps had tzinfo stripped without converting, making filtering machine-dependent - normalize every operand to UTC and use a half-open [start, end + 1 day) #1126
This commit is contained in:
@@ -2,10 +2,11 @@
|
||||
into a historical window.
|
||||
|
||||
Regressions for #992 (flat articles bypassed the date filter), #1007 (global
|
||||
news injected future articles), #993 (empty-after-filter returned a blank body).
|
||||
news injected future articles), #993 (empty-after-filter returned a blank body),
|
||||
and #1126 (inclusive upper bound leaked the midnight-after article; host-local
|
||||
timestamp parsing made filtering machine-dependent).
|
||||
"""
|
||||
import time
|
||||
from datetime import datetime
|
||||
from datetime import datetime, timezone
|
||||
|
||||
import pytest
|
||||
|
||||
@@ -13,17 +14,20 @@ import tradingagents.dataflows.yfinance_news as ynews
|
||||
|
||||
|
||||
def _epoch(date_str):
|
||||
return int(time.mktime(datetime.strptime(date_str, "%Y-%m-%d").timetuple()))
|
||||
"""Epoch seconds for UTC midnight of ``date_str`` (host-timezone independent)."""
|
||||
return int(datetime.strptime(date_str, "%Y-%m-%d").replace(tzinfo=timezone.utc).timestamp())
|
||||
|
||||
|
||||
@pytest.mark.unit
|
||||
def test_flat_article_publish_time_is_parsed():
|
||||
# #992: flat articles now carry a pub_date (was always None -> unfilterable).
|
||||
# #1126: parsed as UTC-aware, so the date can't shift with the host timezone.
|
||||
data = ynews._extract_article_data(
|
||||
{"title": "X", "publisher": "P", "link": "l", "providerPublishTime": _epoch("2025-05-09")}
|
||||
)
|
||||
assert data["pub_date"] is not None
|
||||
assert data["pub_date"].strftime("%Y-%m-%d") == "2025-05-09"
|
||||
assert data["pub_date"].tzinfo is not None
|
||||
assert data["pub_date"] == datetime(2025, 5, 9, tzinfo=timezone.utc)
|
||||
|
||||
|
||||
@pytest.mark.unit
|
||||
@@ -40,9 +44,30 @@ def test_window_excludes_future_and_undated_in_backtest():
|
||||
@pytest.mark.unit
|
||||
def test_window_keeps_undated_in_live_window():
|
||||
# Live window (reaches today): undated articles can't be "future", so keep them.
|
||||
start = datetime.now()
|
||||
end = datetime.now()
|
||||
assert ynews._in_news_window(None, start, end) is True
|
||||
now = datetime.now(timezone.utc)
|
||||
assert ynews._in_news_window(None, now, now) is True
|
||||
|
||||
|
||||
@pytest.mark.unit
|
||||
def test_upper_bound_is_exclusive():
|
||||
# #1126: an article stamped exactly midnight AFTER end_date leaked in under
|
||||
# the old inclusive bound; the whole of end_date itself must still be kept.
|
||||
start = datetime(2025, 5, 1)
|
||||
end = datetime(2025, 5, 9)
|
||||
midnight_after = datetime(2025, 5, 10, 0, 0, 0, tzinfo=timezone.utc)
|
||||
last_moment = datetime(2025, 5, 9, 23, 59, 59, tzinfo=timezone.utc)
|
||||
assert ynews._in_news_window(midnight_after, start, end) is False
|
||||
assert ynews._in_news_window(last_moment, start, end) is True
|
||||
|
||||
|
||||
@pytest.mark.unit
|
||||
def test_offset_aware_timestamp_is_converted_not_truncated():
|
||||
# #1126: 2025-05-10T01:00+05:00 is really 2025-05-09T20:00Z -> inside the
|
||||
# window. Stripping tzinfo (old behavior) misread it as 05-10 and dropped it.
|
||||
start = datetime(2025, 5, 1)
|
||||
end = datetime(2025, 5, 9)
|
||||
aware = datetime.fromisoformat("2025-05-10T01:00:00+05:00")
|
||||
assert ynews._in_news_window(aware, start, end) is True
|
||||
|
||||
|
||||
@pytest.mark.unit
|
||||
|
||||
Reference in New Issue
Block a user