Files
nanocode/TradingAgents/docs/workflow-analysis.md
T
Ubuntu 32b43f85bd a
2026-07-03 16:58:28 +08:00

19 KiB
Raw Blame History

TradingAgents 股票分析工作流程详解

文档时间: 2026-05-05 相关文档: 技术架构分析 配套图表: 流程图 | 架构图


一、一次分析的完整生命周期

当用户在 Web UI 输入 600362 并点击"分析",系统会经历以下完整流程:

用户点击 [分析] → 后台异步任务 → 约 3-8 分钟后 → 输出交易决策

整个流程由 LangGraph StateGraph 驱动,状态在 15+ 个节点间流转。下面按执行顺序逐步拆解。


二、流程图

流程图

详细架构图: 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()

# 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:最终输出

经过以上所有阶段后,系统输出:

{
    "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 框架,做了以下适应性修改(详见架构文档):

差异点 原始实现 当前实现
数据源 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,速度更快精度略低

九、监控与调试

查看服务日志

journalctl -u tradingagents.service -f

查看分析任务状态

curl http://129.211.173.87:8500/api/task/{task_id}

重启服务

sudo systemctl restart tradingagents.service