A股量化策略落地:特征工程与大模型决策的关键实践
写量化策略的人最怕的不是亏钱是不知道钱为什么亏。上篇把框架搭起来之后真正决定这套系统能不能从“纸面模型”变成“真金白银”的就是特征工程和大模型决策落地这两件事。我见过不少朋友跑通示例代码就觉得完事了结果一上实盘不是信号时灵时不灵就是大模型输出根本没法对接下单最后只能手动看盘还是回到了老路。这篇作为下篇我把特征工程和大模型决策落地这段拆开讲。重点是我自己踩过的坑、反复验证过的做法以及为什么有些操作看起来多余实际却决定了策略能否稳定跑下去。适合已经搭好基础框架、准备把策略真正跑起来的朋友也适合对AI量化感兴趣但还没理清“特征”和“模型”关系的新手。1. 从数据到特征A股量化策略的第一道分水岭1.1 特征工程要解决的核心问题很多新手拿到A股行情数据之后第一个动作就是把“开盘价、收盘价、成交量”直接扔给模型。这种做法不是说完全没用而是浪费了数据里最关键的信息而且会让模型的泛化能力极差。特征工程的核心目标是把原始行情数据转换成“能稳定反映市场状态、可跨周期复用、且具备经济含义”的变量。A股市场有几个特殊性直接决定了特征工程要比其他市场做得更讲究。涨跌停和T1制度意味着日内的动量效应会被截断次日开盘的跳空行为特别重要。横截面特征比单一股票的时序特征更稳定因为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 从决策到订单风控闸门与执行通道大模型输出决策之后中间还隔着一道不能省略的“风控闸门”。我自己在系统里写了五条强制校验规则大模型生成的任何决策不过完这五条就不允许进入下单通道当前股票是否处于涨停、跌停或者停牌状态如果是直接拒绝。建议仓位是否超出单票最大仓位限制超出则强制截断到限制值。当前账户是否有足够可用资金没有则挂起决策。买入操作是否违反T1交易的可用持仓约束。与上一交易日相比仓位变动幅度是否超过单日调仓上限超过则分日执行。这五条规则不是业务的负担而是让你敢把大模型放在实盘链路里的底气。大模型的判断能力再强它也不会知道账户当前真实可用资金是多少更不会知道某只股票刚好因为停牌无法交易。这些机械操作必须在交易系统层解决。执行通道方面我倾向于让决策模块与交易接口解耦大模型输出的是一个决策文件由独立的执行模块去读取。这个设计的好处是即使交易柜台或券商接口临时出问题决策模块仍然可以继续运行修复执行模块不需要重新触发一次大模型推理降低耦合度。4. 完整落地流程A股量化策略从框架到上线4.1 基础框架与关键选型有了前面这些组件落地一套完整流程需要大致分为数据层、特征层、决策层和执行层四个模块。数据层负责收集行情、财务和状态数据特征层负责对数据进行清洗、预处理和特征计算决策层负责把特征描述转换成大模型输入并解析输出结果执行层负责校验风控规则、生成订单和执行。技术选型上数据层一般用Python配合关系型数据库存日频数据和元数据特征层基于Pandas或者处理框架做批量计算决策层用现成的大模型接口或者本地部署的开源模型。我自己更倾向于本地部署开源模型做决策因为连续调用会积累成本而且数据不出本地隐私面更可控。如果资金量不大可以考虑最简单的部署方式一台能联网的服务器、一个数据库、一个定时任务调度器就足够把整个流程跑起来。不要一开始就追求微服务架构等策略稳定盈利、需要扩容时再拆分也不迟。跑通逻辑永远比炫技术重要。4.2 一个步骤化的实操流水账典型复盘我以一个模拟运行项目来做例子说明整个流程怎么串联起来。首先股票池设定为某指数成分股中流动性排名靠前的50只票因为小票流动性差执行成本高不适合做日频轮动。每日收盘后数据脚本开始更新当日行情和财务数据对复权价格做校验确认没有异常的跳空数据之后进入特征计算。特征计算完成后模块会把当日特征和最近20个交易日的特征合成一个综合快照同时生成市场环境摘要。这个摘要就是给大模型的输入。执行调度器接着调用决策模块向模型发送构建好的提示词获取JSON输出经过解析和完整性校验后生成当日建议清单。再经过风控闸门逐条过滤最终只留下合规且生效的调仓指令。指令写入订单表之后执行模块批量发起委托并每隔一段时间主动查询委托状态。假如某笔委托因为跌停无法成交就自动撤销并记录原因。整个流程从收盘后到全部完成通常控制在较短的时间内核心逻辑清晰没有任何一个环节依赖盘中人工干预。这个流程跑了一段时间后我最大的心得是这一套系统的日常运维重点不是模型调优而是数据质量和状态检查。每天只要数据干净、任务按时跑完、大模型输出能正常解析这套系统就算正常运行了。4.3 回测中容易踩的坑未来函数、幸存者偏差与过拟合回测不是为了让自己高兴是为了发现系统在真实环境里可能犯的错误。有三个坑是最典型、也是最容易让回测结果虚高的。未来函数是最常见的隐形坑。比如用当日全部成分股做排名却把当天收盘后的股票池信息当成“已知信息”来筛选导致模型总是选到未来涨得好的股票。我记得最深刻的一次是调试某模拟策略时发现一份包含当日涨停信号的特征在回测中产生了错觉般的高收益实际上这些信号在开盘前根本无法获取。后来统一把所有特征计算逻辑锁定为“只用当前周期已收盘的数据”排查结果才变得可信。幸存者偏差来自股票池的构建。如果直接用当前时点仍然上市、仍然在指数里的股票做历史回测那退市和被剔除的股票就全部天然被排除在外了。解决办法是构建一个包含历史时点所有上市股票的数据集并在每个时间截面用当时可获取的股票池结构进行回测。这个过程会麻烦很多但不做回测结果就会明显偏高。过拟合则更隐蔽。特征工程里面加工得越多、参数量越大越容易被回测期的数据“照顾”得很好。降低过拟合的策略一是做样本外验证把近一段时间的行情数据留出来专门做验证训练时完全不看这些数据二是控制模型复杂度特征数量宁可少而精三是做滚动训练定期用最新数据重新拟合避免模型在旧市场环境里越走越远。5. 常见问题与排查技巧实录5.1 训练与实盘差异大的原因如果回测曲线很漂亮实盘却频繁止损最先怀疑的方向应该是数据不一致。常见情况包括回测用的是复权价实盘委托按真实价波动计算不一致回测忽略了滑点和手续费导致每次交易实际成本比预期高很多回测里的成交假设是“信号出现就能立刻以收盘价成交”但实际上次日开盘跳空可能让成交价偏离判断。解决方法是把成交假设尽量“往坏了想”。我回测时默认引入固定的交易成本和滑点信号出现在收盘后的就在次日开盘价基础上额外加一档滑点估算成交。虽然这么做会降低回测数字但实盘体验会接近很多。5.2 大模型输出不稳定怎么办大模型即使是同一天同一批输入连续调用两次也可能给出不同答案。这在决策链路里是个大隐患。我常用的办法是降低温度系数直接降到一个很低的值甚至接近确定性输出。温度越低输出越保守、越固定。不要指望大模型发挥“创造力”在决策场景里稳定比创新重要。还可以增加结果投票机制同一个问题换不同措辞问三次要求模型只输出决策字段然后对三次结果取多数。如果三次结果不一致就以最保守的决策为准。这种方法损失了一点点决策弹性但大大提高了实盘系统的可预期性。5.3 特征与数据更新的运维细节数据更新是直接引发实盘事故的重灾区。节假日之后的交易日如果数据源前一天的行情文件没同步全特征计算会出现时间缺口产生异常特征值。我的应对方法是在每日流程开始前加一道数据完整性检查明确按“股票池所有样本都包含当日行情”做比对缺一个就整日流程报警不再继续后续计算。宁可少做一天决策也不能用半残废的数据去喂模型。另外财报数据的更新时间和行情不在同一个频率上。基本面的特征更新频率要单独维护尽量避免在新财报还没完全披露时用旧数据替代新数据。还可以给特征打一个“更新时间戳”模型决策时能够感知每类特征的新鲜度这比统一假设“所有特征都是最新的”要靠谱得多。5.4 问题排查速查表我在调试过程中整理了一张速查表遇到异常可以直接对照查省去反复试错的时间。现象优先排查方向处理建议回测好、实盘差成交假设、滑点手续费、复权回测中加入保守成本检查成交价假设大模型输出残缺提示词格式约束、返回长度限制要求JSON输出、增加解析容错、失败即空仓特征值异常大极端值、除权除息、停牌去极值、复权校验、剔除停牌样本信号换手过高特征噪声大、数据源异常平滑特征、加调仓限制重大时间差异时区、节假日、数据缺口数据完整性检查、报警截停这套表不至于覆盖所有问题但它能帮助我快速定位方向不用每次都把系统从头到尾重新翻一遍。我个人在实际操作中的体会是特征工程和大模型决策落地本质上是“把不确定性一步步压缩成确定性”的过程。特征工程负责把市场噪声变成有效信号预处理负责把信号变得干净大模型负责把干净信号变成可执行的决策而风控负责让决策在真实环境里安全落地。每个环节都让噪声小一点、确定性多一点整个系统才可能稳定。最后再分享一个经验上线前尽可能强迫自己连续数周不开“自动执行”开关系统每天照常输出决策但只记录不实际下单。把这些虚拟决策和真实市场的次日走势拿来对比检查系统逻辑在实盘环境里是否成立。这段被忽视的观察期往往能暴露回测阶段永远发现不了的问题。