基于LLM的小市值量化框架:新闻情绪与技术信号融合实践
从新闻情绪到交易信号:基于LLM的小市值量化框架实践解析
如果你做过小市值股票的量化研究,大概率会碰到一类很典型的困惑:技术指标在大部分时间都有效,但一旦遇到突发新闻或市场情绪转向,价格行为会瞬间脱离历史统计规律。过去我们处理这种问题,主要靠人工盯盘、事件驱动模型或简单的关键词情绪打分,但前两者成本太高,后者又过于粗糙。现在,Large Language Model的介入,让一条新的路径变得可行:让模型直接阅读新闻、理解宏观数据,再把它们和技术指标压缩成统一的交易信号。
这篇文章不打算复述“LLM很强大”这类空话,而是围绕一个具体的项目主题展开:如何构建一个由LLM驱动的小市值交易辅助框架,把金融新闻情绪、宏观经济指标与技术信号整合到一个可验证的系统中。我会把这个框架拆成数据层、LLM处理层、信号合成层和回测层,并给出可以直接参考的Python代码和工程建议。需要提前说明的是,这更多是一套研究与实践框架,不是“输入代码就能稳定盈利”的银弹;真正的难点往往不在模型调用,而在数据对齐、信号归因和回测防过拟合。
如果你正准备做类似的方向,建议先看完整体架构,再决定要从哪一层入手。下面我们从“为什么是小市值”这个问题开始。
1. 为什么小市值是LLM量化最值得先试的场景
小市值股票天然存在严重的信息不对称。机构研究覆盖少,公开研报有限,交易者更多依赖新闻、社交媒体和盘口情绪做决策。这种环境下,传统量价因子虽然仍有统计意义,但容易在消息驱动的跳空行情中失效。原因是技术指标本质上是过去价格的滞后函数,它无法在信息出现的瞬间评估“这条新闻到底有多重要”、对哪家公司影响多大、市场会按什么路径消化。
而LLM的优势恰好落在非结构化文本理解上。它可以做情绪极性判断、实体识别、事件分类、甚至根据宏观数据推断政策导向。对小市值公司来说,一条区域政策、一次行业展会、一份订单公告,都可能成为短期价格的重要驱动。传统关键词匹配无法区分“合同纠纷败诉”和“合同中标公告”的差别,但LLM在语义层面可以做到。
更关键的是,小市值股票的数据量相对集中,新闻数量远少于大盘蓝筹,这使得我们可以在有限成本内完成全文级分析,而不需要像处理全市场新闻那样做高成本抽样。也就是说,小市值场景是LLM从“概念演示”走向“可回测策略”的一个比较现实的切入口。
当然,小市值也有自己的麻烦:流动性差、冲击成本高、财务数据容易造假、涨跌停和停牌规则会改变收益分布。所以,把LLM接入交易系统之前,必须先想清楚它的输出到底扮演什么角色。我倾向于把它定位为“信号增强器”而非“交易决策器”,最终下单还是由规则引擎或人审核完成。
2. 系统整体架构与数据流设计
整个框架可以拆成五个部分:数据接入层、LLM处理层、特征融合层、信号生成层和回测/风控模块。每个部分之间通过标准化的中间文件或消息队列连接,避免LLM调用阻塞整个流程。
数据流的逻辑是这样的:先收集当日新闻、宏观指标、行情快照和技术指标,形成三条独立的时间线;接着把新闻文本和宏观事件发送给LLM,让模型输出结构化结果,例如情绪分数、影响实体、事件类别;然后把这些结构化结果与技术指标在时间戳上对齐,构成一个多维特征矩阵;最后通过规则或轻量模型合成交易信号,送入回测框架。
这里最容易被低估的是“时间对齐”。LLM处理新闻有延迟,不同数据源的发布时间戳各不相同,如果直接按自然日合并,就会引入未来数据偏差。更稳妥的做法是使用“可获取时间”(available time)来标记信息,而不是发布时间。例如某条新闻在下午2点35分出现在API响应中,那么只有2点35分之后的bar才能使用这条特征。这个细节决定了回测结果是否可信。
另一个容易被忽略的设计是失败降级。LLM服务可能出现超时、限额或内容审核拒绝。框架里必须预留一个规则兜底分支:当LLM不可用时,可以退回到关键词情绪分数或中性信号,而不是让整个系统停摆。下面我会把每一层的关键实现拆开讲。
3. 数据层:新闻情绪、宏观指标与技术信号的预处理
数据层是整个项目的地基。在这个阶段,我们需要的不是把所有数据都接进来,而是先定义“一条有效事件信息”的最小字段集合。推荐至少包含:股票代码、事件时间戳、事件级别(公司/行业/宏观)、事件类型(公告/新闻/政策/分析师评级)、原始文本、来源、经过清洗的文本,以及一条唯一的ID。这对后面的LLM批处理和缓存都有帮助。
3.1 新闻数据采集与清洗
新闻数据来源可以是公开API、爬虫抓取或商业数据源。需要注意版权和合规问题,本文只讨论处理流程。采集后的原始文本通常包含HTML标签、无关导航内容、重复转载和营销性文字。清洗步骤一般包括:
- 去除HTML标签、URL、多余空白字符
- 提取正文主体,去掉标题重复句子
- 识别并合并同一事件的转载新闻,保留最早来源
- 过滤掉包含“推荐”“广告”“点击领取”等噪声文本
清洗后的新闻要存成标准格式,例如JSON或Parquet。下面是一个清洗后的新闻记录示例:
这里“available_time”是系统真正拿到这条数据并可以触发策略的时间,不是公告发布的时间。如果公告在盘中发布,但数据源延迟20分钟,那么策略只能在延迟后的时间点使用它。
3.2 宏观指标处理
宏观指标包括利率、PMI、CPI、社融、工业增加值等,通常按月或按季发布。它们本身频率很低,但对小市值股票的影响往往通过流动性和风险偏好传导。处理宏观指标时要额外注意“发布时点的滞后性”,也就是指标通常对应上个月或上个季度的情况。所以不能把2025年3月中旬公布的2月PMI当作3月初已知信息来模拟决策。
更实用的做法是把宏观指标做成状态变量,比如“利率处于上升通道”“PMI连续三个月大于50”,再让LLM对这些状态做情景化解释,而不是把原始数值直接塞给模型。这样可以降低模型对噪声数字的敏感度,同时让特征更具可解释性。
3.3 技术指标计算
技术指标是模型特征框架里相对成熟的部分。常用的小市值短期信号包括:动量(过去5日、10日收益率)、波动率(ATR或历史波动率)、成交量变化(量比)、相对强弱(RSI)、移动平均线偏离度等。下面是一个使用Pandas计算常用技术指标的示例:
注意,所有技术指标计算都要在历史数据上“滚动”完成,不能使用未来信息。pandas的rolling默认就是滑动窗口,但需要确认窗口内是否包含当前值。按需调整。
4. LLM模块设计:从一篇新闻到结构化信号
LLM在这个框架中的核心任务不是“预测明天会涨还是会跌”,而是把一个非结构化文本转换成可以进入因子库的结构化信号。你可以把它理解为:让模型扮演一个金融信息抽取员,输出情绪极性、事件影响方向、受影响实体,以及置信度。
4.1 Prompt设计思路
Prompt设计决定了输出质量的稳定性。一个比较可靠的模式是:先给模型设定角色与任务,再给出输出格式约束,最后是文本内容。输出格式强烈建议使用JSON,并且要求模型只输出JSON,不要额外解释。下面是一个可用的Prompt模板:
这里的一个关键设计是“短期影响方向”与“情绪”分离。情绪可能是正面的,但“利润预增公告”对股价的影响方向和“公司中标项目”的影响方向不完全一样。分开判断可以给后续因子合成更多自由度。
4.2 调用LLM并解析结果
无论使用OpenAI兼容接口、国产大模型API,还是本地部署的开源模型,调用方式基本类似。下面以Python调用一个兼容OpenAI Chat Completions格式的API为例:
这段代码里temperature设置为0,目的是让输出尽量稳定,减少随机性对信号的影响。response_format要求JSONObject,并不是所有API都支持,使用前需要确认供应商能力;如果不支持,可以用正则从字符串中抽取JSON块。
解析结果后,还需要检查字段是否完整,比如sentiment是否只包含三个枚举值、sentiment_score是否在0到1之间。如果模型返回的JSON格式不符合预期,最简单的方法是把该条新闻丢进“待人工复核”列表,而不是强行解析。
4.3 批量处理与缓存策略
小市值策略的新闻数量可能每天有几百到几千条,逐条调用API会带来延迟和成本问题。可用的方式是做“批量+缓存”:
- 对同一事件主体的新闻在短时间内去重,避免重复调用
- 对同一文本的哈希值建立缓存,如果之前分析过且模型版本未变,直接复用结果
- 非实时研究场景可以使用离线批处理,把分析结果写入数据库,回测时只读取
下面是一个简单的批次处理函数,用来控制并发和失败重试:
在生产环境中,更推荐用消息队列(如Redis Stream或RabbitMQ)来异步消费新闻任务,但研究阶段用简单列表循环即可。
5. 信号合成:把LLM输出与技术指标变成可交易的分数
得到LLM的结构化输出后,还不能直接下单。我们需要把这些输出与现有技术指标放在同一个特征空间里,再通过规则或模型合成一个“信号强度分数”。这里要注意一个问题:LLM输出的情绪分数是横截面特征,需要与其他股票在同一时期比较,才能体现相对强弱。换句话说,情绪分数0.8在今天是高位还是低位,取决于今天整个市场或同行业股票的情绪分布。
5.1 构建特征函数
下面这个函数展示如何把三条数据源压缩成一个综合因子。它综合了情绪得分、事件类型的先验影响、宏观状态、以及技术指标中的动量与成交量确认。权重初始值来自经验,后续可以用历史数据做优化。
这里的权重并不一定能适用于所有市场环境,但它演示了“多源信号如何表达成一个分数”。更严谨的做法是用滚动窗口计算每个因子与未来收益的IC值,再动态调整权重。
5.2 生成交易信号
基于综合因子,可以设置阈值来生成交易信号。比如:
- 综合因子大于0.6:买入候选
- 综合因子小于-0.6:卖出或回避候选
- 其他情况:不操作
需要强调,阈值必须根据回测结果确定,不能拍脑袋。同时要加上流动性过滤,例如排除日成交额低于某个阈值的股票;也可以加上波动率过滤,例如排除ATR过大导致止损空间明显不足的标的。
在小市值策略里,建议把“SELL”信号分成两类:一类是持仓中出现了负面事件而主动卖出,另一类是因子分数降到低位而被动减仓。两类信号对应的逻辑不同,前者要尽量快,后者可以分批执行。
6. 回测与验证:避免被LLM增强后的过拟合欺骗
回测是整个框架中最容易出问题,也最容易被忽视的环节。因为LLM引入后,特征维度增加,策略有更多自由度去拟合历史数据。如果回测没有做好防未来数据和防过拟合,最终结果会很漂亮,但实盘一塌糊涂。
6.1 回测框架的四个必查项
第一,必须使用事件可获取时间。新闻和宏观数据的发布时间是关键,不能简单使用自然日。第二,必须考虑涨跌停和流动性约束。小市值股票经常出现开盘一字涨停或跌停,信号虽然生成了,但实际不可能成交。第三,必须考虑交易成本。小市值股票买卖价差大,滑点显著;回测中建议每边至少扣除0.1%到0.3%的成本,或使用更保守的冲击成本模型。第四,必须做样本外测试。把数据按时间切分,前70%用于因子研发,后30%用于验证。
6.2 一个简单的回测指标计算示例
下面代码展示如何基于信号和价格数据计算最基础的收益指标。这个示例简化了交易成本与持仓周期,主要用来理解逻辑,不是完整回测引擎。
这段代码没有处理组合持仓和在途资金,但能用于快速检查信号思路是否合理。如果你想认真做研究,推荐用成熟的回测库,例如backtrader、vectorbt、聚宽或掘金,而不是自己从零造轮子。小市值策略尤其考验回测工具的精细度。
6.3 模型与因子归因
既然引入了LLM,还需要回答一个问题:最终策略的超额收益主要来自情绪因子、宏观因子还是技术因子?这要用因子归因分析。一个简单的方法是分别计算“去掉LLM特征”和“保留LLM特征”的两条净值曲线,观察它们的差异。如果去掉LLM特征后收益基本不变,那说明LLM目前只是装饰品,并没有带来真正的信息增量。
更细的归因可以做逐步回归或特征重要性分析。值得提醒的是,金融数据的信噪比很低,因子重要性的波动会比工程场景更大。建议用多个时间窗口重复验证,不要依赖单次结果显示的“重要性排名”。
7. 关键技术难点与工程化风险
这个框架真正的难点不是训练模型,而是数据工程和策略可信度。下面几个问题几乎每个做LLM量化的人都会遇到。
第一个是数据延迟与事实性错误。LLM有幻觉风险,可能把新闻中的关键数字理解错误。比如把“同比下降”识别为正面消息。缓解方法是要求模型输出时引用原文片段,然后做规则校验;或者把数字抽取和情感判断拆成两个任务。对涉及明确数字的事件,用正则先抽取金额、百分比,再让模型结合上下文判断。
第二个是API成本与吞吐量。如果每天分析上千条新闻且使用商业大模型,成本会迅速上升。更经济的方案是分层处理:先用廉价的关键词规则过滤明显中性新闻,只有通过初筛的新闻才进入LLM分析。或使用开源模型本地部署,一台带较好CPU/GPU的服务器可以满足中小型研究团队的吞吐要求。
第三个是过拟合与市场状态切换。小市值股票的alpha来源在不同年份差异巨大。2021年小市值表现好,2023年和2024年则出现过极端波动。如果策略只在某一段市场状态下做参数调优,很容易在另一段失效。因此回测区间必须覆盖牛熊、震荡、高波动和低波动环境,并且要设定“参数不能频繁调整”的纪律。
第四个是交易执行的现实约束。小市值股票容量有限,回测中一个信号承载的资金量可能很大,实际买不到那么多。建议在回测中增加流动性约束,比如“单笔下单量不得超过当日成交量的1%”,这样可以显著降低虚假收益。
第五个是合规与数据授权。使用新闻数据、宏观数据时要注意授权边界,避免将未授权数据用于商业策略。如果你是个人研究,更要注意数据来源的合规性。涉及实际交易还必须遵守所在市场的交易规则和监管要求,任何违规策略都可能带来严重后果。
8. 常见问题与排查方法
下面整理了这个框架开发过程中比较常见的问题,以及对应的排查思路。
| 问题现象 | 可能原因 | 排查方式 | 解决方案 |
|---|---|---|---|
| LLM返回JSON解析失败 | 模型输出包含额外文本或格式不规范 | 打印原始响应内容,检查是否有Markdown代码块包裹 | 设置response_format,增加正则提取,启用重试机制 |
| 情绪分数与常识相反 | Prompt缺少时间方向或事件类型约束 | 检查原始新闻文本,查看模型是否混淆“同比”“环比” | 在Prompt中增加“注意同比增长/下降的影响方向”,并把数字提取与判断分开 |
| 回测收益虚高 | 使用了未来信息 | 逐条检查数据时间戳,特别是新闻和宏观数据的可用时间 | 统一使用available_time,并做数据泄漏自检 |
| 策略在样本内表现好,样本外失效 | 过拟合或市场状态切换 | 对比样本内外指标,检查参数是否过多 | 减少参数数量,做滚动窗口验证,加入参数稳定性约束 |
| API调用频繁超时 | 没有做批量控制和重试 | 查看调用日志和限流错误码 | 加入批处理、缓存、重试与降级逻辑 |
| 小市值股票买入后无法成交 | 流动性不足或涨跌停限制 | 检查回测中成交价和成交量的假设 | 增加流动性过滤,在回测中模拟涨跌停和成交概率 |
排查时要善用日志。建议为每个数据源和模块记录单独的日志,包括原始输入、模型输出、处理结果和耗时。这样一旦某一天策略异常,能快速定位是数据源坏了、模型调用出错了,还是因子合成逻辑被脏数据干扰了。
9. 工程化落地与最佳实践
如果你决定把这个框架从研究推进到可运行的辅助系统,下面几条工程建议值得认真对待。
9.1 数据管道要“可重放”
所有原始数据必须持久化,并且策略中间结果要与原始版本号绑定。LLM模型会升级,Prompt会修改,如果历史回测结果无法复现,研究就失去了意义。建议代码仓库里同时保存Prompt模板版本和LLM输出结果文件。不同版本的输出不要互相覆盖。
9.2 LLM调用要做好安全与权限控制
如果系统后续接入了实盘或模拟交易,LLM不应该直接产生下单指令。更稳妥的架构是:LLM的输出只能生成“信号建议”,再由独立的规则引擎做交易校验。规则引擎要包含:可交易标的白名单、最大单票仓位、单日最大买入金额、涨跌停状态过滤、合法交易时段校验。这些规则可以用代码写死,也可以放在配置中心,但必须保证人工可审查、紧急时可关闭。
9.3 监控与告警
生产环境的LLM策略系统需要监控三个层面的指标:数据延迟、模型调用成功率、因子分布漂移。如果连续多天情绪因子分布均值从0.5漂移到0.65,说明LLM的输出行为可能发生了变化,需要重新验证Prompt或Model版本。如果API调用成功率低于阈值,系统应该能自动切换到备用模型或规则降级模式。
9.4 版本管理与团队协作
建议把Prompt看成代码一样管理,使用的模型名称、温度、输出格式、系统角色都记录在配置文件中,提交到Git仓库。每次修改都要有diff记录。团队中负责策略的人、负责数据的人、负责工程的人,要对“信号语义”达成一致。不要让每个成员各自写Prompt而互不兼容。可以约定统一的字段命名规范,比如情绪一律使用sentiment,影响方向一律使用short_term_impact,这样下游代码才不会被字段名变异拖垮。
9.5 从小规模模拟盘开始
无论回测多漂亮,都建议先在模拟盘中运行至少一个月。重点观察信号频率、滑点假设、成交率和LLM响应稳定性。如果模拟盘与回测差距过大,要先回头检查回测中的成本假设和成交假设,而不是急着调整模型参数。小市值策略对执行细节极度敏感,宁可先运行得慢一点,也要保证每个决策点都有解释和记录。
回到我们最初的话题:LLM确实改变了处理金融文本的方式,但改变的是“信息提取效率”,而不是“市场预测魔法”。新闻情绪、宏观指标和技术信号在框架里是三种不同性质的数据源,LLM的价值在于把它们翻译成统一的结构化信号。你能不能用好这个信号,仍然取决于数据质量、回测纪律和风控意识。如果你正在搭建自己的小市值量化研究系统,不妨从最小闭环开始:选10只股票,跑一个月新闻数据,记录50条LLM分析结果,然后人工核对每一条情绪判断是否合理。等这一步稳定了,再逐步扩展到全市场和更复杂的信号合成方案。
这个方向最值得长期积累的,不是某个提示词的技巧,而是“怎样让模型输出与金融现实保持一致”的一整套校验和迭代方法。把它沉淀成自己的数据管道、测试集和复盘流程,比任何单个模型都更有复用价值。