☰
LLM+算法交易实战:从信号生成到回测落地的完整指南
2026/9/29 17:08:35 网站建设 项目流程

这篇研究笔记断断续续写了快半年,核心只围绕一件事:把LLM塞进算法交易的管线里,到底能干什么、不能干什么、怎么干才不翻车。

市场上讲LLM交易的资料很多,但大部分要么停在“大模型好厉害,能读新闻”这种概念层面,要么直接跳到“让AI全自动交易”这种危险且不现实的幻想。我自己的体会是,真正能把LLM用起来的路径,是一条从“交易什么”到“如何执行”的完整链路——先解决标的选择和信号生成,再解决信号怎么变成订单、订单怎么执行、执行之后怎么复盘。两个环节的问题完全不同,混在一起聊必乱。

这篇文章是我自己踩坑后的整理,内容涉及整体架构、信号生成、执行落地、回测评估、避坑实录五个部分。适合正在研究LLM+量化交易的人,尤其是那种已经会写Python、懂一点传统因子策略、想试试大模型能不能带来增量的朋友。不懂代码也没关系,核心思路和坑点我尽量用人话讲清楚。

1. 从“交易什么”到“如何执行”:这个转变为什么重要

1.1 传统算法交易天然有两个瓶颈

传统算法交易的本质,是把人类交易员的规则用程序固化下来。比如均线突破、RSI超买超卖、因子多空组合,这些都是先定义信号,再写执行逻辑。这套方法很成熟,但有一个天然的短板:信号来源太“薄”。

这里的“薄”不是贬义,而是指传统信号大多来自结构化数据——价格、成交量、财务指标。这类数据干净、连续、可计算,但信息维度有限。一个行业突发政策、一份措辞微妙的公司公告、社交媒体上开始发酵的舆情,这些信息在价格数据里要到很久之后才会体现出来。等量价信号出现,行情往往已经走完一半。

另一个瓶颈是规则本身的脆弱性。传统策略最大的敌人是“失效”——一个在历史回测里表现优异的规则,换到未来场景可能立刻拉胯。因为市场参与者会学习,同一个形态出现的次数越多,套利空间就越小。人工维护规则库,本质上是在跟市场赛跑,而且经常跑不赢。

1.2 LLM在这个链路里的真实位置

很多人一听到“LLM+交易”,第一反应是让大模型直接下单。我的看法是,这条路目前走不通,也不该走。LLM本身不是精确的计算器,它的强项是语义理解、信息综合和模式识别,而不是高频计算和严格风控。你让大模型帮你算仓位,它可能一本正经地给你一个错误答案,而且错误得很均匀——这是最可怕的。

所以在我设计的管线里,LLM的位置不是“决策者”,而是“信号生成器”。它负责读取非结构化信息(新闻、公告、研报、舆情),输出结构化的观点和评分,再由传统量化框架去做仓位计算、风险控制和执行管理。

这样分工的好处非常明显:

  • LLM负责它擅长的:处理模糊的、非结构化的、需要语义理解的信息。
  • 传统代码负责它擅长的:精确计算、规则执行、风控约束。
  • 即使LLM偶尔输出离谱结论,下游的规则层也能拦住大部分风险。

说白了,让大模型当参谋,不让它当指挥官。这个定位从研究角度来说更安全,从工程角度来说更可控。

1.3 我最终采用的混合式管线架构

整个系统我从一开始就没有追求“端到端”,而是用了混合式管线。架构大概长这样:

  1. 数据层:行情数据、公告新闻、研报摘要、舆情数据,统一入湖。
  2. 信号层:LLM读取非结构化数据,输出结构化信号(目标标的、方向偏好、置信度)。
  3. 决策层:传统规则模型接收信号,结合价格因子,计算仓位和止损止盈。
  4. 执行层:订单管理、撮合逻辑、滑点控制、模拟盘验证。
  5. 回测层:事件驱动回测框架,专门评估LLM信号的历史表现。

这套架构的核心原则是“各司其职”。每个模块都能独立测试、独立替换,不会因为某一部分升级而牵一发动全身。尤其是LLM部分,我随时可以换不同参数规模的模型做对比,而决策层和执行层完全不用动。

2. 交易什么:用LLM做标的选择与信号生成

2.1 喂给LLM的“食材”决定上限

“交易什么”这个问题,落到实操层面就是:你让LLM看什么。我的经验是,数据质量对LLM表现的影响,远大于模型参数大小的影响。喂进去一堆噪音,再强的模型也给你吐出一堆噪音。

