TradingAgents/docs/system-design.md

145 lines
7.6 KiB
Markdown

# System Design
## 1. Purpose and Capabilities
TradingAgents orchestrates a team of specialized LLM agents to perform research-driven equity trading analysis. The framework mirrors a buy-side firm structure: analysts source and synthesize signals, researchers debate positions, traders operationalize the plan, and a governance layer manages risk. The automation is built on LangGraph and LangChain primitives, letting the graph express agent interactions, tool usage, and stateful debates.
Key capabilities:
- Multi-role analysis spanning technicals, sentiment, news, and fundamentals.
- Debate-style reasoning with configurable rounds and memory-backed reflection.
- Risk management loop that challenges trade proposals before execution.
- CLI experience for interactive runs and package APIs for programmatic use.
## 2. System Context
```mermaid
graph TD
User[Quant Researcher / Trader]
Scheduler[Automation / Batch Jobs]
CLI[TradingAgents CLI]
SDK[TradingAgents Python API]
Graph[TradingAgentsGraph Core]
LLMProviders[OpenAI / Anthropic / Google]
DataProviders[Yahoo Finance, Finnhub, Reddit, Google News, SimFin]
Cache[Offline Data Cache]
Results[results/ logs]
User -->|configure runs| CLI
Scheduler -->|invoke| SDK
CLI --> Graph
SDK --> Graph
Graph -->|tool calls| DataProviders
Graph -->|fallback| Cache
Graph -->|prompt invocations| LLMProviders
Graph --> Results
```
The `TradingAgentsGraph` (`tradingagents/graph/trading_graph.py`) is the execution nucleus shared by both the CLI (`cli/main.py`) and direct library usage (`main.py`). External dependencies are abstracted behind the `Toolkit` and `dataflows` packages.
## 3. Architectural Layers
```mermaid
flowchart TD
subgraph Interface
CLI[[CLI: Rich + Typer]]
API[[Python API]]
end
subgraph Orchestration
GraphSetup[[GraphSetup]]
Conditional[[ConditionalLogic]]
Propagator[[Propagator]]
SignalProcessor[[SignalProcessor]]
Reflector[[Reflector]]
end
subgraph AgentTeams
Analysts[[Analyst Nodes]]
Researchers[[Bull/Bear Researchers + Manager]]
Trader[[Trader Node]]
Risk[[Risk Debate + Judge]]
end
subgraph DataPlane
Toolkit[[Toolkit Tools]]
Dataflows[[Offline Dataflows]]
Memories[[FinancialSituationMemory]]
end
Interface --> Orchestration
Orchestration --> AgentTeams
AgentTeams --> Orchestration
Orchestration --> DataPlane
DataPlane --> AgentTeams
```
- **Interface layer**: Either the CLI (`cli/main.py`) or library consumers call `TradingAgentsGraph.propagate()`.
- **Orchestration layer**: Builds and runs the LangGraph state machine, manages recursion limits, reflection, and signal extraction.
- **Agent teams**: Each node is a partially applied function that consumes and emits `AgentState` objects (`tradingagents/agents/utils/agent_states.py`).
- **Data plane**: Tool invocations request live data; offline caches and vector memories provide continuity between runs.
## 4. Execution Flow
```mermaid
sequenceDiagram
participant Caller as CLI / API Client
participant Graph as TradingAgentsGraph
participant Analysts as Analyst Team
participant Researchers as Bull & Bear Researchers
participant Manager as Research Manager
participant Trader as Trader
participant Risk as Risk Debate Circle
participant Judge as Risk Manager
participant Signals as Signal Processor
Caller->>Graph: propagate(ticker, trade_date)
Graph->>Graph: create_initial_state()
Graph->>Analysts: Market/Sentiment/News/Fundamentals nodes
Analysts-->>Graph: Enriched AgentState + reports
Graph->>Researchers: Bull/Bear alternating via ConditionalLogic
Researchers-->>Graph: Debate transcripts
Graph->>Manager: Summarize & craft investment plan
Manager-->>Trader: Updated state with plan
Graph->>Trader: Request final proposal
Trader-->>Risk: Trader plan stored in state
Graph->>Risk: Iterate risky/neutral/safe analysts
Risk-->>Judge: Debate history + recommendations
Judge-->>Graph: Final trade decision
Graph->>Signals: process_signal(final_trade_decision)
Signals-->>Caller: BUY / SELL / HOLD
```
Conditional edges in `ConditionalLogic` decide when analysts stop calling tools, how many debate rounds execute, and when the flow reaches the judge.
## 5. State and Memory Management
The shared `AgentState` typed dict contains the latest reports, debate transcripts, and final decisions. Helper classes (`Propagator`, `SignalProcessor`) construct and interpret this state.
Long-lived learning happens via `FinancialSituationMemory` (`tradingagents/agents/utils/memory.py`), which:
- Embeds summarized situations through OpenAI embeddings (or Ollama when running locally).
- Stores them in a transient ChromaDB instance per role (bull, bear, trader, judges).
- Retrieves the closest recommendations to steer future prompts.
Reflection routines in `Reflector` append new lessons after each run, closing the learning loop.
## 6. Data Acquisition and Tooling
`Toolkit` (`tradingagents/agents/utils/agent_utils.py`) wraps both online APIs and offline cache lookups. The data flow rules are:
- **Online mode**: Agents call OpenAI functions to fetch data (e.g., `get_YFin_data_online`, `get_global_news_openai`).
- **Offline mode**: Agents fall back to curated datasets under `tradingagents/dataflows/` (e.g., Finnhub JSON exports, SimFin CSVs, Reddit scrapes).
- Calls route through `langgraph.prebuilt.ToolNode`, so tool outputs are appended to the message stream until the analyst stops requesting data.
The `dataflows/interface.py` module normalizes inputs (date windows, ticker symbols) and formats responses into LLM-friendly Markdown blocks.
## 7. Configuration and Extensibility
- Default settings live in `tradingagents/default_config.py`. Consumers can copy and mutate this dict before instantiating `TradingAgentsGraph`.
- `GraphSetup.setup_graph()` accepts the analyst roster, allowing narrower runs or experiments with custom nodes.
- To add an agent, implement a node factory that accepts an LLM and toolkit/memory dependency, then register it in `GraphSetup` together with an entry in the `Toolkit` if data access is needed.
- Conditional logic thresholds (`max_debate_rounds`, `max_risk_discuss_rounds`, recursion limits) are passed into `ConditionalLogic` and `Propagator` during graph construction.
## 8. Non-Functional Considerations
- **Latency & cost**: Runs invoke multiple LLM calls per agent and extensive tool usage; choose lighter models (`o4-mini`, `gpt-4.1-mini`) for testing.
- **Reproducibility**: With online tools enabled, outputs depend on live APIs; disable online mode for deterministic replay from cached data.
- **Statefulness**: ChromaDB collections are in-memory per process; persisting them requires swapping the `chromadb` client configuration.
- **Observability**: The CLI (`cli/main.py`) visualizes progress, but programmatic users should persist `TradingAgentsGraph.log_states_dict` if audit trails are required.
## 9. Known Gaps and Future Enhancements
- The default `data_dir` in `DEFAULT_CONFIG` is developer-specific and should be externalized via environment configuration for portability.
- Risk and research debate limits are hard-coded when `ConditionalLogic` is instantiated inside `TradingAgentsGraph`; exposing them as config entries would simplify tuning.
- Reflection outputs are stored but not yet reinjected into prompts across runs; wiring the reflection step into the workflow is on the roadmap.
- Automated testing around agent prompts is limited; contract tests for data formatting and state transitions would improve reliability.