写量化策略的人,最怕的不是亏钱,是不知道钱为什么亏。上篇把框架搭起来之后,真正决定这套系统能不能从“纸面模型”变成“真金白银”的,就是特征工程和大模型决策落地这两件事。我见过不少朋友跑通示例代码就觉得完事了,结果一上实盘,不是信号时灵时不灵,就是大模型输出根本没法对接下单,最后只能手动看盘,还是回到了老路。
这篇作为下篇,我把特征工程和大模型决策落地这段拆开讲。重点是我自己踩过的坑、反复验证过的做法,以及为什么有些操作看起来多余,实际却决定了策略能否稳定跑下去。适合已经搭好基础框架、准备把策略真正跑起来的朋友,也适合对AI量化感兴趣但还没理清“特征”和“模型”关系的新手。
1. 从数据到特征:A股量化策略的第一道分水岭
1.1 特征工程要解决的核心问题
很多新手拿到A股行情数据之后,第一个动作就是把“开盘价、收盘价、成交量”直接扔给模型。这种做法不是说完全没用,而是浪费了数据里最关键的信息,而且会让模型的泛化能力极差。特征工程的核心目标,是把原始行情数据转换成“能稳定反映市场状态、可跨周期复用、且具备经济含义”的变量。
A股市场有几个特殊性,直接决定了特征工程要比其他市场做得更讲究。
涨跌停和T+1制度意味着日内的动量效应会被截断,次日开盘的跳空行为特别重要。横截面特征比单一股票的时序特征更稳定,因为A股有几千只股票,同一天里哪些股票相对强势、哪些相对弱势,这个相对关系比绝对值更能反映市场偏好。行业轮动和风格切换频繁,行业属性和市值属性必须作为特征参与建模,否则模型很容易学出“不真实的规律”。
所以特征工程在这里要解决的真正问题,不是“选哪些指标”,而是“这些指标能否在实盘环境里被稳定、无偏地计算出来”。比如用收盘价计算收益时,如果不考虑除权除息,就会算出假的下跌信号。用成交量判断资金活跃度时,如果不剔除停牌日,就会把无交易状态当成极度低迷。这些都是数据层面的坑,却影响整个策略的根基。
1.2 三类最实用的特征体系拆解
在实际项目中,我把A股量化特征分成三套体系,每一套都有各自的作用,组合起来用效果比单独用高得多。
第一套是“量价特征”,主要刻画个股自身的交易状态。常见的有:
- 过去5日、20日收益率和波动率
- 换手率及其短期变化率
- 成交额相对20日均值的倍率(放量缩量)
- 收盘价偏离20日均线的幅度(乖离率)
- 日内振幅与当日涨跌幅的比值
量价特征的最大优点是频率高、更新快,适合日频甚至分钟级策略的信号构建。但单独使用时噪声很大,容易在震荡行情中反复给出假信号。
第二套是“基本面特征”,主要是从公开财务数据和估值数据中提取的信息。市值、市盈率、市净率、ROE、营收同比增速,这些都是慢变量,更新频率低,但信息质量高。量价特征负责捕捉“什么时候买”,基本面特征负责解决“买什么”,两者结合才有完整逻辑。
第三套是“市场环境特征”,目的是让模型感知“当前整个市场处于什么状态”。市场整体的收益率、上涨家数占比、行业轮动速度、市场波动率,都属于这一类。这些特征不是针对单只股票,而是用于描述背景。大模型决策落地这一步尤其依赖这层特征,因为大模型如果不知道“现在是普涨、普跌还是震荡”,它给出的判断就失去了依据。
我自己的习惯是,先把这三套特征都准备好,再做特征预处理。不要一上来就极端地只留几个因子,因为预处理之后特征的重要性排序往往会发生变化。
2. 特征预处理:比想象中更关键的三个环节
2.1 去极值与标准化:别让极端值绑架你的模型
A股数据里充斥着极端值。市值里有几百亿的巨头,也有十几个亿的小盘股。收益分布长尾很重,一个连续跌停的票,其波动率会瞬间拉得极高。如果这些原始特征直接进入模型,少数样本会主导整个学习过程,模型会退化成一个“只对极端行情敏感的守门员”。
去极值我推荐用分位数去极值或者MAD法,个人更常用分位数去极值。比如把所有样本在截面上的某一特征值按从小到大排序,把超过5%分位和95%分位的数值,统一截断到对应分位数的位置。这种方式比直接删掉极值样本更合适,因为你想保留“这个股票是极端异常”这个信息,只是不让它的具体数值过分影响模型。
标准化必须针对每个截面单独做,不能拿历史全局的均值和方差去标准化当前截面。原因是A股市场的绝对数值水平会随行情变化,全局标准化会让同一个数字在不同时期代表完全不同的相对含义。截面标准化更干净,它计算的是“在当前这个时间点,所有股票中这一特征的相对位置”。
这里有个容易忽略的细节:涨停和跌停的股票,在截面标准化之前需要单独处理。因为涨跌停封板状态下,价格被限制住了,量能也异常,直接放进截面计算会污染整个分布。我通常的做法是,先把涨跌停状态的股票单独标记,不参与特征标准化,但保留一个“是否封板”的0/1变量喂给模型。
2.2 中性化处理:剥离行业与风格暴露
中性化这个词听起来很学术,其实做的事情很简单:把被行业和市值等风格因素解释掉的那部分信息去掉,只保留个股自身独特的部分。
举一个直观的例子:如果白酒行业整体上涨,那么行业里某只个股股价上涨,可能并不是因为它自己有特别好的逻辑,只是因为行业贝塔在起作用。如果你的模型把“行业普涨”也当成这只股票的Alpha特征,那下次行业轮动时,模型就会在完全不相关的股票上给出错误信号。
中性化的实现方式有很多,最常用的是线性回归法:把待中性化的特征作为因变量,行业哑变量和取对数的市值作为自变量,做一次截面回归,然后用残差作为新的特征值。本质上就是“用行业和市值能解释的部分都已经解释完了,剩下的残差才是这一特征独有的信息”。
做完中性化之后,一般要再补一次标准化,因为残差的尺度也会漂移。另外,中性化处理会让特征本身变得更加“干净”,但同时也会削弱信号敏感度。如果策略本身就是做行业轮动,那就不能用行业中性化后的特征去做选股,这时候要把行业暴露保留下来。特征怎么预处理,最终要取决于策略逻辑,而不是机械套一套流程。
2.3 特征有效性检验:怎么判断一个特征是“真因子”还是“噪声”
准备了一堆特征之后,不要急着丢进模型。先做有效性检验,这一关能帮你筛掉大量“看起来有用,实际是过拟合”的变量。
检验特征有效性,最常用的指标是IC(信息系数),也就是计算特征值在未来一期收益之间的秩相关系数。IC的绝对值越高,说明特征预测能力越强。IC的稳定性也很重要,我会看过去12个月的IC序列,如果靠少数几个月份的爆发撑起平均值,那这个特征的实际价值要打折扣。
除了IC,还应该做分层回测。把股票按特征值从小到大分成五组或十组,看每组在未来一段时间的平均收益是否单调。如果第一组和第十组收益差距明显且方向稳定,说明这个特征有区分度。如果收益是中间高、两端低,或者各组之间没有规律,那就说明是非线性关系,在传统线性模型里没法直接用,可能要在深度学习模型或者大模型决策里才发挥价值。
特征有效性检验还有一个现实功能:给特征打标签。我把通过检验的高质量特征标记为核心特征,只在每月调仓时使用;波动大但偶尔有效的特征标记为辅助特征,动态组合的时候用;检验不合格的直接淘汰。这时候特征集就不再是一堆“变量”,而是一套有优先级、有逻辑的信息资产。
3. 大模型决策落地:从“能聊天”到“能下单”
3.1 大模型在量化策略里的真实角色定位
很多人对大模型在量化里的期望过高,觉得它能像巴菲特一样直接告诉你买哪只股票。实盘体验下来,大模型的定位应该是一个“决策优化器”,而不是“预测器”。它不适合去预测明天某只股票涨还是跌,因为价格预测本质上是概率问题,大模型的训练目标不是最小化预测误差。它真正擅长的是,在给定一组已经量化好的特征和信号之后,综合这些信息去做“状态判断、风险权衡和行动选择”。
比如,特征工程模块输出一只股票当前的热度、趋势、估值水平、行业位置和波动状态,这些都是结构化数据。大模型可以把这些信息整合起来,判断“当前这种状态下,该股票属于进攻型配置还是防御型配置”,并给出对应的仓位动态调整区间,以及买入后止损位设置的逻辑依据。这种判断不是从零预测未来,而是根据已有信息做“情境化决策”,这就是大模型最核心的价值。
这个定位一旦清楚了,很多问题就迎刃而解。你不需要大模型输出一个天马行空的选股名单,而是要求它在“策略规则允许的范围内”做决策。你不需要它解释复杂的经济形势,只需要它把当前特征状态翻译成操作区间和风控条件。边界设得越清楚,大模型在实盘里的表现越稳定。
3.2 结构化特征如何被大模型“理解”:特征描述化与上下文构建
大模型本身吃的是文本,不是数值表格。特征工程产生的是一堆数字,要让大模型理解这些数字,最直接的办法是把关键特征“描述化”,转成自然语言。
我用的模板大致是这样:AI量化决策系统,请基于以下特征状态对股票X进行综合评价。当前市场环境处于震荡偏弱,近5日市场涨跌家数比约1比2,行业轮动速度中等。股票X当前换手率为5.2%,显著高于近20日均值,说明资金关注度提升。20日收益率8.5%,但已经连续上涨五天,短期乖离率偏大。市盈率处于行业30%分位,估值不高。当前技术信号偏多,但波动率正在快速放大。
这段描述里的每一个信息都来自特征工程模块,但大模型能够综合这些信息的“含义”,结合它对金融常识的理解,做出一段合理的分析。比直接扔一组数字给它,效果要强非常多。
上下文构建要包含三个层次:市场层(当前大盘环境)、个股层(特征事实)、约束层(策略允许的交易规则和仓位限制)。约束层最关键,它告诉大模型“即便你想追高,也要遵守单票不超过10%仓位的纪律”,这相当于在模型输出前就框定了安全边界。
另外,大模型单次输入的上下文长度有限,特征描述不要贪多。我的经验是精选8到12个最关键的信息点就够了,信息太多反而会让大模型抓不住重点,输出变得泛化、废话变多。
3.3 决策输出的校验与结构化解析
大模型输出的文字分析本身不能直接下单,必须先把它的决策转换成一个结构化对象。我建议在提示词里就写死输出格式,要求大模型以JSON格式返回,里面只包含几个指定字段:操作建议(增仓、减仓、持仓不动)、置信度(高、中、低)、建议仓位区间、风险提示。
例如大模型的返回可能是:
{"action": "hold", "confidence": "medium", "position_range": [0.2, 0.3], "risk_note": "波动率偏高,不宜加仓"}
这一步看起来简单,实际操作时有一个大坑:大模型偶尔会返回残缺的JSON,或者在JSON里塞进去多余的解释文本。解析层的容错能力必须写够。我会先把返回内容里的代码块标记去掉,再用JSON解析器尝试解析,失败的情况下用正则把action和confidence字段单独抽出来。这些都失败的话,直接将本条决策标记为无效,保持旧仓位,不做任何操作。记住,“无法决策”本身就是一个有效的安全决策。
3.4 从决策到订单:风控闸门与执行通道
大模型输出决策之后,中间还隔着一道不能省略的“风控闸门”。我自己在系统里写了五条强制校验规则,大模型生成的任何决策,不过完这五条就不允许进入下单通道:
- 当前股票是否处于涨停、跌停或者停牌状态,如果是,直接拒绝。
- 建议仓位是否超出单票最大仓位限制,超出则强制截断到限制值。
- 当前账户是否有足够可用资金,没有则挂起决策。
- 买入操作是否违反T+1交易的可用持仓约束。
- 与上一交易日相比,仓位变动幅度是否超过单日调仓上限,超过则分日执行。
这五条规则不是业务的负担,而是让你敢把大模型放在实盘链路里的底气。大模型的判断能力再强,它也不会知道账户当前真实可用资金是多少,更不会知道某只股票刚好因为停牌无法交易。这些机械操作必须在交易系统层解决。
执行通道方面,我倾向于让决策模块与交易接口解耦:大模型输出的是一个决策文件,由独立的执行模块去读取。这个设计的好处是,即使交易柜台或券商接口临时出问题,决策模块仍然可以继续运行,修复执行模块不需要重新触发一次大模型推理,降低耦合度。
4. 完整落地流程:A股量化策略从框架到上线
4.1 基础框架与关键选型
有了前面这些组件,落地一套完整流程需要大致分为数据层、特征层、决策层和执行层四个模块。数据层负责收集行情、财务和状态数据;特征层负责对数据进行清洗、预处理和特征计算;决策层负责把特征描述转换成大模型输入,并解析输出结果;执行层负责校验风控规则、生成订单和执行。
技术选型上,数据层一般用Python配合关系型数据库存日频数据和元数据;特征层基于Pandas或者处理框架做批量计算;决策层用现成的大模型接口或者本地部署的开源模型。我自己更倾向于本地部署开源模型做决策,因为连续调用会积累成本,而且数据不出本地,隐私面更可控。
如果资金量不大,可以考虑最简单的部署方式:一台能联网的服务器、一个数据库、一个定时任务调度器,就足够把整个流程跑起来。不要一开始就追求微服务架构,等策略稳定盈利、需要扩容时再拆分也不迟。跑通逻辑永远比炫技术重要。
4.2 一个步骤化的实操流水账:典型复盘
我以一个模拟运行项目来做例子,说明整个流程怎么串联起来。
首先,股票池设定为某指数成分股中流动性排名靠前的50只票,因为小票流动性差,执行成本高,不适合做日频轮动。每日收盘后,数据脚本开始更新当日行情和财务数据,对复权价格做校验,确认没有异常的跳空数据之后进入特征计算。
特征计算完成后,模块会把当日特征和最近20个交易日的特征合成一个综合快照,同时生成市场环境摘要。这个摘要就是给大模型的输入。执行调度器接着调用决策模块,向模型发送构建好的提示词,获取JSON输出,经过解析和完整性校验后生成当日建议清单。
再经过风控闸门逐条过滤,最终只留下合规且生效的调仓指令。指令写入订单表之后,执行模块批量发起委托,并每隔一段时间主动查询委托状态。假如某笔委托因为跌停无法成交,就自动撤销并记录原因。整个流程从收盘后到全部完成,通常控制在较短的时间内,核心逻辑清晰,没有任何一个环节依赖盘中人工干预。
这个流程跑了一段时间后,我最大的心得是:这一套系统的日常运维重点,不是模型调优,而是数据质量和状态检查。每天只要数据干净、任务按时跑完、大模型输出能正常解析,这套系统就算正常运行了。
4.3 回测中容易踩的坑:未来函数、幸存者偏差与过拟合
回测不是为了让自己高兴,是为了发现系统在真实环境里可能犯的错误。有三个坑是最典型、也是最容易让回测结果虚高的。
未来函数是最常见的隐形坑。比如用当日全部成分股做排名,却把当天收盘后的股票池信息当成“已知信息”来筛选,导致模型总是选到未来涨得好的股票。我记得最深刻的一次,是调试某模拟策略时发现,一份包含当日涨停信号的特征在回测中产生了错觉般的高收益,实际上这些信号在开盘前根本无法获取。后来统一把所有特征计算逻辑锁定为“只用当前周期已收盘的数据”,排查结果才变得可信。
幸存者偏差来自股票池的构建。如果直接用当前时点仍然上市、仍然在指数里的股票做历史回测,那退市和被剔除的股票就全部天然被排除在外了。解决办法是构建一个包含历史时点所有上市股票的数据集,并在每个时间截面用当时可获取的股票池结构进行回测。这个过程会麻烦很多,但不做,回测结果就会明显偏高。
过拟合则更隐蔽。特征工程里面加工得越多、参数量越大,越容易被回测期的数据“照顾”得很好。降低过拟合的策略,一是做样本外验证,把近一段时间的行情数据留出来专门做验证,训练时完全不看这些数据;二是控制模型复杂度,特征数量宁可少而精;三是做滚动训练,定期用最新数据重新拟合,避免模型在旧市场环境里越走越远。
5. 常见问题与排查技巧实录
5.1 训练与实盘差异大的原因
如果回测曲线很漂亮,实盘却频繁止损,最先怀疑的方向应该是数据不一致。常见情况包括:回测用的是复权价,实盘委托按真实价,波动计算不一致;回测忽略了滑点和手续费,导致每次交易实际成本比预期高很多;回测里的成交假设是“信号出现就能立刻以收盘价成交”,但实际上次日开盘跳空可能让成交价偏离判断。
解决方法是把成交假设尽量“往坏了想”。我回测时默认引入固定的交易成本和滑点,信号出现在收盘后的,就在次日开盘价基础上额外加一档滑点估算成交。虽然这么做会降低回测数字,但实盘体验会接近很多。
5.2 大模型输出不稳定怎么办
大模型即使是同一天同一批输入,连续调用两次也可能给出不同答案。这在决策链路里是个大隐患。我常用的办法是降低温度系数,直接降到一个很低的值,甚至接近确定性输出。温度越低,输出越保守、越固定。不要指望大模型发挥“创造力”,在决策场景里稳定比创新重要。
还可以增加结果投票机制:同一个问题换不同措辞问三次,要求模型只输出决策字段,然后对三次结果取多数。如果三次结果不一致,就以最保守的决策为准。这种方法损失了一点点决策弹性,但大大提高了实盘系统的可预期性。
5.3 特征与数据更新的运维细节
数据更新是直接引发实盘事故的重灾区。节假日之后的交易日,如果数据源前一天的行情文件没同步全,特征计算会出现时间缺口,产生异常特征值。我的应对方法是在每日流程开始前加一道数据完整性检查,明确按“股票池所有样本都包含当日行情”做比对,缺一个就整日流程报警,不再继续后续计算。宁可少做一天决策,也不能用半残废的数据去喂模型。
另外,财报数据的更新时间和行情不在同一个频率上。基本面的特征更新频率要单独维护,尽量避免在新财报还没完全披露时,用旧数据替代新数据。还可以给特征打一个“更新时间戳”,模型决策时能够感知每类特征的新鲜度,这比统一假设“所有特征都是最新的”要靠谱得多。
5.4 问题排查速查表
我在调试过程中整理了一张速查表,遇到异常可以直接对照查,省去反复试错的时间。
| 现象 | 优先排查方向 | 处理建议 |
|---|---|---|
| 回测好、实盘差 | 成交假设、滑点手续费、复权 | 回测中加入保守成本,检查成交价假设 |
| 大模型输出残缺 | 提示词格式约束、返回长度限制 | 要求JSON输出、增加解析容错、失败即空仓 |
| 特征值异常大 | 极端值、除权除息、停牌 | 去极值、复权校验、剔除停牌样本 |
| 信号换手过高 | 特征噪声大、数据源异常 | 平滑特征、加调仓限制 |
| 重大时间差异 | 时区、节假日、数据缺口 | 数据完整性检查、报警截停 |
这套表不至于覆盖所有问题,但它能帮助我快速定位方向,不用每次都把系统从头到尾重新翻一遍。
我个人在实际操作中的体会是:特征工程和大模型决策落地,本质上是“把不确定性一步步压缩成确定性”的过程。特征工程负责把市场噪声变成有效信号,预处理负责把信号变得干净,大模型负责把干净信号变成可执行的决策,而风控负责让决策在真实环境里安全落地。每个环节都让噪声小一点、确定性多一点,整个系统才可能稳定。
最后再分享一个经验:上线前,尽可能强迫自己连续数周不开“自动执行”开关,系统每天照常输出决策,但只记录不实际下单。把这些虚拟决策和真实市场的次日走势拿来对比,检查系统逻辑在实盘环境里是否成立。这段被忽视的观察期,往往能暴露回测阶段永远发现不了的问题。