在第 7 练中,我们将基于 MAS 来解决量化投资场景中的常见问题——因子挖掘。
在量化投资领域,因子可以简单理解为一种对资产价格有预测能力的时序特征,因子的数量与质量则是量化投资的核心竞争力之一。
随着量化投资进入“拥挤时代”,有效的量化投资策略对于因子数量和质量提出了更高的要求。传统的人工挖掘因子的速度较慢、成本较高,遗传规划(Genetic Programming)算法虽能生成海量因子,却面临“公式黑箱”与“可解释性差”的难题。如何利用大语言模型(LLM)对金融语义和经济逻辑的理解能力,构建可解释、高效率的因子挖掘流水线,成为行业前沿的探索方向。
- 设计项目实现的方案, 并利用 Vibe Coding 完成项目构建。
- 因子挖掘流水线设计,包括但不限于:算子池设计、因子生成、因子计算、因子评价、因子优化。
- 输出内容设计,包括但不限于:中间过程报告、总结报告、可视化因子分析
多智能体量价因子挖掘系统 (Multi-Agent System for Factor Mining)
基于大语言模型的自动化量化因子挖掘框架,通过四个协作 Agent 实现因子的自动生成、计算、评估和优化闭环。并通过 tools 功能提高 Agent 表现。
| Agent | 名称 | 职责 | 其他说明 |
|---|---|---|---|
| Agent 1 | 因子构想家 (Ideator) | 基于金融逻辑生成因子表达式 | 支持使用 Tools 功能增强 Agent 即刻验证的能力 |
| Agent 2 | 因子计算师 (Calculator) | 解析表达式、计算因子值、修复错误 | 修复失败表达式时使用 LLM 进行修复 |
| Agent 3 | 因子评估师 (Evaluator) | 计算 IC/ICIR 等指标、生成分析报告 | 由 Agent 撰写评估分析报告 |
| Agent 4 | 因子优化家 (Optimizer) | 基于评估反馈优化因子 | 支持使用 Tools 功能增强 Agent 即刻验证的能力 |
初始化 → 加载数据 → [生成基础因子池] → [迭代挖掘 × N轮] → 生成最终报告 → 生成可视化图表 → 保存最终结果
Step 1: 因子构想 (Agent1)
│ 输入: 因子数量、历史因子列表、优化反馈、数据描述、可用字段
│ 任务: 生成新的因子表达式,支持 text/tool/function_call 三种模式
│ 输出: 因子列表(名称、表达式、逻辑)
v
Step 2: 因子计算 (Agent2)
│ 输入: 因子表达式列表
│ 任务: 批量计算因子值,失败时 LLM 修复表达式
│ 输出: 计算结果(成功/失败、因子值、错误信息)
v
Step 3: 因子评估 (Agent3)
│ 输入: 计算成功的因子结果
│ 任务: 计算 IC/ICIR 等指标,生成综合评分和分析报告
│ 输出: 评估结果(评分、有效性、方向、指标)
v
Step 4: 更新最佳因子
│ 任务: 维护最佳因子列表,按评分排序
│ 输出: 更新后的最佳因子列表
v
Step 5: 保存迭代结果
│ 任务: 保存每轮数据和报告
│ 输出: iteration_{i}.json 和 report_iteration_{i}.md
v
Step 6: 因子优化 (Agent4,非最后一轮)
│ 输入: 评估结果、分析报告、因子数量
│ 任务: 生成优化因子和反馈,支持变异/交叉/精炼策略
│ 输出: 优化因子列表和反馈信息,传递给下一轮
v
进入下一轮
Step 1 - 因子构想:FactorIdeator Agent 使用 LLM 生成因子表达式。第1轮基于数据描述探索性生成,后续轮基于优化反馈改进。支持三种模式:text(文本解析)、function_call(结构化输出)、tool(工具增强,可即时验证)。
Step 2 - 因子计算:FactorCalculator 解析并计算因子表达式,支持基础因子引用展开。计算失败时自动调用 LLM 修复。
Step 3 - 因子评估:FactorEvaluator 计算多周期 IC/ICIR、分层回测等指标,生成综合评分(0-100,加权 IC/ICIR/单调性/胜率)。使用 LLM 生成分析报告。
Step 4 - 更新最佳因子:将评估结果与现有最佳因子比较,更新列表,按评分排序。
Step 5 - 保存迭代结果:保存每轮详细数据到 JSON 文件,分析报告到 Markdown 文件。
Step 6 - 因子优化:FactorOptimizer Agent 使用 LLM 基于评估反馈优化因子,通过变异、交叉、精炼生成新因子,并提供反馈给下一轮构想。
系统支持三种 LLM 生成模式,通过 config.yaml 中的 generation_mode 切换:
generation_mode: "text"- LLM 自由返回文本,程序通过正则/JSON 解析提取因子
- 兼容性最好,适用于所有 LLM
- 解析可靠性依赖 LLM 的格式遵从度
generation_mode: "function_call"- 使用 LangChain
with_structured_output()+ Pydantic Schema - LLM 直接返回结构化数据,无需文本解析
- 每轮 1 次 API 调用,成本最低
- 需要 LLM 支持 function calling
generation_mode: "tool"- LLM 通过 Agentic Loop 迭代调用工具
- 可调用
validate_and_compute_factor验证表达式并查看统计量 - 可调用
evaluate_factor_quick快速评估 IC/ICIR - 闭环生成:构思 → 验证 → 评估 → 修正 → 确定
- 该模式下因子生成质量较高,但是消耗的Toke也较多
三种模式对比:
| 特性 | Text | Structured Output | Tool |
|---|---|---|---|
| 交互方式 | 单轮文本 | 单轮结构化 | 多轮工具调用 |
| 因子质量 | 一般 | 一般 | 高(可自我验证) |
| API 调用 / 轮 | 1 | 1 | 多轮 |
| 兼容性 | 所有 LLM | 需支持 FC | 需支持 FC |
| 回退机制 | - | → Text | → FC → Text |
LLM 构思因子
│
├── 调用 validate_and_compute_factor("div(sub(close, ts_mean(close,20)), ts_std(close,20))")
│ └── 返回: {valid: true, stats: {coverage: 0.92, mean: 0.01, std: 1.23, ...}}
│
├── 调用 evaluate_factor_quick(expression, "zscore_20d")
│ └── 返回: {mean_ic: 0.035, icir: 0.42, quality: "good", ...}
│
├── 保留该因子,构思下一个...
│
├── 调用 validate_and_compute_factor("ts_return(close, -5)")
│ └── 返回: {valid: false, error: "时间窗口必须为正整数"}
│
├── 修正 → validate_and_compute_factor("ts_return(close, 5)")
│ └── 返回: {valid: true, ...}
│
└── 最终输出所有通过验证的因子列表
系统支持预先生成一组"基础因子",供后续因子构建时作为积木引用。
base_factors:
enabled: true
factors_per_category: 2
categories:
- momentum # 动量类
- reversal # 反转类
- volatility # 波动率类
- volume_price # 量价背离类
- trend # 趋势类
- liquidity # 流动性类
temperature: 0.5在因子表达式中使用 $因子名 引用基础因子:
# 基础因子: $momentum_5d = ts_return(close, 5)
# 基础因子: $volatility_20d = ts_std(close, 20)
# 复合因子:动量/波动率比
div($momentum_5d, $volatility_20d)
# 展开后等价于:
div(ts_return(close, 5), ts_std(close, 20))基础因子由 BaseFactorGenerator 通过 LLM + Tool Calling 生成,存储在 BaseFactorRegistry 中。
| 字段 | 说明 | 示例用途 |
|---|---|---|
open |
开盘价 | 缺口分析 |
high |
最高价 | 压力位、振幅 |
low |
最低价 | 支撑位、振幅 |
close |
收盘价 | 动量、均线 |
vol |
成交量 | 量能分析 |
amount |
成交额 | 资金流向 |
pct_chg |
涨跌幅 | 收益率分析 |
实际可用字段取决于
config.yaml中的data_fields配置。
| 算子 | 语法 | 说明 |
|---|---|---|
abs |
abs(x) |
绝对值 |
sign |
sign(x) |
符号函数 |
log |
log(x) |
自然对数 |
neg |
neg(x) |
取负 |
sqrt |
sqrt(x) |
平方根 |
| 算子 | 语法 | 说明 |
|---|---|---|
add |
add(x, y) |
加法 |
sub |
sub(x, y) |
减法 |
mul |
mul(x, y) |
乘法 |
div |
div(x, y) |
除法 |
max |
max(x, y) |
最大值 |
min |
min(x, y) |
最小值 |
power |
power(x, n) |
幂运算 |
| 算子 | 语法 | 说明 |
|---|---|---|
ts_mean |
ts_mean(x, d) |
d 日移动平均 |
ts_std |
ts_std(x, d) |
d 日移动标准差 |
ts_sum |
ts_sum(x, d) |
d 日移动求和 |
ts_max |
ts_max(x, d) |
d 日移动最大值 |
ts_min |
ts_min(x, d) |
d 日移动最小值 |
ts_delta |
ts_delta(x, d) |
d 日差分 (x - x_d天前) |
ts_delay |
ts_delay(x, d) |
d 日延迟 (x_d天前) |
ts_return |
ts_return(x, d) |
d 日收益率 |
ts_corr |
ts_corr(x, y, d) |
d 日滚动相关系数 |
# 布林带位置 (Z-Score)
div(sub(close, ts_mean(close, 20)), ts_std(close, 20))
# 量价同步变化
mul(ts_delta(close, 1), ts_delta(vol, 1))
# 标准化动量
div(ts_delta(close, 5), ts_std(close, 10))
# 量价相关性
ts_corr(close, vol, 20)
# 使用基础因子的复合因子
div($momentum_5d, $volatility_20d)| 指标 | 说明 | 有效阈值 | 优秀阈值 |
|---|---|---|---|
| Mean IC | 因子值与未来收益的 Spearman 相关系数均值 | |IC| > 0.02 | |IC| > 0.05 |
| ICIR | IC 均值 / IC 标准差,衡量 IC 稳定性 | |ICIR| > 0.1 | |ICIR| > 0.5 |
| IC 胜率 | IC 为正的交易日占比 | > 55% | > 65% |
| 多空收益 | 最高组与最低组的收益差 | > 0.5% | > 1% |
评分 = IC得分(40%) + ICIR得分(30%) + 分层单调性得分(20%) + IC胜率得分(10%)
其中:
- IC得分 = min(|IC| / 0.05 * 40, 40)
- ICIR得分 = min(|ICIR| / 0.5 * 30, 30)
- 单调性得分 = min(|多空收益| / 0.01 * 20, 20)
- 胜率得分 = max(0, min((胜率 - 0.5) / 0.2 * 10, 10))
- 正向因子 (IC > 0):因子值越大,未来收益越高
- 负向因子 (IC < 0):因子值越小,未来收益越高
系统自动识别因子方向,负向因子在使用时取反。
MASFactorMiner/
├── run.py # 运行入口
├── config/
│ └── config.yaml # 配置文件
├── src/
│ ├── __init__.py
│ ├── main.py # 主控编排 (FactorMiner)
│ │
│ │ # ── 四大 Agent ──
│ ├── agent_ideator.py # Agent1: 因子构想家
│ ├── agent_calculator.py # Agent2: 因子计算师
│ ├── agent_evaluator.py # Agent3: 因子评估师
│ ├── agent_optimizer.py # Agent4: 因子优化家
│ │
│ │ # ── 基础设施 ──
│ ├── llm_client.py # LLM 客户端 (chat/FC/Tool Loop)
│ ├── operators.py # 算子定义与实现
│ ├── data_loader.py # 数据加载器
│ ├── schemas.py # Pydantic 输出 Schema
│ ├── agent_tools.py # Tool 模式工具定义
│ │
│ │ # ── 基础因子 ──
│ ├── base_factor_generator.py # 基础因子生成器
│ ├── base_factor_registry.py # 基础因子注册表
│ ├── expression_utils.py # 表达式展开/验证工具
│ │
│ │ # ── 可视化 ──
│ └── factor_visualizer.py # 图表生成模块
│
├── results/ # 输出结果目录
├── .env # LLM API 配置
├── pyproject.toml # 项目依赖
└── README.md
| 模块 | 文件 | 职责 |
|---|---|---|
| LLM 客户端 | llm_client.py |
封装 LangChain ChatOpenAI,提供 chat()、chat_with_structured_output()、chat_with_tools_loop() |
| 输出 Schema | schemas.py |
定义 FactorList、OptimizedFactorList、MutationResult 等 Pydantic 模型 |
| Tool 定义 | agent_tools.py |
定义 validate_and_compute_factor 和 evaluate_factor_quick 两个 LLM 可调用工具 |
| 算子引擎 | operators.py |
实现所有一元/二元/时序算子,支持 pandas DataFrame 运算 |
| 表达式工具 | expression_utils.py |
基础因子引用展开 ($name → 表达式)、算子计数、表达式验证 |
# 使用 uv (推荐)
uv sync
# 或使用 pip
pip install -r requirements.txtPython 版本要求: >= 3.11
核心依赖:
langchain/langchain-openai>= 1.0.0 (LLM 调用框架)pandas/numpy/scipy(数值计算)pydantic>= 2.0.0 (结构化输出 Schema)matplotlib/seaborn(可视化)
创建 .env 文件:
LLM_API_KEY=your_api_key
LLM_URL_BASE=https://your-llm-server/v1
MODEL_NAME=your-model-name兼容所有 OpenAI API 格式的模型服务(OpenAI、DeepSeek、Qwen 等)。
将日频量价数据 CSV 文件放入项目根目录,并在 config/config.yaml 中配置数据路径和字段映射。
# 使用默认配置
python run.py
# 指定配置文件
python run.py -c config/config.yaml
# 覆盖迭代参数
python run.py --max-iterations 5 --factors-per-round 10| 参数 | 简写 | 说明 | 默认值 |
|---|---|---|---|
--config |
-c |
配置文件路径 | config/config.yaml |
--max-iterations |
- | 最大迭代轮数 | 配置文件中的值 |
--factors-per-round |
- | 每轮生成因子数量 | 配置文件中的值 |
配置文件位于 config/config.yaml。
llm:
temperature: 0.7 # 生成温度 (0-1),越高越有创造性
max_tokens: 16384 # 单次生成最大 token 数API 密钥等敏感信息从 .env 文件读取:
LLM_API_KEY: API 密钥LLM_URL_BASE: API 基础 URLMODEL_NAME: 模型名称
data:
file_path: "etf_2025_data.csv"
has_header: true
code_column: "code"
date_column: "date"
adj_factor_column: "adj_factor"
data_fields:
- "open"
- "high"
- "low"
- "close"
- "vol"
- "amount"
- "pre_close"
- "change"
- "pct_chg"
- "adj_factor"
data_description: |
该数据是ETF的日频交易数据...data_description 会传递给 Agent1 的 LLM,描述越详细,生成的因子越合理。
factor_mining:
factors_per_round: 10 # 每轮生成因子数量
max_iterations: 3 # 最大迭代轮数
max_expression_depth: 9 # 表达式最大嵌套深度
lookback_days: 60 # 时序计算回溯天数
# LLM 交互模式: "text" / "function_call" / "tool"
generation_mode: "function_call"
# Tool 模式配置
tool_mode:
max_loop_iterations: 20 # Agentic Loop 最大迭代次数
verbose: true # 是否打印工具调用详情
# 算子采样(增加因子多样性)
operator_sampling:
enabled: false
sample_ratio: 0.7 # 每轮随机保留 70% 算子
core_operators: # 必须保留的核心算子
- "add"
- "sub"
- "mul"
- "div"
- "ts_mean"
- "ts_std"
- "ts_return"| 参数 | 说明 | 建议值 |
|---|---|---|
factors_per_round |
每轮生成因子数量 | 5-15 |
max_iterations |
迭代轮数 | 3-10 |
generation_mode |
LLM 交互模式 | "function_call" 或 "tool" |
operator_sampling.enabled |
启用算子采样可增加多样性 | true |
evaluation:
ic_periods: [1, 2, 3, 5] # IC 计算周期(天)
main_period: 5 # 主评估周期
ic_threshold: 0.02 # IC 绝对值阈值
icir_threshold: 0.1 # ICIR 绝对值阈值
consider_negative_ic: true # 保留负 IC 因子(取反使用)
quantile_groups: 8 # 分层回测组数optimization:
strategies:
- "mutation" # 变异:微调参数或算子
- "crossover" # 交叉:组合多个因子
- "refinement" # 精炼:简化或增强表达式
top_k_factors: 5 # 每轮保留的优秀因子数量output:
results_dir: "results"
generate_plots: true
plot_period: 5
save_intermediate: true每次运行在 results/ 下创建带时间戳的结果目录:
results/run_20260205_143052/
├── config.yaml # 本次运行的配置快照
├── data/
│ ├── iteration_1.json # 第 1 轮迭代详细数据
│ ├── iteration_2.json
│ └── iteration_3.json
├── factors/
│ ├── all_factors.json # 所有因子完整信息
│ ├── base_factors.json # 基础因子池(若启用)
│ └── valid_factors_summary.csv # 有效因子汇总表
├── reports/
│ ├── report_iteration_1.md # 每轮分析报告
│ ├── report_iteration_2.md
│ ├── report_iteration_3.md
│ └── final_report.md # 最终汇总报告
└── plots/
├── final_factors_comparison.png # 因子对比图
├── final_summary_dashboard.png # 汇总仪表板
└── final_{factor_name}_detail.png # 单因子详图
| 图表 | 内容 |
|---|---|
factors_comparison.png |
所有因子的评分、IC、ICIR、胜率对比 |
summary_dashboard.png |
汇总仪表板:关键指标、分布、排行榜 |
{factor_name}_detail.png |
单因子详图:累计 IC、IC 时序、IC 分布、分层收益 |
系统会自动使用 LLM 修复表达式。如仍失败,检查:
- 表达式语法是否正确(括号匹配、算子存在)
- 时间窗口参数是否为正整数
- 数据字段名是否与
data_fields配置一致
- 切换到
generation_mode: "tool"让 LLM 自我验证 - 增加
factors_per_round生成更多候选 - 增加
max_iterations迭代轮数 - 降低
ic_threshold和icir_threshold - 启用
operator_sampling增加多样性
- 使用
generation_mode: "function_call"或"text"(每轮仅 1 次调用) - 减少
factors_per_round - 减少
max_iterations - 使用更便宜的模型
兼容所有 OpenAI API 格式的服务:
- OpenAI (GPT-4, GPT-4o 等)
- DeepSeek
- Qwen (通义千问)
- 其他兼容 OpenAI 格式的本地或云端模型
Function Call 和 Tool 模式需要模型支持 function calling 能力。
金融人工智能北京市重点实验室
MIT License

