472 lines
19 KiB
Markdown
472 lines
19 KiB
Markdown
# TradingAgents 技术架构分析及 akshare 集成修改
|
||
|
||
> **文档时间**: 2026-05-05
|
||
> **项目路径**: `/home/ubuntu/forgithub/TradingAgents`
|
||
> **运行端口**: `:8500` (Web UI)
|
||
|
||
---
|
||
|
||
## 一、项目概述
|
||
|
||
TradingAgents 是一个基于 LLM 的多智能体(Multi-Agent)金融交易分析框架。它模拟真实投资决策中的"研究员→辩论→交易员"流程,由多个分析师角色协作完成对单只股票的深入分析,并输出最终交易决策(买入/卖出/持有)。
|
||
|
||
核心思想:**用 LLM 扮演不同角色的分析师,使用真实市场数据工具,通过辩论机制达成投资共识。**
|
||
|
||
---
|
||
|
||
## 二、技术栈
|
||
|
||
| 层次 | 技术选型 |
|
||
|------|----------|
|
||
| 多智能体编排 | LangGraph(StateGraph) |
|
||
| LLM 接口 | LangChain + DeepSeek / OpenAI |
|
||
| 工具系统 | LangChain `@tool` 装饰器 |
|
||
| 数据源 | akshare / yfinance / Alpha Vantage |
|
||
| Web 服务 | FastAPI + 自定义 SPA 页面 |
|
||
| 部署 | systemd(`tradingagents.service`) |
|
||
|
||
---
|
||
|
||
## 三、架构分层
|
||
|
||
### 3.1 整体流程
|
||
|
||
```
|
||
用户输入 (ticker + date)
|
||
│
|
||
▼
|
||
┌──────────────────────┐
|
||
│ TradingAgentsGraph │ ← LangGraph StateGraph
|
||
│ (trading_graph.py) │
|
||
└──────┬───────────────┘
|
||
│
|
||
▼
|
||
┌───────────────────────────────────────┐
|
||
│ Researcher Team │
|
||
│ ┌──────────┐ ┌──────────┐ │
|
||
│ │ Market │ │ News │ ... │ ← 并行分析
|
||
│ │ Analyst │ │ Analyst │ │
|
||
│ └────┬─────┘ └────┬─────┘ │
|
||
│ │ │ │
|
||
│ └─────┬──────┘ │
|
||
│ ▼ │
|
||
│ Debate Layer (1~N rounds) │ ← 多轮辩论
|
||
│ │ │
|
||
│ ▼ │
|
||
│ Final Decision │
|
||
│ (Buy/Sell/Hold) │
|
||
└───────────────────────────────────────┘
|
||
│
|
||
▼
|
||
输出:分析报告 + 交易决策
|
||
```
|
||
|
||
### 3.2 节点说明
|
||
|
||
| 节点 | 文件 | 角色 | 使用的工具 |
|
||
|------|------|------|-----------|
|
||
| **Market Analyst** | `analysts/market_analyst.py` | 技术面分析师 | `get_stock_data`, `get_indicators` (RSI, MACD, 布林带等 19 项指标) |
|
||
| **News Analyst** | `analysts/news_analyst.py` | 宏观新闻分析师 | `get_news`, `get_global_news` |
|
||
| **Social Media Analyst** | `analysts/social_media_analyst.py` | 社交媒体分析师 | `get_news` |
|
||
| **Fundamentals Analyst** | `analysts/fundamentals_analyst.py` | 基本面分析师 | `get_fundamentals`, `get_balance_sheet`, `get_cashflow`, `get_income_statement` |
|
||
| **Debate Layer** | `trading_graph.py` | 多智能体辩论 | 各分析师报告交叉辩论 |
|
||
| **Final Decision** | `trading_graph.py` | 最终交易决策 | 综合所有报告和辩论结果 |
|
||
|
||
### 3.3 数据流
|
||
|
||
```
|
||
每个 Analyst 节点
|
||
│
|
||
├─ 构造 system prompt + 数据查询指令
|
||
├─ 通过 LangChain tool 调用 route_to_vendor()
|
||
├─ route_to_vendor 按优先级选择数据源
|
||
│ ├─ akshare (默认)
|
||
│ ├─ yfinance (fallback)
|
||
│ └─ alpha_vantage (fallback)
|
||
└─ 返回格式化数据,LLM 生成分析报告
|
||
```
|
||
|
||
---
|
||
|
||
## 四、核心模块
|
||
|
||
### 4.1 Graph 编排层
|
||
|
||
**文件**: `tradingagents/graph/trading_graph.py`
|
||
|
||
- 基于 LangGraph `StateGraph` 构建
|
||
- `setup_graph()` 按选定的分析师列表动态添加节点
|
||
- 支持配置 `max_debate_rounds`(默认 1 轮,可多轮辩论)
|
||
- 输出最终状态和交易决策
|
||
|
||
**文件**: `tradingagents/graph/setup.py`
|
||
|
||
- 提供 `create_complete_graph()` 工厂函数
|
||
- 封装完整流程:研究员 → 辩论 → 终判
|
||
|
||
### 4.2 工具层
|
||
|
||
**文件**: `tradingagents/agents/utils/agent_utils.py`
|
||
|
||
- `create_completion()` — LLM 调用封装,支持 reasoning_effort 参数
|
||
- `ToolKit` — 工具集管理,按分析师类型分发工具
|
||
|
||
**工具定义文件**(位于 `agents/utils/`):
|
||
|
||
| 文件 | 包含工具 |
|
||
|------|---------|
|
||
| `core_stock_tools.py` | `get_stock_data` |
|
||
| `technical_indicators_tools.py` | `get_indicators` (19 项技术指标) |
|
||
| `fundamental_data_tools.py` | `get_fundamentals`, `get_balance_sheet`, `get_cashflow`, `get_income_statement` |
|
||
| `news_data_tools.py` | `get_news`, `get_global_news`, `get_insider_transactions` |
|
||
|
||
所有工具统一通过 `route_to_vendor(method, *args)` 调用,实现数据源透明切换。
|
||
|
||
### 4.3 数据源层
|
||
|
||
**入口**: `tradingagents/dataflows/interface.py`
|
||
|
||
```
|
||
route_to_vendor(method, *args)
|
||
│
|
||
├─ 读取 config["data_vendors"] 确定主数据源
|
||
├─ 按 fallback 链依次尝试:
|
||
│ ├─ akshare (优先级最高)
|
||
│ ├─ yfinance
|
||
│ └─ alpha_vantage
|
||
└─ 返回第一个成功结果
|
||
```
|
||
|
||
**配置系统**: `tradingagents/dataflows/config.py` + `tradingagents/default_config.py`
|
||
|
||
- `default_config.py` 定义全局默认配置
|
||
- `config.py` 提供运行时 `get_config()` / `set_config()` 接口
|
||
- 可通过 `set_config({"data_vendors": {"...": "akshare"}})` 动态切换
|
||
|
||
### 4.4 Web 服务层
|
||
|
||
**文件**: `web_server.py`
|
||
|
||
- FastAPI 应用,端口 `8500`
|
||
- `POST /api/analyze` — 提交分析任务(后台异步执行)
|
||
- `GET /api/task/{task_id}` — 查询任务状态
|
||
- `GET /` — 内置 Web 面板(`web.html`)
|
||
|
||
---
|
||
|
||
## 五、akshare 集成修改(详细改动点)
|
||
|
||
### 5.1 修改动机
|
||
|
||
原始项目的默认数据源是 `yfinance`,存在以下问题:
|
||
|
||
1. **国内访问不稳定**: yfinance 对非美股数据支持有限,频繁触发 Rate Limit
|
||
2. **A 股数据质量差**: yfinance 的 A 股 OHLCV 数据常常缺失或不准确
|
||
3. **新闻源偏西式**: yfinance 的新闻来源主要是英文媒体,对 A 股分析不友好
|
||
4. **无国内数据源**: 缺少针对中国市场的本地化数据适配
|
||
|
||
**解决方案**: 集成 **akshare**(国内开源金融数据接口库)作为主数据源,yfinance 降级为 fallback。
|
||
|
||
### 5.2 文件变更清单
|
||
|
||
| 文件 | 类型 | 行数 | 说明 |
|
||
|------|------|------|------|
|
||
| `tradingagents/dataflows/akshare_data.py` | **新增** | 563 | A股/港股/美股行情、财务数据、技术指标适配 |
|
||
| `tradingagents/dataflows/akshare_news.py` | **新增** | 165 | 个股新闻(东方财富)、全球新闻(CCTV)适配 |
|
||
| `tradingagents/dataflows/interface.py` | **修改** | +22 | 注册 akshare 到 VENDOR_METHODS,调优 fallback 顺序 |
|
||
| `tradingagents/default_config.py` | **修改** | +14/-8 | 默认 vendor 改为 akshare |
|
||
| `web_server.py` | **新增** | 124 | FastAPI Web 服务 + 后台任务 |
|
||
| `web.html` | **新增** | 480 | 前端分析面板 |
|
||
|
||
### 5.3 akshare_data.py 详细设计
|
||
|
||
#### 5.3.1 市场检测
|
||
|
||
```python
|
||
def _detect_market(symbol: str) -> str:
|
||
"""自动识别股票所属市场"""
|
||
# 6位数字 → A股上海/深圳
|
||
# 5位数字 → 港股
|
||
# 字母 → 美股
|
||
```
|
||
|
||
通过 ticker 格式自动路由到正确的 akshare 接口:
|
||
- `600xxx` / `000xxx` / `300xxx` → A 股(`ak.stock_zh_a_hist`)
|
||
- `00700` / `09988` → 港股(`ak.stock_hk_hist`)
|
||
- `AAPL` / `MSFT` / `TSLA` → 美股(`ak.stock_us_hist`)
|
||
|
||
#### 5.3.2 实现的接口
|
||
|
||
| 接口 | 签名 | akshare 函数 | 说明 |
|
||
|------|------|-------------|------|
|
||
| `get_stock_data` | `(symbol, start_date, end_date)` | `stock_zh_a_hist` / `stock_hk_hist` / `stock_us_hist` | 三市场统一 OHLCV 数据 |
|
||
| `get_indicators` | `(symbol, indicator, curr_date, look_back_days)` | `stock_zh_a_hist` + 手动计算 | 19 项技术指标(RSI/MACD/布林带等) |
|
||
| `get_fundamentals` | `(ticker, curr_date)` | `stock_individual_info_em` | 公司概况/市盈率/市净率等 |
|
||
| `get_balance_sheet` | `(ticker, freq, curr_date)` | `stock_balance_sheet_by_report_em` | 资产负债表(年报/季报) |
|
||
| `get_cashflow` | `(ticker, freq, curr_date)` | `stock_cash_flow_sheet_by_report_em` | 现金流量表 |
|
||
| `get_income_statement` | `(ticker, freq, curr_date)` | `stock_profit_sheet_by_report_em` | 利润表 |
|
||
| `get_insider_transactions` | `(ticker)` | — | 抛出异常触发 fallback 到 yfinance |
|
||
|
||
#### 5.3.3 技术指标计算实现
|
||
|
||
采用**原始公式重算**而非依赖第三方库,确保数据一致性:
|
||
|
||
```
|
||
rsi → 100 - (100 / (1 + RS)) [平均涨跌幅比值法]
|
||
macd → EMA(12) - EMA(26), Signal=EMA(9) [指数加权移动平均]
|
||
bb → MA ± 2*STD [布林带]
|
||
atr → TR 的 Wilder 平滑 [真实波幅]
|
||
sma_20 → MA(20)
|
||
ema_20 → EMA(20)
|
||
```
|
||
|
||
共支持 19 项常用技术指标,覆盖趋势类、动量类、波动类、成交量类。
|
||
|
||
#### 5.3.4 输出格式
|
||
|
||
所有接口返回统一格式:**Pandas DataFrame → Markdown 表格字符串**,与 yfinance 适配器输出格式一致,保证 LLM 可正常解析。
|
||
|
||
```markdown
|
||
| Date | Open | High | Low | Close | Volume |
|
||
|------------|--------|--------|--------|--------|-----------|
|
||
| 2026-04-25 | 12.50 | 12.80 | 12.30 | 12.65 | 12345678 |
|
||
```
|
||
|
||
#### 5.3.5 TQDM 噪音抑制
|
||
|
||
akshare 内部使用 tqdm 显示进度条,在 LLM 工具调用场景中会产生大量噪音输出。通过在 akshare import 之前设置环境变量解决:
|
||
|
||
```python
|
||
os.environ.setdefault('TQDM_DISABLE', '1')
|
||
import akshare as ak
|
||
```
|
||
|
||
### 5.4 akshare_news.py 详细设计
|
||
|
||
#### 5.4.1 实现的接口
|
||
|
||
| 接口 | 说明 | 数据来源 |
|
||
|------|------|---------|
|
||
| `get_news(ticker, start_date, end_date)` | 个股新闻 | `ak.stock_news_em`(东方财富) |
|
||
| `get_global_news(curr_date, look_back_days, limit)` | 宏观/全球新闻 | `ak.news_cctv`(CCTV 新闻联播) |
|
||
|
||
#### 5.4.2 Ticker 规范化
|
||
|
||
```
|
||
600362 → 600362 (A股,不变)
|
||
000001 → 000001 (A股,不变)
|
||
AAPL → AAPL (美股,不变)
|
||
→ 回退到原 ticker
|
||
```
|
||
|
||
#### 5.4.3 东方财富新闻接口特点
|
||
|
||
- 返回 15 天内个股相关新闻,含标题、发布时间、来源
|
||
- 自动按日期过滤,限制返回最近 50 条
|
||
- 格式化输出为 Markdown 表格,便于 LLM 分析
|
||
|
||
#### 5.4.4 CCTV 新闻接口特点
|
||
|
||
- 获取新闻联播文字稿摘要
|
||
- 适合宏观政策面分析
|
||
- 输出为时间线格式的文本列表
|
||
|
||
### 5.5 interface.py 修改详情
|
||
|
||
#### 5.5.1 VENDOR_METHODS 注册
|
||
|
||
为以下 9 个方法注册了 akshare 实现:
|
||
|
||
```python
|
||
VENDOR_METHODS = {
|
||
"get_stock_data": {"akshare": ..., "yfinance": ..., "alpha_vantage": ...},
|
||
"get_indicators": {"akshare": ..., "yfinance": ...},
|
||
"get_fundamentals": {"akshare": ..., "yfinance": ..., "alpha_vantage": ...},
|
||
"get_balance_sheet": {"akshare": ..., "yfinance": ..., "alpha_vantage": ...},
|
||
"get_cashflow": {"akshare": ..., "yfinance": ..., "alpha_vantage": ...},
|
||
"get_income_statement": {"akshare": ..., "yfinance": ..., "alpha_vantage": ...},
|
||
"get_news": {"akshare": ..., "yfinance": ...},
|
||
"get_global_news": {"akshare": ..., "yfinance": ...},
|
||
"get_insider_transactions": {"akshare": ..., "yfinance": ..., "alpha_vantage": ...},
|
||
}
|
||
```
|
||
|
||
#### 5.5.2 Fallback 顺序优化
|
||
|
||
`get_insider_transactions` 的字典键顺序调整为 **akshare → yfinance → alpha_vantage**:
|
||
|
||
```
|
||
原始顺序: alpha_vantage → yfinance → [无 akshare]
|
||
修改后: akshare → yfinance → alpha_vantage
|
||
```
|
||
|
||
原因:如果 alpha_vantage 排在 yfinance 之前,当 akshare 不支持时,会先尝试 alpha_vantage —— 它的 `get_api_key()` 在无 API key 时会抛出 `ValueError`(非 `AlphaVantageRateLimitError`),导致异常直接传播、不会继续尝试 yfinance。
|
||
|
||
调整后 fallback 路径:
|
||
1. `akshare` → 抛出 `AlphaVantageRateLimitError`(触发 fallback)
|
||
2. `yfinance` → 获取数据(成功)✓
|
||
|
||
#### 5.5.3 数据源分类优化
|
||
|
||
将 akshare 明确归入 `all_available_vendors`,确保它在所有 `data_vendors` 分类组中可用:
|
||
|
||
```python
|
||
all_available_vendors = ["akshare", "yfinance", "alpha_vantage"]
|
||
```
|
||
|
||
### 5.6 default_config.py 修改
|
||
|
||
```python
|
||
# 修改前
|
||
"data_vendors": {
|
||
"core_stock_data": {"primary": "yfinance"},
|
||
"technical_indicators": {"primary": "yfinance"},
|
||
"fundamental_data": {"primary": "yfinance"},
|
||
"news_data": {"primary": "yfinance"},
|
||
}
|
||
|
||
# 修改后
|
||
"data_vendors": {
|
||
"core_stock_data": {"primary": "akshare"},
|
||
"technical_indicators": {"primary": "akshare"},
|
||
"fundamental_data": {"primary": "akshare"},
|
||
"news_data": {"primary": "akshare"},
|
||
}
|
||
```
|
||
|
||
效果:所有分析请求默认走 akshare,彻底避免 yfinance Rate Limit 问题。
|
||
|
||
### 5.7 web_server.py 设计
|
||
|
||
#### 5.7.1 API 端点
|
||
|
||
| 方法 | 路径 | 说明 |
|
||
|------|------|------|
|
||
| GET | `/` | Web 分析面板(`web.html`) |
|
||
| GET | `/api/health` | 健康检查 |
|
||
| POST | `/api/analyze` | 提交分析任务,返回 task_id |
|
||
| GET | `/api/task/{task_id}` | 查询任务状态和结果 |
|
||
|
||
#### 5.7.2 异步任务机制
|
||
|
||
```python
|
||
class AnalysisRequest(BaseModel):
|
||
ticker: str # 股票代码
|
||
date: Optional[str] # 分析日期,默认今天
|
||
analysts: Optional[list] # 分析师列表,默认 ["market", "news"]
|
||
max_debate_rounds: int # 辩论轮次,默认 1
|
||
```
|
||
|
||
分析流程在 `BackgroundTasks` 中异步执行,通过线程安全的 `tasks_store` 字典管理任务状态。
|
||
|
||
### 5.8 web.html 设计
|
||
|
||
- 纯原生 HTML/CSS/JS 单页应用
|
||
- 响应式设计,支持移动端
|
||
- 输入框:股票代码 + 日期 + 分析师选择 + 辩论轮次
|
||
- 实时轮询任务状态(每 3 秒)
|
||
- 结果展示:Markdown 渲染的交易决策和分析报告(使用 marked.js)
|
||
- 适配 DeepSeek 推理过程的 `reasoning_content` 展示
|
||
|
||
---
|
||
|
||
## 六、部署架构
|
||
|
||
```
|
||
http://129.211.173.87:8500/
|
||
│
|
||
┌────────┴────────┐
|
||
│ web_server.py │
|
||
│ (FastAPI) │
|
||
│ port :8500 │
|
||
└────────┬────────┘
|
||
│
|
||
┌────────┴────────┐
|
||
│ TradingAgents │
|
||
│ Graph │
|
||
│ (LangGraph) │
|
||
└──────┬─────────┘
|
||
│
|
||
┌───────────┼───────────┐
|
||
▼ ▼ ▼
|
||
┌─────────┐ ┌─────────┐ ┌─────────┐
|
||
│ akshare │ │yfinance │ │ alpha │
|
||
│ (主要) │ │(备用1) │ │vantage │
|
||
└─────────┘ └─────────┘ └─────────┘
|
||
```
|
||
|
||
- **进程管理**: systemd `tradingagents.service`
|
||
- **LLM 后端**: DeepSeek(通过 `DEEPSEEK_API_KEY` 环境变量)
|
||
- **数据源**: akshare(默认,国内数据丰富)+ yfinance(fallback,美股内部交易等场景)
|
||
|
||
---
|
||
|
||
## 七、修改前后对比
|
||
|
||
| 维度 | 修改前 | 修改后 |
|
||
|------|--------|--------|
|
||
| **默认数据源** | yfinance | **akshare** |
|
||
| **A 股行情** | 不稳定,频繁 Rate Limit | ✅ 稳定,无限制 |
|
||
| **A 股财务数据** | ❌ 不可用 | ✅ 完整(资产负债表/利润表/现金流) |
|
||
| **技术指标** | 依赖 yfinance 返回 | ✅ 原始公式重算,19 项指标 |
|
||
| **个股新闻** | 英文来源,A 股覆盖差 | ✅ 东方财富,中文,时效性强 |
|
||
| **宏观新闻** | 英文来源 | ✅ CCTV 新闻联播,政策面 |
|
||
| **港股支持** | 部分 | ✅ 完整 |
|
||
| **Rate Limit** | 频繁触发 | ✅ 已消除 |
|
||
| **内部交易** | yfinance | akshare 自动 fallback 到 yfinance |
|
||
| **Web UI** | ❌ 无 | ✅ 新增 FastAPI + Web 面板 |
|
||
| **任务异步** | ❌ 无 | ✅ 后台任务 + 状态查询 |
|
||
| **TQDM 噪音** | — | ✅ 已抑制 |
|
||
|
||
---
|
||
|
||
## 八、项目目录结构
|
||
|
||
```
|
||
TradingAgents/
|
||
├── tradingagents/
|
||
│ ├── agents/
|
||
│ │ ├── analysts/ # 四个分析师角色
|
||
│ │ │ ├── fundamentals_analyst.py
|
||
│ │ │ ├── market_analyst.py
|
||
│ │ │ ├── news_analyst.py
|
||
│ │ │ └── social_media_analyst.py
|
||
│ │ └── utils/ # 工具定义和 LLM 封装
|
||
│ │ ├── agent_utils.py # LLM 调用 + ToolKit
|
||
│ │ ├── core_stock_tools.py # get_stock_data
|
||
│ │ ├── technical_indicators_tools.py # get_indicators
|
||
│ │ ├── fundamental_data_tools.py # 财务分析工具
|
||
│ │ └── news_data_tools.py # 新闻工具
|
||
│ ├── dataflows/ # 数据源层
|
||
│ │ ├── interface.py # 路由分发 + VENDOR_METHODS
|
||
│ │ ├── config.py # 运行时配置
|
||
│ │ ├── akshare_data.py # 🆕 akshare 行情+财务适配
|
||
│ │ ├── akshare_news.py # 🆕 akshare 新闻适配
|
||
│ │ ├── yfinance_news.py # yfinance 新闻
|
||
│ │ ├── y_finance.py # yfinance 行情
|
||
│ │ └── alpha_vantage*.py # Alpha Vantage 适配
|
||
│ ├── graph/ # LangGraph 编排
|
||
│ │ ├── trading_graph.py # 主图定义
|
||
│ │ └── setup.py # 图工厂
|
||
│ └── default_config.py # 默认配置(已改为 akshare)
|
||
├── docs/ # 文档
|
||
│ ├── architecture-and-modifications.md # 🆕 本文档
|
||
│ └── ...
|
||
├── web_server.py # 🆕 FastAPI Web 服务
|
||
├── web.html # 🆕 前端面板
|
||
└── pyproject.toml # 依赖管理
|
||
```
|
||
|
||
---
|
||
|
||
## 九、关键代码路径
|
||
|
||
| 功能 | 起点 | 链路 |
|
||
|------|------|------|
|
||
| 用户提交分析 | `web_server.py:94 POST /api/analyze` | → `run_analysis_task` → `TradingAgentsGraph.propagate()` |
|
||
| 获取行情数据 | `core_stock_tools.py:get_stock_data` | → `route_to_vendor("get_stock_data", ...)` → `akshare_data.get_stock_data()` |
|
||
| 获取技术指标 | `technical_indicators_tools.py:get_indicators` | → `route_to_vendor` → `akshare_data.get_indicators()` |
|
||
| 获取财务数据 | `fundamental_data_tools.py:get_fundamentals` | → `route_to_vendor` → `akshare_data.get_fundamentals()` |
|
||
| 获取新闻 | `news_data_tools.py:get_news` | → `route_to_vendor` → `akshare_news.get_news()` |
|
||
| 数据源切换 | `interface.py:route_to_vendor` | 按 config → fallback 链尝试 |
|