项目地址:virattt/ai-hedge-fund ⭐ 56.6k
定位:教育研究用途的 AI 多智能体投资决策系统,不构成真实交易建议。
一、从一个问题开始:AI 能做投资分析吗?
如果让巴菲特、彼得·林奇、迈克尔·伯里同时研究同一只股票,然后由风险经理汇总意见、投资组合经理做最终决策——这是多少人梦寐以求的投资委员会。
这个项目的回答是:可以用 AI 来模拟这个流程。
它将 19 位投资大师和专业分析师的思维方式"注入"大语言模型(LLM),构成一个多智能体协作的投资决策系统。每个 Agent 各司其职,最终由组合经理综合所有信号给出交易指令。
二、全局架构:一张图搞懂整个系统
┌─────────────────────────────────────────────────────────────────┐
│ 用户输入层 │
│ CLI (main.py) / Web App (React + FastAPI) │
└────────────────────────────┬────────────────────────────────────┘
│ 股票代码 / 日期范围 / 选用分析师
▼
┌─────────────────────────────────────────────────────────────────┐
│ LangGraph 状态机(工作流) │
│ │
│ start_node │
│ │ │
│ ├──── warren_buffett_agent ────┐ │
│ ├──── ben_graham_agent ────────┤ │
│ ├──── cathie_wood_agent ───────┤ │
│ ├──── michael_burry_agent ─────┤ │
│ ├──── technical_analyst_agent ─┤ 并行执行 │
│ ├──── fundamentals_analyst ────┤ │
│ ├──── sentiment_analyst ───────┤ │
│ ├──── valuation_analyst ───────┤ │
│ └──── ... (19个分析师) ─────────┘ │
│ │ │
│ ▼ │
│ risk_management_agent │
│ (波动率 + 相关性调仓限额) │
│ │ │
│ ▼ │
│ portfolio_manager │
│ (综合信号 → 最终交易决策) │
└────────────────────────────┬────────────────────────────────────┘
│ buy / sell / short / cover / hold
▼
输出交易决策 + 信号详情
关键设计:所有分析师 Agent 并行执行(通过 LangGraph 的边连接到同一个 risk_management_agent),互不阻塞,最后统一汇总。
三、核心概念解析
3.1 AgentState:流转于整个工作流的"公共黑板"
整个系统的数据共享靠一个 TypedDict:
class AgentState(TypedDict):
messages: Annotated[Sequence[BaseMessage], operator.add] # 消息历史(追加)
data: Annotated[dict[str, any], merge_dicts] # 股票数据、信号(合并)
metadata: Annotated[dict[str, any], merge_dicts] # 模型配置、调试开关
理解这个结构至关重要:
data 字段内部结构示意:
{
"tickers": ["AAPL", "MSFT"],
"portfolio": { "cash": 100000, "positions": {...} },
"start_date": "2024-01-01",
"end_date": "2024-03-01",
"analyst_signals": {
"warren_buffett_agent": {
"AAPL": {"signal": "bullish", "confidence": 85, "reasoning": "..."},
"MSFT": {"signal": "neutral", "confidence": 60, "reasoning": "..."}
},
"technical_analyst_agent": { ... },
"risk_management_agent": {
"AAPL": {"remaining_position_limit": 15000.0, "current_price": 182.5}
}
}
}
每个 Agent 读取 data,将自己的分析结果写入 analyst_signals[自己的名字],下游 Agent 可以读取所有上游的信号。这是一种黑板架构(Blackboard Pattern)。
3.2 工作流是如何构建的?
# src/main.py - 核心工作流组装逻辑
def create_workflow(selected_analysts=None):
workflow = StateGraph(AgentState)
workflow.add_node("start_node", start)
analyst_nodes = get_analyst_nodes() # 从配置获取所有分析师
if selected_analysts is None:
selected_analysts = list(analyst_nodes.keys())
# 注册选定的分析师节点
for analyst_key in selected_analysts:
node_name, node_func = analyst_nodes[analyst_key]
workflow.add_node(node_name, node_func)
workflow.add_edge("start_node", node_name) # start → 各分析师(并行)
# 所有分析师 → 风险管理 → 投资组合经理 → 结束
workflow.add_node("risk_management_agent", risk_management_agent)
workflow.add_node("portfolio_manager", portfolio_management_agent)
for analyst_key in selected_analysts:
node_name = analyst_nodes[analyst_key][0]
workflow.add_edge(node_name, "risk_management_agent")
workflow.add_edge("risk_management_agent", "portfolio_manager")
workflow.add_edge("portfolio_manager", END)
workflow.set_entry_point("start_node")
return workflow
可视化工作流执行顺序:
start_node
│
├─────────────────────────────────────────────────────────┐
│ (以下并行,互不依赖) │
▼ ▼
warren_buffett_agent technical_analyst_agent
│ │
└──────────────────────┬──────────────────────────────────┘
▼
risk_management_agent
(需要等所有分析师完成)
│
▼
portfolio_manager
│
▼
END
四、19 位分析师 Agent 详解
4.1 分析师配置表
┌──────────────────────────┬───────────────────────────────────────────────────┐
│ 分析师 │ 投资风格 │
├──────────────────────────┼───────────────────────────────────────────────────┤
│ Warren Buffett │ 价值投资,护城河,安全边际,DCF内在价值 │
│ Ben Graham │ 价值投资鼻祖,深度低估,安全边际 │
│ Charlie Munger │ 优质企业,合理价格,长期持有 │
│ Peter Lynch │ 十倍股,"买你所了解的",PEG比率 │
│ Cathie Wood │ 颠覆性创新,高增长赛道 │
│ Bill Ackman │ 激进投资人,推动管理层变革 │
│ Michael Burry │ 逆向做空,深度基本面分析 │
│ Mohnish Pabrai │ Dhandho 哲学,低风险高回报 │
│ Phil Fisher │ 成长股,"小道消息"研究法(Scuttlebutt) │
│ Nassim Taleb │ 黑天鹅,尾部风险,反脆弱,哑铃策略 │
│ Aswath Damodaran │ 估值大师,故事+数字,严格财务建模 │
│ Stanley Druckenmiller │ 宏观投资,货币/大宗商品/利率 │
│ Rakesh Jhunjhunwala │ 印度大牛,新兴市场,宏观+行业 │
│ Technical Analyst │ 趋势跟踪+均值回归+动量+波动率+统计套利 │
│ Fundamentals Analyst │ 财务报表,ROE/成长/健康度/估值多维评分 │
│ Valuation Analyst │ 内在价值计算,多种估值模型 │
│ Sentiment Analyst │ 内幕交易,市场情绪 │
│ News Sentiment Analyst │ 新闻舆情分析 │
│ Growth Analyst │ 成长趋势,PEG,成长质量 │
└──────────────────────────┴───────────────────────────────────────────────────┘
4.2 以 Warren Buffett Agent 为例深入剖析
这是最完整的分析师实现,包含 8 个维度的纯代码评分 + LLM 最终判断。
分析流程图:
输入:ticker + 财务数据
│
├─→ analyze_fundamentals() ROE/负债/利润率/流动比率 → 0~10分
├─→ analyze_consistency() 盈利增长一致性 → 0~3分
├─→ analyze_moat() 护城河(ROE稳定性/毛利率) → 0~5分
├─→ analyze_pricing_power() 定价权(毛利扩张) → 0~5分
├─→ analyze_book_value_growth() 每股账面价值增长 → 0~5分
├─→ analyze_management_quality() 回购/分红 → 0~2分
└─→ calculate_intrinsic_value() 三阶段DCF估值
│
└─→ 计算安全边际 = (内在价值 - 市值) / 市值
↓ 将所有分析结果打包为 facts dict
generate_buffett_output()
↓ 发送给 LLM(扮演巴菲特角色)
↓ 返回 {signal, confidence, reasoning}
↓
输出:{"AAPL": {"signal": "bullish", "confidence": 78, "reasoning": "..."}}
三阶段 DCF 估值模型(代码简化展示):
# 第一阶段:高增长期(5年,上限8%)
# 第二阶段:过渡期(5年,上限4%)
# 第三阶段:永续增长率(2.5%,对应长期GDP增速)
# 折现率:10%(保守)
# 额外保守系数:再打85折
intrinsic_value = (stage1_pv + stage2_pv + terminal_pv) * 0.85
margin_of_safety = (intrinsic_value - market_cap) / market_cap
4.3 Technical Analyst:纯算法的五维信号融合
技术分析师不调用 LLM,完全用数学计算信号,然后加权融合:
策略 权重 核心指标
────────────────────────────────────────────────────────
趋势跟踪 25% EMA(8/21/55) + ADX趋势强度
均值回归 20% 布林带 + Z-Score + RSI(14/28)
动量分析 25% 1/3/6个月动量 + 成交量确认
波动率分析 15% 历史波动率 + VIX机制 + ATR比率
统计套利 15% Hurst指数 + 偏度/峰度
加权综合分 > 0.2 → bullish
加权综合分 < -0.2 → bearish
否则 → neutral
Hurst 指数解读(项目中实现):
H < 0.4 → 均值回归市场(适合布林带策略)
H ≈ 0.5 → 随机游走(难以预测)
H > 0.6 → 趋势市场(适合趋势跟踪策略)
五、风险管理:不只是"别买太多"
5.1 双重调整机制
Risk Manager 对每个股票计算允许的最大持仓额度,分两步调整:
步骤1:波动率调整
──────────────────────────────────────────
年化波动率 < 15% → 可用仓位 = 组合 × 25%(低波,可多配)
年化波动率 15~30% → 可用仓位 = 组合 × 15~20%(标准)
年化波动率 30~50% → 可用仓位 = 组合 × 7.5~15%(高波,减配)
年化波动率 > 50% → 可用仓位 = 组合 × 10%(极高波,最小配置)
步骤2:相关性调整(乘以相关性倍数)
──────────────────────────────────────────
与持仓平均相关性 ≥ 0.8 → × 0.70(高相关,减少集中风险)
与持仓平均相关性 0.6~0.8 → × 0.85
与持仓平均相关性 0.4~0.6 → × 1.00(中性)
与持仓平均相关性 0.2~0.4 → × 1.05(低相关,轻微加仓)
与持仓平均相关性 < 0.2 → × 1.10(分散化奖励)
最终仓位上限 = min(波动率调整后限额 × 相关性倍数, 可用现金)
举例:组合总值 $100,000,NVDA 年化波动率 60%,与现有持仓平均相关 0.75:
- 基础仓位:10,000
- 相关性调整:8,500
- 最多允许投入 $8,500
六、Portfolio Manager:最终决策的守门人
组合经理不仅仅是汇总信号投票,它还做了确定性约束预计算:
# 先用纯逻辑计算"物理上允许的操作"
allowed_actions = compute_allowed_actions(tickers, prices, max_shares, portfolio)
# 例如:
# {
# "AAPL": {"buy": 45, "sell": 100, "hold": 0}, # 有100股可卖,最多再买45股
# "MSFT": {"short": 30, "cover": 0, "hold": 0}, # 没有多头,可做空30股
# }
# 只有"hold"选项的股票直接预填,不浪费 LLM token
# 其余发给 LLM 做最终选择
发给 LLM 的提示极度精简(节省成本):
Signals:
{"AAPL":{"warren_buffett_agent":{"sig":"bullish","conf":78},"technical_analyst_agent":{"sig":"bearish","conf":65},...}}
Allowed:
{"AAPL":{"buy":45,"sell":100,"hold":0}}
Pick one allowed action per ticker, quantity ≤ max. Reasoning max 100 chars.
LLM 返回结构化输出(Pydantic 强制校验):
class PortfolioDecision(BaseModel):
action: Literal["buy", "sell", "short", "cover", "hold"]
quantity: int
confidence: int # 0-100
reasoning: str # 最多100字符
七、数据层与缓存
数据流向图
FinancialDatasets.ai API
│
│ REST请求(带重试+限流处理)
▼
src/tools/api.py
┌──────────────────────────────────────────────┐
│ get_prices() 价格数据(OHLCV) │
│ get_financial_metrics() 财务指标(ROE/PE/...) │
│ search_line_items() 财务行项目(DCF用途) │
│ get_insider_trades() 内幕交易记录 │
│ get_company_news() 新闻数据 │
│ get_market_cap() 市值 │
└──────────────────────┬───────────────────────┘
│
内存缓存层
src/data/cache.py
┌──────────────────────────────┐
│ Cache(单例,进程内) │
│ - prices_cache │
│ - financial_metrics_cache │
│ - insider_trades_cache │
│ - company_news_cache │
└──────────────────────────────┘
相同参数第二次请求直接读缓存
数据模型(Pydantic 强类型):
class FinancialMetrics(BaseModel):
ticker: str
market_cap: float | None
price_to_earnings_ratio: float | None
return_on_equity: float | None
debt_to_equity: float | None
operating_margin: float | None
revenue_growth: float | None
# ... 40+ 个字段
八、LLM 支持矩阵
项目支持极其丰富的 LLM 选择,覆盖国内外主流:
提供商 示例模型 API Key 环境变量
──────────────────────────────────────────────────────────
OpenAI gpt-4.1, gpt-4o OPENAI_API_KEY
Anthropic claude-opus-4.5 ANTHROPIC_API_KEY
DeepSeek deepseek-chat DEEPSEEK_API_KEY
Google gemini-2.0-flash GOOGLE_API_KEY
Groq llama-3.3-70b GROQ_API_KEY
Kimi (月之暗面) moonshot-v1-8k MOONSHOT_API_KEY
xAI grok-3 XAI_API_KEY
GigaChat GigaChat GIGACHAT_API_KEY
Azure OpenAI 自定义部署 AZURE_OPENAI_API_KEY
OpenRouter 多模型路由 OPENROUTER_API_KEY
Ollama 本地部署任意模型 无需Key
本地部署(Ollama)示例:
# 先安装并启动 ollama,下载模型
ollama pull llama3.1:8b
# 使用本地模型运行
poetry run python src/main.py --ticker AAPL --ollama
九、实战示例
示例1:入门 —— 快速跑起来(5分钟)
# 1. 克隆项目
git clone https://github.com/virattt/ai-hedge-fund.git
cd ai-hedge-fund
# 2. 安装依赖
poetry install
# 3. 配置 API Key(至少配置一个 LLM + 金融数据源)
cp .env.example .env
# 编辑 .env:
# OPENAI_API_KEY=sk-...
# FINANCIAL_DATASETS_API_KEY=fd-...
# 4. 运行,分析苹果公司
poetry run python src/main.py --ticker AAPL
# 输出示例:
# AAPL: action=buy, quantity=23, confidence=72
# Reasoning: Strong moat, FCF positive, slight overvaluation offset by growth
示例2:进阶 —— 多股票 + 指定分析师 + 显示推理过程
# 只用巴菲特 + 技术分析师分析三只科技股,并展示推理过程
poetry run python src/main.py \
--ticker AAPL,MSFT,NVDA \
--start-date 2024-01-01 \
--end-date 2024-06-30 \
--analysts warren_buffett technical_analyst \
--show-reasoning
# 控制台输出会显示每个 Agent 的详细分析:
# ========== Warren Buffett Agent ==========
# AAPL: score=28/40, margin_of_safety=-0.18, moat=strong, signal=neutral
# MSFT: score=35/40, margin_of_safety=0.05, moat=excellent, signal=bullish
示例3:进阶 —— 回测历史策略表现
# 用 Michael Burry(逆向做空)+ 技术分析师,回测 2023 全年
poetry run python src/backtester.py \
--ticker SPY,QQQ,TLT \
--start-date 2023-01-01 \
--end-date 2023-12-31 \
--analysts michael_burry technical_analyst \
--initial-cash 100000
# 回测每个交易日执行一次决策,最终输出:
# Sharpe Ratio: 1.23
# Max Drawdown: -8.5%
# Total Return: +34.2%
# Long/Short Ratio: 2.1
示例4:高级 —— 自定义新分析师
假设你想加入一个"A股专属分析师",步骤如下:
第一步:创建分析师文件 src/agents/a_share_analyst.py
from langchain_core.messages import HumanMessage
from langchain_core.prompts import ChatPromptTemplate
from pydantic import BaseModel, Field
from typing_extensions import Literal
from src.graph.state import AgentState, show_agent_reasoning
from src.tools.api import get_financial_metrics
from src.utils.llm import call_llm
from src.utils.progress import progress
import json
class AShareSignal(BaseModel):
signal: Literal["bullish", "bearish", "neutral"]
confidence: int = Field(description="置信度 0-100")
reasoning: str = Field(description="分析理由")
def a_share_analyst_agent(state: AgentState, agent_id: str = "a_share_analyst_agent"):
"""A股专属分析师:关注北向资金、政策面、市盈率分位数"""
data = state["data"]
tickers = data["tickers"]
end_date = data["end_date"]
analysis_results = {}
for ticker in tickers:
progress.update_status(agent_id, ticker, "获取A股财务数据")
metrics = get_financial_metrics(ticker, end_date, period="annual", limit=5)
if not metrics:
continue
m = metrics[0]
# A股特色指标:低PE + 高ROE + 低负债
score = 0
if m.price_to_earnings_ratio and m.price_to_earnings_ratio < 20:
score += 2
if m.return_on_equity and m.return_on_equity > 0.12:
score += 2
if m.debt_to_equity and m.debt_to_equity < 0.6:
score += 1
# 让 LLM 扮演"A股价值投资者"
template = ChatPromptTemplate.from_messages([
("system", "你是一位专注A股市场的价值投资分析师,"
"关注政策导向、行业景气度和估值合理性。"),
("human", "股票 {ticker} 的评分是 {score}/5,PE={pe},ROE={roe}。"
"请给出投资信号(bullish/neutral/bearish)和理由。\n"
'返回JSON: {{"signal":"...","confidence":int,"reasoning":"..."}}')
])
prompt = template.invoke({
"ticker": ticker, "score": score,
"pe": m.price_to_earnings_ratio,
"roe": m.return_on_equity
})
result = call_llm(prompt, AShareSignal, agent_id, state)
analysis_results[ticker] = result.model_dump()
message = HumanMessage(content=json.dumps(analysis_results), name=agent_id)
state["data"]["analyst_signals"][agent_id] = analysis_results
return {"messages": [message], "data": state["data"]}
第二步:注册到配置 src/utils/analysts.py
from src.agents.a_share_analyst import a_share_analyst_agent
ANALYST_CONFIG["a_share_analyst"] = {
"display_name": "A股分析师",
"description": "A股价值投资专家",
"investing_style": "关注政策导向、低估值、高ROE的A股标的",
"agent_func": a_share_analyst_agent,
"type": "analyst",
"order": 19,
}
完成!现在可以用 --analysts a_share_analyst 使用它了。
示例5:高级 —— 通过 Python API 嵌入到自己的系统
from src.main import run_hedge_fund
# 构建投资组合初始状态
portfolio = {
"cash": 500000.0,
"margin_requirement": 0.5,
"margin_used": 0.0,
"positions": {
"AAPL": {"long": 0, "short": 0, "long_cost_basis": 0.0,
"short_cost_basis": 0.0, "short_margin_used": 0.0},
"TSLA": {"long": 0, "short": 0, "long_cost_basis": 0.0,
"short_cost_basis": 0.0, "short_margin_used": 0.0},
},
"realized_gains": {"AAPL": {"long": 0.0, "short": 0.0},
"TSLA": {"long": 0.0, "short": 0.0}},
}
# 只用 4 位分析师,用 claude-opus-4-5 模型
result = run_hedge_fund(
tickers=["AAPL", "TSLA"],
start_date="2024-01-01",
end_date="2024-03-31",
portfolio=portfolio,
show_reasoning=True,
selected_analysts=["warren_buffett", "cathie_wood",
"technical_analyst", "risk_management"],
model_name="claude-opus-4-5",
model_provider="Anthropic",
)
# 解析结果
decisions = result["decisions"]
signals = result["analyst_signals"]
for ticker, decision in decisions.items():
print(f"{ticker}: {decision['action']} {decision['quantity']}股 "
f"(置信度: {decision['confidence']}%)")
print(f" 理由: {decision['reasoning']}")
# 查看各分析师的原始信号
for agent, ticker_signals in signals.items():
for ticker, signal in ticker_signals.items():
print(f" [{agent}] {ticker}: {signal.get('signal')} "
f"conf={signal.get('confidence')}")
示例6:高级 —— 启动 Web 应用界面
# 最简单的方式(推荐,适合非技术用户)
./run.sh # Mac/Linux
run.bat # Windows
# 手动方式
# 终端1:启动后端
cd app/backend
poetry run uvicorn main:app --reload
# 访问 http://localhost:8000/docs 查看 API 文档
# 终端2:启动前端
cd app/frontend
npm run dev
# 访问 http://localhost:5173 使用可视化界面
Web UI 提供:
- 可视化选择分析师(勾选框)
- 实时显示每个 Agent 的分析进度
- 交互式图表展示投资组合历史
- 回测结果的 Sharpe/Drawdown 图表
十、回测引擎深度解析
回测是检验策略的核心工具。引擎的执行逻辑:
初始化
│ 预拉取1年数据并缓存(避免回测中频繁 API 调用)
↓
按交易日循环 (每个工作日)
│
├─→ 获取当日价格
│
├─→ 调用 run_hedge_fund()(模拟当日决策)
│ 输入:lookback_start ~ 当日
│ 输出:各股票 action + quantity
│
├─→ 执行交易(TradeExecutor)
│ buy → 扣减现金,增加多头持仓
│ sell → 增加现金,减少多头持仓
│ short → 计算保证金,增加空头持仓
│ cover → 计算盈亏,减少空头持仓
│
├─→ 计算当日组合价值(多头市值 - 空头市值 + 现金)
│
└─→ 输出每日明细表 + 更新性能指标
Sharpe Ratio = 年化收益 / 年化波动率
Sortino Ratio = 年化收益 / 下行波动率
Max Drawdown = 最大从峰值回撤比例
Long/Short Ratio = 多头敞口 / 空头敞口
十一、项目目录结构速查
ai-hedge-fund/
├── src/
│ ├── main.py # 入口:工作流组装 + CLI
│ ├── backtester.py # 回测入口
│ │
│ ├── agents/ # 所有分析师 Agent(19个)
│ │ ├── warren_buffett.py
│ │ ├── technical_analyst.py
│ │ ├── risk_manager.py
│ │ ├── portfolio_manager.py
│ │ └── ...
│ │
│ ├── graph/
│ │ └── state.py # AgentState 定义
│ │
│ ├── llm/
│ │ ├── models.py # LLM 提供商适配层
│ │ ├── api_models.json # 在线模型列表
│ │ └── ollama_models.json # 本地模型列表
│ │
│ ├── tools/
│ │ └── api.py # 金融数据 API 封装 + 缓存
│ │
│ ├── data/
│ │ ├── models.py # Pydantic 数据模型
│ │ └── cache.py # 内存缓存
│ │
│ ├── backtesting/
│ │ ├── engine.py # 回测引擎
│ │ ├── trader.py # 交易执行
│ │ ├── metrics.py # Sharpe/Drawdown 计算
│ │ └── portfolio.py # 组合持仓管理
│ │
│ └── utils/
│ ├── analysts.py # 分析师注册表(单一配置源)
│ ├── llm.py # call_llm 工具函数(重试/结构化输出)
│ ├── progress.py # 进度显示
│ └── display.py # 终端格式化输出
│
├── app/ # Web 应用
│ ├── backend/ # FastAPI 后端
│ └── frontend/ # React/Vite 前端
│
├── .env.example # API Key 配置模板
└── pyproject.toml # Poetry 依赖管理
十二、设计亮点与局限性
亮点
1. 代码与 LLM 的职责分离:数值计算(DCF、波动率、技术指标)全用纯 Python,LLM 只负责"判断"和"推理",而非计算。这保证了可重复性和可调试性。
2. Pydantic 强类型约束:所有 LLM 输出都有 Pydantic 模型校验,避免幻觉导致的格式错误破坏后续流程,并有多次重试 + 默认值兜底。
3. 确定性约束前置:组合经理先用纯逻辑算出"物理上允许的操作",再送给 LLM 选择,避免 LLM 输出不合法操作(如买入超过现金量)。
4. 极低 token 消耗设计:信号压缩为 {sig, conf},推理限制在 100 字符以内,预填充 hold 类型股票,大幅节省成本。
5. 高度可扩展:新增分析师只需两步——写分析函数 + 注册到 ANALYST_CONFIG。
局限性
- 金融数据依赖 FinancialDatasets.ai(需付费 Key),A 股数据覆盖有限
- 内存缓存进程重启后丢失,高频回测会重复 API 调用
- 回测不考虑滑点、手续费、市场冲击成本
- "模仿"大师只是提示词策略,并非真正学习了其决策模式
十三、总结
ai-hedge-fund 是一个教学意义极强的工程实践项目,它展示了如何将 LangGraph 多智能体框架、金融量化分析和大语言模型三者有机结合。
核心架构用一句话概括:并行的专家 Agent 各自产出信号,经过量化风控约束,由组合经理 LLM 做最终决策。
无论你是想学习多智能体系统设计、探索 LLM 在金融领域的应用,还是搭建自己的量化研究平台,这个项目都是极好的起点。
再次强调:本项目为教育目的,不构成任何投资建议,请勿用于真实交易。
十四、更多分析师深度解析
14.1 Nassim Taleb Agent:最复杂的风险哲学实现
Taleb Agent 是整个项目中维度最多、逻辑最独特的分析师,完全按照《反脆弱》的思想框架构建,共有 7 个子分析维度,总分 46 分:
维度 满分 核心逻辑
──────────────────────────────────────────────────────────────────────
尾部风险 (Tail Risk) 8分 峰度/偏度/尾比率/最大回撤
反脆弱性 (Antifragility) 10分 净现金/低杠杆/利润率稳定性/FCF一致性
凸性 (Convexity) 10分 R&D期权性/上行/下行比率/现金期权
脆弱性检测 (Fragility) 8分 杠杆/利息覆盖率/盈利波动/利润缓冲
同行参与 (Skin in Game) 4分 内幕净买入/买卖比率
波动率机制 (Vol Regime) 6分 当前波动率/历史均值比/波动率的波动率
黑天鹅哨兵 (Black Swan) 4分 负面新闻占比/成交量异常/价格偏离
波动率机制评分中最有趣的一条逻辑——"低波动才是危险"(即"火鸡问题"):
波动率机制比值 < 0.7 → 0分 (注意!这是得分最低的情况!)
"极端低波动率——火鸡问题(Thanksgiving Turkey),
平静期积累的脆弱性随时可能爆发"
波动率机制比值 1.0~1.3 → 3分 (正常区间)
波动率机制比值 1.3~2.0 → 4分 (最高分!高波动对反脆弱者是机会)
这与传统风险管理完全相反——大多数人怕高波动,Taleb 认为高波动才是真实的,低波动才是风险压抑的信号。
黑天鹅哨兵里的逆向逻辑(与 Michael Burry 如出一辙):
# 高负面新闻 + 无成交量恐慌 = 逆向机会
if neg_ratio > 0.4 and volume_spike < 1.5 and score < 4:
score = min(score + 1, 4)
reasoning.append("逆向机会——负面情绪未伴随恐慌抛售")
14.2 Michael Burry Agent:数字驱动的逆向做空者
Burry 的实现只有 4 个维度,但极度聚焦:
维度 满分 核心指标
────────────────────────────────────────────
价值分析 6分 FCF收益率(≥15%得4分)+ EV/EBIT(<6得2分)
资产负债表 3分 D/E < 0.5 + 净现金地位
内幕交易活动 2分 过去12个月净内幕买入量
逆向情绪 1分 ≥5条负面新闻(越被嫌弃越好)
LLM 提示词充分体现了 Burry 的人设风格:
- "数字先行,极简表达"
- "关注下行风险,债务是死穴"
- "负面新闻墙 = 潜在机会(前提是基本面支撑)"
14.3 Cathie Wood Agent:增长赛道的评分体系
Wood 的分析分三层:
第一层:颠覆性潜力(满分5分,归一化自12分)
├─ 营收增长加速(+2)
├─ 最新营收增长率 >100%/50%/20%(+3/2/1)
├─ 毛利率扩张 >5%(+2)
├─ 毛利率绝对值 >50%(+2)
├─ 正向经营杠杆(+2)
└─ R&D强度 >15%/8%/5%(+3/2/1)
第二层:创新增长(满分5分,归一化自15分)
├─ R&D支出增长 >50%(+3)
├─ R&D强度趋势上升(+2)
├─ FCF增长且一致正值(+3)
├─ 营业利润率 >15%(+3)
└─ 资本开支强度 + 再投资率(+2+2)
第三层:估值(满分5分)
└─ 高成长 DCF:20%增长率 + 25x终值倍数
安全边际 >50% → +3, >20% → +1
总分 ≥ 70% → bullish,≤ 30% → bearish
Wood 用 20% 成长率 + 25 倍终值(而非 Buffett 的 4% + 戈登模型),这正是她乐于买入"贵但高增长"的标的而不在乎 P/E 的数学依据。
14.4 情绪分析 Agent:两信号源加权融合
情绪分析师完全不调用 LLM,纯规则:
信号来源 权重 数据
───────────────────────────────────────────────
内幕交易方向 30% transaction_shares > 0 → bullish
transaction_shares < 0 → bearish
新闻情绪 70% sentiment == "positive" → bullish
sentiment == "negative" → bearish
其他 → neutral
最终信号 = argmax(加权后多/空票数)
置信度 = max(加权多票, 加权空票) / 加权总票数 × 100%
内幕交易权重(30%)低于新闻(70%),原因是内幕交易可能有多种解读(员工期权行权 ≠ 看空),而新闻情绪覆盖面更广、样本量更大。
14.5 估值 Agent:四模型加权内在价值
Valuation Agent 是整个项目中估值模型最完整的 Agent,同时运行 4 种方法:
方法 权重 核心公式
────────────────────────────────────────────────────────────────────
增强 DCF(三情境) 35% 熊/基/牛三场景 × (0.2/0.6/0.2)
WACC = 股权成本(CAPM) + 税后债务成本
Owner Earnings 法 35% 净利润 + D&A - 维护性资本开支 - 营运资本变化
(Buffett 的"真实盈利能力")
EV/EBITDA 历史中位数法 20% 用历史中位 EV/EBITDA 倍数估算当前隐含价值
剩余收益模型 (RIM) 10% 账面价值 + PV(超额收益) + PV(终值超额收益)
(Edwards-Bell-Ohlson 模型)
WACC 计算(代码中真实实现):
资本成本 (CAPM): Ke = Rf + β × ERP = 4.5% + 1.0 × 6% = 10.5%(默认)
债务成本: Kd = 由利息覆盖率推算(覆盖率越高,债务越便宜)
WACC = (E/V × Ke) + (D/V × Kd × (1-税率))
边界约束: max(6%, min(20%, WACC)) ← 防极端情况
DCF 三情境设计:
成长率调整 WACC调整 终值调整
熊市情境(20%) ×0.5 ×1.2 ×0.8
基准情境(60%) ×1.0 ×1.0 ×1.0
牛市情境(20%) ×1.5 ×0.9 ×1.2
加权内在价值 = 熊×0.2 + 基×0.6 + 牛×0.2
最终信号判断:
加权差距 > 15% → bullish(低估超 15%)
加权差距 < -15% → bearish(高估超 15%)
否则 → neutral
十五、投资组合交易引擎:做多/做空的完整会计处理
回测引擎的 Portfolio 类实现了精确的持仓核算,这是整个系统能进行做空回测的基础。
15.1 五种操作的现金流向
操作 现金变化 持仓变化
─────────────────────────────────────────────────────────────────────
BUY -数量×价格 多头持仓+数量,更新均价成本
SELL +数量×价格 多头持仓-数量,计入已实现盈亏
SHORT +融券收入-保证金 空头持仓+数量,锁定保证金
COVER -回补成本+释放保证金 空头持仓-数量,计入已实现盈亏
HOLD 无变化 无变化
做空的现金流细节(与大多数教学项目不同,这里实现正确):
# 开空:收到融券收入,但同时锁定保证金
proceeds = price × quantity # 融券收入(卖空所得)
margin_required = proceeds × 0.5 # 需冻结 50% 保证金(默认)
cash += proceeds # 收到融券款
cash -= margin_required # 冻结保证金
margin_used += margin_required # 记录已用保证金
# 平空:回购股票,释放保证金,计算盈亏
realized_gain = (avg_short_price - cover_price) × quantity # 空头盈利
cash -= cover_cost # 回购花费
cash += margin_to_release # 释放保证金
margin_used -= margin_to_release
15.2 净清算价值(NLV)计算
NLV = 现金
+ Σ(多头持仓量 × 当前价格)
- Σ(空头持仓量 × 当前价格) ← 空头是负债
注意:空头敞口是减项——若空头头寸亏损(股价上涨),组合价值会下降,这与真实市场行为一致。
十六、性能指标详解:如何评价策略好坏
指标 计算公式 含义
──────────────────────────────────────────────────────────────────────
Sharpe Ratio √252 × (超额日均收益 / 日收益标准差)
> 1.0 优秀,> 2.0 卓越
分母包含上行和下行波动,"惩罚"所有波动
Sortino Ratio √252 × (超额日均收益 / 下行偏差)
只惩罚下行波动,对策略更公平
>> Sharpe 说明策略收益主要来自上行
Max Drawdown (谷值 - 峰值) / 峰值 × 100%
衡量最坏时刻的账面亏损
-20% 以内较健康,-50% 以上很危险
基准对比 策略收益率 vs SPY 同期收益率
正超额收益 = alpha 存在(是否真正有价值)
Long/Short Ratio 多头敞口 / 空头敞口
> 1 = 净多头偏向,< 1 = 净空头偏向
无风险利率默认使用 4.34%(annual_rf_rate = 0.0434),对应美国当前较高利率环境。
十七、CLI 交互体验:questionary 的精妙使用
项目没有简单地用 argparse 做命令行,而是用 questionary 实现了交互式终端 UI:
运行时用户体验:
? Select your AI analysts.
Instructions:
1. Press Space to select/unselect analysts.
2. Press 'a' to select/unselect all.
3. Press Enter when done.
◯ Aswath Damodaran
◉ Ben Graham ← 绿色高亮,已选中
◯ Bill Ackman
◉ Warren Buffett ← 绿色高亮,已选中
◯ Cathie Wood
...
? Select your LLM model:
> gpt-4.1 (OpenAI) ← 绿色箭头指向当前选项
claude-opus-4-5 (Anthropic)
deepseek-chat (DeepSeek)
gemini-2.0-flash (Google)
llama-3.3-70b (Groq)
[自定义 Ollama 模型...]
运行时进度显示(rich.Live实时刷新):
⋯ Warren Buffett [AAPL] Calculating intrinsic value
✓ Technical Analyst [AAPL] Done
✓ Technical Analyst [MSFT] Done
⋯ Ben Graham [MSFT] Analyzing balance sheet
⋯ Risk Management [AAPL] Calculating volatility- and correlation-adjusted limits
绿色 ✓ = 完成,黄色 ⋯ = 进行中,红色 ✗ = 错误,颜色来自 colorama + rich。
十八、v2 目录:下一代架构预览
项目根目录有一个 v2/ 文件夹,是正在开发中的新版本骨架。从目录名可以推测方向:
v2/
└── (初始数据层)
Create initial data layer (4 days ago)
这暗示 v2 将把数据层独立出来——从当前的进程内内存缓存,演进为持久化数据层(可能是 SQLite / PostgreSQL + Alembic 迁移),这样回测就不需要每次重新拉取 API 数据。pyproject.toml 里已经有 sqlalchemy 和 alembic 依赖,印证了这个方向。
十九、完整依赖图谱
ai-hedge-fund 核心依赖关系
┌─────────────────────────────────────────────────────────────┐
│ 应用层 │
│ langchain / langgraph ←→ pydantic ←→ python-dotenv │
├─────────────────────────────────────────────────────────────┤
│ LLM 适配层 │
│ langchain-openai langchain-anthropic langchain-deepseek │
│ langchain-groq langchain-ollama langchain-google │
│ langchain-xai langchain-gigachat (OpenRouter via OAI) │
├─────────────────────────────────────────────────────────────┤
│ 数据与计算层 │
│ pandas numpy scipy │
│ requests (→ financialdatasets.ai API) │
├─────────────────────────────────────────────────────────────┤
│ Web 应用层 │
│ fastapi uvicorn sqlalchemy alembic httpx │
├─────────────────────────────────────────────────────────────┤
│ CLI / 展示层 │
│ rich colorama tabulate questionary matplotlib │
└─────────────────────────────────────────────────────────────┘
二十、常见问题与调试指南
Q1:运行报错 "FINANCIAL_DATASETS_API_KEY not found"
# 检查 .env 文件是否在项目根目录
ls -la | grep .env
# 确认内容
cat .env | grep FINANCIAL_DATASETS_API_KEY
# 应输出:FINANCIAL_DATASETS_API_KEY=your-key-here
Q2:回测速度很慢
原因:每个交易日都会调用 LLM 和 API,100 个交易日 × 3 只股票 × 平均 0.5 元/次 LLM = 150 元。
优化方案:
# 只用 2 个轻量分析师(减少 LLM 调用次数)
poetry run python src/backtester.py \
--ticker AAPL \
--start-date 2024-01-01 \
--end-date 2024-01-31 \ # 先只测一个月
--analysts technical_analyst fundamentals_analyst \
--model deepseek-chat # DeepSeek 价格是 GPT-4 的 1/20
# 或使用本地 Ollama(零成本)
poetry run python src/backtester.py \
--ticker AAPL \
--ollama
Q3:LLM 输出解析失败
call_llm 有 3 次重试 + default_factory 兜底,失败时会打印:
Error in LLM call after 3 attempts: ...
常见原因:模型不支持 JSON mode(DeepSeek / Gemini),系统已自动 fallback 到 extract_json_from_response 解析 markdown 代码块。若仍失败,换用 OpenAI / Anthropic。
Q4:如何只运行单个分析师测试
# 直接在 Python 中调用单个 agent 函数
from src.agents.warren_buffett import warren_buffett_agent
from src.graph.state import AgentState
from langchain_core.messages import HumanMessage
state = AgentState(
messages=[HumanMessage(content="test")],
data={
"tickers": ["AAPL"],
"start_date": "2024-01-01",
"end_date": "2024-03-01",
"analyst_signals": {},
"portfolio": {"cash": 100000, "positions": {}}
},
metadata={
"show_reasoning": True,
"model_name": "gpt-4.1",
"model_provider": "OpenAI"
}
)
result = warren_buffett_agent(state)
print(result["data"]["analyst_signals"]["warren_buffett_agent"])
Q5:如何给每个分析师用不同模型(节省成本)
这个功能在 Web App 后端已实现(通过 request.get_agent_model_config(agent_name) 按 agent 分配模型),CLI 目前统一使用同一模型。可以参照 src/utils/llm.py 的 get_agent_model_config 函数自行扩展。
二十一、二次开发路线图
根据代码结构,以下是从简到难的二次开发方向:
🟢 入门级(1~2天)
添加新的分析师 Agent:参照上文"示例4",任何股票分析思想都能封装成 Agent。
替换数据源:修改 src/tools/api.py,将 FinancialDatasets.ai 替换为 Yahoo Finance(yfinance)或 AKShare(A股):
# 用 yfinance 替换 get_prices 的 API 部分
import yfinance as yf
def get_prices_yf(ticker, start_date, end_date):
df = yf.download(ticker, start=start_date, end=end_date)
# 转换为 Price 对象列表...
🟡 进阶级(3~7天)
持久化缓存:将 src/data/cache.py 从内存缓存改为 SQLite:
import sqlite3
class PersistentCache:
def __init__(self, db_path="cache.db"):
self.conn = sqlite3.connect(db_path)
# 建表、CRUD...
增加组合再平衡逻辑:在 portfolio_management_agent 中加入目标权重约束,比如单股不超过 20%,按信号强度自动分配权重。
添加止损机制:在 TradeExecutor 中加入止损检查:
# 如果亏损超过 15%,强制清仓
if (current_price - cost_basis) / cost_basis < -0.15:
return self.apply_long_sell(ticker, position["long"], current_price)
🔴 高级(1~4周)
实时交易接入(谨慎!):将 run_hedge_fund 封装为定时任务,通过 Alpaca / Interactive Brokers API 执行真实交易。但强烈建议先在纸交易模式(Paper Trading)运行数月。
多智能体辩论机制:让看多分析师和看空分析师在组合经理决策前进行"辩论"——每轮将对方信号作为输入,产生新的反驳或确认,类似 Society of Mind。
强化学习优化权重:将技术分析师的 5 个策略权重({trend: 0.25, momentum: 0.25, ...})变成可学习的参数,用回测收益作为奖励信号训练。
二十二、核心设计模式总结
读完全部代码,可以提炼出几个值得借鉴的工程模式:
模式一:算法评分 + LLM 判断的混合架构
不让 LLM 做计算,只让它做判断。所有数值分析(DCF、波动率、技术指标)在代码中完成,压缩为"事实摘要"(facts dict)送给 LLM,LLM 返回结构化的 {signal, confidence, reasoning}。这样既保留了 LLM 的模式识别能力,又避免了幻觉影响数值计算。
模式二:Pydantic 全链路类型约束
从 API 响应(PriceResponse、FinancialMetricsResponse)到 LLM 输出(WarrenBuffettSignal、PortfolioManagerOutput),全程 Pydantic 强校验。任何数据格式异常在边界处立刻暴露,不会在系统内部静默传播。
模式三:单例注册表 + 配置驱动
ANALYST_CONFIG 是整个系统的单一事实来源(Single Source of Truth)。CLI 的选择列表、API 的分析师枚举、工作流的节点注册,全部派生自这一个字典,不存在多处硬编码需要同步修改的问题。
模式四:进度作为副作用
progress.update_status() 被调用于每个 Agent 的每个步骤,既用于终端实时显示(rich.Live),又通过 register_handler 机制向 Web 后端推送 WebSocket 事件。进度状态与业务逻辑完全解耦,分析师代码无需知道自己运行在 CLI 还是 Web 环境。
模式五:确定性约束前置
compute_allowed_actions 先于 LLM 调用运行,计算出物理上合法的操作集合,传递给 LLM 作为约束。这是一种**约束满足(Constraint Satisfaction)**的设计,防止 LLM 输出不合法的指令(如买超现金、卖出不持有的股票)。
二十三、博客最终总结
这个项目是一个罕见地将金融理论、量化计算、多智能体系统、大语言模型四者真正融合的开源作品,而不是表面上的"LLM + 一点点数据"的玩具项目。
从代码质量看,它有很多值得称道的工程实践:Pydantic 全链路、单例配置驱动、确定性约束、重试容错、进度与业务解耦。从教学价值看,它几乎是 LangGraph 多智能体应用的最佳实战教材。
如果你要用这个项目做学习,推荐路径:
第一周:跑通 CLI,理解 AgentState 和工作流结构
第二周:阅读 warren_buffett.py,理解"算法评分+LLM判断"模式
第三周:深读 risk_manager.py 和 portfolio_manager.py,理解资金管理
第四周:跑一次完整回测,分析 Sharpe/Drawdown 结果
第五周:写自己的分析师 Agent,贡献 PR
最后再次重申:本项目为教育目的,所有分析仅供学习参考,不构成任何投资建议。市场有风险,投资需谨慎。