神经网络在交易中的应用:多元时间序列的双重聚类(DUET)(基础篇)
用双重聚类拆解多元时间序列
把多个品种的价格走势当成一条多元时间序列来喂给神经网络,难点在于不同品种量纲和波动节奏不一致。Dmitriy Gizlyk 提出的 DUET 思路,是先对时间维和特征维分别做聚类,再让网络在压缩后的结构里学映射关系,而不是一股脑塞进全连接层。 这套方法在 MT5 里可直接用 MQL5 组织特征矩阵。下面这段是构建多元序列缓冲区的核心片段,注意 iClose 取的是不同品种的同周期收盘价,行数是窗口长度、列数是品种数。 外汇与贵金属具备高杠杆与跳空风险,任何聚类特征都只是提高信号概率,不构成方向保证。实盘前应在策略测试器用 2020–2025 年数据跑一遍,观察聚类数在 3–8 之间时样本内吻合度变化。
class="type">class="kw">double matrix[][SYMBOLS]; class="type">int window = class="num">30; for(class="type">int s=class="num">0; s<SYMBOLS; s++) for(class="type">int b=class="num">0; b<window; b++) matrix[b][s] = iClose(SymList[s], PERIOD_H1, b);
◍ 多元序列为什么比单变量更贴近盘面
多元时间序列指同一时间戳下多个相互关联变量的集合,用来刻画复杂过程。和只看一根价格线的单变量序列不同,它把变量间的相关性一并纳入,预测模型因此更贴近真实市场结构。 在外汇与贵金属这类高波动品种里,多元分析常用于价格预测、波动率估计与策略构建。比如预测金价时,把成交量、实际利率、美元指数与突发新闻同框处理,往往能挖出单看价格挖不到的联动模式——这类模式常出现在避险切换的瞬间。 处理上的硬骨头是同时抓住时间依赖与跨通道依赖。经济危机时,资产相关性结构会突变,传统静态模型容易失效,这是实盘回测里最容易被打脸的环节。 现有做法分三类:逐通道独立分析(丢关系)、全通道硬拼(引冗余)、变量聚类(伤灵活)。DUET 论文换了个思路,用时间聚类(TCM)按相似特征分组以适配经济周期阶段,用通道聚类(CCM)筛关键变量去噪,再用融合模块(FM)同步两类信息。作者实验显示其预测精度优于旧法,但外汇贵金属仍属高风险,模型优势不代表胜率保证,建议开 MT5 用多品种相关性矩阵自行验证突变区间。
「DUET 怎么把多变量时序拆开再拼回去」
DUET 框架干的事,是把多元时间序列同时在时间维和通道维做双聚类,再融合预测。思路接近老手分析师先把大盘拆成独立模块各自看、再合起来下判断,但它是自动跑的,不靠人拍脑袋。 输入先过实例归一化:拔掉异常值、压平剧烈跳动,让训练集和测试集分布差异不那么致命。金融高频数据里噪声常盖掉真趋势,这步相当于给后面所有模块降噪打底。 时间聚类模块(TCM)用混合专家(MoE)架构,按先前聚类动态挑编码器处理每段序列,再把隐含特征拆成长期和短期趋势。不同性质的数据——比如秒级 tick 和日线——可以分到不同专家手里,避免一刀切。 通道聚类模块(CCM)走频域,算振幅矢量距离、筛掉冗余通道。就像筛宏观和技术指标,只留有意义的相关信号,顺手扒出资产间隐藏关系,给套利或系统性风险识别留线索。 融合模块(FM)用掩蔽注意力把时间和通道表示拼起来,动态调权重,过滤无关聚类。最后预测模块聚完特征逆归一化出原始尺度的未来值。相比传统要人工调参的方法,DUET 能自动抓结构特征并实时改设置,对外汇、贵金属这种高波动高风险品种的高频序列尤其能打,但实盘仍可能因宏观事件突变而失效,需自行在 MT5 用历史数据回测验证。
用 OpenCL 给 Top-K 编码器做并行门控
DUET 框架把时间序列切成片段后,用一堆并行编码器抽特征,但原作者建议只保留最相关的 k 个潜在分布。假设片段服从潜在正态,靠噪声门控挑 k 个:给 logit 加正态噪声 ε 稳住训练,再用 Softplus 卡住方差为正,最后 SoftMax 算权重。这样不相关的滤波器乘掩码后直接归零。 挑 k 个最相关编码器的活儿放在 OpenCL 里跑,内核 TopKgates 接三个缓冲区指针(输入、噪声、结果)加一个 k 值。任务空间是二维的,第一维按局部组切,组大小和编码器数量对齐——同一段的线程绑在一组里算。 内核先算偏移,把输入 load 进来;噪声非 0 时按方差和噪声调 logit。之后在本地内存开数组做线程间交换,外层循环步长等于数组大小,嵌套循环数出比自己大的元素个数,只有最大的 k 个线程没超阈值,结果写进 gates 缓冲,其余写最小常量(后续 SoftMax 权重变 0)。 光有前向不够,训练得回传梯度,TopKgatesGrad 内核干这个:前向结果等于最小常量的线程梯度直接写 0(编码器被弃用);否则把输出误差搬进 logit 梯度。方差梯度要看噪声——噪声为 0 就写 0,否则按噪声系数和激活导数调。两个内核源码在附件,主程序侧用 CNeuronTopKGates 包了一层,卷积层滤波器数 = 编码器数 ×2(均值+方差),Init 里顺手复用父类 SoftMax 转概率。 MoE 主体在 CNeuronMoE:第一层卷积并行算所有编码器,张量维度 {Units, Encoders, Dimension} 得先转置才能喂给第二层卷积,中间 SoftPlus 引入非线性,反向转置补回。前向就是把 Top-K 概率行向量乘对应编码器输出矩阵求加权和,存进结果缓冲。外汇/贵金属序列用这套筛编码器,过拟合风险高,建议先拿历史 tick 在 MT5 策略测试器跑通附件代码再上实盘。
__kernel <span class="keyword">class="type">void</span> TopKgates(__global <span class="keyword">const</span> <span class="keyword">class="type">class="kw">float</span> *inputs, __global <span class="keyword">const</span> <span class="keyword">class="type">class="kw">float</span> *noises, __global <span class="keyword">class="type">class="kw">float</span> *gates, <span class="keyword">const</span> <span class="keyword">class="type">uint</span> k) { class="type">size_t idx = get_local_id(<span class="number">class="num">0</span>); class="type">size_t <span class="keyword">var</span> = get_global_id(<span class="number">class="num">1</span>); class="type">size_t window = get_local_size(<span class="number">class="num">0</span>); class="type">size_t vars = get_global_size(<span class="number">class="num">1</span>); <span class="keyword">const</span> <span class="keyword">class="type">int</span> shift_logit = <span class="keyword">var</span> * <span class="number">class="num">2</span> * window + idx; <span class="keyword">const</span> <span class="keyword">class="type">int</span> shift_std = shift_logit + window;