简介:面向金融科技研究者与量化交易开发者的多智能体AI交易框架代码包,基于TradingAgents开源项目做了中文增强,覆盖A股、港股、美股,支持接入Tushare、AKShare、BaoStock等数据源,并集成DeepSeek、Claude、GPT等大模型,用于股票分析研究、报告导出及多智能体协作实践。压缩包共2000个文件,大小约17.43MB,以Python源码为主,辅以Markdown文档、Vue前端组件、TypeScript脚本及Shell/Bat部署脚本,目录结构清晰,便于分模块查阅和二次开发。目前已有109人浏览学习,适合专业投资者、金融科技研究人员以及关注LangGraph多智能体编排的技术开发人员。资源内含FastAPI后端服务、Vue 3前端界面、多智能体调度逻辑,并提供Dockerfile、docker-compose及多种启动脚本,可快速搭建本地环境,体验从数据获取、智能分析到报告生成的全流程;注意该项目仅用于研究与教育目的,不构成投资建议。
1. 多智能体AI金融交易:这份源码包把“AI操盘”从概念变成可运行系统
多智能体系统在金融交易里被讨论了很久,但绝大多数文章停在架构图和理论推导。这份源码包不一样,它把完整的交易决策链路拆成了可独立运行又协作通信的智能体集合——市场分析智能体负责解读行情特征,风控智能体对每个动作做仓位和止损约束,交易执行智能体负责订单生成与撮合模拟,调度模块负责汇总它们的状态并对外输出统一决策。打开代码包第一眼就能看到清晰的模块划分和可配置的策略接口,不是那种只能跑通demo的玩具代码。适合两类人:一是想研究多智能体在交易场景里如何落地的开发者,二是手里已有行情数据源、想拿一套可扩展的代码框架做策略验证的量化从业者。本文把这套框架拆开讲透,从环境搭建、模块协作、训练调参到回测对接模拟盘,每一步都给可复现的命令和参数。
2. 框架整体设计与核心模块:从“单智能体”到“多智能体协作”的架构拆解
2.1 四个核心角色:分析、风控、执行、调度
打开源码包的根目录,agents文件夹下能看到四个独立的智能体模块:analysis_agent、risk_agent、execution_agent和dispatcher。很多第一次接触这套代码的人会误以为“多智能体”只是把几个策略函数放在一起跑,实际上这里有明确的职责边界和通信协议。每个智能体是一个独立的类,继承自BaseAgent,通过消息队列订阅自己关心的系统事件。
analysis_agent负责从行情数据里提取特征,把原始价格序列转化成信号和置信度。它的输出不是简单的“买”或“卖”,而是一组带概率的中间结果。risk_agent订阅分析结果后,结合当前账户权益、历史回撤和持仓情况,给出允许的最大仓位比例和触发止损的参考价位。execution_agent接收前两者的输出,生成具体的限价单或市价单,并维护一个“未成交订单簿”。dispatcher是全局调度者,它不是业务决策者,而是协调者——它维护各智能体的运行状态,处理消息超时和异常重试。
常见做法里,交易系统的多智能体协作有两种模式:一是共享黑板数据,所有智能体读写同一个状态表;二是消息驱动,智能体之间有明确的事件流。这套框架用的是第二种,msg_bus目录里实现了基于内存队列的消息总线,每个智能体注册自己的主题,生产者和消费者解耦。如果你后续想改成 Redis 或 RabbitMQ,只需要把msg_bus底层的发布订阅接口重新实现一遍。这比那种硬编码函数调用的架构好改得多。
2.2 数据流与协作机制:一次完整决策是怎么走完的
从收到一条新K线到最终生成订单,完整的数据流是这样的:数据模块data_fetcher把行情快照写入历史库,同时发布MarketDataEvent到消息总线。analysis_agent消费该事件后,把特征输入到选定的预测模型里,产出信号元组——格式是(方向, 置信度, 推荐入场价区间)。接着它把结果发布为SignalEvent。
risk_agent订阅到SignalEvent后,先读取当前账户的PositionState,再结合风控配置里的最大单笔亏损比例和日最大回撤阈值,计算出一个可执行仓位比例。这里的计算逻辑不复杂,但参数设置很讲究,比如把最大单笔亏损设为总权益的1%、单日最大回撤设为3%,这部分在后面的章节会展开讲。风控结果发布为RiskAdjustedOrderEvent,里面包含了建议仓位和止损参考价。
execution_agent是最贴近市场的模块。它在收到风控调节后的信号时,不会立刻下单——它先检查是否有未成交订单占用了资金,再按当前盘口深度估算滑点成本,最后生成订单对象。如果订单超过一定时间没有成交,它会触发撤单重发逻辑。
dispatcher在整条链路里起到看门狗的作用。每个智能体启动时向调度器注册心跳,超过heartbeat_timeout阈值还没上报,调度器会把该智能体标记为异常并重启。这个设计在实盘中非常重要,因为任何一个环节卡死都会导致整个交易循环中断。从框架设计角度说,这套消息基线定义得比较干净,你在二次开发时新增一个“舆情分析智能体”或者“资金流监控智能体”,只需要实现BaseAgent抽象方法,再在配置里声明订阅主题,就能挂到总线上参与决策,不影响现有链路。
2.3 模拟环境与实盘接口的抽象边界
这套代码能跑回测,也能对接模拟交易,得益于接口抽象做得比较彻底。market目录下定义了MarketEngine基类,回测时用BacktestMarketEngine,它读取历史和静态快照数据,按时间推进撮合;实盘时用BrokerMarketEngine,它通过券商提供的 API 和行情网关交互。策略层和智能体层只依赖MarketEngine的get_tick、send_order、cancel_order这几个方法,完全不关心数据来自 CSV 文件还是 TCP 流。
这样设计的直接好处是:你在本机回测调好的策略参数,切换到模拟盘时不需要改智能体代码,只需要改配置文件里的market.engine字段。代价是部分实盘特有的行为——比如部分成交、风控规则变化、交易所故障熔断——在回测引擎里是模拟不出来的。框架在broker_adapter目录里提供了一些工具函数处理部分成交的情况,但它在默认回测模式下是关闭的,需要手动开启。
我一般会把“回测引擎”和“实盘引擎”看成两个产品来维护——它们虽然接口一致,但不能简单认为回测通过实盘就一定安全,资金安全要靠风控智能体在实盘侧的额外检查来兜底。这份代码在抽象边界上是合格的,但边界之外的坑得自己心里有数。
3. 环境安装与依赖配置:从源码包到跑起来第一版系统
3.1 依赖清单与版本坑
源码包根目录提供了requirements.txt,核心依赖包括:Python 3.9 以上、numpy、pandas、PyYAML、msgpack,以及用于做模型推理的 torch。如果你只是先跑通分析和风控链路,不训练模型,torch 可以不装;但要启动完整的训练和推理流程,torch 是绕不开的。
这里有一个高频翻车点:numpy 和 pandas 的版本不兼容。源码包在写requirements.txt时锁定的是numpy==1.24.3、pandas==2.0.3。如果你本机环境太新,numpy 升到 1.26 以上,部分依赖 npy 格式的旧代码可能直接报错。我遇到过在全新环境里用默认pip install -r requirements.txt装好后,跑data_loader出现分段错误的情况,最终定位是 numpy 版本和 torch 的 C 扩展库 ABI 版本不匹配。建议按下面顺序操作:
conda create -n maf python=3.9 conda activate maf pip install numpy==1.24.3 pandas==2.0.3 PyYAML msgpack pip install torch --index-url https://download.pytorch.org/whl/cpu参数说明:Python 版本锁在 3.9 而不是 3.11,是因为多智能体系统里的asyncio任务调度在 3.9 和 3.10 之间有一处 API 变化,源码在编写时只做了 3.9 的兼容测试;torch 用 CPU 版本先把链路跑通,训练时再换 CUDA 版本。这里用--index-url指定的是 CPU 轮子地址,避免在无 GPU 机器上装一个阴影巨大的 CUDA 包。
3.2 三步把项目跑起来
依赖装好后,不要急着看代码,系统设计了一个quick_start.py脚本,会自动完成环境自检和数据准备。执行:
python quick_start.py --demo这个命令会检查 Python 版本、关键依赖、目录结构,并生成一份最小可运行的配置。如果自检通过,会输出三行提示,分别是“环境检查 OK”“板块数据就绪”“最小配置已生成”。
接着初始化数据库表结构。框架默认用 SQLite 存储回测结果和账户流水,也可以用 MySQL,但 MySQL 需要额外建库,连接串的写法在config/db.yaml里。不建议一上来就用 MySQL,很多第一次跑的人因为密码带特殊字符导致连接失败,还以为是代码问题。先用 SQLite 把流程跑通,再换生产级数据库才是正路:
python init_db.py --engine sqlite最后启动一个迷你回测,用自带的三天样本数据验证链路:
python run_backtest.py --config config/quick_start.yaml跑完关注三个指标是否正常输出:成交笔数、期末权益、最大回撤。这里样本数据故意做得非常短,它的价值不是策略收益,而是验证消息总线、智能体协作、订单生成和记账流水这些环节没有断。
3.3 配置文件的字段含义与默认值
以config/quick_start.yaml为例,里面的一段配置值得逐字段解释:
market: engine: backtest initial_cash: 1000000 fee_rate: 0.0005 slippage: 0.0001 agents: analysis: model_path: models/sample_lgbm.pkl lookback_window: 20 risk: max_loss_per_trade: 0.01 max_daily_drawdown: 0.03 position_limit: 0.2 msg_bus: max_queue_size: 2048 heartbeat_timeout: 10参数含义:engine决定用回测还是实盘,initial_cash是初始资金,fee_rate是单边手续费率,slippage是按成交价额外扣除的滑点比例;lookback_window是多少根K线作为特征窗口;max_loss_per_trade是单笔最大亏损止损比例;max_daily_drawdown是单日最大回撤限制;position_limit是单标的最大仓位占权益比例。msg_bus里的max_queue_size过小时,行情密集时消息会积压甚至丢弃,快速行情下建议调大;heartbeat_timeout是智能体无心跳上报多久后判定异常。
这里特别提醒一个参数依赖关系:max_loss_per_trade与position_limit是乘数关系。如果你单笔止损设了 1%,而仓位比例上限是 100%,碰到连续跌停的极端行情,实际亏损会远超 1%。框架里有风控模块强制校验两者的乘积不超过账户权益的 3%,但如果你想做更激进或更保守的组合,必须要自己提前算好这两者的乘积,别只在风控模块里改一个字段。
4. 策略定义与模型训练:让多个智能体学会协作
4.1 策略文件怎么写:信号、权重、阈值
这个框架里的策略不是写死在某个strategy.py里,而是通过config/strategies/下的 YAML 文件声明。每个策略定义一个信号来源(对应某个分析智能体的输出),一组权重和一个触发阈值。例如一个“均线突破 + 波动率过滤”的策略:
strategy_id: ma_breakout_v1 signal_source: analysis_agent indicators: ma_short_window: 5 ma_long_window: 20 atr_window: 14 entry_rule: condition: close_above_ma_short AND close_above_ma_long volatility_filter: atr_percent < 0.02 exit_rule: stop_loss_atr_multiplier: 2.0 take_profit_atr_multiplier: 3.0 position_scale: method: risk_based base_ratio: 0.1代码逻辑拆解:signal_source声明这个策略从哪个智能体拿信号,意味着你可以定义多个分析智能体,每个专注一类技术形态,然后在策略层做组合;indicators段是策略依赖的技术指标参数;entry_rule是入场条件,要求价格上穿短均线且短均线高于长均线,同时用 ATR 百分比过滤低波动时段;exit_rule用 ATR 倍数设置止损和止盈,比固定百分比更适应市场波动;position_scale里method: risk_based表示仓位由风险模块按当前波动率动态计算,base_ratio是基础仓位比例,实际下单时风控智能体会在此基础上乘以波动率倒数做调整。
这种声明式策略配置的好处是:回测时你可以快速切换策略参数,不用改代码重跑;对实盘也非常友好,参数表在 YAML 里一目了然。但注意 YAML 解析出来是纯 Python 字典,没有天然的类型校验。比如atr_percent你填成字符串"0.02"而没写数字,运行时许多比较会静默通过,但结果完全错误。我建议在这个框架里加一个小函数,在加载每个策略文件后检查关键字段的类型,否则排查起来极其痛苦。
4.2 训练流程与验证集划分
训练脚本和回测脚本是分开的,框架作者没有把训练逻辑混进回测里,这点思路很清晰。train_agent.py承担的角色是:用历史数据训练分析智能体内部的预测模型,再把模型权重导出,供实盘或回测时推理使用。
python train_agent.py --config config/train_lgbm.yaml默认训练用的模型是 LightGBM 分类器,输入特征约 40 维,包括动量、波动率、成交量变化、资金流强度等;标签是未来 N 根K线是否上涨超过一定比例。训练脚本里已经做了时间序列切分,不会用未来函数,这一点很重要。它把数据按时间顺序切成三段:前 60% 训练、中间 20% 验证、最后 20% 用于测试。测试集在训练结束后才暴露,用来估算模型在未见数据上的表现。
我不建议直接重新训练整个模型,而是先跑框架自带的“增量训练”模式,在原有模型权重基础上继续训练,这样能保留模型此前见过的市场状态信息,新的样本不会让模型剧烈偏移。如果你直接全量重训,用一个固定随机种子跑出来的结果可能和源码里给出的验证报告差异很大——这是正常现象,因为特征标准化系数是在训练集上拟合的,换了数据分布,结果自然不同。
4.3 关键超参数:batch size、学习率、训练轮次
训练核心参数在config/train_lgbm.yaml里配置:
| 参数名 | 默认值 | 作用 | 调参建议 |
|---|---|---|---|
learning_rate | 0.05 | 树模型学习率 | 降到 0.02 以下可减少过拟合,但训练时间变长 |
num_leaves | 31 | 树复杂度 | 数据量大可调到 63,小样本保持 31 以下 |
sequence_length | 20 | 特征序列长度 | 越长越能捕捉趋势,但开仓信号滞后 |
batch_size | 1024 | 单批训练样本数 | 内存足够时调到 4096 可加快收敛 |
epochs | 300 | 最大训练轮次 | 观察验证损失,连续 20 轮不降就停 |
学习率和num_leaves是树模型的两个核心复杂度控制。这两者调太高,模型会对历史行情中的噪声过度拟合,回测曲线好看,但换到没见过的行情就明显失效。sequence_length受市场周期影响很大,在日内分钟数据上 20 根K线代表 20 分钟,在日线上代表 20 个交易日,含义完全不同。框架的这个参数是全局的,意味着你切换数据周期时需要同步调整。
验证的时候,我习惯每 50 轮打印一次训练集和验证集的准确率与 F1 值。如果验证集指标连续多轮不降,就果断停止,而不是把 300 轮都跑完。框架自带early_stopping_rounds=20的设置,但默认开关是关的,需要在配置文件里显式打开。
5. 回测评估与实盘对接:从模拟盘到实盘之间那几步
5.1 回测模块的用法与关键指标
回测是验证多智能体协作效果最快的手段。直接用命令跑一次完整回测,输出会有收益曲线、回撤曲线、月度收益分解,以及一组核心风险指标:
python run_backtest.py --config config/backtest_full.yaml --output reports/bt_2020_2024.html关键指标看四个:年化收益率不稀奇,夏普比率要大于 1 才说明风险调整后收益有吸引力;最大回撤要控制在心理和资金承受范围内;卡玛比率(年化收益除以最大回撤)是实战中我最看重的指标,大于 1.5 算合格;胜率没那么重要,盈亏比才是关键。框架在回测报告里会给出逐笔交易的盈亏分布,我一直建议做人肉检查——抽样看 20 笔交易,确认入场逻辑和出场逻辑不是靠运气,而是靠策略规则。
回测报告里还有一个小功能:它把dispatcher调度日志同步输出,可以看到每个智能体在哪个时间点收到信号、花了多少时间处理,以及消息总线上是不是有堆积。这个对排查性能瓶颈很有价值。
5.2 模拟盘到实盘的切换:BrokerAdapter 的边界
框架定义了BrokerAdapter抽象类,回测引擎和实盘引擎的区别只在于实现方式不同。你切换到模拟盘时,流程是:
python run_live_trading.py --config config/sim_now.yaml --broker paper配置文件里需要改的核心项是market.engine: broker,并且指定broker.paper: true。模拟盘的行情和延迟与实盘几乎一致,区别是订单不会真正进交易所。
我踩过的坑是:模拟盘和实盘的成交规则不一样。模拟盘往往在“当前价可成交”时立刻给你成交,实盘则受盘口深度和对手单影响,可能出现排队未成交、部分成交。框架的execution_agent会生成订单后等待fill_confirmation消息,但模拟盘的确认几乎是瞬时返回的,导致你误以为实盘也会这样。解决方法是把回测和模拟盘里的order_timeout设成 5 秒以上,强制走撤单重发逻辑,提前暴露出成交延迟的风险。
5.3 常见问题与避坑:4条具体踩坑记录
坑一:回测收益很高,实盘一跑就变形。现象是回测年化 30%,模拟盘一周亏了 5%。原因不是模型失效,而是框架默认回测时以收盘价成交,而实盘市价单有滑点和盘口深度限制。解决:在配置里打开滑点模型,设slippage: 0.0005,并且把成交价从“收盘价”改成“下一根K线开盘价”。那之后我做任何策略回测,都会先把这两个选项设成保守值再谈收益。
坑二:消息总线拥堵导致数据延迟。现象是回测一切正常,模拟盘一跑,系统日志里频繁出现queue full。原因是max_queue_size默认 2048,行情密集时,K线事件和信号事件积压触发丢弃策略。解决:调大max_queue_size到 8192,同时把分析智能体的特征计算从同步改为异步。从那以后我对所有“队列满”类报错都特别敏感,因为它往往是海象“来得及”时的第一根稻草。
坑三:多智能体跑多标的时账户资金重复占用。现象是两只股票同时触发买入信号,各自按策略计算仓位,加起来超过了账户可用资金。原因在于资金占用检查只在execution_agent里做了单标的维度,没做全局汇总。解决:在dispatcher里加一道全局资金校验,任何新订单在发出前必须检查所有未完成订单的占用资金总和。框架新版已经在调度层修掉了这个逻辑,但用旧版本时这部分得自己补上。
坑四:训练好的模型在跨品种时严重失效。现象是最初在股指期货日线上训练,换到某个商品期货的小时线上回测,胜率直接跌破 40%。原因是特征标准化参数是在原品种的波动区间上算的,换品种后数据分布偏移太大。解决:在config/train_lgbm.yaml里设feature_adaptation: per_market,让每个品种单独计算标准化系数,不要共享全局均值和方差。现在我做任何跨品种训练前都要看一眼验证集的分布差异,低于一定阈值才继续。
6. 进阶:把框架调成自己能持续用的交易工具
6.1 自定义智能体角色的步骤
你自己加一个智能体,流程不复杂:在agents/下建一个新文件,继承BaseAgent,实现on_event和compute两个方法就行。比如加一个“成交量异动监控智能体”,入口是订阅MarketDataEvent,输出一个AnomalyEvent。然后要在config/agents.yaml里注册新智能体的名字和要订阅的主题。注册之后调度器会自动发现并启动,不需要改主程序。
我特别建议你自定义一个“盘后复盘智能体”。它不需要参与实时交易链路,只在每天收盘后读取当日成交记录和行情数据,自动生成一份包含“策略实际执行偏差”的复盘报告:比如某个信号触发了,但执行智能体因为订单超时没有成交,是不是因为流动性不足?这类偏差信息对于持续调优策略非常有价值,而框架里没有内置这个角色,需要自己写。代码量不大,但是每次复盘都由系统自动产出报告,省下大量手工统计时间。
6.2 一套可复用的复盘方法论
我的习惯是每周做一次完整的“数据—决策—执行”三段复盘。数据侧看特征分布是否有明显漂移,比如波动率中枢是不是上移了;决策侧看分析智能体的信号分布,是不是变得过于频繁或过于稀疏;执行侧看订单成交率、滑点冲击成本。框架提供的回测报告和日志已经把这三段的数据落到了 SQLite 里,你可以写一小段 SQL 查询来快速计算指标。例如查本周滑点成本占总交易成本的占比,就能知道是不是某些时段流动性变差导致出价被动。
6.3 性能压测与多智能体并行
框架默认的智能体是顺序执行的,但支持切换成 asyncio 并行模式。切换后,分析智能体、风控智能体、执行智能体可以同时处理不同标的的信号,吞吐量明显提升。压测时要注意每个智能体实例的内存占用和 CPU 占用,可以用系统自带工具观察,如果某个智能体的 CPU 持续跑满,说明特征计算逻辑拖累了整体链路。通常把特征计算改成矩阵化,或者加缓存,就能降下来。
多智能体系统的独特价值在于分工和隔离——某个智能体出了问题,其他模块还能运行,交易系统不至于整体停止。但正因为这样,实时监控和日志完整性就成了最后的底线。从那以后我每次部署前都会强制走一遍“信号注入测试”:人为构造一条已知结果的行情消息,塞进消息总线,看整个链路是否正确执行并记录日志。这套流程配合复盘报告,让我有信心把这个框架用在真实交易决策辅助上。希望这份拆解能帮你少走一些弯路,尽快把这套代码跑起来,变成你自己趁手的交易研究工具。
本文还有配套的精品资源,点击获取