我最终整理了一套相对稳定的数据输入组合:

  • 公司公告:财报、重大合同、股权变动,重点处理公告里措辞变化(比如“重大利好”和“重大影响”完全不是一个量级)。
  • 券商研报摘要:提取目标价、评级、核心逻辑。注意研报有滞后性,我会给它打上发布时间的衰减权重。
  • 行业新闻与政策动态:重点覆盖持仓池里公司所在行业的垂直新闻,而不是泛财经头条。
  • 舆情数据:社交平台上关于标的的热度变化,情感倾向。这块噪音最大,需要单独做置信度加权。

这些数据统一用RAG(检索增强生成)的方式喂给模型。简单说就是把文档切片、向量化、存入知识库,查询的时候先检索相关内容,再连同问题一起送给LLM生成答案。这样做的原因是:上下文窗口再大也装不下所有文档,只检索和当前标的相关的内容,既能控制成本,又能提升回答精度。

实际测试下来,RAG比“把所有文档一股脑塞进上下文”的效果好得多。原因是模型注意力会被无关信息稀释,检索后只传关键片段,输出的聚焦度明显提升。

2.2 提示词设计:让LLM输出可直接入库的结构化信号

LLM输出天然是自然语言,但交易系统需要的是结构化数据。所以提示词设计的目标只有一个:把模糊的观点变成可计算的字段。

我用的提示词模板经过了好几轮迭代,最终稳定成一个固定格式。核心结构大致是:

你是量化研究团队的首席分析师。请阅读以下资料,对指定标的多空观点做出判断。 要求: 1. 只输出JSON格式结果,不要输出任何多余文字。 2. 判断必须基于资料中的信息,禁止编造。 3. 如果信息不足,将置信度设为低,并明确输出信息不足的结论。 参考输出格式: { "ticker": "标的代码", "direction": "多/空/中性", "confidence": 0.0, "key_points": ["逻辑1", "逻辑2"], "risk_factors": ["风险1"] }

这个提示词看起来简单,但里面有几个细节直接影响可用性。

第一是只允许输出JSON。我不止一次见过模型输出“好的,我将开始分析……”这种废话,然后JSON里混进文本,解析直接崩掉。所以我在提示词里明确加了“不要输出任何多余文字”,并且在解析时用正则兜底抓取大括号之间的内容。

第二是置信度必须有界。我给confidence字段限定了0到1的范围。这里有一个哭笑不得的教训:早期版本允许模型自由打分,模型给过0.98的高置信度,但后续判断完全错误。后来我调整了规则,要求模型只有在信息足够多、逻辑一致时才给高置信度,否则一律压低。这相当于给模型的“自信”上了一道紧箍咒。

第三是温度参数调到0.1到0.3之间。温度越高,模型输出越有创造性,但对交易场景来说,创造性等于灾难。我实测过温度0.7和温度0.2的输出差异,前者经常出现天马行空的逻辑,后者稳定重复性好。交易信号要的是可复现性,不是文学创作。

2.3 信号审核:绝不能让LLM的输出直接进订单

不管提示词写得多么精巧,LLM总会有翻车的时候。我在研究中遇到过模型把停牌股票当成正常交易标的、把历史公告当成实时新闻、甚至把某一轮对话中自己说过的话当成事实依据来引用。

所以我的管线里加了一个独立的信号审核层。这个层不依赖LLM,而是用普通代码规则做交叉验证:

  • 标的是否在允许交易列表内?(排除停牌、ST、当日异常波动的标的)
  • 时间戳是否在公告发布之后?防止用未来信息(穿越样本外测试的坑,回测里尤其致命)。
  • 置信度是否达到阈值?低于阈值一律丢弃,不进入决策层。
  • 方向判断是否与价格趋势因子矛盾?如果矛盾,降低信号权重,而不是直接信任某一方。

注意:信号审核层不是风控系统,但它是风控的第一个环节。它的目的是拦截“低级错误”,而不是拦截“观点错误”。观点错误要靠仓位管理和止损来应对,指望审核层过滤观点错误是不现实的。

3. 如何执行:从信号到订单的工程化落地

3.1 信号归一化与时效性处理

LLM信号和传统价格因子的数据形态差异非常大,直接混在一起用会出现量纲问题。我的做法是做一个归一化层,把不同类型信号映射到同一标准尺度上。

具体来说,我用的是分位数映射。比如LLM输出的置信度区间,先收集历史一段时间内的所有信号,按分位数切成1到10的档位,然后用档位值参与后续计算。这样做的好处是不受模型本身的“自信倾向”影响——有的模型天生爱给高分,有的模型天生保守,分位数映射能把这种偏差抹平。

时效性处理是另一个重点。LLM处理非结构化数据需要时间,从数据产生到模型输出,往往有几秒甚至十几秒的延迟。对于日频策略来说这不算什么,但对于分钟级策略来说,这个延迟是致命的。

