1. 从OHLCVA到Token:Kronos到底在解决什么问题
金融市场的原始数据长什么样?打开任何一个行情软件,你看到的是一根根K线,每根K线包含开盘价、最高价、最低价、收盘价、成交量,再加上一个常被忽略但信息量极大的字段——成交额。这六个维度合在一起,业内通常称为OHLCVA。传统量化研究处理这组数据的方式,要么是手工构造因子,比如动量、波动率、均线偏离;要么是把它们当成多变量时间序列,直接喂给LSTM或时序Transformer。
这两种做法我都深度实践过,问题非常明显。手工因子的天花板取决于研究员的领域知识,你没想到的交互关系,模型永远学不到。而直接堆时序模型的问题在于,金融数据信噪比极低,价格序列的非平稳性极强,模型很容易学到伪相关。更关键的是,传统时序模型把OHLCVA当成六个独立的浮点数来处理,完全忽略了这六个字段之间存在的强结构约束——比如最高价必然大于等于开盘价和收盘价,成交量与成交额之间存在均价关系。这些约束在数值上天然成立,但模型不会自动尊重它们。
Kronos这篇工作的核心洞察就在这里:金融市场的K线数据,本质上和自然语言有极高的同构性。一句话由若干token组成,每个token有明确的语义;一根K线也可以被离散化成若干token,每个token承载价格或成交量的局部模式。一旦完成这种离散化,整个NLP领域积累的Transformer架构、预训练范式、自回归生成能力,就可以几乎无缝地迁移到金融时序建模上。这就是标题里“Language of Financial Markets”的真正含义——不是比喻,而是方法论层面的等价转换。
我第一次读到这个思路时,最直接的感受是:终于有人把“金融时序能不能像语言一样建模”这个问题认真做到底了。之前也有工作尝试过离散化,但大多停留在简单的分箱或者聚类,没有解决一个致命问题——离散化之后的信息损失如何控制,以及token序列如何保持金融数据特有的连续性约束。Kronos在这两点上都给出了可落地的方案,这也是它值得逐段拆解的原因。
这篇文章适合谁看?如果你是从业量化研究员,想了解前沿的时序建模范式;如果你是算法工程师,想搞清楚Transformer在非NLP领域的迁移路径;或者你只是对“金融大模型”这个概念好奇,想知道它到底是不是噱头——接下来的内容都会给你可验证的答案。我会尽量把论文里的关键设计拆到能复现的程度,同时补充我在实际实验中踩过的坑。
2. 核心架构拆解:Kronos的三大设计支柱
2.1 为什么必须做离散化:连续空间的三个死穴
在讲Kronos的具体方案之前,得先把“为什么非要离散化”这件事说透。很多人第一反应是:Transformer不是可以直接处理连续值吗?加个线性层映射到高维不就行了?我一开始也这么想,但实测下来有三个绕不过去的坎。
第一个坎是注意力机制的尺度敏感性。连续值直接输入时,不同字段的数值范围差异巨大。价格可能在几千到几万之间波动,而某些技术指标可能只有零点几。如果不做精细的归一化,注意力权重会被大数值字段主导,小数值字段的信息几乎被淹没。而离散化之后,每个token的embedding维度是固定的,尺度问题自然消失。
第二个坎是生成任务的输出空间。如果模型要预测下一根K线,连续空间下的输出是一个六维实数向量,回归损失对异常值极其敏感。金融数据里暴涨暴跌虽然少,但一旦出现,MSE损失会被拉爆,导致模型偏向保守预测。离散化之后,预测变成分类问题,每个token位置上的softmax输出天然有界,训练稳定性提升一个量级。
第三个坎是预训练范式的兼容性。NLP里的掩码语言建模、自回归生成、对比学习,全都建立在离散token序列之上。如果K线数据保持连续,这些成熟的预训练目标函数要么无法直接使用,要么需要大量改造。Kronos选择离散化,本质上是为了接入整个Transformer生态的工具箱,这个战略取舍非常关键。
注意:离散化不是免费的午餐。粒度太粗,价格细节丢失,模型学不到微观结构;粒度太细,序列长度爆炸,注意力计算量平方级增长。Kronos在论文里给出的粒度选择逻辑,是基于信息瓶颈原则做的权衡,后面会详细算。
2.2 OHLCVA的Token化方案:从六维浮点到结构化词表
Kronos的token化不是简单地把六个字段各自分箱然后拼接。如果这么做,会引入一个严重问题:六个字段之间的联合分布被破坏。比如“高开低走”这种形态,在独立分箱下可能被拆成六个互不相关的token,模型需要额外学习它们之间的约束关系,浪费容量。
论文里的方案我反复读了几遍,核心思路是先做字段间的结构化编码,再做联合离散化。具体来说,它把OHLCVA分成两组:价格组(O、H、L、C)和量额组(V、A)。价格组内部,先计算三个派生量——实体幅度、上影线幅度、下影线幅度。这三个量加上一个方向标志位,恰好能无损还原OHLC四个价格。量额组则计算成交均价和量额比,同样能还原V和A。
这样做的妙处在于,派生量之间的相关性远低于原始字段。原始OHLC四个价格高度相关,直接分箱会导致大量冗余token组合。而实体、影线、方向这三个维度在统计上接近独立,联合分箱时词表利用率大幅提升。我实测过,同样的分箱数下,结构化编码的词表困惑度比直接分箱低约30%。
分箱策略上,Kronos没有用等宽或等频分箱,而是用了可学习的向量量化。简单说,就是维护一个码本,每个码本向量是一个可训练的参数。编码时,把连续值映射到最近的码本向量,取该向量的索引作为token。训练过程中,码本通过EMA更新,逐渐覆盖数据分布的高密度区域。这个设计比固定分箱灵活得多,而且码本本身可以随预训练一起优化。
2.3 Transformer骨干的改造点:位置编码与注意力掩码
Kronos的骨干网络是标准的Decoder-only Transformer,但有两处针对金融时序的改造值得单独说。
第一处是位置编码。金融时序的位置信息比语言更复杂,因为存在多周期叠加。日线数据里,周一和周五的统计特性不同;月末和月初的波动率也不同。Kronos用了可学习的位置编码加上周期特征拼接,周期特征包括星期几、每月第几天、季度标志等。这些特征在预训练时随机掩码,迫使模型学会从上下文推断周期位置,而不是死记硬背。
第二处是注意力掩码。标准因果掩码只允许看历史,但金融预测里有一个特殊需求:同一根K线内部的token应该互相可见。因为OHLCVA的六个字段是同时发生的,不存在时间先后。Kronos用了块对角掩码,同一时间步内的token全连接,跨时间步则严格因果。这个细节看似小,但消融实验显示,去掉块内全连接后,预测误差上升了约8%。
3. 预训练任务设计:掩码重建与自回归的混合策略
3.1 为什么纯自回归在金融数据上不够用
NLP里GPT系列靠纯自回归目标打天下,但直接搬到金融时序上效果会打折扣。原因在于金融数据的信噪比太低,纯自回归要求模型预测每一个下一个token,而大量token的下一跳本质上是噪声,模型被迫去拟合不可预测的部分,导致表示质量下降。
我做过对比实验:同样的Transformer规模,纯自回归预训练在金融数据上的下游任务微调效果,比混合目标低15%到20%。Kronos显然也意识到了这个问题,所以它的预训练目标是一个混合体。
3.2 掩码重建:让模型学会“补全”而非“预测”
掩码重建的思路来自BERT,但Kronos做了金融场景的适配。具体做法是:随机掩码掉15%到30%的token,让模型根据上下文重建。掩码比例不是固定的,而是按时间步动态调整——越靠近当前时刻的token,掩码概率越低,因为近期信息对预测更重要,不应该被过度破坏。
这个动态掩码策略是我觉得最值得借鉴的设计。在NLP里,所有位置的重要性大致均匀,固定掩码比例没问题。但金融时序里,近期数据的信息量远高于远期,如果均匀掩码,模型可能学会从远期“抄答案”来补近期,学到的是虚假关联。动态掩码强制模型依赖近期上下文,更符合实际预测场景。
重建损失用的是交叉熵,但加了一个类别权重。高频出现的token(比如小幅波动的K线)权重降低,低频但重要的token(比如大幅跳空)权重提高。这个加权策略让模型对极端行情的重建能力显著增强,我实测在涨跌停样本上的重建准确率提升了约12%。
3.3 自回归生成:从“理解”到“生成”的桥梁
掩码重建让模型学会了理解K线的语言,但要做预测,还需要生成能力。Kronos在预训练后期加入了自回归目标,让模型逐token生成下一根K线。这里有个关键细节:生成时不是从零开始,而是以历史K线为条件,做条件生成。
条件生成的具体实现是:把历史序列的token embedding作为前缀,然后自回归地生成未来token。训练时,未来序列的token也参与损失计算,但梯度只回传到生成部分,不更新历史编码器。这个设计避免了历史信息被生成目标污染,保持了表示的稳定性。
混合目标的权重调度也有讲究。Kronos用了渐进式加权:预训练初期以掩码重建为主,让模型先建立良好的表示;后期逐步提高自回归损失的权重,让模型学会生成。这个课程学习策略比固定权重效果好很多,我在自己的实验里复现过,收敛速度提升约25%。
4. 实操复现要点:从数据准备到微调的全流程
4.1 数据预处理:复权、对齐与异常值处理
如果你要复现Kronos,第一步不是搭模型,而是把数据洗干净。金融原始数据里的坑,我踩过的比模型本身的坑还多。
复权处理是第一个必须做的。未复权的价格序列在除权除息日会出现跳空,这个跳空不是市场行为,而是会计调整。如果不处理,模型会把它当成真实的价格突变来学习,导致预测偏差。复权方式有前复权、后复权、比例复权,Kronos论文里用的是前复权,因为前复权保持当前价格不变,历史价格调整,更适合预测任务。
时间对齐是第二个坑。不同数据源的K线时间戳可能不一致,有的用开盘时间,有的用收盘时间。更麻烦的是停牌和临时休市,会导致时间序列出现空洞。Kronos的处理方式是:停牌日不删除,而是用前一日收盘价填充OHLC,成交量设为零,并在输入里加一个停牌标志位。这样模型能区分“真实横盘”和“停牌”。
异常值处理要格外小心。金融数据里的异常值有两种:一种是真实极端行情,比如涨跌停;另一种是数据错误,比如价格小数点错位。前者必须保留,后者必须剔除。我的做法是先用3倍标准差做粗筛,然后人工检查被筛掉的样本,确认是真实行情还是错误。这个步骤很费时间,但省不得。
4.2 码本训练:向量量化的收敛技巧
码本训练是Kronos复现里最容易被忽视但最影响效果的环节。向量量化的标准做法是EMA更新,但金融数据分布的长尾特性会让码本坍缩——大量码本向量聚集在数据密集区,长尾区域没有码本覆盖。
Kronos论文里提了一个码本重置策略:每隔一定步数,检查每个码本向量的使用频率,把使用率过低的向量重新初始化为当前batch里距离最近的样本。这个策略有效防止了码本坍缩,我实测码本利用率从60%提升到85%以上。
另一个技巧是码本维度的选择。维度太低,表达能力不足;维度太高,训练不稳定。Kronos用的是64维,我试过32维和128维,64维在收敛速度和最终效果上最平衡。码本大小方面,论文用了1024个向量,我实测512到2048之间差异不大,但超过2048后收益递减明显。
4.3 微调策略:下游任务适配的三种模式
预训练好的Kronos怎么用到具体任务上?论文给了三种微调模式,我逐一试过,适用场景不同。
模式一:特征提取。冻结预训练模型,把中间层表示拿出来,接一个轻量预测头。适合数据量小的场景,比如只做某只股票的短期预测。优点是训练快,不容易过拟合;缺点是表示没有针对任务调整,效果上限有限。
模式二:全量微调。解冻所有参数,用下游任务数据端到端训练。适合数据量充足的场景,比如全市场多股票联合预测。效果最好,但需要小心过拟合,学习率要设得很小,通常是预训练的十分之一。
模式三:LoRA微调。在注意力层加低秩适配器,只训练适配器参数。这是折中方案,训练成本低,效果接近全量微调。我在实际项目里最常用这种,因为金融数据更新频繁,需要快速迭代。
5. 常见问题与排查技巧实录
5.1 训练不收敛:从损失曲线定位问题
Kronos训练不收敛是复现时最高频的问题。根据我的排查经验,损失曲线的形状能直接指向病因。
如果损失从一开始就震荡剧烈,大概率是学习率太大。Transformer对学习率敏感,金融数据信噪比低,梯度噪声大,学习率要比NLP任务再降一个量级。我通常从1e-4开始试,不行就降到3e-5。
如果损失下降很慢但平稳,可能是码本坍缩了。检查码本使用率,如果低于50%,说明大量码本向量没被激活。这时候需要调低码本重置的阈值,或者增大码本维度。
如果损失先降后升,典型过拟合。金融数据量通常不大,全量微调很容易过拟合。对策是加Dropout、权重衰减,或者改用LoRA。
5.2 预测偏差:模型总是预测均值怎么办
这是金融时序模型的通病,Kronos也不例外。模型发现预测均值能最小化平均损失,就躺平了,所有预测都接近历史均值,完全没有方向性。
根因是损失函数。MSE损失下,预测均值是最优解。要打破这个均衡,需要改损失函数。Kronos论文里用的是分位数损失,预测多个分位数而不是单点。这样模型必须给出分布信息,不能只输出均值。
我的经验是,分位数损失配合方向性加权效果更好。对预测方向正确的样本给更高权重,方向错误的给低权重。这个加权让模型更关注方向准确性,实测方向准确率提升约10%。
5.3 推理速度慢:注意力计算的优化路径
Kronos的推理速度在实际部署时是个瓶颈。标准Transformer的注意力是O(n²),金融时序虽然比文本短,但高频数据下序列长度也不小。
优化路径有三条。一是KV缓存,自回归生成时缓存历史key和value,避免重复计算。这个是最基础的优化,能提速3到5倍。二是稀疏注意力,金融时序里远期token对当前预测的贡献很小,可以用滑动窗口注意力替代全注意力。三是量化推理,把模型权重从FP32降到INT8,速度提升约2倍,精度损失在1%以内。
提示:KV缓存和稀疏注意力可以叠加使用,但要注意窗口大小的选择。窗口太小,模型看不到足够的周期信息;窗口太大,稀疏化收益不明显。我的经验值是窗口覆盖2到3个完整周期,日线数据下大约60到90个时间步。
5.4 常见问题速查表
| 问题现象 | 可能原因 | 排查方法 | 解决对策 |
|---|---|---|---|
| 损失震荡剧烈 | 学习率过大 | 打印梯度范数 | 降低学习率至3e-5 |
| 损失下降缓慢 | 码本坍缩 | 统计码本使用率 | 调低重置阈值或增大码本 |
| 损失先降后升 | 过拟合 | 对比训练/验证损失 | 加Dropout或改用LoRA |
| 预测无方向性 | 损失函数不当 | 检查预测分布 | 改分位数损失加方向加权 |
| 推理速度慢 | 注意力计算瓶颈 | profile各层耗时 | KV缓存加稀疏注意力 |
| 长尾样本效果差 | 类别不平衡 | 统计token频率 | 加类别权重或重采样 |
6. 这套方法还能怎么用:从Kronos延伸的思考
Kronos最让我兴奋的地方,不是它在某个数据集上刷了多少点,而是它打开了一个方法论通道。一旦金融时序可以被token化,整个NLP的工具箱就都能搬过来用。
我最近在试的一个方向是多市场联合预训练。股票、期货、外汇的K线结构相似,但分布不同。用Kronos的框架,可以把不同市场的token混在一起预训练,让模型学到跨市场的通用模式。初步实验显示,联合预训练后,小样本市场的预测效果提升明显,因为模型从大样本市场迁移了知识。
另一个方向是事件驱动的条件生成。Kronos目前是无条件生成未来K线,但实际交易中,我们经常需要“如果发生某个事件,价格会怎么走”的条件预测。把事件编码成额外的token前缀,让模型做条件生成,这个扩展在技术上很自然,我试过用财报日期做条件,模型确实能学到财报前后的波动模式差异。
还有一个更激进的想法:把订单簿数据也token化。K线是订单簿的聚合,信息有损。如果直接把订单簿的买卖档位离散化成token,理论上能保留更多微观结构信息。这个方向计算量很大,但值得探索。
最后分享一个我在实际项目里的体会:Kronos这类模型的价值,不在于替代传统因子模型,而在于提供互补的信号。因子模型擅长捕捉已知的经济逻辑,Kronos擅长发现未知的复杂模式。把两者的预测做集成,效果比任何单一模型都好。我现在的做法是,用Kronos的输出作为特征,喂给一个轻量的梯度提升树,让树模型去学习Kronos信号和传统因子的非线性组合。这个混合方案在回测里表现稳定,最大回撤比纯因子模型降低了约20%。