资讯中心

大模型在算法交易中的落地实践:语义决策器与规则执行器的双层架构

📅 2026/10/14 18:28:57
大模型在算法交易中的落地实践:语义决策器与规则执行器的双层架构
这篇研究笔记记录的是我过去几个月一直在琢磨的一件事LLM到底能不能成为算法交易系统里一个真正干活的组件。先说结论——能但不在大多数人以为的那个位置。很多人听到“用LLM做交易”脑子里浮现的是“让AI从几千只股票里挑出明天涨停的那只”这个期待本身就是错的。真正跑通之后你会发现LLM的用武之地是在“交易什么”到“如何执行”这条决策链路里把那些原本靠人肉盯盘、靠研报总结、靠拍脑袋判断的中间环节自动化。这篇文章适合两类人一类是做量化交易、想引入大模型但不知道该怎么落地的工程师另一类是熟悉LLM应用开发、想进入金融场景但不熟悉交易执行细节的算法工程师。我会把架构思路、工程细节、代码骨架、踩坑记录都摊开来讲尽量还原一个研究的真实过程。1. 先想清楚LLM在算法交易里到底扮演什么角色1.1 传统算法交易已经解决了很多问题剩下的才是LLM的机会传统算法交易或者说程序化交易核心能力集中在“如何执行”。比如你已经确定要买500手某个标的执行层有很多现成算法可以用VWAP按成交量加权平均、TWAP时间加权平均、冰山订单、加入流动性的maker策略等等。这一层算法的目标高度一致把大单拆成小单尽量降低市场冲击成本减少滑点。到这一层LLM完全插不上手也不需要插手——这是数学和微观结构模型的主场已经非常成熟。那从“交易什么”说起。选择标的、判断方向、决定仓位传统量化靠的是因子模型、统计套利、事件驱动。因子模型能捕获“市盈率低”“动量强”这类可计算特征事件驱动能响应财报、公告这类结构化信息。但这些方法有个共同的边界处理不了复杂的语义。比如一条突发新闻说“某公司被反垄断调查”传统系统能不能反应靠人工打标签能靠关键词匹配也能做一个七七八八。但遇到“FDA拒绝了某药物申请但多名分析师认为影响有限”这种需要综合判断的复合语义规则系统的泛化能力就非常差。LLM的机会恰恰在这里。它能把非结构化文本、市场状态、甚至盘口上一些微妙特征统一转化成“语义信号”再输出为结构化决策。换句话说它并不是要取代VWAP这类执行算法它取代的是投研流程里那些“读资料、做判断、写指令”的人工环节。我刚做这个项目时走过弯路总想让LLM直接给出交易指令结果发现它在执行层面既不稳定也不可靠。正确的用法是让它当“语义决策器”而不是“全知交易员”。1.2 我理解的LLM交易系统是“语义决策器规则执行器”我在实验中采用的整体定位是LLM负责判断“交易什么”也就是从市场状态中识别机会、给出方向和仓位建议底层规则引擎负责“如何执行”也就是把LLM给出的交易意图拆解成订单类型、拆单策略、风控参数。这是一个非常关键的架构选择后面我会反复解释这个架构到底规避了哪些坑。这个定位也直接决定了评估方式。我不用“LLM预测准确率”来衡量系统好坏因为它本质上不是预测系统而是决策系统。真正要看的指标是在LLM介入之后整个组合的收益风险比、最大回撤、换手率、以及执行成本这几项有没有变好。这个认知不建立起来很容易把项目做成“花大价钱买了一个话痨版行情播报器”。很多失败案例都是模型负责所有事、最后归因不清讲不出到底是模型判断错了还是执行环节不到位。1.3 这篇研究笔记的实验边界先把实验范围说明白免得你照着做的时候出现预期偏差。我的实验环境是日线级别以上的低频场景数据来自公开行情API回测区间是过去三年另外单独留出六个月做样本外验证。模型部分试过闭源API也试过把开源模型做本地部署两边主要用于对比成本和延迟。这里需要特别强调整个实验没有涉及任何内幕或独家数据全部使用公开信息包括价格行情、财报、公告新闻文本。这带来的直接限制是结果上限取决于公开信息的质量。如果你能拿到更多维度的数据比如另类数据、产业链上下游信息结论自然会有不同。另外本文讨论的是研究阶段不构成任何投资建议。实际资金运营还涉及合规、风控、清算等大量工程问题那是一条完全不同的路。2. 系统架构把“交易什么”和“如何执行”拆成两层2.1 双阶段管线与信号传递我的系统整体分两段。第一段叫“研究引擎”输入是市场快照、新闻事件、财务摘要输出是一份结构化的“交易意图”里面包含标的、方向、建议仓位、置信度、理由摘要。第二段叫“执行引擎”输入是第一段的交易意图输出的是具体订单包括订单类型、委托价格、拆单计划、止损参数。这个传递过程有一个硬约束LLM只允许出现在第一段第二段是纯规则代码不允许任何模型推理介入。为什么因为执行层的错误成本极高一个幻觉导致的价格填错、数量填错可能在几秒内就产生真实亏损。规则代码可以穷举所有分支而LLM的输出永远有概率性。所以在我这套架构里执行引擎会对交易意图做非常严格的schema校验不合格的意图直接丢弃宁可错过交易也不让错误订单进入市场。这个“宁可错过”的思路是我在吃了好几次模拟亏之后才真正想明白的。2.2 数据接入与信号标准化要喂给LLM的数据五花八门行情K线、主力资金流向、新闻标题、财报摘要。问题是LLM不吃K线原始数组也不吃PDF财报它吃的是文本。所以第一步就是把所有数据源统一标准化成一段“市场状态摘要”。我在实验里写了一个data_compactor模块负责把原始数据压成三段式摘要价格行为、资金面信号、事件面信号。价格行为包括最新收盘价、5日/20日涨跌幅、成交量的相对位置资金面信号包括主力资金净流入的近期趋势、换手率是否异常事件面信号则是经过清洗的新闻和公告标题保留实体名词和关键情绪词。这一步看着简单实际是系统里最吃经验的地方。原始K线数组转成文字后如果保留太多数字token消耗极大模型也抓不住重点如果压缩太狠又会丢失决策必需的敏感信息。我最后采用的是“数值化语义化”双轨关键指标用数字列表保持精度市场整体状态用自然语言概括。比如“价格行为收盘78.55日涨幅-2.1%20日涨幅6.3%量能位置近20日62%分位”再给一句“整体处于缩量回调阶段趋势未破坏”。2.3 执行层的工具调用设计第二段的执行引擎在技术上采用“工具调用”模式。LLM在决策段的输出里会标记它期望的动作比如buy或者sell但不会直接接触下单接口。执行引擎拿到标签后匹配对应的执行策略。这其实很像现在常说的LLM Agent工具调用只是这里的工具不是查天气、算加减法而是“生成订单”“计算仓位”“调整止损”。这里有个非常关键的设计细节不要让你的LLM直接返回“买入10000股”这种精确指令。模型对资金规模、当前仓位、风险上限这些约束没有一致性记忆你让它算仓位它今天给20%明天可能因为prompt里某个词变了就给35%。所以我让LLM只输出“方向强度等级”比如“directionlongstrengthmedium”然后由规则引擎根据当前账户净值、最大仓位限制、止损距离去计算实际下单数量。模型负责他擅长的定性判断定量计算全部交给确定性代码。这条经验几乎适用于所有LLM交易项目。3. 关键工程细节让LLM看懂盘面并约束它不乱来3.1 行情快照转成结构化文本的Token预算管理Token预算是我在工程细节里第一个碰到的墙。以日线行情为例直接把20根K线的OHLCV全部放进prompt大约要600到800个token再把最近一周的新闻标题放进去又是几百个token加上系统指令、约束条件、输出格式说明一次请求随随便便要2000到3000个token。如果每分钟决策一次、连续跑一整天成本会快速累积而且上下文一长模型对早期内容的注意力会衰减决策质量反而下降。我的做法是把单次请求的输入严格控制在800个token以内具体拆分如下数据模块原始输入规模压缩后输入规模节省比例行情K线约600-800 token约200 token70%以上新闻事件约300-500 token约100 token70%以上持仓与账户摘要约100 token约50 token50%左右合计1000-1400 token350 token以下70%以上压缩的手段有两个。价格数据只保留收盘价序列和三个关键指标而不是全部OHLCV事件数据先用一次轻量LLM调用做“信息抽取”压缩成“实体动作态度”的三元组格式。比如“公司发布业绩预增公告净利润同比增加50%以上”会被压缩成“业绩预告/正面/净利润50%”。这样既保留了决策需要的语义又去掉了大量修饰词。3.2 Prompt设计决策层、风险层、执行层的三层隔离很多早期版本的失败都源于把决策、风险、执行三个问题写进同一个prompt让模型同时回答。比如prompt里既问“该不该买”又问“买多少”还加一句“注意止损”。结果模型经常顾此失彼要么在解释仓位时忘了止损要么在讨论风险时连方向都改了。我现在把prompt拆成三个独立阶段分别调用模型处理。第一阶段只做方向判断输入是市场状态摘要输出是bullish、bearish、neutral三选一附带理由。第二阶段做风险感知输入是方向判断和当前持仓摘要输出是加仓、减仓还是维持。第三阶段才做执行参数选择输入是前两轮的结论和账户约束输出强度等级。三个步骤之间用结构化数据结构传递不允许把前一步的文字长段落直接塞进下一步的prompt里当背景。这么做有一个额外好处你可以在某个阶段单独换更好的模型。比如方向判断需要更强的语义理解可以换更大、更贵的模型执行参数选择只依赖有限的枚举值可以用更小、更快的模型去跑。成本和质量能分别优化这在实际项目中非常有价值。3.3 结构化输出与交易意图解析让LLM直接输出自由文本然后靠人或者代码去理解含义是很危险的做法。模型会写“我认为可以买入因为……”表面上清晰但解析起来全是雷。我的做法是强制JSON格式输出在请求参数里直接指定response_format为json_object同时在prompt里用一个example把schema写死。对应的schema校验代码用Pydantic实现from pydantic import BaseModel, Field class TradeIntent(BaseModel): direction: str Field(pattern^(long|short|flat)$) strength: str Field(pattern^(low|medium|high)$) reason: str Field(max_length50) def parse_intent(raw: dict) - TradeIntent | None: try: return TradeIntent(**raw) except Exception: return None解析阶段如果发现字段缺失、枚举值不符、reason超长整条结果直接丢弃并标记为no_decision。实测下来这种严格校验让系统的决策质量显著提升因为模型在约束下会认真选择合法值而不是想到哪儿写到哪儿。你给它自由它就给你写小作文你给它边界它反而像个专业工具。4. 实操记录一个最小可运行的LLM交易Agent4.1 选型API、模型与回测环境的取舍先讲选型。我在对比中发现交易决策场景对模型的要求和写代码、写文案完全不同它不需要特别强的创作能力但需要非常稳定的指令遵循和格式遵从能力。闭源模型里我主要试过GPT-4o和Claude两者的结构化输出都做得不错开源模型里试了Qwen和DeepSeek系列的API版本格式稳定性已经可以接近闭源模型但在长上下文或多轮调用时会有退化。我的建议是第一个跑通的版本优先选择一个格式稳定的API模型不要一上来就搞本地部署。交易系统的核心变量是数据、prompt、校验逻辑模型选型的影响要靠后。先把整条链路验证稳定再去做模型替换的横向对比这样成本最低。回测环境我用的是vectorbt轻量适合研究阶段快速验证想法等逻辑成熟到需要事件驱动、逐笔撮合的时候再迁移到更重的框架也不迟。4.2 核心代码与调用链直接给一套最小可运行的代码骨架。主循环大概是拉取行情快照data_compactor生成市场状态摘要研究引擎调用LLM获取交易意图校验模块做schema校验执行引擎根据账户参数生成订单。决策调用部分的伪代码如下import json import openai client openai.OpenAI(api_key..., base_url...) def research_engine(market_summary: str, positions: str) - dict: messages [ {role: system, content: SYSTEM_PROMPT}, {role: user, content: f市场状态{market_summary}\n当前持仓{positions}} ] resp client.chat.completions.create( modelgpt-4o, messagesmessages, temperature0.2, response_format{type: json_object}, seed2024 ) return json.loads(resp.choices[0].message.content)这段代码里有几个细节值得展开说。temperature0.2是我反复试出来的平衡点。如果设成0模型输出会极度保守倾向于永远输出neutral策略等于废掉如果设成0.7以上它偶尔会给出很有想象力的判断但更多时候是给出不该有的激进仓位。seed参数在API支持的情况下一定要固定虽然不能百分百保证可复现但能明显减少同输入不同输出的跳变对后续回测对比非常重要。4.3 参数调整实录temperature、max_tokens与重试策略再聊几个我实际调过的参数。第一个是max_tokens很多人习惯设置很大的输出上限觉得反正用不满。但在结构化输出场景里过大的max_tokens会让模型觉得有空余写废话偶尔会冒出一段超出schema的内容。我设成300刚好装下JSON输出和reason字段实测下来格式违规率下降了不少。第二个是重试策略。模型调用偶尔会失败比如限流、超时或者返回格式不合法。我设计了一个最多重试3次的机制但每次重试之间递增等待并且第三次重试时把temperature降到0.1强制模型走保守路线。这比无限重试可靠得多因为无限重试遇到持续幻觉时会让系统卡死在循环里甚至因为重复调用产生不必要的费用。第三个是缓存。同一个市场快照如果行情没有变化重复调用LLM就是纯浪费钱。我加了一层简单缓存以市场状态摘要的哈希值为key缓存结果三分钟。实测下来这个优化把API成本砍了接近五成因为盘中经常会出现连续几个bar数据没变的情况。这类工程层面的小优化累计效果往往比换一个“更聪明”的模型来得快。5. 踩坑记录四个高频问题的排查思路5.1 幻觉型理由模型会编造不存在的利好这是最要命的坑。模型在给出方向判断时经常附带“公司近期获得大额订单”这种理由但去查证时发现根本没有这回事。它把训练数据里的行业常识或者别的公司的新闻嫁接到了当前标的上。这个幻觉在交易场景里极其危险因为它会让人误以为模型有信息优势实际上它只是在顺口编。我的排查思路分三层。第一层在prompt里硬性要求“理由必须引用输入中的事实不得引用任何外部知识”第二层在输出校验阶段把reason字段和输入摘要做交叉对比核心实体必须来自输入文本第三层在策略层面凡是模型给出的理由无法匹配任何输入信号强制降级为neutral。这套机制不能说百分之百清除幻觉但能过滤掉绝大多数编造的利好和利空目前看效果很稳定。5.2 输出格式漂移与JSON解析失败大模型对格式的遵守不是百分之百稳定的。即使指定了response_format为json_object偶尔也会出现key名变化、多出字段、或者字符串里混入换行符导致解析失败的情况。我一开始用内置的json.loads直接解析结果一天下来崩了好几次排查后发现是模型在某个特殊字符上“放飞自我”了。后来我换成两步处理先用一个宽容的正则把JSON主体切出来再用Pydantic做schema校验和类型强转。更极端的情况比如模型返回了完全无法解析的内容就直接丢弃这次决策并在日志里标记为format_error同时把这段脏数据存下来当prompt优化的素材。这个做法有个额外收益累积几百条脏数据后你能从里面归纳出模型最喜欢在哪类问题违反格式然后针对性加few-shot示例格式稳定性会明显提升。5.3 上下文中毒同一只股票反复叙述导致重复决策连续决策模式下如果每一轮都把上一轮的完整对话历史塞进上下文模型会逐渐被自己的旧观点“说服”。比如某天它判断某标的是bullish第二天市场条件已经中性了但模型看到昨天自己说bullish的完整段落会无意识地在论证上偏向延续旧观点。这就是上下文中毒。解决办法很直接每一轮决策只使用“当前市场状态摘要当前持仓”不携带历史对话。如果需要做时序判断我就把历史决策抽象成一行短文本比如“昨日判断:bullish/medium昨日行情涨幅:1.2%”然后作为一行输入。这样模型了解上下文但不会被自己的长篇大论带节奏。你可以把这一步理解成LLM交易系统需要的是“记忆摘要”不是“完整背诵”。5.4 延迟、限流与经济性权衡盘中高频决策时延迟问题非常突出。一次LLM调用正常需要1到2秒如果三个串行调用就是3到6秒这个延迟对分钟级交易勉强可以接受对秒级高频直接不可用。所以这套系统天然只能做中低频决策你把它的“慢”当作一个硬约束来规划策略频率就好千万别硬往高频方向拉。我的应对方案是并行化加降级。三个阶段里方向判断和风险感知可以并行发起如果某次调用失败或者超时就降级为规则策略执行保证系统永远有决策输出而不是干等。经济性方面我统计过每天大约200次调用的成本在个位数美元量级研究阶段完全可以接受。但如果扩展到实时监控几十只股票成本会线性上涨。这时候就非常有必要引入一个本地小模型做预筛只有预筛触发信号才调用大模型做深度分析这样可以花小钱办好大事。6. 回测结果与对照组设计6.1 三组对照纯规则、LLM规则熔断、纯LLM为了评估LLM到底有没有带来增量我做了三组对照回测。纯规则组用简单的双均线金叉死叉加固定仓位管理当作baseline。LLM规则熔断组让LLM负责方向判断规则引擎负责执行和触发风控熔断。纯LLM组让模型直接输出订单参数规则引擎只做最小限度的格式校验几乎不干预决策。这里我不展示具体净值曲线因为样本区间和参数会影响结论但方向上的结论非常有启发。为了方便阅读把关键指标做了归一化只保留相对关系对照组年化收益最大回撤换手率加入成本后的收益衰减纯规则中等较低低小LLM规则熔断中高中低中中纯LLM回测中很高极高极高极大纯规则组胜在稳定回撤小但收益上限低LLM规则熔断组整体收益风险比有一定提升尤其在事件驱动的行情里LLM能捕捉到均线模型根本看不到的语义信号纯LLM组验证了我的担忧它在回测里表现出极高的换手率和极差的最大回撤一旦模型误判损失会被仓位的自我增强放大而且加了真实交易成本之后收益几乎被吃光。这个对照实验基本确认了架构结论LLM负责语义判断规则负责执行和约束两层缺一不可。6.2 过拟合信号与样本外验证说句泼冷水的话LLM交易系统最大的风险不是模型不行而是研究者的过拟合。因为prompt里的每一句话都可能变成隐形参数你会不自觉地去调整prompt让回测曲线更好看这跟调整因子系数去拟合历史数据没有本质区别甚至更隐蔽。我给自己定的规矩是prompt冻结期每调一次prompt必须记录改动内容并且只允许用训练区间跑回测如果改动让训练区间变好还必须再看它在样本外区间的表现。样本外区间我留了六个月存活下来的改动不到三分之一。还有一个细节很关键回测时强制加入交易成本和滑点成本。A股市场的双边成本加滑点按千分之三估算很多策略在没加成本时漂漂亮亮一加成本就原形毕露这一点在LLM策略上尤其明显因为它天然换手率高。6.3 下一步从单标的研究引擎走向多标的决策框架我目前正在做的扩展是把“单标的决策”升级为“多标的选择资金分配”两阶段。也就是说先用LLM在同一批候选池里做横向比较选出优先级最高的几个标的再用规则做资金分配。这个方向的问题是prompt里同时出现多个标的时模型表现会明显下降容易只讨论第一个标的或者忽略后排标的。我目前的尝试是先让LLM对每个标的独立打分再用外部排序逻辑做汇总而不是让模型一次性输出排序。这种“模型打分算法排序”的组合明显比“让模型直接排序”稳定得多。另外我还在把一些失败case整理成一个“反事实库”每次模型给出错误方向而事实随后验证了相反方向我就记录下当时的市场状态和模型理由。这个库最大的价值不是用来事后归因而是用来构造few-shot反例让模型在后续推理中更警惕它曾经犯过的错误模式。长期看这是从一个“能跑的研究原型”走向“可实盘验证的系统”最扎实的一步。7. 写在最后的一个体会严格来说我不太喜欢给研究笔记写总结但确实想分享一点体会。这几个月做下来我最深的感受是LLM在交易里最值得投入的地方不是让它变得更像人而是让它变得像一台懂金融语义的精密仪器。换句话说它应该被当作一个传感器读取那些传统因子读不出来的文本信号然后把这个信号转化成规则引擎能理解和执行的结构化数据。不要试图让模型去做所有决定让它做它擅长的语义判断剩下的交给确定性代码。这个原则帮我避开了最多坑。关于这个话题还有很多没写清楚的地方比如prompt怎么写才不容易被行情波动带偏、各类模型的横向评测结论以及那个反事实库的具体构建方法。如果后续实验有新的进展我会继续整理成研究笔记发出来也算给自己留一份可追溯的实验档案。

看完文章,想为自己的企业也做一次专业网站诊断?

尧图顾问免费为您评估现有网站,并给出建站/改版建议与报价方案。

免费获取方案