我的方案是给每个信号打上新鲜度标签,分三档:新鲜(5分钟内)、可用(30分钟内)、过期(超过30分钟)。过期信号不进决策层,直接丢弃。这个规则虽然简单,但有效避免了“用旧闻做交易”的尴尬。

3.2 仓位计算:用信号分数决定下注多少

“如何执行”里最容易被忽视的是仓位管理。很多人觉得信号对了就能赚钱,实际上仓位管理才是账户生存的基石。

我采用的方案是信号分数加固定风险预算的混合模型。信号分数来自归一化后的LLM输出,再加一个价格趋势因子的修正。仓位上限由风险预算决定,每笔交易的亏损上限控制在账户净值的1%以内。

举个具体的例子:假设账户净值100万,单笔亏损上限1%就是1万。如果止损距离是5%,那么这笔交易的仓位上限就是1万除以5%等于20万,也就是20%仓位。然后根据信号分数在这个上限内打折,信号分数越高仓位越高,但永远不会突破20%这个硬顶。

这个逻辑用代码实现非常简单:

def calculate_position_size(equity, stop_loss_pct, signal_score, max_risk=0.01): risk_amount = equity * max_risk # 单笔最大亏损金额 raw_size = risk_amount / stop_loss_pct # 基于止损距离的仓位上限 adjusted_size = raw_size * signal_score # 信号分数打折 return min(adjusted_size, raw_size) # 不超过硬顶

核心思想是:信号只决定“愿不愿意参与”,风险预算决定“最多亏多少”。这两个维度必须分开,否则很容易在信号强的时候仓位失控。

3.3 订单执行:模拟盘先行,滑点不可预估

信号变成订单,中间还有一道执行流程。我自己的研究分两个阶段,先模拟盘跑三轮,期间不做任何实盘操作,等系统稳定后再谈实盘。

模拟盘阶段要特别注意滑点问题。很多人在模拟盘里觉得成交价就是信号价,实际上这个假设在真实市场里几乎不成立。我的做法是模拟盘里主动加一个滑点惩罚:买入价在信号价基础上加0.1%,卖出价减0.1%。这个惩罚虽然粗糙,但能让你提前感受真实交易中的摩擦成本,避免回测曲线好看到失真。

执行方式上,我全部采用限价单而不是市价单。市价单的优势是成交快,但劣势是价格不可控,尤其对于流动性较差的标的,冲击成本可能吞掉大部分利润。限价单虽然有时候会不成交,但至少在价格上是确定的。我会给限价单设置一个价格容忍区间,比如信号价的0.2%以内,超过就放弃,不追单。

4. 回测框架设计与因子评估

4.1 事件驱动回测是标配,向量化回测在这里行不通

传统量化里常用向量化回测,效率高,但在LLM信号场景下完全不适用。原因很简单:向量化回测假设信号序列是预先算好的、连续的、无延迟的。但LLM信号的生成有时间延迟,有调用失败,有上下文依赖,这些因素必须按事件顺序逐笔模拟。

所以我用的是事件驱动回测框架。核心逻辑是一个事件循环,按时间顺序处理数据事件、信号事件、订单事件、成交事件。这样能精确模拟信号生成延迟、订单排队、成交价格偏移等真实情况。

代价是回测速度变慢。我的数据覆盖了近三年的日频数据,加上分钟级撮合模拟,跑一轮完整回测需要两到三个小时。但换来的是结果可信度大幅提升,这笔时间花得值。

4.2 评估指标:不只盯收益率,更要看IC和衰减

LLM信号的评估,我习惯用一个组合指标体系,核心是IC(信息系数)和ICIR(信息比率的变体)。

IC的计算方式很简单:把信号的排名和未来收益的排名做Spearman相关。如果信号排名靠前的标的未来收益也排名靠前,说明信号有预测力。IC的绝对值在0.03以上就有一点使用价值,0.05以上就算不错,超过0.08在这个领域已经非常优秀。

但光看IC还不够,还要看衰减速度。LLM信号的有效期往往很短。我按月滚动计算IC,观察IC随时间推移的走势。如果第一个月IC是0.06,第三个月降到0.01,说明这个信号衰减很快,只能做短周期策略。相反,如果IC稳定在0.04左右持续半年,那这个信号的可持续性就强很多。

另外还要看换手率。LLM信号如果天天反转方向,策略会频繁交易,手续费和滑点会吃掉大部分利润。我在回测里专门统计了信号反转率,目标是控制在30%以下,超过这个阈值我会怀疑信号过于敏感。

4.3 样本外测试与防过拟合的三道闸门

LLM策略很容易过拟合。原因不难理解:模型参数多、提示词可调的空间大、数据生成方式灵活。你在历史上调出一个好看的曲线,可能只是凑巧。

