TradingAgents/PLAN.md

300 lines
15 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Implementation Plan: Medium-Term Positioning Upgrade
## Lead Architect Overview
Four objectives to upgrade TradingAgents for medium-term (13 month) positioning:
1. **Agentic Debate** — Increase debate rounds to 23
2. **Fundamental Data** — Extend look-back to 8 quarters with TTM trend computation
3. **Relative Performance** — Sector & peer comparison tools
4. **Macro Regime Flag** — Classify market as risk-on / risk-off / transition
---
## Step 1: Agentic Debate — Increase Rounds (Architect + API Integrator)
**Assigned to: API Integrator Agent**
**Risk: LOW** — Config-only change, conditional logic already supports arbitrary round counts.
### Changes:
- **File:** `tradingagents/default_config.py`
- Change `"max_debate_rounds": 1``"max_debate_rounds": 2`
- Change `"max_risk_discuss_rounds": 1``"max_risk_discuss_rounds": 2`
- **File:** `tradingagents/graph/trading_graph.py` (line 146)
- Pass config values to `ConditionalLogic`:
```python
self.conditional_logic = ConditionalLogic(
max_debate_rounds=self.config.get("max_debate_rounds", 2),
max_risk_discuss_rounds=self.config.get("max_risk_discuss_rounds", 2),
)
```
- **NOTE:** Currently `ConditionalLogic()` is called with no args, so it uses its own defaults of 1. The config values are never actually wired in. This is a bug fix.
### Verification:
- Investment debate: count threshold = `2 * 2 = 4` → Bull speaks 2×, Bear speaks 2× before judge
- Risk debate: count threshold = `3 * 2 = 6` → Each of 3 analysts speaks 2× before judge
- `max_recur_limit` of 100 is sufficient (was 100, worst case ~20 graph steps)
---
## Step 2: Fundamental Data — 8-Quarter TTM Trend (API Integrator + Economist)
**Assigned to: API Integrator (data layer) + Economist (TTM computation logic)**
**Risk: MEDIUM** — Requires new data tool + prompt update + TTM computation module.
### 2A: New TTM Computation Module (Economist Agent)
- **New file:** `tradingagents/dataflows/ttm_analysis.py`
- `compute_ttm_metrics(income_df, balance_df, cashflow_df) -> dict`
- Sum last 4 quarters of income stmt for flow items (Revenue, Net Income, EBITDA, Operating Income, Gross Profit)
- Use latest quarter for balance sheet (stock items: Total Assets, Total Debt, Equity)
- Compute key ratios: Revenue Growth (QoQ and YoY), Margin trends (Gross, Operating, Net), ROE trend, Debt/Equity trend, FCF trend
- `format_ttm_report(metrics: dict, ticker: str) -> str`
- Markdown report with 8-quarter trend table + TTM summary + quarter-over-quarter trajectory
### 2B: New Tool — `get_ttm_analysis` (API Integrator Agent)
- **File:** `tradingagents/agents/utils/fundamental_data_tools.py`
- Add new `@tool` function `get_ttm_analysis(ticker, curr_date) -> str`
- Internally calls existing vendor-routed `get_income_statement`, `get_balance_sheet`, `get_cashflow` with `freq="quarterly"`
- Passes raw data to `compute_ttm_metrics()` and `format_ttm_report()`
- **File:** `tradingagents/agents/utils/agent_utils.py`
- Export `get_ttm_analysis` tool
### 2C: Update Fundamentals Analyst Prompt (Economist Agent)
- **File:** `tradingagents/agents/analysts/fundamentals_analyst.py`
- Add `get_ttm_analysis` to tools list
- Update system prompt from "past week" to:
> "You are a researcher tasked with analyzing fundamental information covering the last 8 quarters (2 years) for a company. First call `get_ttm_analysis` to obtain a Trailing Twelve Months (TTM) trend report including revenue growth, margin trajectories, and key ratio trends. Then supplement with `get_fundamentals` for the latest snapshot. Write a comprehensive report covering multi-quarter trends, not just the most recent filing."
- **File:** `tradingagents/graph/trading_graph.py``_create_tool_nodes()`
- Add `get_ttm_analysis` to the `"fundamentals"` ToolNode
### 2D: Data Layer — Ensure 8 Quarters Available
- **yfinance:** `ticker.quarterly_income_stmt` returns up to 5 quarters. To get 8, we need to combine quarterly + annual or make 2 calls. Actually, yfinance returns the last 4-5 quarters by default. We'll need to fetch 2+ years of data.
- Approach: Call `ticker.quarterly_income_stmt` which returns available quarters (typically 4-5). Also call `ticker.income_stmt` (annual) for older periods. Combine to reconstruct 8 quarters.
- **Alternative (preferred):** yfinance `ticker.get_income_stmt(freq="quarterly", as_dict=False)` can return more data. Test this.
- **Fallback:** Alpha Vantage INCOME_STATEMENT endpoint returns up to 20 quarterly reports — use this as the configured vendor for TTM.
- **File:** `tradingagents/default_config.py`
- Add to `tool_vendors`: `"get_ttm_analysis": "alpha_vantage,yfinance"` to prefer Alpha Vantage for richer quarterly history
### Data Source Assessment:
| Source | Quarters Available | Notes |
|--------|-------------------|-------|
| yfinance `quarterly_income_stmt` | 4-5 | Limited but free |
| Alpha Vantage `INCOME_STATEMENT` | Up to 20 quarterly | Best option, needs API key |
| Alpha Vantage `BALANCE_SHEET` | Up to 20 quarterly | Same |
| Alpha Vantage `CASH_FLOW` | Up to 20 quarterly | Same |
---
## Step 3: Relative Performance — Sector & Peer Comparison (API Integrator + Economist)
**Assigned to: API Integrator (tools) + Economist (comparison logic)**
**Risk: MEDIUM** — New tools leveraging existing scanner infrastructure.
### 3A: New Peer Comparison Module (Economist Agent)
- **New file:** `tradingagents/dataflows/peer_comparison.py`
- `get_sector_peers(ticker) -> list[str]`
- Use yfinance `Ticker.info["sector"]` to identify sector
- Return top 5-8 peers from same sector (use existing `_SECTOR_TICKERS` mapping from `alpha_vantage_scanner.py`, or yfinance Sector.top_companies)
- `compute_relative_performance(ticker, peers, period="6mo") -> str`
- Download price history for ticker + peers via `yf.download()`
- Compute: 1-week, 1-month, 3-month, 6-month returns for each
- Rank ticker among peers
- Compute ticker's alpha vs sector ETF
- Return markdown table with relative positioning
### 3B: New Tools — `get_peer_comparison` and `get_sector_relative` (API Integrator)
- **File:** `tradingagents/agents/utils/fundamental_data_tools.py`
- `get_peer_comparison(ticker, curr_date) -> str`@tool
- Calls `get_sector_peers()` and `compute_relative_performance()`
- Returns ranked peer table with ticker highlighted
- `get_sector_relative(ticker, curr_date) -> str`@tool
- Compares ticker vs its sector ETF over multiple time frames
- Returns outperformance/underperformance metrics
- **File:** `tradingagents/agents/utils/agent_utils.py`
- Export both new tools
### 3C: Wire Into Fundamentals Analyst (API Integrator)
- **File:** `tradingagents/agents/analysts/fundamentals_analyst.py`
- Add `get_peer_comparison` and `get_sector_relative` to tools list
- Update prompt to instruct: "Also analyze how the company performs relative to sector peers and its sector ETF benchmark over 1-week, 1-month, 3-month, and 6-month periods."
- **File:** `tradingagents/graph/trading_graph.py``_create_tool_nodes()`
- Add both tools to `"fundamentals"` ToolNode
### 3D: Vendor Routing
- These tools use yfinance directly (no Alpha Vantage endpoint for peer comparison)
- No vendor routing needed — direct yfinance calls inside the module
- Register in `TOOLS_CATEGORIES` under `"fundamental_data"` for consistency
---
## Step 4: Macro Regime Flag (Economist Agent)
**Assigned to: Economist Agent**
**Risk: MEDIUM** — New module + new state field + integration into Research Manager.
### 4A: Macro Regime Classifier Module (Economist)
- **New file:** `tradingagents/dataflows/macro_regime.py`
- `classify_macro_regime(curr_date: str = None) -> dict`
- Returns: `{"regime": "risk-on"|"risk-off"|"transition", "confidence": float, "signals": dict, "summary": str}`
- Signal sources (all via yfinance — free, no API key needed):
1. **VIX level**: `yf.Ticker("^VIX")`<16 risk-on, 16-25 transition, >25 risk-off
2. **VIX trend**: 5-day vs 20-day SMA — rising = risk-off signal
3. **Credit spread proxy**: `yf.Ticker("HYG")` vs `yf.Ticker("LQD")` — HYG/LQD ratio declining = risk-off
4. **Yield curve proxy**: `yf.Ticker("TLT")` (20yr) vs `yf.Ticker("SHY")` (1-3yr) — TLT outperforming = risk-off (flight to safety)
5. **Market breadth**: S&P 500 (`^GSPC`) above/below 200-SMA
6. **Sector rotation signal**: Defensive sectors (XLU, XLP, XLV) outperforming cyclicals (XLY, XLK, XLI) = risk-off
- Scoring: Each signal contributes -1 (risk-off), 0 (neutral), or +1 (risk-on). Aggregate:
- Sum >= 3: "risk-on"
- Sum <= -3: "risk-off"
- Otherwise: "transition"
- `format_macro_report(regime_data: dict) -> str`
- Markdown report with signal breakdown, regime classification, and confidence level
### 4B: New Tool — `get_macro_regime` (API Integrator)
- **File:** `tradingagents/agents/utils/fundamental_data_tools.py` (or new `macro_tools.py`)
- `get_macro_regime(curr_date) -> str`@tool
- Calls `classify_macro_regime()` and `format_macro_report()`
- **File:** `tradingagents/agents/utils/agent_utils.py`
- Export `get_macro_regime`
### 4C: Add Macro Regime to Agent State
- **File:** `tradingagents/agents/utils/agent_states.py`
- Add to `AgentState`:
```python
macro_regime_report: Annotated[str, "Macro regime classification (risk-on/risk-off/transition)"]
```
### 4D: Wire Into Market Analyst (API Integrator)
- **File:** `tradingagents/agents/analysts/market_analyst.py`
- Add `get_macro_regime` to tools list
- Update prompt to include: "Before analyzing individual stock technicals, call `get_macro_regime` to determine the current market environment (risk-on, risk-off, or transition). Interpret all subsequent technical signals through this macro lens."
- Return `macro_regime_report` in output dict
- **File:** `tradingagents/graph/trading_graph.py``_create_tool_nodes()`
- Add `get_macro_regime` to `"market"` ToolNode
### 4E: Feed Macro Regime Into Downstream Agents
- **File:** `tradingagents/agents/managers/research_manager.py`
- Add `macro_regime_report` to the `curr_situation` string that gets passed to the judge
- Update prompt to reference macro regime in decision-making
- **File:** `tradingagents/agents/managers/risk_manager.py`
- Include macro regime context in risk assessment prompt
- **File:** `tradingagents/graph/trading_graph.py``_log_state()`
- Add `macro_regime_report` to logged state
---
## Step 5: Integration Tests (Tester Agent)
**Assigned to: Tester Agent**
### 5A: Test Debate Rounds — `tests/test_debate_rounds.py`
- Test `ConditionalLogic` with `max_debate_rounds=2`:
- Verify bull/bear alternate correctly for 4 turns
- Verify routing to "Research Manager" after count >= 4
- Test `ConditionalLogic` with `max_risk_discuss_rounds=2`:
- Verify aggressive→conservative→neutral rotation for 6 turns
- Verify routing to "Risk Judge" after count >= 6
- Test config values are properly wired from `TradingAgentsGraph` config to `ConditionalLogic`
### 5B: Test TTM Analysis — `tests/test_ttm_analysis.py`
- Unit test `compute_ttm_metrics()` with mock 8-quarter DataFrames
- Verify TTM revenue = sum of last 4 quarters
- Verify margin calculations
- Verify QoQ and YoY growth rates
- Unit test `format_ttm_report()` output contains expected sections
- Integration test `get_ttm_analysis` tool with real ticker (mark `@pytest.mark.integration`)
### 5C: Test Peer Comparison — `tests/test_peer_comparison.py`
- Unit test `get_sector_peers()` returns valid tickers for known sectors
- Unit test `compute_relative_performance()` with mock price data
- Verify correct return calculations
- Verify ranking logic
- Integration test with real ticker (mark `@pytest.mark.integration`)
### 5D: Test Macro Regime — `tests/test_macro_regime.py`
- Unit test `classify_macro_regime()` with mocked yfinance data:
- All risk-on signals → "risk-on"
- All risk-off signals → "risk-off"
- Mixed signals → "transition"
- Unit test `format_macro_report()` output format
- Unit test scoring edge cases (VIX at boundaries, missing data gracefully handled)
- Integration test with real market data (mark `@pytest.mark.integration`)
### 5E: Test Config Wiring — `tests/test_config_wiring.py`
- Test that `TradingAgentsGraph(config={...})` properly passes debate rounds to `ConditionalLogic`
- Test that new tools appear in the correct ToolNodes
- Test that new state fields exist in `AgentState`
---
## File Change Summary
| File | Action | Objective |
|------|--------|-----------|
| `tradingagents/default_config.py` | EDIT | #1 debate rounds, #2 tool vendor |
| `tradingagents/graph/trading_graph.py` | EDIT | #1 wire config, #2/#3/#4 add tools to ToolNodes, #4 log macro |
| `tradingagents/graph/conditional_logic.py` | NO CHANGE | Already supports arbitrary rounds |
| `tradingagents/agents/utils/agent_states.py` | EDIT | #4 add macro_regime_report |
| `tradingagents/agents/analysts/fundamentals_analyst.py` | EDIT | #2/#3 new tools + prompt |
| `tradingagents/agents/analysts/market_analyst.py` | EDIT | #4 macro regime tool + prompt |
| `tradingagents/agents/managers/research_manager.py` | EDIT | #4 include macro in decision |
| `tradingagents/agents/managers/risk_manager.py` | EDIT | #4 include macro in risk assessment |
| `tradingagents/agents/utils/fundamental_data_tools.py` | EDIT | #2/#3 new tool functions |
| `tradingagents/agents/utils/agent_utils.py` | EDIT | #2/#3/#4 export new tools |
| `tradingagents/agents/__init__.py` | NO CHANGE | Tools don't need agent-level export |
| `tradingagents/dataflows/ttm_analysis.py` | NEW | #2 TTM computation |
| `tradingagents/dataflows/peer_comparison.py` | NEW | #3 peer comparison logic |
| `tradingagents/dataflows/macro_regime.py` | NEW | #4 macro regime classifier |
| `tradingagents/dataflows/interface.py` | EDIT | #2/#3 register new tools in TOOLS_CATEGORIES |
| `tests/test_debate_rounds.py` | NEW | #1 tests |
| `tests/test_ttm_analysis.py` | NEW | #2 tests |
| `tests/test_peer_comparison.py` | NEW | #3 tests |
| `tests/test_macro_regime.py` | NEW | #4 tests |
| `tests/test_config_wiring.py` | NEW | Integration wiring tests |
---
## Execution Order
1. **Step 1** (Debate Rounds) — Independent, can start immediately
2. **Step 4A** (Macro Regime Module) — Independent, can start in parallel
3. **Step 2A** (TTM Module) — Independent, can start in parallel
4. **Step 3A** (Peer Comparison Module) — Independent, can start in parallel
5. **Step 2B2D** (TTM Integration) — Depends on 2A
6. **Step 3B3D** (Peer Integration) — Depends on 3A
7. **Step 4B4E** (Macro Integration) — Depends on 4A
8. **Step 5** (All Tests) — Depends on all above
Steps 1, 2A, 3A, 4A can all run in parallel.
---
## Risk Mitigation
- **yfinance quarterly data limit:** If yfinance returns <8 quarters, TTM module gracefully computes with available data and notes the gap. Alpha Vantage fallback provides full 20 quarters.
- **New state field (macro_regime_report):** Default empty string. All existing agents that don't produce it will leave it empty no reducer conflicts.
- **Rate limits:** Macro regime and peer comparison both call yfinance which has no rate limit. Sector performance via Alpha Vantage is already rate-limited at 75/min.
- **Backward compatibility:** All changes are additive. `max_debate_rounds=1` still works. New tools are optional in prompts. `macro_regime_report` defaults to empty.