From a58aa613fcb0777c84055a93462a890d9201cf89 Mon Sep 17 00:00:00 2001 From: Yijia-Xiao Date: Wed, 23 Sep 2026 21:35:15 +0000 Subject: [PATCH] fix: name no date after the run in what a historical run reads - coverage and withholding notices named where a vendor's coverage starts or today's date - the instrument context named today's date in every analyst prompt --- tests/test_fundamentals_lookahead.py | 2 +- tests/test_news_lookahead.py | 2 +- tests/test_undated_tools_as_of.py | 26 ++++++++++++++++++++++- tradingagents/agents/utils/agent_utils.py | 6 +++--- tradingagents/dataflows/date_window.py | 4 ++-- tradingagents/dataflows/y_finance.py | 2 +- 6 files changed, 33 insertions(+), 9 deletions(-) diff --git a/tests/test_fundamentals_lookahead.py b/tests/test_fundamentals_lookahead.py index 5c4bd02fb..81757346e 100644 --- a/tests/test_fundamentals_lookahead.py +++ b/tests/test_fundamentals_lookahead.py @@ -68,7 +68,7 @@ class TestYFinanceHistoricalRun: out = _yf(_PAST) assert f"Point-in-time as of: {_PAST}" in out assert "withheld" in out - assert _PAST in out and _TODAY in out + assert _PAST in out and _TODAY not in out def test_no_wall_clock_retrieval_stamp(self): # The old header stamped datetime.now(), which is what surfaced the leak. diff --git a/tests/test_news_lookahead.py b/tests/test_news_lookahead.py index 2d7106415..01ce1a08f 100644 --- a/tests/test_news_lookahead.py +++ b/tests/test_news_lookahead.py @@ -128,7 +128,7 @@ def test_ticker_news_window_before_feed_coverage_is_unavailable(monkeypatch): out = ynews.get_news_yfinance("AAPL", "2026-08-07", "2026-08-14") assert "RECENT" not in out assert "unavailable" in out and "not an absence" in out - assert "2026-09-10" in out # says how far back the feed actually reaches + assert "2026-09-10" not in out # an article after the window @pytest.mark.unit diff --git a/tests/test_undated_tools_as_of.py b/tests/test_undated_tools_as_of.py index 3570d7c2e..742631b08 100644 --- a/tests/test_undated_tools_as_of.py +++ b/tests/test_undated_tools_as_of.py @@ -42,7 +42,7 @@ def test_yfinance_insider_filings_after_the_date_are_dropped(): def test_yfinance_insider_date_before_coverage_is_unavailable_not_absent(): out = _yf_insider(_insider_frame("2026-09-08", "2025-06-02"), "2024-01-01") assert "unavailable" in out and "No insider transactions reported" not in out - assert "2025-06-02" in out # where coverage starts + assert "2025-06-02" not in out # a transaction after the run date @pytest.mark.unit @@ -271,3 +271,27 @@ def test_a_historical_run_is_not_told_todays_date(func, args): out = getattr(y_finance, func)(*args) assert date.today().isoformat() not in out + + +def _dates_after(text: str, cutoff: str) -> list[str]: + import re + return [d for d in re.findall(r"\d{4}-\d{2}-\d{2}", text) if d > cutoff] + + +@pytest.mark.unit +def test_an_unavailable_notice_names_no_date_after_the_run(): + """A notice explaining why data is missing named where the vendor's coverage + starts or today's date, both after a historical run's date.""" + from tradingagents.agents.utils.agent_utils import build_instrument_context + from tradingagents.dataflows.date_window import coverage_gap, withhold_live_profile + from tradingagents.dataflows.utils import get_current_date + + today = get_current_date() + notices = [ + coverage_gap([pd.Timestamp(today, tz="UTC")], "2025-01-01", "2025-01-07", "Feed", "news"), + withhold_live_profile("2025-01-07", "AAPL"), + _yf_insider(_insider_frame(today), "2025-01-07"), + build_instrument_context("EXMP", "stock", {"company_name": "Example"}, curr_date="2025-01-07"), + ] + for notice in notices: + assert _dates_after(notice, "2025-01-07") == [], notice diff --git a/tradingagents/agents/utils/agent_utils.py b/tradingagents/agents/utils/agent_utils.py index 8948d628a..bb47097cc 100644 --- a/tradingagents/agents/utils/agent_utils.py +++ b/tradingagents/agents/utils/agent_utils.py @@ -183,9 +183,9 @@ def build_instrument_context( today = get_current_date() if curr_date and str(curr_date) < today: context += ( - f" This identity is how the vendor describes the instrument today " - f"({today}), not necessarily on {curr_date}: a name or " - f"classification changed since then would read as the current one." + f" This identity is how the vendor describes the instrument today, " + f"not necessarily on {curr_date}: a name or classification changed " + f"since then would read as the current one." ) if is_crypto: diff --git a/tradingagents/dataflows/date_window.py b/tradingagents/dataflows/date_window.py index 57ba38e1b..607a1cd46 100644 --- a/tradingagents/dataflows/date_window.py +++ b/tradingagents/dataflows/date_window.py @@ -53,7 +53,7 @@ def coverage_gap( if datetime.strptime(end_date, "%Y-%m-%d").date() > now.date(): reason = "the window extends past today" elif oldest.date() > datetime.strptime(start_date, "%Y-%m-%d").date(): - reason = f"it only serves recent items (coverage starts {oldest:%Y-%m-%d})" + reason = "it only serves recent items" else: return None return f"<{source} unavailable for {start_date}..{end_date}: {reason}, so this is not an absence of {subject}>" @@ -111,7 +111,7 @@ def withhold_live_profile(curr_date: str | None, label: str) -> str | None: f"# Company Fundamentals for {label}\n" f"# Point-in-time as of: {curr_date}\n\n" f"Profile fundamentals are withheld for this date. This vendor serves " - f"only present-day values ({today}) with no historical vintage: market " + f"only present-day values with no historical vintage: market " f"cap, valuation multiples, the 52-week range and TTM income move with " f"today's quote, and even the name, sector and industry reflect today " f"rather than {curr_date} (companies rename and get reclassified). " diff --git a/tradingagents/dataflows/y_finance.py b/tradingagents/dataflows/y_finance.py index 3cd75d62f..d326ffdf5 100644 --- a/tradingagents/dataflows/y_finance.py +++ b/tradingagents/dataflows/y_finance.py @@ -442,7 +442,7 @@ def get_insider_transactions( if kept.empty: return ( f"" + "Yahoo serves recent transactions only>" ) data = kept