From 3f6ad5dc12e65777b51cb385c468e9c4b318ac56 Mon Sep 17 00:00:00 2001 From: Yijia-Xiao Date: Thu, 24 Sep 2026 18:54:19 +0000 Subject: [PATCH] docs: say which agent writes each state field, and what the debate limits count - state field descriptions name the Research Manager, the News and Fundamentals Analysts and the Portfolio Manager; comments that only repeat them are gone - the debate-limit comments count turns per max_debate_rounds and max_risk_discuss_rounds - date_window's docstring covers all the point-in-time rules it holds --- tradingagents/agents/state.py | 42 +++++++++++------------- tradingagents/dataflows/date_window.py | 17 +++++----- tradingagents/graph/conditional_logic.py | 4 +-- 3 files changed, 31 insertions(+), 32 deletions(-) diff --git a/tradingagents/agents/state.py b/tradingagents/agents/state.py index 7faa545e5..e0eab07ce 100644 --- a/tradingagents/agents/state.py +++ b/tradingagents/agents/state.py @@ -8,71 +8,69 @@ from typing_extensions import TypedDict class InvestDebateState(TypedDict): bull_history: Annotated[ str, "Bullish Conversation history" - ] # Bullish Conversation history + ] bear_history: Annotated[ str, "Bearish Conversation history" - ] # Bullish Conversation history - history: Annotated[str, "Conversation history"] # Conversation history - current_response: Annotated[str, "Latest response"] # Last response - judge_decision: Annotated[str, "Final judge decision"] # Last response - count: Annotated[int, "Length of the current conversation"] # Conversation length + ] + history: Annotated[str, "Conversation history"] + current_response: Annotated[str, "Latest response"] + judge_decision: Annotated[str, "Final judge decision"] + count: Annotated[int, "Length of the current conversation"] # Risk management team state class RiskDebateState(TypedDict): aggressive_history: Annotated[ str, "Aggressive Agent's Conversation history" - ] # Conversation history + ] conservative_history: Annotated[ str, "Conservative Agent's Conversation history" - ] # Conversation history + ] neutral_history: Annotated[ str, "Neutral Agent's Conversation history" - ] # Conversation history - history: Annotated[str, "Conversation history"] # Conversation history + ] + history: Annotated[str, "Conversation history"] latest_speaker: Annotated[str, "Analyst that spoke last"] current_aggressive_response: Annotated[ str, "Latest response by the aggressive analyst" - ] # Last response + ] current_conservative_response: Annotated[ str, "Latest response by the conservative analyst" - ] # Last response + ] current_neutral_response: Annotated[ str, "Latest response by the neutral analyst" - ] # Last response + ] judge_decision: Annotated[str, "Judge's decision"] - count: Annotated[int, "Length of the current conversation"] # Conversation length + count: Annotated[int, "Length of the current conversation"] class AgentState(MessagesState): company_of_interest: Annotated[str, "Company that we are interested in trading"] asset_type: Annotated[str, "Asset type under analysis such as stock or crypto"] instrument_context: Annotated[str, "Deterministic ticker identity resolved at run start"] - trade_date: Annotated[str, "What date we are trading at"] + trade_date: Annotated[str, "The analysis date; data is served as of it"] sender: Annotated[str, "Agent that sent this message"] # research step market_report: Annotated[str, "Report from the Market Analyst"] sentiment_report: Annotated[str, "Report from the Sentiment Analyst"] - news_report: Annotated[ - str, "Report from the News Researcher of current world affairs" - ] - fundamentals_report: Annotated[str, "Report from the Fundamentals Researcher"] + news_report: Annotated[str, "Report from the News Analyst on company and world news"] + fundamentals_report: Annotated[str, "Report from the Fundamentals Analyst"] # researcher team discussion step investment_debate_state: Annotated[ InvestDebateState, "Current state of the debate on if to invest or not" ] - investment_plan: Annotated[str, "Plan generated by the Analyst"] + investment_plan: Annotated[str, "Investment plan from the Research Manager"] - trader_investment_plan: Annotated[str, "Plan generated by the Trader"] + trader_investment_plan: Annotated[str, "Transaction proposal from the Trader"] # risk management team discussion step risk_debate_state: Annotated[ RiskDebateState, "Current state of the debate on evaluating risk" ] - final_trade_decision: Annotated[str, "Final decision made by the Risk Analysts"] + final_trade_decision: Annotated[str, "Final decision from the Portfolio Manager"] final_rating: Annotated[str, "The Portfolio Manager's 5-tier rating, or REVIEW when it has none"] past_context: Annotated[str, "Memory log context injected at run start (same-ticker decisions + cross-ticker lessons)"] portfolio_context: Annotated[str, "Caller-supplied holdings and cash, rendered at run start; empty when not provided"] diff --git a/tradingagents/dataflows/date_window.py b/tradingagents/dataflows/date_window.py index aeca0f121..b74202d14 100644 --- a/tradingagents/dataflows/date_window.py +++ b/tradingagents/dataflows/date_window.py @@ -1,12 +1,13 @@ -"""Shared look-ahead-safe date-window filtering for dated content. +"""Point-in-time rules shared by every dated path: data is served as of the run's date. -News, StockTwits, and Reddit all pull recent items that must be trimmed to the -analysis window so a historical/backtest run never sees content published after -its as-of date. Centralizing the rule keeps every source consistent (#1126, -#1220): every timestamp is normalized to UTC, the upper bound is exclusive at -midnight after ``end`` (so an item stamped exactly then can't leak), and an -undated item is kept only when the window reaches the present (a live run), since -in a backtest we can't prove it isn't future. +- ``as_of`` / ``as_of_window`` clamp a date or window the model asks for to the + trade date, so no tool reaches a vendor with a later one. +- ``in_window`` trims dated items (news, StockTwits, Reddit) to the analysis + window: timestamps normalized to UTC, the upper bound exclusive at midnight + after ``end``, and an undated item kept only when the window reaches the + present, since a backtest cannot prove it is not from the future (#1126, #1220). +- ``coverage_gap`` reports a window a feed cannot reach as unavailable, not empty. +- ``withhold_live_profile`` withholds present-day snapshots from historical runs. """ from __future__ import annotations diff --git a/tradingagents/graph/conditional_logic.py b/tradingagents/graph/conditional_logic.py index 9d41160a0..2c6caca2c 100644 --- a/tradingagents/graph/conditional_logic.py +++ b/tradingagents/graph/conditional_logic.py @@ -14,7 +14,7 @@ class ConditionalLogic: if ( state["investment_debate_state"]["count"] >= 2 * self.max_debate_rounds - ): # 3 rounds of back-and-forth between 2 agents + ): # max_debate_rounds turns each for bull and bear return "Research Manager" if state["investment_debate_state"]["current_response"].startswith("Bull"): return "Bear Researcher" @@ -24,7 +24,7 @@ class ConditionalLogic: """Determine if risk analysis should continue.""" if ( state["risk_debate_state"]["count"] >= 3 * self.max_risk_discuss_rounds - ): # 3 rounds of back-and-forth between 3 agents + ): # max_risk_discuss_rounds turns each for the three risk analysts return "Portfolio Manager" if state["risk_debate_state"]["latest_speaker"].startswith("Aggressive"): return "Conservative Analyst"