我给自己定了一个防过拟合的三道闸门规则:

  • 第一道:时间切割。把数据按时间切成前70%做训练调参,后30%做样本外验证。样本外表现不佳的策略直接放弃,不做任何回补调参。
  • 第二道:市场状态分离。样本内和样本外的市场状态必须不同。比如样本里包含单边行情和震荡行情,样本外最好也覆盖类似分布。不然你调出来的策略可能只适应某一种特殊行情。
  • 第三道:参数扰动测试。核心参数上下浮动20%,观察回撤变化。如果参数稍微一改就大幅恶化,说明策略结构不稳定,剔除。

这三道闸门帮我淘汰掉了很多“看起来很美”的策略。淘汰率高,但留下来的每一个都有相对扎实的样本外表现。

5. 常见问题与实战避坑实录

5.1 LLM输出不稳定,同一批数据两次结果不一样

这是最让人头疼的问题。哪怕是温度调到0.1,模型也不能保证两次输出完全一致。对于交易系统来说,不可复现的特性非常致命。

我做了两件事缓解:

第一是请求时固定随机种子。部分推理框架支持设置seed参数,能显著降低输出方差。但注意不是所有模型服务都支持,需要看具体情况。

第二是多次采样取众数。对每个信号请求至少跑三次,取方向判断出现次数最多的结果,置信度取三次的平均值。这个方法简单粗暴但有效。代价是成本变成三倍,所以我现在只在信号进入决策层之前做这个校验,而不是所有请求都采样三次。

5.2 延迟问题:LLM响应太慢,跟不上行情

这个问题在实盘测试阶段特别明显。一次LLM请求从发送到返回,最慢能到十几秒。对于分钟级策略来说,这个延迟意味着信号出来的时候行情早已变化。

我的应对思路是预生成+缓存。具体做法是:对持仓池内的标的研究对象,在盘前预先用最新公告和隔夜新闻生成一份信号快照。盘中每5分钟增量更新一次,但只对发生新事件的标的做重算。这样既保证了信号的新鲜度,又把单次请求的延迟影响降到最低。

另一个杂但有效的技巧是调用异步化。把LLM请求放到异步任务队列里,不阻塞主循环。信号返回后由后台线程写入消息队列,决策层从队列里消费信号。这个架构把延迟从“阻塞”变成了“延迟抖动”,对交易系统来说是一个质的改善。

5.3 成本问题:跑一次完整研究的API费用偏高

LLM交易研究要比普通自然语言处理任务贵得多,因为你需要大量历史数据反复回测。一次完整的样本内+样本外测试,可能需要上万次模型调用,费用相当可观。

我控制成本的几个实用招数:

  • 减少输入token。公告和新闻全文可能很长,但真正关键的信息往往在头几段。我用摘要模型先压缩长文本,再送入主模型。
  • 分级使用模型。日常的粗筛过滤用轻量模型,只有进入候选池的少数标的才调用强模型做深度分析。
  • 复用历史结果。同一份资料在短时间内不会变化,把LLM输出结果缓存下来,重复回测时直接读缓存,不必重新调用模型。

这三招组合起来,成本能降到原来的三分之一左右。虽然还是比纯传统因子研究贵,但已经属于可接受的范围。

5.4 幻觉数据:模型一本正经地“编”出公司公告

这是最危险的坑。有一次我在回测中发现某个标的的信号特别好,查了一下原始资料,结果发现模型引用了一份不存在的合同公告——它把历史公告里的“拟合作”直接脑补成了“已签订重大合同”。

从那以后,我强制在提示词里加了一句话:“如果你不确定资料中是否存在某条信息,请明确回答信息不足。”同时在下游加了一个校验:所有关键事实字段必须在原始资料检索结果中存在,否则置信度直接归零。

LLM的幻觉问题无法完全消除,但可以通过工程手段把它拦截在交易决策之前。宁可漏掉一个真实信号,也不能让一个幻觉信号进订单。

写在最后的一点体会

研究做了大半年,最大的感悟是:LLM交易不是“让AI替你赚钱”的躺赢故事,而是一个高风险、高复杂度、高不确定性的系统工程。

模型输出不稳定,那就提示词加校验,下游加审核,回测加隔离;信号衰减快,那就缩短持有周期,做滚动评估,及时淘汰失效信号;成本太高,那就分级调用、缓存复用、压缩输入。每一个问题单看都不难,难的是把它们串成一套不会在关键环节掉链子的系统。

我个人接下来打算沿着“LLM作为自治代理”的方向继续探索——让模型不仅仅输出单次信号,而是维护一个持续更新的交易认知库,自动检索新信息、更新旧观点、评估历史判断的得失。这条路显然比“信号生成器”更复杂,但也更有想象空间。到时候有了阶段性成果,再单独写一篇笔记分享。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询