资讯详情

诺奖物理思想落地量化:用“市场记忆”构建可回测预测模型

📅 2026/10/12 13:27:18 | 华诺云谱 👁 阅读
诺奖物理思想落地量化:用“市场记忆”构建可回测预测模型
2024年诺贝尔物理学奖揭晓后量化圈的反应很有意思。很多人诧异物理学奖落到了机器学习头上但如果你做过一段时间的量化预测模型就知道“市场记忆”这个概念和物理奖里那套联想记忆网络几乎是天生一对。这篇不是科普诺奖而是想把获奖工作的底层逻辑搬进我们自己每天打交道的K线、涨跌和信号里落地成一个可回测、可迭代、带“市场记忆”的量化预测模型。文中含完整的数学框架、Python代码骨架和实测排障经验适合被过拟合折磨过的量化开发者也适合用物理思维做金融建模的研究者。1. 物理奖与量化交易的交叉点一个被忽视的“记忆”视角1.1 诺奖级工作到底“物理”在哪里先说结论这届诺奖的核心贡献是把物理系统的能量景观、自旋相互作用、统计力学方法变成了一套可以训练、可以收敛的机器学习范式。传统神经网络是“从数据里学权重”而获奖工作的底层更接近物理系统里所有单元互相作用整体有一个能量函数系统演化就是往能量低的地方走训练则是在“记住某些状态”和“最低能量结构”之间做权衡。说人话就是物理学家把“记忆”定义成了能量景观里的山谷。每个被记住的稳定状态就是山谷底部。你给系统一个残缺的输入它会自动沿着能量面滑向最近的记忆谷底完成“补全”。这种模型在几十年前主要用于图像恢复、联想记忆这类任务但它在金融时间序列里的潜力一直被低估。我做量化这些年最头疼的问题不是信号不够多而是信号没有“上下文”。传统因子模型把今天的收益率、波动率算出来然后映射成明天的多空判断本质上是在和“无记忆的截面”打交道。市场昨天的状态是什么样的历史上有没有和当前特别像的一段时间如果有一模一样的记忆那段时间之后市场怎么走的这类问题恰恰是联想记忆网络最擅长回答的。1.2 市场为什么可以被当作“记忆系统”金融市场价格行为不是纯随机的它有强烈的状态重复倾向低波动区间里指数温和上行高波动区间里指数剧烈震荡突破行情往往出现在量能突然放大的那几天。这些“状态模式”会在不同年份反复出现但每次细节都略有不同就像同一张照片被加了噪声。传统监督学习面对这种重复加噪的模式需要一个很大的样本量才能稳定拟合。而联想记忆网络天生就是为“小样本、带噪声、模式匹配”设计的它能存下若干历史状态然后在当前状态中找到最近的“历史影子”再用这个影子的后续收益分布来做预测。这套逻辑非常像人做交易时的直觉“这个盘面和2019年某段时间几乎一样那次之后涨了三天。”我并不是说物理奖的工作可以直接搬到K线上就赚钱。金融市场的状态一直在漂移物理系统的规则却是固定的所以后续章节会重点讨论“市场记忆”和物理记忆的差异以及怎么在量化里做可控的“遗忘”。2. 市场记忆的数学框架从模式存储到状态联想2.1 记忆的数学模型多粒子系统中的“吸引子”为了不让“记忆”停留在感性的比喻层面需要一个严格的数学表达。最简单的联想记忆模型把所有市场状态编码成一个向量 s∈{-1,1}^NN 是状态维度。每个历史状态 s_i 看成 N 个互相作用的粒子模型要做的是找到一个对称权重矩阵 W使得每个已存储状态都是能量函数的局部极小值。能量函数的标准写法是E -1/2 s^T W s回忆联想过程就是重复执行更新规则s_i^{t1} sign(∑_j W_ij s_j^t)这条规则的含义很直观每个“粒子”下一时刻的方向由所有其他粒子的加权投票决定投票结果为正就变成1为负就变成-1。通过不断迭代整个状态向量会收敛到某个能量低谷也就是离初始状态最近的那个“历史记忆”。最经典的权重学习规则是Hebbian外积规则W ∑_k s_k s_k^T - M I其中 M 是存储模式的个数外积规则的好处是单次遍历就能完成训练不需要反向传播和梯度下降。这种“看一眼就记住”的机制放在高频更新的量化系统里非常诱人。不过在实际金融场景里我建议把外积规则换成伪逆规则又称投影记忆规则W S(S^T S)^{-1} S^TS 以历史模式作为列向量这么做有两个理由一是金融特征之间相关性高外积规则容易收到模式串扰的惩罚二是伪逆规则在小样本、高相关场景下存储容量明显高于外积规则。伪逆规则的本质是把每个存储模式做成能量景观中的一个固定点回忆时系统会把输入“投影”到由这些固定点张成的子空间再通过符号函数离散化。2.2 熵、噪声与记忆容量金融状态不是铁磁体这里必须泼一盆冷水。物理学家研究自旋系统时相互作用规则是严格固定的温度、磁场都可控。金融市场的“相互作用规则”本身会漂移状态向量里也充满噪声和异常值。直接把诺贝尔奖的模型拿来做量化会踩一个很大的坑记忆容量超载。在标准联想记忆模型里N 个神经元大约能稳定存储 0.14N 个模式。超过这个容量召回时会出现“伪记忆”——系统会收敛到一个从未存储过的新状态或者收敛到两个状态的混合体。这种退化现象在金融数据里比图像数据更严重因为不同市场状态之间的相关性很高比如缩量阴跌和放量阴跌在一维收益率特征上几乎无法区分。所以我做了两个工程化改造。第一对存储模式做“稀疏化”不把每天的状态都存进记忆库而是用聚类把相似状态合并成一个代表性模式让记忆数量远小于容量上限。第二对时间轴引入衰减权模式不是永久被记住的越靠近当前时刻的模式在能量函数中的权重越高这就是后面要讲的“市场遗忘曲线”。2.3 从能量景观到概率记忆类比的输出不是点位是分布大多数把AI用在量化上的尝试最终输出的都是“明天涨还是跌”或者“未来五天收益率预测值”。这套记忆框架的输出形式应该不一样它应该输出一个“概率分桶”。具体流程是当前时刻得到状态向量 x0联想网络迭代收敛到某个历史状态 s_k然后去统计 s_k 出现之后未来 1/3/5 天的收益率分布。注意这里不是用整个历史收益做经验分布而是只使用状态 s_k 被“触发”之后的那几段后续收益。这种做法本质上是一种基于最近邻的条件概率估计只是“最近邻”的定义从欧氏距离换成了能量场中的吸引域距离。这种设计的好处是天然可解释你可以直接告诉交易员当前行情最像历史哪个状态那个状态出现后历史上有多少次上涨、多少次下跌平均赚多少亏多少。在实盘决策时“我不知道接下来怎么办”是一件很危险的事而记忆模型能把“不知道”转化为“历史上有多少同类样本”这本身就是一种风险控制。3. 实战构建一个带“市场记忆”的量化预测模型3.1 整体架构与数据准备先看整个系统长什么样。数据进来后依次经过四个环节特征工程、记忆库构建、联想召回、分布映射。第一个环节是特征工程这一步决定记忆的质量。我用四组特征作为状态向量的基础动量特征过去 5 日收益率、过去 10 日收益率衡量短期趋势方向。波动率特征过去 20 日收益率标准差以及过去 20 日振幅均值描述市场情绪烈度。量能特征当日成交量相对 20 日均量的比值跟踪资金活跃度。均线偏离特征收盘价相对 20 日均线和 60 日均线的偏离幅度刻画价格乖离。这些特征都是常规技术指标但它们组合起来可以比较好地描述“市场正处于什么季节”。为了把连续特征转成联想记忆需要的双极向量我采用了分位数二值法对每个特征以滚动窗口的历史分位数比如 40% 和 60%为阈值高于上阈值为1低于下阈值为-1中间区域记为0。初始输入中允许0表示“不确定”联想更新时只对非零分量做投票这样可以大幅减少噪声对召回的干扰。作为示例我用公开可得的指数日线数据做演示你也可以换成任何品种的K线。数据范围取最近三年前 60% 作为记忆库构建区间后 40% 作为样本外测试区间。这里不建议用全部历史数据构建记忆库因为越古老的状态对当前市场的参考价值越低强行加入只会稀释记忆容量。3.2 记忆库构建与联想调用的完整流程记忆库的构建我分成三步第一步是滑动窗口抽取候选状态。每隔 3 个交易日取一次特征向量这样既能覆盖足够多的状态又避免相邻日状态高度雷同。对每个候选状态用它之后 5 日的涨跌幅打上标签1表示上涨-1表示下跌。第二步是聚类压缩。我会把候选状态用简单聚类聚成若干个簇然后用簇中心作为记忆库中的“原型状态”。为什么不能直接存全部候选状态一方面存储容量限制另一方面相似状态堆在一起会导致召回时能量景观里出现“过宽山谷”任何带一点噪声的输入都会落到同一个谷底反而丧失区分度。聚类数量我一般控制在一个经验范围状态维度 N 的 0.3 到 0.8 倍。第三步是训练记忆权重矩阵。把聚类得到的原型状态 s_1, s_2, ..., s_M 排成矩阵 S然后计算 W S(S^T S λI)^{-1} S^T。这里的 λ 是一个极小的正则项防止 S^T S 奇异。注意这个 W 不需要反复迭代计算一次性求逆即可。联想调用过程没有那么复杂。每个交易日收盘后把当日特征向量二值化得到 x0然后执行异步或同步更新规则。同步更新在金融场景里更稳定因为所有“神经元”同时刷新不会因为更新顺序不同产生随机偏差。我设定的最大迭代次数通常是 30 次实际测试中绝大多数样本在 5 到 10 次内就收敛了。代码层面记忆网络收敛后的状态 s* 不一定是记忆库里的某个原型而可能是一个能量景观中的稳定混合态。这时可以计算 s* 与每个原型状态的汉明距离取距离最近的 1 到 3 个原型用它们的标签分布混合出最终的涨跌概率。如果一个交易日里模型连“最接近的历史状态”都找不到——也就是说当前状态向量离所有记忆库原型的距离都很大那这个信号就不该被输出。这种“无法记忆”的阈值机制比硬性预测要可靠得多。3.3 信号生成与风险过滤让模型学会“不知道”模型给出的原始信号是一个分布而不是一个点预测。我把未来 5 日的超额收益分成三段大于 0.5% 记为“上涨区间”小于 -0.5% 记为“下跌区间”中间为“震荡区间”。记忆召回后统计历史上最接近的原型状态触发后未来 5 日落入各段的频数。生成信号有三条规则当“上涨区间”概率超过 60% 且“震荡区间”概率低于 30%生成多头信号。当“下跌区间”概率超过 60% 且“震荡区间”概率低于 30%生成空头信号。其他情况全部记为“无信号”不进仓。这套规则迫使模型只在“历史记忆非常明确”的时候出手其他时间一律等待。我在可解释性上做的最重要一件事是把每个信号附带上“记忆强度”字段该信号对应于几个历史原型、这些原型在记忆库中的日期间隔、平均能量深度是多少。实盘复盘时如果连续亏损优先检查是不是信号来自一个只有两三个历史样本支撑的“孤岛记忆”。风险过滤同样重要。我加了两个硬性过滤波动率过滤和能量距离过滤。波动率超过近一年 80 分位时强制关闭信号输出因为高波动期状态切换太快记忆召回很容易失真。能量距离过滤是指当前状态经过联想迭代后与目标原型状态的平均汉明距离超过阈值比如 0.3N说明当前盘面在历史中没有可靠副本此时也强制空仓。这两个过滤在样本外测试中至少过滤掉了四分之一的无意义信号但保留信号的胜率随之明显抬升。4. 完整代码骨架用最快路径跑通记忆预测4.1 极简记忆网络模块几十行代码实现能量景观先说清楚这个模块的作用。金融里不需要完全复刻教科书里的图像联想网络只需保留“存储—召回—能量”三个核心能力。下面这个类实现了全部逻辑。import numpy as np class MarketMemory: def __init__(self, reg1e-4): self.W None self.weight None self.reg reg def train(self, prototypes, weightsNone): prototypes: shape (N, M)每一列是一个市场原型状态取值 -1/0/1 weights: 每个原型对应的权重可以是时间衰减权重也可以全为1 N, M prototypes.shape if weights is None: weights np.ones(M) # 投影记忆规则W S W (S^T W S reg I)^{-1} S^T W Sw prototypes * weights.reshape(1, -1) gram Sw.T prototypes self.reg * np.eye(M) coeff np.linalg.solve(gram, np.eye(M)) self.W prototypes coeff Sw.T self.prototypes prototypes self.weight weights def energy(self, state): return -0.5 * state self.W state def recall(self, x0, max_iter30, threshold0.0): x x0.copy() for _ in range(max_iter): y x self.W - threshold y np.where(y 0, 1.0, -1.0) # 保留输入中标记为0的“不确定”特征不强制投票 y[x0 0] x0[x0 0] if np.array_equal(y, x): break x y final_energy self.energy(x) dist 0.5 * (self.prototypes.shape[0] - self.prototypes.T x) return x, final_energy, disttrain 方法里的核心是投影矩阵计算prototypes coeff Sw.T等价于把输入空间投影到原型张成的子空间。recall 方法里的threshold参数控制“投票门槛”提高它会迫使系统更谨慎地切换状态。4.2 特征工程与信号生成把记忆模块接到量化流程里记忆网络只是整个流水线的一块砖还需要把行情数据变成状态向量、把召回结果变成交易信号。先看特征工程这一段def build_features(df): df df.copy() df[ret_5] df[close].pct_change(5) df[ret_10] df[close].pct_change(10) df[vol_20] df[close].pct_change().rolling(20).std() df[amp_20] (df[high] - df[low]).rolling(20).mean() / df[close] df[volume_ratio] df[volume] / df[volume].rolling(20).mean() df[ma20_bias] df[close] / df[close].rolling(20).mean() - 1 df[ma60_bias] df[close] / df[close].rolling(60).mean() - 1 return df.dropna()然后把连续特征映射到双极向量。这里用一个qcut_binary函数按滚动分位数把特征分到 -1/0/1 三个档位def qcut_binary(series, lo_q0.4, hi_q0.6, window120): lo series.rolling(window).quantile(lo_q) hi series.rolling(window).quantile(hi_q) res np.zeros(len(series)) res[series hi] 1 res[series lo] -1 return res在实际测试中我建议不要只用一个特征对应一个神经元而是把一个特征按多个分位数拆成多个神经元。比如动量特征同时用 0.25 分位数和 0.75 分位数生成两个二值特征这样能保留“强趋势”和“弱趋势”的层次信息。把四类基础特征扩展到 20 到 30 个神经元记忆容量和表达力都在一个合理的区间。信号生成部分的代码也不复杂。每个交易日做一次记忆调用然后查询原型状态对应的历史标签分布def gen_signal(model, x0, proto_labels, top_k3): _, _, dist model.recall(x0) idx np.argsort(dist)[:top_k] ups proto_labels[idx].mean(axis1).sum() downs (1 - proto_labels[idx]).sum(axis1).sum() total len(idx) up_prob ups / (total * len(proto_labels[0])) down_prob downs / (total * len(proto_labels[0])) if up_prob 0.6 and down_prob 0.3: return 1 if down_prob 0.6 and up_prob 0.3: return -1 return 0这里proto_labels是每个原型状态对应的未来收益涨跌标签矩阵top_k 取最相似的前 k 个原型做“邻居投票”。需要特别提醒一点构建记忆库和原型标签时只用 T 日之前的数据回测时从 T1 日开始逐日滚动调用。所有滚动窗口都不得包含未来信息这是量化回测的生命线。4.3 参数与调优目录一组可以直接上手的经验值经过多轮测试我整理了一张参数参考表参数名作用经验值调优方向特征维度 N状态向量的“神经元”数量20~40维度太高记忆容量要求指数级上升太低则区分度不够原型簇数量 M记忆库中存储的状态数0.3N~0.8N太少召回粗糙太多串扰严重top_k 召回数预测时参考的最近原型数1~5越小越敏感越大越平滑迭代次数上限联想收敛步数20~40收敛慢时优先降维度分位数阈值特征二值化的阈值0.4/0.6窄阈值更敏感宽阈值更稳健能量距离阈值过滤“无记忆”行情的界限0.3N实盘中可结合滚动分位数自适应这套参数不是万能药但它是很好的起点。模型最大的风险在原型数量上如果你把聚类数量设得很大训练集上信号会很丰富样本外却迅速退化。所以进入实盘测试前一定要先做原型数量的敏感性分析把 M 从 0.1N 逐步增加到 N观察样本外胜率和最大回撤怎么变化。5. 常见问题与排查技巧实录5.1 记忆混乱联想结果在几个状态间来回跳跑测试时最烦的症状是同样的输入连续调几次模型有时回到状态A有时回到状态B完全没有稳定性。这类问题的根源一般是存储状态之间相似度过高。我排查时优先计算原型状态两两之间的汉明距离如果最小汉明距离小于 0.2N就说明两个原型几乎没区别需要合并。解决思路也简单先做特征去相关用 PCA 把特征压缩到正交空间再跑聚类或者直接增加特征维度把“肉眼看上去差不多的行情”拆成更多细节。另一个技巧是调高 recall 的 threshold 参数相当于给状态切换加了一个摩擦系数能减少振荡。5.2 过拟合但不是深度学习那种过拟合记忆模型同样会过拟合只不过表现出来的是“记忆库装满后信号质量崩塌”。原因在于当原型数量逼近存储容量上限能量景观里会出现伪记忆谷底模型开始“回忆”那些历史上从未真正出现过的状态。这种情况没法靠加 Dropout 缓解只能做减法减少原型数量或者对原型做稀疏化只保留有显著标签区分度的状态。我常用一个检查方法把记忆库连接权重矩阵 W 的特征值分布打印出来。健康状态应该是少数大特征值对应部分原型其余特征值接近零如果特征值分布非常平坦说明记忆库已经超载伪记忆正在形成。5.3 极端行情面前记忆模型失效很正常有一类失败无法靠调参解决行情特征完全偏离历史记忆区间。比如流动性骤变或者某个市场结构突变模型找不到任何相近原型强制召回的结果就是在胡说八道。我的做法是设置“不知道”开关用能量距离和记忆支持次数两个维度判断。当最接近原型的历史出现次数低于某个阈值比如 10 次或者能量距离超过 95 分位当天信号强制为空仓。量化开发者最容易犯的错误是把这个开关取消觉得“每次都要有信号才算好模型”。实际评测下来一年中模型自动过滤掉的交易日占比合理区间在 20% 到 40%剩下的信号质量反而更高。一个愿意承认自己“不知道”的模型在市场上才活得久。5.4 快速排查清单症状可能原因优先检查项解决方案召回结果震荡原型的汉明距离过近原型相关性矩阵合并原型或PCA降维训练集好、验证集差原型数量超过容量上限特征值分布减少M或加强稀疏化连续亏损信号密集极端行情强制预测能量距离分布开启空仓过滤早段好、近段差市场规则漂移时间衰减权重是否生效对久远原型降权置信度很高却总错标签重叠导致幸存者偏差历史样本独立性统计亏损率、平均持有期是否异常最后分享一点个人体会。用物理奖的思想做量化最大的收获不是模型准确率提升而是它逼你把“预测”换成了“匹配”。不做无根据的展望只回答一个问题当前市场最像历史哪个阶段这个阶段后来发生了什么这种思路天然带着风险意识也更容易被交易团队接受。建议你上手时先从单一品种、日线级别开始把记忆库做到百个以内先把信号可解释性做扎实再谈扩展到更多品种。市场记忆这件事做深了是一套能一直迭代的框架。
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。

↑