资讯动态

用开源智能体框架+IM Agent搭建AI自主模拟炒股系统:从研数据到实盘全记录

发布时间:2026/10/21 18:02:57 来源:尧图企业网站定制
做了几个月 AI 自主模拟炒股我最大的体会不是某个策略跑出了多惊艳的收益而是把一条“研数据 → 出信号 → 下决策 → 做复盘”的完整链路交给 Agent 自主跑通这件事本身的工程复杂度远高于我最初的想象。这篇文章准备用“开源智能体框架 办公协作 IM Agent”这套技术组合记录我从零搭出 AI 自主模拟炒股系统、一直切换到小资金实盘的全过程包括架构设计、关键代码、踩坑记录和一些只有真跑过才会明白的细节。如果你本身有一定 Python 基础想试水量化投研又不想天天盯盘这篇文章应该能让你少走不少弯路。1. 项目整体设计与为什么这么做1.1 这套系统到底解决什么问题很多人一提“AI 炒股”第一反应是写个策略回测脚本跑出漂亮曲线然后就没有然后了。真正的痛点通常不是策略而是策略之外的自动化数据更新、信号生成、下单执行、持仓跟踪、异常告警、交易日复盘这些环节如果全部靠人手动操作一天至少浪费两三个小时而且极其容易漏。这套系统的目标很明确只保留一个人机接口其它脏活全部交给 Agent。每天开盘前Agent 自动拉取最新行情和公告摘要结合预设策略生成当日操作建议盘中定时监控持仓异动收盘后自动生成交易日志和复盘结论通过 IM Agent 推送到手机端。我只需要在消息流里回“确认”“暂停”或者“改仓位上限”系统就能按指令执行。适合参考这套方案的主要是三类人有工程基础、想用 Agent 串联量化投研流程的开发者已经用脚本做策略回测、但迟迟没有推进到自动化执行的人想通过模拟交易积累盘感、又不满足于手动下单的投资者。建议不要一开始就冲着实盘去。我先把这套系统完整跑在模拟环境里两个多月把接口稳定性、决策链路和异常恢复都磨顺了才切换成小资金实盘。后面你会看到模拟盘和实盘的差距远不止手续费那几个点。1.2 为什么选 Agent 框架而不是老实写定时任务你可能会问用 cron 定时跑几个 Python 脚本不就行了吗为什么非要引入 Agent我最初也是这么想的。但实际一跑就发现问题固定脚本只能执行固定逻辑。比如行情大跌时我想临时把仓位上限从三成降到一成某个持仓突然出了利空我想让系统跳过原定的加仓计划。这些临时判断你在脚本里写起来非常别扭要么加一堆 if else要么改代码重启完全谈不上“自主”。引入智能体框架后核心变化在于决策回路。Agent 不再是“执行完一条命令就结束”而是可以循环调用工具、观察结果、再决定下一步。比如今天开盘前Agent 发现自选股里的消费板块指数异动它不会直接下单而是先把行情异常标记写入状态文件再调策略引擎算一遍信号最后生成一条带有置信度的建议推送到 IM Agent。我这里的项目内部代号叫 ClawFlow实际选用的是一个社区里很常见的开源 Agent 调度框架支持工具注册、子 Agent 编排和状态持久化。这里不提具体项目名避免像带货。重点是它解决了一个核心问题把“数据获取”“策略计算”“模拟下单”“消息推送”拆成四个工具由一个调度器统一编排Agent 根据当前会话状态决定调用哪个工具而不是我手动一个个去触发。办公协作 IM Agent 则负责最外层的人机交互通道。为什么选它而不是自己搭个 Web 前端因为“消息即接口”手机端原生支持、权限隔离成熟、消息记录天然留痕。对于个人项目来说这是成本最低的遥控器方案。1.3 整体架构分层整个系统按职责分成五层触发层定时调度、交易日历判断、盘中定时器决策层一个“投资助理” Agent负责读行情、算信号、查持仓、生成操作建议执行层模拟交易接口封装负责下单、撤单、查成交风控层独立的规则引擎仓位上限、单票止损、交易时段校验通讯层IM Agent 回调服务负责把 Agent 的决策推给用户并把用户的确认指令送回执行层。分这么细不只是为了代码好看。后面排查问题的时候你会感谢这种边界清晰的设计。比如某次重复下单问题定位在触发层没做去重和策略逻辑一点关系都没有如果全部代码糊在一个脚本里排查成本会高很多。2. 核心模块拆解与关键技术点2.1 行情与数据链路行情是整个系统的地基数据错了后面全错。我这里使用的是某开源行情数据包内部封装了日线、分钟线和基础财务字段的获取接口。按照常见实践我把数据访问统一收敛到一个模块里外面任何 Agent 工具都不直接裸调第三方接口。数据链路中有三个细节值得特别注意第一是时间对齐。你拿到的行情时间戳有时是自然日有时是交易时段。比如日线数据的日期是“2025-03-14”但如果你用自然日去推算“昨天”碰到周末和节假日就会错位。我的处理方式是引入交易日历表所有调度都基于交易日而不是自然日。第二是复权因子。用日线算技术指标时如果股票发生除权除息不复权数据会产生价格跳空导致 MACD、RSI 这些指标出现假信号。我在这里吃过亏系统在某只股票除权当天给出了“放量突破”的错误信号差点在模拟盘上追高。后来我在数据模块里强制统一使用前复权并且标记除权日策略引擎遇到除权日会跳过信号生成。第三是频率控制。行情接口不是无限免费使用的频繁调用会被限流。我把日线数据缓存到本地 SQLite只有在交易时段内的特定时间点才刷新一次。算下来一天请求量控制在几百次以内完全不会触发风控。2.2 策略引擎与信号生成策略引擎我没有让 Agent 自由发挥而是固定成“规则 参数表”的形式。原因很简单Agent 如果直接在对话里生成买卖点你没法保证它下次跑出来的逻辑和上次一致。可重复性对交易系统来说是底线。我这里用了三种策略信号趋势跟踪基于双均线金叉/死叉适合判断中期方向超跌反弹基于 RSI 低于阈值后拐头适合捕捉短线修复量能确认当日成交量大于近 5 日均量 1.5 倍作为趋势信号的辅助确认。每个信号都会输出一个分数最后汇总成综合建议加仓、持有、减仓、清仓。仓位比例则由风控规则决定策略引擎本身不直接决定下单手数。这里有个常见认知误区策略越复杂越好。实际跑下来双均线加 RSI 的组合已经足够暴露问题。真正拉开差距的是执行纪律和风险约束而不是指标精度。2.3 订单执行与模拟撮合模拟交易接口我用的是券商提供的仿真环境支持普通的限价单、市价单查询和撤单。执行模块的重点不在撮合逻辑而在幂等性。网络超时后Agent 重试时可能会重复提交订单。我在订单层引入了一个客户端订单 ID每次下单前生成全局唯一 ID模拟接口如果发现同一 ID 已存在会直接返回原单结果而不是再创建一笔新单。这个设计后来在实盘阶段也保了我的命。后面常见问题部分我会详细讲一次真实的重复下单事故这里先记住结论所有写操作必须幂等。2.4 消息与人的协作回路IM Agent 不是简单发个通知而是要形成双向交互。我定义了几个核心指令确认按建议执行下单拒绝跳过本次建议暂停停止所有自动操作直到手动恢复调整 仓位上限 20%修改风控参数持仓立即返回当前持仓摘要。用户发出的文本指令先进消息回调服务解析成结构化事件后写入一个内部消息队列决策 Agent 从队列里消费最新事件作为下一次决策的上下文之一。这样设计的好处是即使错过消息窗口重启后也能从队列里恢复状态不会丢指令。消息推送的格式也值得说一句。不要推一大段 JSON 给用户要推人话。我最终的推送模板是【信号】标的: XXXX | 方向: 买入 理由: 日线站上20日均线RSI58量能放大1.6倍 建议仓位: 20% | 当前持仓成本: 12.35 请回复: 确认/拒绝/暂停一眼能看懂决策依据也留了痕。这种格式我用了很久没有改过。2.5 记忆与状态管理Agent 的最大痛点之一是上下文污染。如果每轮决策都把前 30 天的历史订单塞进上下文很快对话就会变得又慢又乱甚至超出模型窗口。我的做法是分两级短期记忆只保留最近 20 条决策记录由调度器自动裁剪长期记忆每天收盘后把当天的决策依据、信号数值、成交结果压缩成一条摘要追加到本地 JSONL 文件。Agent 开盘前只读最新的摘要和持仓快照不回看全量日志。长期记忆文件实际上承担了“人的复盘笔记”的功能。某次调参后效果变差我就是靠翻摘要找到改动前后差异的。3. 从零到实盘的全过程实现3.1 环境准备与最小 Agent 跑通先准备基础环境。我用的是 Python 3.11虚拟环境管理用的 uv依赖安装速度比 pip 快不少。安装好 ClawFlow 依赖后先不急着接行情和交易而是跑一个最小 Hello Agent确认调度、工具注册、消息推送三条链路是通的。一个最小工具定义大致是这样tool(get_today_signal) def get_today_signal(stock_code: str) - dict: 读取策略引擎输出的今日信号 result strategy_service.calc_daily_signal(stock_code) return {stock: stock_code, action: result.action, score: result.score}工具注册完成后Agent 的 system prompt 里写清楚角色边界你是投资决策助手。你只能调用已注册工具不允许编造行情。 每次给出建议前必须展示依据仓位建议必须遵守风控参数。 收到“确认”指令后才能调用下单工具。这个提示词很重要。没有边界约束的 Agent 会在没有指令的情况下自己下单这是模拟盘阶段最容易出现的失控行为。3.2 接入行情与模拟盘行情模块我封装为DataConnector对外只暴露三个方法daily_bars()、minute_bars()、trade_calendar()。模拟盘封装为PaperBroker提供submit_order()、cancel_order()、query_position()。由于模拟盘和实盘接口结构不同我在设计时定义了一个统一的BrokerAPI抽象基类class BrokerAPI(ABC): abstractmethod def submit_order(self, order: Order) - OrderResult: ... abstractmethod def query_account(self) - Account: ... abstractmethod def query_position(self, stock_code: str) - Position: ...PaperBroker和LiveBroker都继承这个基类。切换实盘时主程序只需要改一行配置其余代码完全不用动。这个抽象层带来的好处在实盘首周被验证了无数次因为你会发现模拟接口和实盘接口的字段差异多得离谱比如成交状态命名不同、委托数量精度不同、手续费结构不同。如果不做抽象后期改造成本会非常大。3.3 让 IM Agent 成为遥控器IM Agent 回调服务的逻辑不复杂。收到消息后先用一个简单的意图识别函数判断指令类型然后走不同的处理分支async def handle_message(payload): content payload[text].strip() if content 持仓: return await query_position_text() if content.startswith(调整): return await update_risk_param(content) if content 确认: return await confirm_last_signal() if content 暂停: await scheduler.pause() return 已暂停所有自动操作这个服务我用了一个轻量的异步框架跑在云主机上监听消息回调。回调地址用 HTTPS 加密传输回调令牌用环境变量注入不写死在代码里。注意不要图省事把回调地址做成公网无鉴权接口。曾经有段时间我为了调试方便关了鉴权结果第二天收到垃圾消息刷屏导致 Agent 误读指令差点触发模拟下单。从那以后鉴权和白名单就一直开着。3.4 定时调度与自动循环调度是整个系统的骨架。我用的是系统级定时任务来触发 Agent 跑三个固定任务# 开盘前 9:15 生成晨报和交易建议 15 9 * * 1-5 cd /opt/clawflow uv run python -m tasks.morning_brief # 盘中 14:30 做一次持仓巡检 30 14 * * 1-5 cd /opt/clawflow uv run python -m tasks.intraday_check # 收盘后 16:00 生成复盘摘要 0 16 * * 1-5 cd /opt/clawflow uv run python -m tasks.daily_review调度配置里最容易漏的是交易日判断。如果你只在 cron 里写周一到周五节假日你的系统照样会跑然后拿到的行情可能是空的或者上一个交易日的数据造成信号误判。所以每个任务执行第一步一定是查交易日历if not trade_calendar.is_trading_day(today): return另外我在任务入口处加了一个全局互斥锁。某个任务如果上一次运行还没结束这次直接跳过。否则开盘瞬间几个任务同时跑持仓查询和下单可能产生竞态。3.5 从模拟盘切换到小资金实盘模拟盘稳定跑了两个多月后我决定切小资金实盘。切换前列了一张检查清单每项都确认无误才动策略逻辑参数与模拟盘完全对齐手续费和滑点模型已加入回测风控参数修改独立于策略代码所有下单入口走统一BrokerAPI抽象实盘接口的限价单字段已对拍每日最大亏损触发后自动禁用下单需手动恢复。实盘首周我只放了两成仓位而且只用一只流动性比较好的标的做验证。目标是验证链路稳定性不是赚收益。事实上首周还小亏了几个点但链路上零故障订单全部正常回报推送全部及时这就够了。很多人会问模拟盘证明有效后实盘是不是就能照搬我的回答是模拟环境会让你忽略执行成本、流动性冲击和极端行情下的接口卡顿。小资金、小仓位先跑起来相当于给你的系统再做一次压力测试只是这次是真金白银的测试。4. 常见问题与排查经验4.1 行情时间戳不同步导致信号错位现象某天晨报里的“今日信号”和盘中实际走势明显对不上回查日志发现信号用的行情日期是前一天。原因行情模块在非交易时段返回了缓存数据但缓存没有带交易日字段。策略引擎按自然日取数取到了过期数据。解决所有行情响应统一返回trade_date策略引擎只认交易日不认当前系统日期。并且每份缓存都带时间戳超过 24 小时强制失效。4.2 Agent 重复决策和重复下单这是模拟盘阶段最严重的一次事故。某个周五盘中触发了止损条件风控层发出减仓指令但 Agent 因为消息回调超时认为指令没送达于是重新生成了一模一样的减仓建议并自动执行了两次导致仓位从七成直接砍到三成执行结果偏离预期。教训所有交易类写操作必须走幂等控制器。我在订单模块里增加客户端订单 ID 后这类问题基本绝迹。另一个防线是风控层增加“同标的同方向指令最小间隔”默认 5 分钟内不接受重复指令。4.3 IM Agent 上下文被历史订单刷爆跑了一个月后某天的晨报推送突然变得很慢打开日志发现 Agent 上下文里塞了上千条历史订单。原因是短期记忆裁剪逻辑只处理了决策记录没有处理工具返回值。每次查询持仓返回的完整 JSON 都被塞进上下文。解决对持仓查询结果做字段裁剪只保留股票代码、数量、成本、市值四项订单历史默认不进入上下文除非 Agent 显式要求。4.4 模拟盘赚钱实盘亏钱的经典陷阱回测和模拟环境里你的成交价用的是收盘价或者模型价。实盘里同样的信号可能因为集合竞价的跳空、盘中滑点、手续费损耗导致实际收益显著差于模拟。我的应对方式很朴素模拟环境里统一加上一个“悲观滑点假设”每笔成交假设比目标价多滑 0.2%。指标计算也全部基于保守价格。别小看这 0.2%对于高频调仓的策略来说它能把年化收益吃掉一大半。如果模拟环境下扣掉 0.2% 滑点后策略仍然为正实盘才有跑下去的基础。4.5 异常中断与状态恢复某次云主机重启后调度任务恢复了但 Agent 的记忆文件没有正确加载导致它以为自己没有任何持仓开盘后尝试用全部可用资金买入建仓和真实持仓完全脱节。问题出在启动顺序主程序先启动了调度器后加载记忆文件调度器在记忆加载完成前就触发了第一个任务。修复所有任务入口强制先加载状态快照快照加载失败则任务直接拒绝执行。后来我又加了一个 watchdog 脚本每 10 分钟检查一次持仓快照文件是否新鲜如果超过 30 分钟未更新直接向 IM Agent 推送告警。下面把排查经验整理成速查表方便后续参考现象可能原因解决方案信号与盘面明显对不上行情缓存过期日期对齐错误缓存带交易日字段强制过期机制重复下单或重复执行写操作未做幂等客户端订单 ID 唯一化推送延迟严重上下文体积过大裁剪工具返回值压缩记忆摘要模拟盘盈利、实盘亏损忽略滑点和手续费模拟环境加入悲观滑点假设重启后持仓状态丢失状态快照加载时序不对任务入口先加载快照失败即拒跑收到垃圾消息触发误读接口未鉴权开启白名单和推送令牌5. 复盘与个人体会5.1 几个月的运行结果先声明这里不构成任何投资建议我也只是拿小仓位验证工程方案。模拟盘连续运行 20 个交易日系统总共生成 32 次交易信号实际执行 28 次剩余 4 次被风控拦截。整个周期账户收益折算年化大约在 8% 到 12% 之间最大回撤控制在 4% 以内。实盘首周小仓位运行账面浮亏 2%但链路零故障所有自动指令全部正确执行这个结果符合预期。坦率讲这套系统的收益率并不惊艳。但它让我把过去手动做投研的整个过程标准化了。以前每天花在盯盘和复盘上的时间至少两小时现在只需要在早上和下午各花一分钟看推送做确认或拒绝。时间精力省下来反而能更冷静地审视策略本身。5.2 哪些环节收益最大如果按投入产出比排序排第一的是风控层不是策略。风控规则帮我避开的亏损远大于策略本身创造的收益。排第二的是幂等设计它让系统在异常重试时不会做错事。第三才是策略信号因为简单规则已经够用了。踩过几次坑之后我现在对 AI 自主交易的态度是策略可以交给模型但决策边界必须由人定。Agent 负责把“市场发生了什么、我的策略怎么看、建议怎么做”讲清楚最终确认权始终留在人手里。这不是保守是工程上必要的安全阀。5.3 后续想做的扩展下一步我打算给系统加一个基于持仓集中度的动态风控模块当某一行业敞口超过预设阈值时自动提示降低相关标的的仓位上限。另一个想法是把每日复盘摘要做成可查询的知识库让 Agent 在制定新策略时参考历史表现。这些扩展都依赖现在这套稳定运行的底座先把地基打牢再谈上层建筑。如果你也想搭一套类似的系统我的建议是从模拟盘开始不要一上来就接真钱。先把数据链路、订单幂等、消息推送、异常恢复这四个基础模块跑稳再讨论策略优化。这四条不扎实再好的策略也会在执行环节漏掉一大半收益。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