This commit is contained in:
Ubuntu
2026-07-03 16:58:28 +08:00
commit 32b43f85bd
6240 changed files with 1987678 additions and 0 deletions
+480
View File
@@ -0,0 +1,480 @@
# TradingAgents 股票分析工作流程详解
> **文档时间**: 2026-05-05
> **相关文档**: [技术架构分析](./architecture-and-modifications.md)
> **配套图表**: [流程图](workflow-pipeline.html) | [架构图](workflow-architecture.html)
---
## 一、一次分析的完整生命周期
当用户在 Web UI 输入 `600362` 并点击"分析",系统会经历以下完整流程:
```
用户点击 [分析] → 后台异步任务 → 约 3-8 分钟后 → 输出交易决策
```
整个流程由 **LangGraph StateGraph** 驱动,状态在 15+ 个节点间流转。下面按执行顺序逐步拆解。
---
## 二、流程图
![流程图](workflow-pipeline.html)
> 详细架构图: [workflow-architecture.html](workflow-architecture.html)
---
## 三、分阶段详解
### 阶段 1:请求接收与任务创建
**入口**: `web_server.py` → `POST /api/analyze`
```
用户输入: { ticker: "600362", date: "2026-04-30", analysts: [...], max_debate_rounds: 1 }
```
1. 生成唯一的 `task_id`(格式: `600362_20260505191807`)
2. 创建任务记录写入 `tasks_store`(内存字典)
3. 通过 FastAPI `BackgroundTasks` 异步启动 `run_analysis_task()`
4. 立即返回 `{"task_id": "...", "status": "pending"}`
5. 前端每 3 秒轮询 `GET /api/task/{task_id}` 获取进度
### 阶段 2:Graph 初始化
**文件**: `tradingagents/graph/trading_graph.py` → `TradingAgentsGraph.propagate()`
```python
# 1. 读取配置
config = get_config() # 默认 vendor: akshare
llm_name = config["llm_provider"] # DeepSeek
# 2. 初始化 LangGraph StateGraph
workflow = StateGraph(AgentState)
# 3. 按用户选择的分析师类型动态添加节点
# 可选: market, sentiment, news, fundamentals
# 默认: market + news
```
`AgentState` 中关键字段:
| 字段 | 初始值 | 说明 |
|------|--------|------|
| `messages` | `[]` | 全流程消息日志 |
| `ticker` | `"600362"` | 股票代码 |
| `trade_date` | `"2026-04-30"` | 分析日期 |
| `company_name` | `""` | 公司名称(初始为空) |
| `market_report` | `""` | 市场分析报告 |
| `sentiment_report` | `""` | 情绪分析报告 |
| `news_report` | `""` | 新闻分析报告 |
| `fundamentals_report` | `""` | 基本面报告 |
| `investment_plan` | `""` | 投资决策草案 |
| `final_decision` | `""` | 最终交易信号 |
| `current_debate_round` | `0` | 当前辩论轮次 |
### 阶段 3:并行分析师采集(核心环节)
这是整个流程中**数据量最大、耗时最长**的阶段。四个分析师节点通过 LangGraph 的并行边**同时启动**。
#### 3.1 市场分析师 (Market Analyst)
**文件**: `tradingagents/agents/analysts/market_analyst.py`
**角色定位**: 技术面专家
**System Prompt 核心**:
> "You are a trading assistant agent with extensive market insight. Your task is to analyze market data using technical indicators."
**执行的工具调用**:
```
1. get_stock_data("600362", "2026-03-30", "2026-04-30")
→ 路线: route_to_vendor → akshare_data.get_stock_data()
→ 输出: 最近一个月 OHLCV 数据(~22条日K线)
2. get_indicators("600362", "rsi", "2026-04-30", 30)
3. get_indicators("600362", "macd", "2026-04-30", 30)
4. get_indicators("600362", "bollinger_bands", "2026-04-30", 30)
5. get_indicators("600362", "volume", "2026-04-30", 30)
... (最多调用 19 项技术指标中的 5-8 项关键指标)
```
**指标清单**(akshare_data.py 支持的全部 19 项):
| 类别 | 指标 |
|------|------|
| 趋势类 | sma_20, ema_20, macd, adx |
| 动量类 | rsi, stochastic_oscillator, williams_r, cci |
| 波动类 | bollinger_bands, atr, standard_deviation |
| 成交量类 | obv, volume, volume_sma |
| 其他 | mfi, ppo, roc, triple_ema, vortex |
**输出**: 一份 800-1500 字的 Markdown 技术分析报告,含关键指标解读和趋势判断。
#### 3.2 社交媒体分析师 (Social Media Analyst)
**文件**: `tradingagents/agents/analysts/social_media_analyst.py`
**角色定位**: 市场情绪雷达
**执行的工具调用**:
```
1. get_news("600362", "2026-04-01", "2026-05-04")
→ 路线: route_to_vendor → akshare_news.get_news()
→ 数据源: 东方财富个股新闻
→ 输出: 最近 15 天内与该股相关的新闻(最多50条)
```
**输出**: 一份舆情分析报告,提炼市场情绪信号(恐慌/贪婪/中性)。
#### 3.3 新闻分析师 (News Analyst)
**文件**: `tradingagents/agents/analysts/news_analyst.py`
**角色定位**: 宏观政策雷达
**System Prompt 核心**:
> "You are a news analyst agent with expertise in global macro trends. Your task is to analyze news related to the company and the broader economic landscape."
**执行的工具调用**:
```
1. get_news("600362", "2026-04-01", "2026-05-04")
→ 与社媒分析师相同的数据源,但解读角度不同
2. get_global_news("2026-05-04", look_back_days=7, limit=20)
→ 路线: route_to_vendor → akshare_news.get_global_news()
→ 数据源: CCTV 新闻联播文字稿
→ 输出: 宏观政策、经济事件摘要
```
**输出**: 一份包含个股新闻分析和宏观经济背景的综合报告。
#### 3.4 基本面分析师 (Fundamentals Analyst)
**文件**: `tradingagents/agents/analysts/fundamentals_analyst.py`
**角色定位**: 价值投资者
**System Prompt 核心**:
> "You are a fundamental analysis expert with deep knowledge of valuation methodologies. Your task is to analyze company fundamentals and financial health."
**执行的工具调用** (共 4 次):
```
1. get_fundamentals("600362")
→ 数据: 公司概况、市盈率、市净率、总市值、流通股本等
2. get_balance_sheet("600362")
→ 数据: 最新一期资产负债表(总资产/负债/权益)
3. get_cashflow("600362")
→ 数据: 最新一期现金流量表(经营/投资/筹资现金流)
4. get_income_statement("600362")
→ 数据: 最新一期利润表(营收/成本/净利润/每股收益)
```
**输出**: 一份包含估值分析、财务健康度评分、盈利能力判断的基本面报告。
### 阶段 4:研究经理汇总
**文件**: `tradingagents/graph/trading_graph.py` → `create_research_manager_node()`
```
输入: 4份分析师报告(并行采集完成后的汇总)
处理: 研究经理 LLM 阅读所有报告,提取关键矛盾点
输出: 投资者简报 (investment briefing)
```
研究经理不产生独立决策,而是**整理和总结**分析师团队输出的核心信息,为下一阶段的辩论做准备。
### 阶段 5:多空辩论 (Debate)
**文件**: `tradingagents/graph/trading_graph.py` → `create_debate_node()` + `debate_bull_researcher()` + `debate_bear_researcher()`
这是框架的**核心创新**:用 LLM 模拟真实投资决策中的多空辩论。
#### 辩论角色
| 角色 | 文件 | 立场 | 职责 |
|------|------|------|------|
| **Bull Researcher** | `agents/researchers/bull_researcher.py` | 多头 | 找出所有支撑买入的论据 |
| **Bear Researcher** | `agents/researchers/bear_researcher.py` | 空头 | 找出所有支撑卖出的论据 |
| **Debate Judge** | `agents/managers/research_manager.py` | 裁判 | 评估双方论据,判断胜负 |
#### 辩论流程
```
轮次 1:
Bull → 提出 3-5 个多方论点(基于分析师报告)
Bear → 反驳多方论点 + 提出 3-5 个空方论点
Judge → 评估双方论据质量,判断本轮是否分出胜负
轮次 2 (如果裁判认为需要继续):
Bull → 回应空方反驳 + 补充新论点
Bear → 回应多方回应 + 强化空方论点
Judge → 再次评估
... 直到 max_debate_rounds 耗尽或裁判判定胜负
```
**关键**: `max_debate_rounds` 在配置中可调,默认 **1 轮**。每增加一轮,LLM 调用次数翻倍,总耗时显著增长。
#### 辩论输出
- 辩论完整记录(谁说了什么)
- 裁判的最终评估(多方胜/空方胜/平局)
### 阶段 6:交易员决策
**文件**: `tradingagents/agents/trader/trader_agent.py`
**System Prompt 核心**:
> "You are a professional trader agent. Based on the analysts' reports and debate results, make a trading decision."
**输入**:
- 4 份分析师报告
- 辩论摘要(裁判评估)
**处理**: 交易员 LLM 综合所有证据,形成投资决策草案
**输出**: `investment_plan` — 包含:
- 决策方向(Buy/Sell/Hold)
- 置信度评估
- 关键依据
- 风险提示
### 阶段 7:三级风控评审
**文件**: `tradingagents/graph/trading_graph.py` → `create_risk_analysis_node()` + 三个风控 agent
这是项目的**第二道安全阀**:交易员的决策必须通过风控审查。
| 风控角色 | 文件 | 风格 | 关注点 |
|----------|------|------|--------|
| **Aggressive** | `agents/risk_mgmt/aggressive_debator.py` | 激进 | 机会最大化,风险容忍度较高 |
| **Conservative** | `agents/risk_mgmt/conservative_debator.py` | 保守 | 本金安全第一,宁可错过不做错 |
| **Neutral** | `agents/risk_mgmt/neutral_debator.py` | 中立 | 平衡收益与风险 |
#### 流程
```
交易员输出投资草案
│
├→ Aggressive 评估 → "风险可接受,建议执行"
├→ Conservative 评估 → "风险过高,建议降低仓位"
└→ Neutral 评估 → "风险适中,可执行但需设置止损"
│
└→ Risk Judge 汇总三个评估 → 最终裁定
```
**Risk Judge** 文件: `tradingagents/agents/managers/risk_manager.py` — 综合三方意见,给出最终风控建议。
**注意**: 风控评审是一个循环 — 如果 `final_decision` 为空(未达成一致),图会回到交易员节点重新决策。
### 阶段 8:最终输出
经过以上所有阶段后,系统输出:
```python
{
"ticker": "600362",
"date": "2026-04-30",
"company_name": "江西铜业",
"market_report": "...", # 技术分析报告
"sentiment_report": "...", # 情绪分析报告
"news_report": "...", # 新闻分析报告
"fundamentals_report": "...", # 基本面报告
"investment_plan": "...", # 交易决策草案
"debate_log": "...", # 辩论记录
"final_decision": "BUY", # 最终交易信号: BUY / SELL / HOLD
"risk_assessment": "...", # 风控评估
"messages": [...] # 全流程消息日志
}
```
---
## 四、完整节点流转图(Graph 内部)
```
┌──────────────┐
│ START │
└──────┬───────┘
│
┌────────────────┼────────────────┐
▼ ▼ ▼ ▼
┌────────────┐ ┌────────────┐ ┌────────────┐ ┌────────────┐
│mkt_start │ │snt_start │ │nws_start │ │fnd_start │
└─────┬──────┘ └─────┬──────┘ └─────┬──────┘ └─────┬──────┘
▼ ▼ ▼ ▼
┌────────────┐ ┌────────────┐ ┌────────────┐ ┌────────────┐
│mkt_analyst │ │snt_analyst │ │nws_analyst │ │fnd_analyst │
│(LLM分析) │ │(LLM分析) │ │(LLM分析) │ │(LLM分析) │
└─────┬──────┘ └─────┬──────┘ └─────┬──────┘ └─────┬──────┘
▼ ▼ ▼ ▼
┌────────────┐ ┌────────────┐ ┌────────────┐ ┌────────────┐
│mkt_tools │ │snt_tools │ │nws_tools │ │fnd_tools │
│(调用数据) │ │(调用数据) │ │(调用数据) │ │(调用数据) │
└─────┬──────┘ └─────┬──────┘ └─────┬──────┘ └─────┬──────┘
▼ ▼ ▼ ▼
┌────────────┐ ┌────────────┐ ┌────────────┐ ┌────────────┐
│mkt_cond │ │snt_cond │ │nws_cond │ │fnd_cond │
│(if 需继续) │ │(if 需继续) │ │(if 需继续) │ │(if 需继续) │
└─────┬──────┘ └─────┬──────┘ └─────┬──────┘ └─────┬──────┘
│ │ │ │
└────────────────┼────────────────┼────────────────┘
▼
┌──────────────┐
│ invest_judge │ (研究经理汇总)
└──────┬───────┘
│
┌───────────┴───────────┐
▼ ▼
┌────────────┐ ┌────────────┐
│bull_resrch │ │bear_resrch │
│(多方) │ │(空方) │
└─────┬──────┘ └─────┬──────┘
│ │
└──────────┬───────────┘
▼
┌──────────────┐
│ invest_judge │ (辩论裁判评估)
└──────┬───────┘
│ (if 辩论未结束 → 回到 bull/bear)
▼
┌──────────────┐
│ trader │ (交易员决策)
└──────┬───────┘
▼
┌──────────────┐
│trader_tools │ (可能需要查询数据)
└──────┬───────┘
│
┌──────────────┼──────────────┐
▼ ▼ ▼
┌──────────┐ ┌──────────────┐ ┌──────────┐
│aggressive│ │conservative │ │ neutral │
│ 风控 │ │ 风控 │ │ 风控 │
└────┬─────┘ └──────┬───────┘ └────┬─────┘
│ │ │
└────────────────┼────────────────┘
▼
┌──────────────┐
│ risk_judge │ (风控终审)
└──────┬───────┘
│ (if 未通过 → 回到 trader)
▼
┌──────────────┐
│ final │ (输出结果)
└──────────────┘
```
---
## 五、关键数据流路径
以"600362 市场分析"为例,追踪一次数据调用的完整路径:
```
1. Market Analyst LLM 决定调用 get_stock_data("600362", ...)
2. LangChain @tool 装饰器触发
→ agents/utils/core_stock_tools.py:28
3. 内部调用 route_to_vendor("get_stock_data", "600362", ...)
→ dataflows/interface.py:140
4. route_to_vendor 读取 config["data_vendors"]["core_stock_data"]
→ {"primary": "akshare"}
5. 按 priority 顺序尝试:
a) akshare → akshare_data.get_stock_data("600362", ...)
- 检测 "600362" 是6位数字 → 路由到 A 股接口
- 调用 ak.stock_zh_a_hist(symbol="600362", period="daily", ...)
- 格式化 DataFrame → Markdown 表格字符串
- 成功!返回数据 ✓
6. route_to_vendor 获得 Markdown 字符串 → 返回给 tool
7. tool 将数据嵌入 LLM context
8. Market Analyst LLM 收到数据,生成技术分析报告
9. 报告写入 state.market_report
```
如果第5步 akshare 失败,route_to_vendor 会自动尝试 yfinance,再失败尝试 alpha_vantage,**完全透明,LLM 无感知**。
---
## 六、耗时分布估算
基于 DeepSeek 推理速度的单次分析耗时(仅供参考):
| 阶段 | LLM 调用次数 | 数据API调用 | 耗时估算 |
|------|-------------|------------|----------|
| 并行分析师(4个) | 8-16次 (LLM + tool) | 8-15次 | 90-180秒 |
| 研究经理汇总 | 1次 | 0 | 10-20秒 |
| 辩论(1轮) | 3次 (Bull/Bear/Judge) | 0 | 30-60秒 |
| 交易员决策 | 1次 | 0-2次 | 15-30秒 |
| 三级风控 | 4次 (3风控+1裁判) | 0 | 40-80秒 |
| **合计** | **17-25次** | **8-17次** | **3-6分钟** |
> **注意**: 如果 `max_debate_rounds` 设为 2 或更多,辩论耗时翻倍。数据源的 Rate Limit 状况也会影响实际耗时。
---
## 七、与原始实现的关键差异
本项目基于开源 TradingAgents 框架,做了以下适应性修改(详见[架构文档](./architecture-and-modifications.md)):
| 差异点 | 原始实现 | 当前实现 |
|--------|---------|---------|
| 数据源 | yfinance 为主 | **akshare 为主**,yfinance 降级为 fallback |
| A股行情 | 不稳定,频繁 Rate Limit | ✅ 稳定,不限流 |
| A股财务数据 | ❌ | ✅ 三大报表完整 |
| 新闻源 | 英文(yfinance news) | ✅ 中文(东方财富 + CCTV) |
| 港股支持 | 部分 | ✅ 完整 |
| Web UI | ❌ 无 | ✅ FastAPI + 前端面板 |
| 部署 | 脚本手动运行 | ✅ systemd 服务自动管理 |
---
## 八、配置调优建议
通过修改 `default_config.py` 或运行时 `set_config()` 可调整的参数:
| 参数 | 默认值 | 建议范围 | 说明 |
|------|--------|---------|------|
| `max_debate_rounds` | 1 | 1-3 | 辩论轮次,越多越深度但越慢 |
| `data_vendors.*.primary` | `"akshare"` | `"akshare"` / `"yfinance"` | 主数据源 |
| `llm_provider` | `"deepseek"` | — | LLM 后端 |
| `quick_thinking` | `False` | `True` / `False` | True 使用 fast model,速度更快精度略低 |
---
## 九、监控与调试
### 查看服务日志
```bash
journalctl -u tradingagents.service -f
```
### 查看分析任务状态
```bash
curl http://129.211.173.87:8500/api/task/{task_id}
```
### 重启服务
```bash
sudo systemctl restart tradingagents.service
```