这次我们来看一个把大语言模型用到小市值股票交易里的研究框架。标题很长核心就一句话让 LLM 同时读取金融新闻情绪、宏观经济指标和技术面信号最后输出交易决策。它不是现成的软件包而是一条完整的策略实现链路适合已经跑过量化回测、想尝试 LLM 因子或多信号融合的读者。小市值股票是这套框架最典型的适配对象因为分析师覆盖少、新闻信息对价格影响更直接LLM 在语义理解上的优势能被放大。传统量化框架很难处理“管理层变动”“供应链中断”“客户砍单”这类非结构化信息而 LLM 可以把这些新闻文本转成可计算的情绪分数再和宏观状态、技术形态放在同一个上下文里做综合判断。这个思路在工程上并不复杂难在三路信号怎么对齐、决策输出怎么稳定、回测怎么避免前视偏差。下面按模块拆解这套框架从信号构建到 LLM 决策、回测验证和风险边界给出可以照着复现的完整流程。1. 核心能力速览能力项说明项目类型LLM 驱动的量化交易研究框架信号来源金融新闻情绪、宏观经济指标、技术面信号决策方式多信号组装上下文LLM 输出交易判断交易对象小市值股票市值区间需自行定义运行环境Python 3.9 及以上需要 LLM API 或本地模型接口数据要求新闻文本、宏观数据、行情数据均需合规授权或公开数据源回测支持可接入 backtrader、vectorbt或自写事件循环批量能力支持批量新闻分析、批量股票池扫描适用阶段策略研究、模拟盘验证为主实盘需严格风控这套框架的重点不是训练一个金融大模型而是把已有的 LLM 能力嵌入量化流程。它解决的问题是传统因子模型很难覆盖的“文本语义 → 交易信号”这一步。和纯技术面策略相比它多了一个事件驱动维度和纯新闻情绪策略相比它又用宏观和技术面做了过滤和确认。2. 框架整体设计与信号融合思路整个框架可以拆成四个阶段新闻文本 - 情绪分数 宏观数据 - 状态特征 行情数据 - 技术指标 ↓ LLM 决策上下文 ↓ BUY / HOLD / SELL ↓ 回测引擎验证三路信号在决策层里的定位完全不同。新闻情绪负责捕捉“预期差”。小市值股票的研报覆盖少一条合格披露、一份业绩预告、一条行业政策新闻都可能造成明显的价格波动。LLM 在这里的作用是把新闻的利好、利空、中性判断转成结构化分数相当于给策略加了一个事件驱动层。宏观指标负责判断“市场环境”。如果利率处于上行周期、流动性收缩小市值股票整体承压这时候即使个股新闻偏利好也不适合重仓。宏观信号不直接决定买卖而是给 LLM 提供一个大背景让模型在风险偏好上做出调整。技术面信号负责“确认和风控”。价格趋势、均线位置、RSI 极值、成交量变化这些信息能反映资金行为。新闻情绪可能提前反映在价格里技术面能帮忙判断市场是否已经消化消息。三路信号融合的关键是时间对齐。新闻有发布时间宏观指标有公布日行情有交易日历。如果把三个时间源的数据不做对齐就拼在一起LLM 很可能会读到“未来信息”回测结果会严重失真。更稳妥的做法是每一路信号都按决策日 T 生成快照T 日收盘后组装上下文T1 日开盘执行。这样能避免前视偏差。3. 环境准备与数据前置条件3.1 运行环境建议使用 Python 3.9 以上的虚拟环境。核心依赖包括 pandas、numpy、openai、ta、backtrader 等。如果本地有可用的 LLM 推理服务也可以不走 OpenAI 的 API而是接本地模型的 OpenAI 兼容接口。python -m venv venv source venv/bin/activate pip install pandas numpy openai ta backtrader这里ta负责算技术指标backtrader做回测openai用来调用 LLM 接口。如果使用其他模型服务需要根据服务商的 SDK 调整代码。不需要装 PyTorch 或 CUDA 相关组件因为大部分推理交给远端 LLM 接口完成。3.2 数据源与授权数据是这套框架里最容易被低估的部分。新闻数据方面可以接入新闻 API也可以自己抓取公告和资讯。需要注意版权和使用条款商用场景必须确认数据授权。宏观数据方面利率、CPI、PMI、M2 等通常有公开来源但不同来源的发布口径可能不同。行情数据方面日线级别数据比较容易获取但小市值股票可能存在停牌、涨跌停、流动性不足等问题历史回测时要单独处理这些情况。3.3 目录结构建议project/ ├── data/ │ ├── news/ # 新闻原始数据 │ ├── macro/ # 宏观指标数据 │ └── market/ # 行情数据 ├── features/ │ ├── sentiment.py # 新闻情绪模块 │ ├── macro.py # 宏观特征模块 │ └── technical.py # 技术特征模块 ├── decision/ │ └── llm_agent.py # LLM 决策模块 ├── backtest/ │ └── engine.py # 回测模块 └── config/ └── settings.py # 全局配置把数据、特征、决策、回测分目录管理后续批量扩展会省很多时间。4. 三路信号模块实现4.1 金融新闻情绪模块新闻情绪模块的核心任务是输入一段新闻文本输出情绪方向、情绪强度和相关实体。这里给出一个批量分析函数使用 OpenAI 兼容接口实际部署时模型名和密钥要按环境替换。import json from openai import OpenAI client OpenAI(api_keyyour-api-key) def analyze_news_sentiment(news_items: list[str]) - list[dict]: 批量分析新闻情绪。 注意模型名、api_key、base_url 需要按实际 LLM 服务替换。 prompt f 你是金融新闻情绪分析器。对于下面每条新闻提取 1. 涉及的公司或板块 2. 情绪方向positive/neutral/negative 3. 情绪强度-1 到 1-1 为极度负面1 为极度正面 4. 一句话摘要 新闻列表 {json.dumps(news_items, ensure_asciiFalse)} 以 JSON 数组返回 [{{entity: ..., sentiment_label: ..., score: 0.0, summary: ...}}] response client.chat.completions.create( modelgpt-4o-mini, messages[ {role: system, content: 你只输出合法 JSON不输出其他内容。}, {role: user, content: prompt}, ], temperature0, response_format{type: json_object}, ) content response.choices[0].message.content return json.loads(content)输出的 JSON 里entity是新闻涉及的公司sentiment_label是方向score是强度summary是摘要。这个结果可以直接转成 DataFrame按股票代码和时间做聚合。实际使用时要注意几个细节。第一response_format参数不是所有模型服务都支持如果报错就去掉这个参数改用更严格的提示词约束。第二新闻文本里可能同时涉及多家公司需要用entity字段区分不能简单地把一条新闻算到所有关联股票头上。第三情绪分数要做归一化处理不同模型的打分尺度可能不一致同一批新闻用同一个模型打分更稳定。4.2 宏观经济指标模块宏观指标的作用是给 LLM 提供市场环境背景。具体选哪些指标取决于策略类型。利率和信用利差反映流动性环境CPI 和 PPI 反映通胀压力PMI 反映经济景气度M2 同比反映货币供给。不需要一次塞太多指标过度冗余的输入反而会让 LLM 决策不稳定。宏观数据的预处理重点是口径统一和缺失值处理。宏观指标的发布频率通常是月度或季度和日频交易信号直接拼接会引入大量重复值。更稳妥的做法是把宏观指标做成“最近值”和“变化方向”两类特征。import pandas as pd def build_macro_features(macro_df: pd.DataFrame) - pd.DataFrame: 输入宏观时间序列输出标准化特征。 多个指标需要按日期对齐缺失值做前向填充。 macro_df macro_df.sort_index() macro_df macro_df.fillna(methodffill) # 转为环比变化 macro_change macro_df.pct_change().fillna(0) # 可选用 z-score 标准化消除量纲差异 macro_norm (macro_df - macro_df.rolling(252).mean()) / macro_df.rolling(252).std() result pd.concat([macro_df, macro_change, macro_norm], axis1) result.columns [ f{col} for col in macro_df.columns ] [ f{col}_change for col in macro_df.columns ] [ f{col}_norm for col in macro_df.columns ] return result.dropna()这里同时保留了宏观指标的水平值、环比变化和标准化值。LLM 对“数值大小”不敏感但对“趋势方向”更敏感所以把_change和_norm都放进去比只给原始值更有效。4.3 技术面信号模块技术面信号用ta库计算。这里给出一个常用的特征构建函数包含均线、RSI、MACD、ATR 和量比。import pandas as pd import ta def build_technical_features(df: pd.DataFrame) - pd.DataFrame: 输入标准 OHLCV 行情数据输出常用技术面特征。 字段要求open, high, low, close, volume df df.copy() df[ma20] ta.trend.sma_indicator(df[close], window20) df[ma60] ta.trend.sma_indicator(df[close], window60) df[rsi14] ta.momentum.rsi(df[close], window14) macd ta.trend.MACD(df[close]) df[macd] macd.macd() df[macd_signal] macd.macd_signal() df[macd_diff] macd.macd_diff() df[atr14] ta.volatility.average_true_range( df[high], df[low], df[close], window14 ) df[volume_ratio] df[volume] / df[volume].rolling(20).mean() return df.dropna()技术面特征不要全量塞给 LLM。考虑到上下文长度和决策稳定性建议只保留最近 5 到 10 天的关键指标或者把指标转成“状态描述”例如“价格在 20 日均线上方”“RSI 处于超卖区间”。结构化描述比裸数字更适合 LLM 理解。5. LLM 决策层设计与调用示例5.1 上下文组装决策层是整个框架的中枢。三路信号在进入 LLM 之前需要先拼装成一份紧凑的上下文。import json def build_decision_prompt( stock_code: str, news_summary: str, macro_features: dict, technical_features: dict, ) - str: prompt f 你是一个小市值股票研究助手请综合以下信号给出交易建议。 股票代码{stock_code} 新闻情绪汇总 {news_summary} 宏观指标特征 {json.dumps(macro_features, ensure_asciiFalse)} 技术面特征 {json.dumps(technical_features, ensure_asciiFalse)} 请从以下三个动作中选择一个BUY / HOLD / SELL。 输出 JSON {{ action: BUY, confidence: 0.0, reason: 简要说明判断依据 }} return prompt5.2 决策输出def generate_trading_decision( stock_code: str, news_summary: str, macro_features: dict, technical_features: dict, ) - dict: prompt build_decision_prompt( stock_code, news_summary, macro_features, technical_features ) response client.chat.completions.create( modelgpt-4o-mini, messages[ {role: system, content: 你是保守的量化交易研究员只输出结构化 JSON。}, {role: user, content: prompt}, ], temperature0, ) content response.choices[0].message.content return json.loads(content)这里把temperature设为 0让模型每次输出的倾向尽量一致。实际操作中LLM 对同样的输入仍可能给出不同结果尤其是面对边界情形时。更稳的做法是多次采样例如同一份上下文连续调用 3 次取多数票作为最终信号。5.3 决策稳定性优化从工程经验看LLM 决策不稳定主要来自三个方面。第一是上下文里的数字太多。LLM 对孤立数字的记忆能力一般多个 0.32、0.87 这种小数混在一起模型很难区分谁是谁。解决办法是在组装上下文之前先把数字转成语义描述比如“RSI 处于 30 以下属于超卖区间”“成交量是 20 日均量的 1.5 倍”。第二是输出类别太开放。让 LLM 直接输出目标价或仓位比例效果通常不好。建议把输出空间压缩成 BUY / HOLD / SELL 三个动作并搭配一个 0 到 1 的 confidence 分数。仓位和止损交给规则层计算不要让模型自由发挥。第三是缺少系统性约束。可以在系统提示词里加入“禁止追涨”“连续亏损后降低仓位”等规则。这样相当于把风控逻辑前置到了模型决策里。6. 小市值交易回测与效果验证6.1 回测框架选择回测可以用 backtrader、vectorbt也可以写一个极简事件循环。对于日频策略自写循环其实够用代码更透明调试也方便。def simple_backtest( df: pd.DataFrame, signals: pd.Series, initial_capital: float 100000, ) - dict: 极简回测信号为 1买入/持有、0空仓。 教学演示不包含滑点、手续费和停牌处理。 capital initial_capital position 0 equity_curve [] for date, row in df.iterrows(): price row[close] signal signals.get(date, 0) if signal 1 and position 0: position int(capital // price) capital - position * price elif signal 0 and position 0: capital position * price position 0 equity_curve.append(capital position * price) final_equity equity_curve[-1] return { final_equity: final_equity, total_return: final_equity / initial_capital - 1, equity_curve: pd.Series(equity_curve, indexdf.index), }这个极简版本默认每天收盘后根据信号买入或卖出。实际回测必须加入交易成本、滑点和涨跌停限制。小市值股票的流动性本来就差如果回测里不考虑冲击成本结果会明显偏乐观。6.2 验证指标效果验证不只看总收益建议至少关注这几个指标指标计算方法作用年化收益率按回测周期换算判断策略整体盈利水平最大回撤净值曲线峰值到谷底的最大跌幅判断策略风险承受能力夏普比率超额收益 / 收益波动率判断风险调整后收益胜率盈利交易次数 / 总交易次数判断决策稳定性换手率交易金额 / 持仓市值判断策略对交易成本的敏感度6.3 前视偏差检查这是回测里最容易踩的坑。新闻发布时间、宏观指标公布时间、行情收盘时间必须严格对齐。正确的顺序是T 日收盘后获取当日行情T 日新闻需要在收盘前已发布才能纳入当日信号宏观指标必须用已经公布的值。任何“未来数据”被混进决策上下文都会让回测结果失真。建议在回测之前做一个数据对齐检查把每一条新闻的发布时间、宏观数据的公布时间、行情数据的交易日期打印出来人工抽查 10 到 20 个样本确认没有时间错位。7. 风险控制与合规边界这套框架涉及金融交易必须明确边界。小市值股票的流动性风险是最突出的。日成交额低、买卖价差大、涨跌停频繁、停牌概率高这些都可能导致信号发出了但实际无法成交。回测和模拟盘都不等于实盘实盘前需要用更细粒度的订单数据进行仿真验证。数据授权同样重要。新闻数据、宏观数据、行情数据都要确认使用条款。抓取未经授权的公开数据用于商用存在版权和合规风险。如果涉及生成式 AI 输出内容需要复核模型输出的准确性。LLM 可能虚构新闻摘要或错误解读数据决策前最好加入一层规则校验例如“新闻实体必须匹配股票池”“情绪分数超出合理范围则丢弃”。必须强调本文内容仅讨论技术实现思路不构成任何投资建议。策略在投入实际资金之前需要在合规框架内完成长期模拟验证。8. 常见问题与排查方法问题现象可能原因排查方式解决方案LLM API 报错api_key 无效或余额不足检查接口返回信息更新密钥或更换模型服务返回内容不是合法 JSON模型输出混入了多余文本打印原始返回内容加强系统提示词或去掉 response_format 后重试新闻情绪分数波动大新闻发布时间和回测日期未对齐检查数据时间戳按公布时间对齐T 日收盘后统一快照回测结果明显偏乐观混入未来数据或未扣除交易成本检查数据对齐逻辑加入成本模型和未来数据检查脚本小市值股票停牌导致信号无法执行回测未处理停牌状态检查历史停牌记录回测中加入可交易性过滤条件批量分析新闻成本过高新闻量太大直接调用强模型查看 API 调用日志先用轻量模型初筛再用强模型分析LLM 决策不稳定上下文数字过多或输出空间过大对比多次调用结果压缩输出类别使用多数票机制显存或内存不足本地模型推理导致查看资源占用改用 API 或量化模型9. 最佳实践与使用建议第一次跑通整套框架时不要追求复杂的模型和丰富的信号。先固定一个股票池选 20 到 50 只小市值股票用三个月到六个月的日频数据跑通流程。重点验证三路信号的数据对齐、LLM 调用是否稳定、回测结果是否可复现。模型选择上不需要一上来就用最强的模型。新闻情绪分析对模型的语义理解能力要求最高可以用强模型技术面特征已经是结构化数据用轻量模型就够。决策层建议用强模型因为需要综合三路信号做权衡。这样配置能把成本控制在合理范围。批量任务要加日志和缓存。新闻分析是典型的可缓存任务同一篇新闻不需要重复打分。建议把新闻文本哈希后写入缓存再做批量分析能省下大量 API 调用成本。接口服务如果开放给其他系统使用必须限制访问范围不要把内置了策略逻辑的服务直接暴露到公网。API 密钥不要写死在代码里用环境变量或密钥管理服务。10. 总结与下一步这套框架最值得试的地方是把新闻文本真正变成了可回测的因子。相比传统因子模型LLM 能理解事件语义这是它最大的增量价值。最先应该验证的是新闻情绪模块的输出稳定性。拿过去一个季度的新闻做测试看情绪方向是否合理、摘要是否准确再决定要不要往下走。最容易踩的坑是数据对齐新闻发布时间、宏观公布日、行情交易日三个时间源不一致回测结果会很失真。后续可以往两个方向扩展。一是在决策层加入更完善的风险管理规则让仓位和止损由规则层控制LLM 只做方向判断。二是把单股分析升级成股票池批量扫描用轻量模型做初筛再用强模型做二次确认形成一套完整的 AI 选股流程。