
简介NBER工作论文33351聚焦Transformer架构在金融资产定价中的前沿应用提出将Transformer嵌入随机贴现因子的人工智能定价模型AIPM。资源面向金融工程与量化投资领域的学术研究人员、机构从业者及高年级学生可用于理解深度学习如何改进股票回报预测与定价误差。内容深入剖析线性与非线性投资组合转换器的构建原理阐述跨资产信息共享机制及注意力机制的定价逻辑并基于1963至2022年美国股票市场数据与随机森林、神经网络等主流机器学习模型进行实证对比逐一拆解AIPM在预测准确度和价格误差上的优势来源并指出信息共享与模型复杂性是提升表现的关键。资源为单个PDF文件压缩包约681KB虽是单文件但正文内容完整适合系统阅读与反复查阅。目前已有124人学习浏览对关注人工智能与量化交叉研究的人士具有较高参考价值。 把Transformer搬进金融资产定价这事儿我前后折腾了大半年。刚动手那会儿我以为把几层encoder和一个attention堆到价格序列上就能跑出alpha结果被数据泄漏、隐性过拟合、样本量不足这些问题折磨得够呛。后来踩完一圈坑回头再看这套“深度学习改进资产定价”的技术路线才算真正想清楚它到底能解决什么问题、该在什么地方发力。这篇文章不打算写成纯理论综述。我尽量用自己在真实研究里的踩坑顺序来讲先讲为什么传统资产定价模型会遇到瓶颈、Transformer比它们强在哪儿再讲self-attention和位置编码在金融数据里的直觉含义然后给出一套可以复现的PyTorch实现最后重点聊几个反复出现的问题和排查思路。适合想用深度学习做多因子选股、资产定价或者学术量化研究的同学尤其是刚开始接触Transformer、又想把它落到金融场景的人。1. 为什么资产定价需要Transformer1.1 传统资产定价模型的三个天花板传统资产定价最经典的就是Fama-French三因子、五因子模型。它的核心逻辑是用一组风险因子去解释股票收益率的横截面差异——每只股票对特定因子的暴露不同所以期望收益不同。这个框架在几十年前很成功到今天依然是指数增强和基金业绩归因的基准方法。但它有三个明显的天花板。第一个是线性假设。因子和预期收益之间的关系被限定成线性加权而现实中的关系大多是非线性的。举个例子小市值因子在低波动环境下可能表现很好但在高波动环境下反而容易踩雷这种“条件依赖”很难用静态线性模型刻画。第二个是交互结构靠人手工设计。价值和动量到底怎么交互流动性和波动率对收益的影响是叠加还是抵消传统做法是人工加交互项但因子一多交互项组合爆炸根本试不过来。第三个是alpha衰减速度加快。当市场越来越拥挤传统因子失效的周期越来越短需要更大容量、更高维度的模型去挖掘信号。这三个天花板叠在一起刚好指向一个方向用更灵活的模型来做因子到收益率的非线性映射并且让模型自己学习因子之间的交互结构而不是靠人肉试。1.2 金融数据本质高维交互与低信噪比金融数据不是干净的文本也不是清晰的图像。它的核心特征可以总结成三句话强噪声、非平稳、高维度交互。强噪声说的是收益率序列里真正的信号占比极低大部分是随机波动。学术界有个粗略提法日频收益率的信噪比低到一个程度你很难指望任何模型能在每天每只股票上都做出准确预测。非平稳则意味着昨天有效的规律今天可能完全失效市场状态切换、风格切换、情绪周期都在不断发生。高维度交互就是同一时刻几千只股票的涨跌之间、因子与因子之间存在大量耦合关系龙头股异动带动整个板块宏观数据发布影响所有资产大小盘风格切换导致因子拥挤度骤变。这类数据环境给深度学习模型提出了一个非常现实的问题模型容量越大越容易把噪声当信号记下来模型容量太小又捕捉不到非线性关系和横截面联动。Transformer正好处在一个有趣的平衡点上——它足够灵活、能建模复杂交互但又可以通过多头注意力、正则化和残差连接把过拟合压住。1.3 为什么是Transformer而不是LSTM/CNN在深度学习做资产定价这条路里很多人第一步会想到LSTM因为价格天然是时间序列。我早期也试过LSTM踩了不少坑之后才逐渐转向Transformer理由有三个。第一是可并行性。LSTM的隐状态是逐步传递的没法充分利用GPU并行训练一个像样的模型要等很久Transformer对整段序列同时计算训练和迭代速度快一个量级在量化研究里快速验证一个想法比什么都重要。第二是长程依赖的捕捉。LSTM理论上有长期记忆但实际训练中梯度衰减问题很难根治Transformer的self-attention让每个位置都能直接和所有历史位置对话跨度多大都只隔着一层注意力权重。第三是横截面建模更方便。资产定价不仅看时间序列还要看同一时点上所有资产之间的相对关系Transformer天然接受二维输入可以在batch里同时处理多个资产的序列让attention在各资产之间做信息交换。CNN更不用说了卷积核的局部视野和金融数据全局联动的特性不太匹配除非你把市场硬编码成图结构否则Transformer是更自然的选择。2. Transformer核心机制在金融场景的对应2.1 self-attention一场资产间的投票会议网上讲self-attention的资料很多但大多以翻译、文本分类为例。放到金融市场里我更愿意把它理解成一场投票会议。每个交易日的截面就像一场会议每只股票都向外界抛出一个问题Query“我明天的收益会受到谁影响”同时向外界展示自己的标签Key“我属于什么行业、动量多强、估值水平如何”。最后每只股票还要把自己的信息内容Value提供出来比如收益率、成交量、因子数值。注意力得分就是投票权当股票A的Query和股票B的Key匹配度高时A的预测会参考更多B的Value。这个机制天然契合金融里的“联动”和“传染”效应。同行业内一家公司业绩暴雷整个板块的估值预期都被重估宏观利率上升所有长久期资产同时承压小盘股流动性枯竭率先下跌的股票带着高波动股票一起走弱。传统模型要靠人设计这些关系Transformer让模型在数据里自己学出来。2.2 位置编码给时间一个合理的表示Transformer结构本身没有顺序信息所以需要用Positional Encoding把时间顺序注入到输入里。经典做法是正弦位置编码第i维的频率按指数方式衰减PE(pos, 2i) sin(pos / 10000^(2i/d_model)) PE(pos, 2i1) cos(pos / 10000^(2i/d_model))这套编码在NLP里能捕捉相对位置关系在金融里的道理类似但有一个关键差异金融序列的时间间隔往往是非均匀的。法定节假日、停牌、财报公告日都会造成时间断层。实操中我建议把原始日期先转换成“距当前交易日数”再进行位置编码如果特征里本身有“距下次财报披露的天数”这种事件型特征也可以直接拼进嵌入层效果往往比单纯依赖固定位置编码好。另一个小技巧是如果你预测的窗口不是固定5日而是动态的就别把位置编码写死让模型从位置嵌入里学出灵活的时间尺度。2.3 多头注意力与残差连接稳健性的来源多头注意力把整个d_model维度切成多个头每个头各自在不同的子空间做注意力计算。对应到金融场景非常直观第一个头可能在捕捉行业板块联动第二个头在捕捉大盘风格切换第三个头在捕捉波动率聚集效应。每个头的关注点不同最后拼接起来相当于一个内置的集成模型。残差连接和LayerNorm则保证了深层网络不会把原始因子信息冲掉。金融数据信噪比低任何一点信息丢掉都是浪费。我在实验里对比过加不加残差连接差距不是几个基点的IC而是模型能不能稳定收敛的问题。所以如果你自己搭Transformer结构这两层设计一定不要省。3. 实操用PyTorch搭建一个资产定价Transformer3.1 数据准备与防泄漏预处理我用日频多因子策略举例。股票池建议选流动性较好、数据完整的股票剔除ST、上市不满一年、停牌超过15天的标的避免极端状态影响模型。特征可以选动量类过去5日、20日、60日收益率、估值类PB、PE、PS、波动率类过去20日收益率标准差、换手率等。每个交易日的特征都要做横截面标准化也就是在同一时点对所有股票的因子做z-score。为什么强调“截面”因为如果用全样本或时间序列的均值方差就混进了未来信息造成数据泄漏。这是深度学习做金融数据时最常见、最隐蔽的错误比模型选错严重得多。标签用未来N日收益率比如未来5日从T1到T5的累计收益。这里要注意两个细节如果股票在T1停牌收益无法实际交易应该剔除如果T1涨停无法买入模拟收益也会失真最好在标签里做相应调整。数据划分采用严格的时间序列划分训练集用前70%时间验证集中间15%测试集最后15%绝不能用随机切分。随机切分在金融时间序列里等于给自己埋雷过去预测未来和随机预测完全是两回事。3.2 模型结构设计与关键代码先上模型代码包含三大部分输入嵌入层、TransformerEncoder、输出预测头。import math import torch import torch.nn as nn class PositionalEncoding(nn.Module): def __init__(self, d_model, max_len512): super().__init__() pe torch.zeros(max_len, d_model) position torch.arange(0, max_len, dtypetorch.float).unsqueeze(1) div_term torch.exp(torch.arange(0, d_model, 2).float() * (-math.log(10000.0) / d_model)) pe[:, 0::2] torch.sin(position * div_term) pe[:, 1::2] torch.cos(position * div_term) pe pe.unsqueeze(0) self.register_buffer(pe, pe) def forward(self, x): return x self.pe[:, :x.size(1), :] class AssetPricingTransformer(nn.Module): def __init__(self, feature_dim, d_model128, nhead8, num_layers4, dropout0.1): super().__init__() self.input_linear nn.Linear(feature_dim, d_model) self.pos_encoder PositionalEncoding(d_model) encoder_layer nn.TransformerEncoderLayer( d_model, nhead, dim_feedforward512, dropoutdropout, batch_firstTrue, activationgelu ) self.transformer nn.TransformerEncoder(encoder_layer, num_layers) self.head nn.Sequential( nn.Linear(d_model, 64), nn.GELU(), nn.Dropout(dropout), nn.Linear(64, 1) ) def forward(self, x): # x: [batch, seq_len, feature_dim] h self.input_linear(x) # 特征升维到d_model h self.pos_encoder(h) # 注入时间顺序 h self.transformer(h) # 多层self-attention h h[:, -1, :] # 取最后一个时间步做预测 return self.head(h).squeeze(-1)几个关键选型说下。input_linear先把原始因子维度统一映射到d_model相当于在入口做特征抽象再进attention网络。预测头就是简单MLP大部分非线性学习已经由encoder完成了head没必要搞太复杂。取最后一个时间步的输出很直观如果你的目标是用过去5日预测第6日收益最后一步已经聚合了前面的信息如果想要模型汇总整个窗口也可以用mean pooling但通常last token效果就不差。损失函数用HuberLoss而不是MSE因为金融标签厚尾严重HuberLoss能减少个别极端股票对梯度的主导。训练循环里我习惯加warmup、cosine衰减和梯度裁剪。金融数据的梯度噪声比NLP大学习率太猛很容易震荡optimizer torch.optim.AdamW(model.parameters(), lr1e-4, weight_decay1e-5) total_steps len(train_loader) * epochs scheduler torch.optim.lr_scheduler.OneCycleLR( optimizer, max_lr1e-4, total_stepstotal_steps, pct_start0.2 ) criterion nn.HuberLoss() for epoch in range(epochs): model.train() for X_batch, y_batch in train_loader: optimizer.zero_grad() pred model(X_batch) loss criterion(pred, y_batch) loss.backward() torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm5.0) optimizer.step() scheduler.step()3.3 评估看清IC和RankIC模型训练完之后我习惯先看两套指标IC和RankIC再做分层回测。IC是预测值和真实收益率的Pearson相关系数衡量模型的线性预测能力。RankIC用的是Spearman秩相关系数更抗极端值。金融里极端值频繁出现RankIC比IC更能反映模型真实的排序能力。代码很简单from scipy.stats import pearsonr, spearmanr pred model(X_test).detach().cpu().numpy() true y_test.numpy() ic pearsonr(pred, true)[0] rank_ic spearmanr(pred, true)[0] print(fIC: {ic:.4f}, RankIC: {rank_ic:.4f})分层回测是更贴近实战的验证方法按预测值从大到小排序等分成10组观察每组未来收益的单调性。如果多头组收益显著高于空头组说明模型捕捉到了横截面差异而不只是靠一两个极端股撑起来。不同模型的效果大致可以参考下面这个说明性对比模型测试集IC测试集RankIC训练耗时单epoch线性回归0.0320.027低XGBoost0.0510.049中LSTM2层0.0480.052高Transformer4层0.0670.071中高具体数值会因数据和参数不同而变但趋势上特征交互足够丰富时Transformer的IC会高于传统模型前提是数据预处理和防泄漏做对了。4. 训练调参与经验技巧4.1 防止过拟合的几个实用手段金融数据量相对NLP场景小得多Transformer结构又相对较大过拟合几乎是绕不开的问题。我的经验是四个维度同时压。模型维度上d_model从128起步就够不要一上来就上512小数据集撑不起大容量。正则化上dropout设0.1到0.2weight decay设1e-5左右这个范围在我试过的多个数据集上都比较稳。训练策略上早停比固定epoch数更实用验证集IC连续几个epoch不再提升就回退最优checkpoint。标签处理上如果噪声太大可以直接用rank变换后的标签替换原始收益率把极端值的影响压下来很多时候比调模型结构更有效。4.2 学习率、批次与训练稳定性金融市场数据的梯度噪声比NLP大学习率设太大容易震荡设太小收敛又太慢。我的经验值是warmup阶段用5%到10%的epoch做线性预热然后把学习率从0逐渐升到1e-4再用cosine或OneCycle衰减掉。梯度裁剪用max_norm5.0能防止个别极端样本把整个模型参数冲飞。batch size不要太大。金融数据内部相关性很强batch设太大反而会让模型在局部模式上过拟合我用128到256居多。如果你想在更大股票池上做实验可以适当加大batch但一定要同步调高weight decay和dropout不然验证集IC会掉得很快。4.3 特征层面的几个隐藏细节金融因子大多重尾直接用原始值喂进模型个别极端值会在线性层里造成很大梯度。我在入模前对所有特征做分位数裁剪把上下1%截断掉效果比单纯标准化更明显。离散特征的处理也是个容易被忽视的点。距离下次财报披露的天数、是否刚发生停牌这类事件型特征跟连续因子性质完全不同。建议在进入input_linear之前先分列处理离散特征过nn.Embedding连续特征保持数值再拼接起来统一映射不要混在一起硬塞进同一个线性层。5. 常见问题与排查技巧实录5.1 训练集IC很高测试集IC接近0这是最典型的问题几乎每个用深度学习做金融数据的人都遇到过。排查顺序我记得很清楚先查数据泄漏再看过拟合。数据泄漏具体看三点一标准化是否用了全样本统计量必须改成截面滚动标准化二标签是否包含未来信息比如把T1日已经发生的涨跌算进了预测目标三训练验证测试集是否时间重叠。如果这三处都正常再怀疑过拟合把d_model和层数降下来试试。5.2 attention模式退化所有头都关注同一个位置把attention map打印出来如果所有头的注意力都集中在一两个token上说明模型没在学有意义的交互更像在学某种捷径。原因通常是输入序列太短或者信息冗余太强。解决办法是加长回看窗口比如从5日拉长到20日或者对输入特征做降维去冗余。如果序列长度实在有限可以用窗口内的统计量比如均值、方差、斜率作为额外特征补充进去让attention有更多内容可以关注。5.3 预测结果和大盘高度相关横截面区分度差这个现象说明模型可能只学到了市场贝塔没学到超额收益信号。我在自己的研究里遇到过好几次最后发现是两个原因。标签上如果用原始收益做目标模型的最优策略可能就是预测市场走势因为市场涨跌解释了收益方差的大部分。解决办法是用超额收益也就是个股收益减去同期市场收益作为训练目标。特征上也同样要多放横截面相对量比如个股动量在全市场的分位、个股估值在行业内的分位让模型更容易看到横截面差异。5.4 梯度不稳定和loss发散先检查标签是不是存在极端值如果没做截断或rank化HuberLoss都压不住。检查完之后再看学习率是不是过大、batch size是不是过小导致梯度方差太大。最后梯度裁剪是很有用的保底手段但不能只靠它兜底根源问题还是要从数据和标签入手。5.5 复现性问题金融研究里最容易被忽略但最容易炸的问题。很多次重新跑一遍发现结果对不上了排查半天最后发现是随机切分数据导致训练集和验证集在不同次实验里不一样。现在的做法是固定全局随机种子把训练、验证、测试的分界日期存成配置文件每次实验都从配置里读保证可复现。checkpoint保存时也把数据划分索引一起存不然模型权重恢复了数据对不上一切白搭。如果你也想在自己的研究里试这个方向我建议先从小样本、低特征维度开始把基准模型和评估流程彻底跑通再去堆模型复杂度。金融市场的数据量相比NLP场景小得可怜过拟合的教训比模型收益来得快得多。先学会观察模型的预测形态、IC曲线和attention分布再谈调模型结构这条路会走得稳很多。本文还有配套的精品资源点击获取