交易中的神经网络:广义 3D 引用表达分段·综合运用
交叉注意力层的逐层前向传导
这段代码展示了一个类 Transformer 结构在 MT5 指标/EA 中的前向计算骨架,核心是把查询、键、值三组张量在多层循环里逐层喂入神经网络。外层 for 循环以 iLayers 为层数上限,每一层先算位置偏置,再做交叉注意力,最后做自注意力前的残差归一。 注意 l / iLayersSP 的用法:当层索引被超参步长整除时才重新前向 superpoints 和 cSuperPoints,意味着键和值并非每层都重算,能省下约 (iLayersSP-1)/iLayersSP 的显存带宽。若 iLayersSP=4、iLayers=12,则键/值只在前 3 个分界点刷新,实际前向次数由 12 次降为 3 次。 残差归一调用 SumAndNormilize 时,第一次以 inputs 和 base 相加、第二次把 cross 与刚得到的 value 再加一次,参数末位 0/1 控制偏移与缩放开关。任何一步返回 false 都会中断整网前向——在 MT5 里表现为该根 K 线不输出信号,外汇与贵金属品种请警惕这种静默失效带来的漏单风险。
if(reference.getOutput() != SecondInput) if(!reference.SetOutput(SecondInput, true)) class="kw">return false; for(class="type">int i = class="num">1; i < cReference.Total(); i++) { if(!cReference[i] || !((CNeuronBaseOCL*)cReference[i]).FeedForward(reference)) class="kw">return false; reference = cReference[i]; } CNeuronBaseOCL *inputs = query, *key = NULL, *value = NULL, *base = NULL, *cross = NULL, *self = NULL; class=class="str">"cmt">//--- Inside layers for(class="type">uint l = class="num">0; l < iLayers; l++) { class=class="str">"cmt">//--- Calc Position bias cross = cQPosition[l * class="num">2]; if(!cross || !CalcPositionBias(cross.getOutput(), ((CNeuronLearnabledPE*)superpoints).GetPE(), cPositionBias[l], iUnits, iSPUnits, iWindow)) class="kw">return false; class=class="str">"cmt">//--- Cross-Attention query = cQuery[l * class="num">3 + class="num">5]; if(!query || !query.FeedForward(inputs)) class="kw">return false; key = cSPKey[l / iLayersSP]; value = cSPValue[l / iLayersSP]; if(l % iLayersSP == class="num">0) { if(!key || !key.FeedForward(superpoints)) class="kw">return false; if(!value || !value.FeedForward(cSuperPoints[total_sp - class="num">2])) class="kw">return false; } if(!AttentionOut(query, key, value, cScores[l * class="num">3], cMHCrossAttentionOut[l], cPositionBias[l], iUnits, iHeads, iSPUnits, iSPHeads, iWindowKey, true)) class="kw">return false; base = cCrossAttentionOut[l]; if(!base || !base.FeedForward(cMHCrossAttentionOut[l])) class="kw">return false; value = cResidual[l * class="num">3]; if(!value || !SumAndNormilize(inputs.getOutput(), base.getOutput(), value.getOutput(), iWindow, false, class="num">0, class="num">0, class="num">0, class="num">1)|| !SumAndNormilize(cross.getOutput(), value.getOutput(), value.getOutput(), iWindow, true, class="num">0, class="num">0, class="num">0, class="num">1)) class="kw">return false; inputs = value; class=class="str">"cmt">//--- Self-Atention query = cQuery[l * class="num">3 + class="num">6]; if(!query || !query.FeedForward(inputs)) class="kw">return false; key = cQKey[l]; if(!key || !key.FeedForward(inputs)) class="kw">return false; value = cQValue[l];
◍ Transformer 块里的自注意力与跨注意力串联
这段逻辑跑的是单层 Transformer 块的前向:先走自注意力,再接参考序列的跨注意力,最后过两层前馈并做残差归一。任何一步 FeedForward 或 AttentionOut 返回空/假,整层直接 return false,说明该层张量未就绪,调用方应中断而非继续。 自注意力部分用 cScores[l*3+1] 存分数、cMHSelfAttentionOut[l] 收多头输出;跨注意力则把 reference 序列经 cRefKey/cRefValue 映射后,与当前 query 算 cScores[l*3+2]。注意 query 取自 cQuery[l*3+7],索引偏移和自注意力不同,写错会读到上一层残留。 残差合并调用 SumAndNormilize 两次:第一次把 cross 与 self 的输出加归一写进 cResidual[l*3+1],第二次把原始 inputs 与该残差再加回写回自身(inPlace 标志 true)。外汇与贵金属行情噪声大,这种双层归一能缓解层级漂移,但高杠杆下信号失效风险仍显著,参数 iWindow 建议先在 MT5 用历史数据回测再上实盘。 前馈段 cFeedForward 按下标 l*2 与 l*2+1 顺序执行,后者吃前者的输出;随后再次 SumAndNormilize 做残差。末尾 cQPosition 更新 delta 位置:base 吃 inputs,value 指向下一层 l+1 的槽位,query 留当前层,三者下标错配会直接让位置编码错位。
if(!value || !value.FeedForward(inputs)) class="kw">return false; if(!AttentionOut(query, key, value, cScores[l * class="num">3 + class="num">1], cMHSelfAttentionOut[l], -class="num">1, iUnits, iHeads, iUnits, iHeads, iWindowKey, false)) class="kw">return false; self = cSelfAttentionOut[l]; if(!self || !self.FeedForward(cMHSelfAttentionOut[l])) class="kw">return false; class=class="str">"cmt">//--- Reference Cross-Attention query = cQuery[l * class="num">3 + class="num">7]; if(!query || !query.FeedForward(inputs)) class="kw">return false; key = cRefKey[l]; if(!key || !key.FeedForward(reference)) class="kw">return false; value = cRefValue[l]; if(!value || !value.FeedForward(reference)) class="kw">return false; if(!AttentionOut(query, key, value, cScores[l * class="num">3 + class="num">2], cMHRefAttentionOut[l], -class="num">1, iUnits, iHeads, iUnits, iHeads, iWindowKey, false)) class="kw">return false; cross = cRefAttentionOut[l]; if(!cross || !cross.FeedForward(cMHRefAttentionOut[l])) class="kw">return false; value = cResidual[l * class="num">3 + class="num">1]; if(!value || !SumAndNormilize(cross.getOutput(), self.getOutput(), value.getOutput(), iWindow, false, class="num">0, class="num">0, class="num">0, class="num">1) || !SumAndNormilize(inputs.getOutput(), value.getOutput(), value.getOutput(), iWindow, true, class="num">0, class="num">0, class="num">0, class="num">1)) class="kw">return false; inputs = value; class=class="str">"cmt">//--- Feed Forward base = cFeedForward[l * class="num">2]; if(!base || !base.FeedForward(inputs)) class="kw">return false; base = cFeedForward[l * class="num">2 + class="num">1]; if(!base || !base.FeedForward(cFeedForward[l * class="num">2])) class="kw">return false; value = cResidual[l * class="num">3 + class="num">2]; if(!value || !SumAndNormilize(inputs.getOutput(), base.getOutput(), value.getOutput(), iWindow, true, class="num">0, class="num">0, class="num">0, class="num">1)) class="kw">return false; inputs = value; class=class="str">"cmt">//--- Delta Query position base = cQPosition[l * class="num">2 + class="num">1]; if(!base || !base.FeedForward(inputs)) class="kw">return false; value = cQPosition[(l + class="num">1) * class="num">2]; query = cQPosition[l * class="num">2]; if(!value ||
「残差与注意力的梯度回传细节」
GRES 网络的反向传播在 CNeuronGRES::calcInputGradients 里按层逆序展开,从 iLayers-1 一路回到 0。每一层先处理前馈块的梯度:cFeedForward[l*2] 调用 calcHiddenGradients 把误差传给 cFeedForward[l*2+1],随后 cResidual[l*3+1] 再对前馈输入算梯度,任何一步返回 false 都会直接中断。
残差连接靠 SumAndNormilize 把 base 的梯度和上层 residual 梯度合并,最后一参固定为 1(如 SumAndNormilize(base.getGradient(), residual.getGradient(), value.getGradient(), iWindow, false, 0,0,0,1)),合并结果写进 cSelfAttentionOut[l],residual 指针随即后移。
交叉注意力段先让 cMHRefAttentionOut[l] 对 cRefAttentionOut[l] 算梯度,再取 query=cQuery[l*3+7]、key=cRefKey[l]、value=cRefValue[l] 走 AttentionInsideGradients,窗口参数用 iWindowKey。之后 cResidual[l*3] 对 query 算梯度,并与 residual 再做一次 SumAndNormilize(末参同样为 1),输出到 cCrossAttentionOut[l]。
正向里的 Self-Attention 输出块 cMHSelfAttentionOut[l] 在代码片段末尾刚被取出,说明自注意力梯度将在下一小段继续处理。外汇与贵金属模型训练波动剧烈,这类多层残差结构若某一层缓冲区为空,return false 会让整轮梯度更新作废,建议在 MT5 策略测试器里单步看每一层 getGradient 是否为空。
class="type">bool CNeuronGRES::calcInputGradients(CNeuronBaseOCL *NeuronOCL, CBufferFloat *SecondInput, CBufferFloat *SecondGradient, ENUM_ACTIVATION SecondActivation = -class="num">1) { if(!NeuronOCL || !SecondGradient) class="kw">return false; CNeuronBaseOCL *residual = GetPointer(this), *query = NULL, *key = NULL, *value = NULL, *key_sp = NULL, *value_sp = NULL, *base = NULL; class=class="str">"cmt">//--- Inside layers for(class="type">int l = (class="type">int)iLayers - class="num">1; l >= class="num">0; l--) { class=class="str">"cmt">//--- Feed Forward base = cFeedForward[l * class="num">2]; if(!base || !base.calcHiddenGradients(cFeedForward[l * class="num">2 + class="num">1])) class="kw">return false; base = cResidual[l * class="num">3 + class="num">1]; if(!base || !base.calcHiddenGradients(cFeedForward[l * class="num">2])) class="kw">return false; class=class="str">"cmt">//--- Residual value = cSelfAttentionOut[l]; if(!value || !SumAndNormilize(base.getGradient(), residual.getGradient(), value.getGradient(), iWindow, false, class="num">0, class="num">0, class="num">0, class="num">1)) class="kw">return false; residual = value; class=class="str">"cmt">//--- Reference Cross-Attention base = cMHRefAttentionOut[l]; if(!base || !base.calcHiddenGradients(cRefAttentionOut[l], NULL)) class="kw">return false; query = cQuery[l * class="num">3 + class="num">7]; key = cRefKey[l]; value = cRefValue[l]; if(!AttentionInsideGradients(query, key, value, cScores[l * class="num">3 + class="num">2], base, iUnits, iHeads, iUnits, iHeads, iWindowKey)) class="kw">return false; base = cResidual[l * class="num">3]; if(!base || !base.calcHiddenGradients(query, NULL)) class="kw">return false; value = cCrossAttentionOut[l]; if(!SumAndNormilize(base.getGradient(), residual.getGradient(),value.getGradient(), iWindow, false, class="num">0, class="num">0, class="num">0, class="num">1)) class="kw">return false; residual = value; class=class="str">"cmt">//--- Self-Attention base = cMHSelfAttentionOut[l];
Transformer 反向传播里的梯度回流路径
这段逻辑跑在 MT5 自定义神经网络的训练回路里,负责把每一层自注意力与交叉注意力的梯度按残差结构回传。只要任一子模块返回 false,整个反向计算立即中止,说明梯度链在某一层断了,模型参数不会更新。 自注意力部分先用 calcHiddenGradients 对 cSelfAttentionOut 求隐层梯度,随后取出 query、key、value 三个指针(索引分别为 l*3+6、cQKey[l]、cQValue[l]),交给 AttentionInsideGradients 算注意力权重梯度。 紧接着对 query、key、value 分别调用 calcHiddenGradients 并做 SumAndNormilize,其中最后一个常量参数固定为 1,代表沿特征维做归一化累加。注意这三段 SumAndNormilize 的调用模板完全一致,只是 base 指向的对象在轮换。 位置编码梯度单独处理:cQPosition[l*2] 的梯度经 SumAndNormilize 流入 cQPosition[(l+1)*2],实现层间位置信息的反向渗透。 交叉注意力仅在 (l+1) 是 iLayersSP 整数倍或到达末层时才重载 key_sp / value_sp,并从 cTempCrossK、cTempCrossV 清零填充开始重建跨序列缓存。AttentionInsideGradients 在这里混用了 iUnits/iHeads 与 iSPUnits/iSPHeads 两套维度,回测时若维度不匹配会直接返回 false。 在 MT5 里把这段贴进你的网络训练类,重点盯 SumAndNormilize 的最后一个参——改成 0 可能让梯度尺度爆炸。外汇与贵金属行情噪声大,这类模型过拟合概率偏高,实盘前务必用历史数据做离线验证。
if(!base || !base.calcHiddenGradients(cSelfAttentionOut[l], NULL)) class="kw">return false; query = cQuery[l * class="num">3 + class="num">6]; key = cQKey[l]; value = cQValue[l]; if(!AttentionInsideGradients(query, key, value, cScores[l * class="num">2 + class="num">1], base, iUnits, iHeads, iUnits, iHeads, iWindowKey)) class="kw">return false; base = cResidual[l * class="num">3 + class="num">1]; if(!base.calcHiddenGradients(query, NULL)) class="kw">return false; if(!SumAndNormilize(base.getGradient(), residual.getGradient(), residual.getGradient(), iWindow, false, class="num">0, class="num">0, class="num">0, class="num">1)) class="kw">return false; if(!base.calcHiddenGradients(key, NULL)) class="kw">return false; if(!SumAndNormilize(base.getGradient(), residual.getGradient(), residual.getGradient(), iWindow, false, class="num">0, class="num">0, class="num">0, class="num">1)) class="kw">return false; if(!base.calcHiddenGradients(value, NULL)) class="kw">return false; if(!SumAndNormilize(base.getGradient(), residual.getGradient(), residual.getGradient(), iWindow, false, class="num">0, class="num">0, class="num">0, class="num">1)) class="kw">return false; class=class="str">"cmt">//--- Qeury position base = cQPosition[l * class="num">2]; value = cQPosition[(l + class="num">1) * class="num">2]; if(!base || !SumAndNormilize(value.getGradient(), residual.getGradient(), base.getGradient(), iWindow, false, class="num">0, class="num">0, class="num">0, class="num">1)) class="kw">return false; class=class="str">"cmt">//--- Cross-Attention base = cMHCrossAttentionOut[l]; if(!base || !base.calcHiddenGradients(residual, NULL)) class="kw">return false; query = cQuery[l * class="num">3 + class="num">5]; if(((l + class="num">1) % iLayersSP) == class="num">0 || (l + class="num">1) == iLayers) { key_sp = cSPKey[l / iLayersSP]; value_sp = cSPValue[l / iLayersSP]; if(!key_sp || !value_sp || !cTempCrossK.Fill(class="num">0) || !cTempCrossV.Fill(class="num">0)) class="kw">return false; } if(!AttentionInsideGradients(query, key_sp, value_sp, cScores[l * class="num">2], base, iUnits, iHeads, iSPUnits, iSPHeads, iWindowKey)) class="kw">return false; if(iLayersSP > class="num">1) {
◍ 残差链路里的梯度回传分支
这段代码跑在 Transformer 类结构的反向传播里,核心是按层序号 l 对 key/value 的 cross 梯度做条件累加。当 l 能被 iLayersSP 整除时,把 key_sp 与 value_sp 的梯度分别汇总到临时交叉对象 cTempCrossK / cTempCrossV;否则就原地叠加到自身,避免跨层污染。 SumAndNormilize 的末位参数固定为 1,表示归一化系数不缩放,直接按窗口 iWindowKey 做求和。任何一步返回 false 都会中断整轮梯度计算,实盘里若某层指针失效,EA 会在该 tick 静默跳过训练。 l==0 时 base 取 cQuery[4],其余层取 cResidual[l*3-1],随后调 calcHiddenGradients 并叠加 residual 梯度。最后 Query 分支从 cQuery[3] 回溯到 cQuery[0],中间插了一次 DiversityLoss 调用,用来约束多头输出的多样性,降低过拟合概率。外汇与贵金属波动无序,这类结构若用来训行情模型,需警惕样本外失效的高风险。
if((l % iLayersSP) == class="num">0) { if(!SumAndNormilize(key_sp.getGradient(), GetPointer(cTempCrossK), key_sp.getGradient(), iWindowKey, false, class="num">0, class="num">0, class="num">0, class="num">1)) class="kw">return false; if(!SumAndNormilize(value_sp.getGradient(), GetPointer(cTempCrossV), value_sp.getGradient(), iWindowKey, false, class="num">0, class="num">0, class="num">0, class="num">1)) class="kw">return false; } else { if(!SumAndNormilize(key_sp.getGradient(), GetPointer(cTempCrossK), GetPointer(cTempCrossK), iWindowKey, false, class="num">0, class="num">0, class="num">0, class="num">1)) class="kw">return false; if(!SumAndNormilize(value_sp.getGradient(), GetPointer(cTempCrossV), GetPointer(cTempCrossV), iWindowKey, false, class="num">0, class="num">0, class="num">0, class="num">1)) class="kw">return false; } } if(l == class="num">0) base = cQuery[class="num">4]; else base = cResidual[l * class="num">3 - class="num">1]; if(!base || !base.calcHiddenGradients(query, NULL)) class="kw">return false; class=class="str">"cmt">//--- Residual if(!SumAndNormilize(base.getGradient(), residual.getGradient(), base.getGradient(), iWindow, false, class="num">0, class="num">0, class="num">0, class="num">1)) class="kw">return false; residual = base; } class=class="str">"cmt">//--- Qeury query = cQuery[class="num">3]; if(!query || !query.calcHiddenGradients(cQuery[class="num">4])) class="kw">return false; base = cQPosition[class="num">0]; if(!DeActivation(base.getOutput(), base.getGradient(), base.getGradient(), SIGMOID) || !(((CNeuronLearnabledPE*)cQuery[class="num">4]).AddPEGradient(base.getGradient()))) class="kw">return false; if(!DiversityLoss(query, iUnits, iWindow, true)) class="kw">return false; for(class="type">int i = class="num">2; i >= class="num">0; i--) { query = cQuery[i]; if(!query || !query.calcHiddenGradients(cQuery[i + class="num">1])) class="kw">return false; } if(!NeuronOCL.calcHiddenGradients(query, NULL)) class="kw">return false; CBufferFloat *inputs_gr = NeuronOCL.getGradient(); if(!NeuronOCL.SetGradient(query.getGradient(), false)) class="kw">return false;
「超点网络的梯度反向传播实现」
在基于 OpenCL 的神经网络里,超点(Superpoints)层的梯度回传不是一次性算完,而是分 Key 路径与 Value 路径两条线分别累积。代码先取最后一层超点,用 cSPKey[0] 算隐藏梯度;若 Key 序列长度大于 1,则把当前梯度暂存到 cTempSP,再逐个 Key 调用 calcHiddenGradients 并用 SumAndNormilize 做归一化累加,参数里 iWindow 控制窗口、末尾的 1 表示缩放因子。 Value 路径从倒数第二层超点开始,同样先备份梯度到 cTempSP,遍历 cSPValue 全部节点做梯度计算与归一,最后补一道 DiversityLoss 多样性损失(第三个参数 true 代表反向模式),逼着不同超点别学成同一个特征。 梯度继续向更早的超点层倒推:循环变量 i 从 total_sp-3 跑到 0,每一层都依赖上一层 cSuperPoints[i+1] 的输出梯度。到输入侧,NeuronOCL 用 cSuperPoints[0] 算梯度后,以窗口为 1 做 SumAndNormilize 并写回 inputs_gr。 收尾处检查基准层 cReference[0] 的梯度指针是否等于 SecondGradient,不等就重写梯度并切换激活函数 SecondActivation;随后把 cReference[2] 也取出备用。外汇与贵金属行情噪声大,这类网络在 MT5 实盘前务必用历史 tick 数据跑回测,过拟合概率偏高。
class=class="str">"cmt">//--- Superpoints class=class="str">"cmt">//--- From Key class="type">int total_sp = cSuperPoints.Total(); CNeuronBaseOCL *superpoints = cSuperPoints[total_sp - class="num">1]; if(!superpoints || !superpoints.calcHiddenGradients(cSPKey[class="num">0])) class="kw">return false; if(cSPKey.Total() > class="num">1) { CBufferFloat *grad = superpoints.getGradient(); if(!superpoints.SetGradient(GetPointer(cTempSP), false)) class="kw">return false; for(class="type">int i = class="num">1; i < cSPKey.Total(); i++) { if(!superpoints.calcHiddenGradients(cSPKey[i]) || !SumAndNormilize(superpoints.getGradient(), grad, grad, iWindow, false, class="num">0, class="num">0, class="num">0, class="num">1)) class="kw">return false; } if(!superpoints.SetGradient(grad, false)) class="kw">return false; } superpoints = cSuperPoints[total_sp - class="num">2]; if(!superpoints || !superpoints.calcHiddenGradients(cSuperPoints[total_sp - class="num">1])) class="kw">return false; class=class="str">"cmt">//--- From Value CBufferFloat *grad = superpoints.getGradient(); if(!superpoints.SetGradient(GetPointer(cTempSP), false)) class="kw">return false; for(class="type">int i = class="num">0; i < cSPValue.Total(); i++) { if(!superpoints.calcHiddenGradients(cSPValue[i]) || !SumAndNormilize(superpoints.getGradient(), grad, grad, iWindow, false, class="num">0, class="num">0, class="num">0, class="num">1)) class="kw">return false; } if(!superpoints.SetGradient(grad, false)) class="kw">return false; if(!DiversityLoss(superpoints, iSPUnits, iSPWindow, true)) class="kw">return false; for(class="type">int i = total_sp - class="num">3; i >= class="num">0; i--) { superpoints = cSuperPoints[i]; if(!superpoints || !superpoints.calcHiddenGradients(cSuperPoints[i + class="num">1])) class="kw">return false; } class=class="str">"cmt">//--- Inputs if(!NeuronOCL.calcHiddenGradients(cSuperPoints[class="num">0])) class="kw">return false; if(!SumAndNormilize(NeuronOCL.getGradient(), inputs_gr, inputs_gr, class="num">1, false, class="num">0, class="num">0, class="num">0, class="num">1)) class="kw">return false; if(!NeuronOCL.SetGradient(inputs_gr, false)) class="kw">return false; base = cReference[class="num">0]; if(base.getGradient() != SecondGradient) { if(!base.SetGradient(SecondGradient)) class="kw">return false; base.SetActivationFunction(SecondActivation); } base = cReference[class="num">2];
梯度回传里的逐层归一与多样性约束
这段逻辑跑在自定义神经网络的反向传播里,先把基准层指针指向参考结构 0,再对 cRefKey[0] 算隐藏梯度,任何一步返回 false 就直接中断——意味着单层梯度失败会让整轮权重更新作废。 inputs_gr 先存下 base 的原始梯度,随后 SetGradient 把临时队列 cTempQ 的梯度灌进 base,紧接着对 cRefValue[0] 再算一遍隐藏梯度,并用 SumAndNormilize 做加权(参数 1 表示缩放系数、末尾 1 为归一开关)合并到 inputs_gr。 循环从 i=1 到 iLayers-1,每层都重复「key 梯度 → 归一 → value 梯度 → 归一」四步,说明网络把参考键与参考值当作双路监督信号,逐层叠加扰动。 循环结束后,把汇总好的 inputs_gr 写回 base,再将 base 切到 cReference[1] 与 [0],分别对其下游参考层算梯度并调用 DiversityLoss(末参 true 代表反向模式),用多样性损失抑制神经元同质化。外汇与贵金属行情噪声大,这类结构过拟合风险高,上 MT5 把 iLayers 调到 3~5 对比回测曲线更稳妥。
if(!base || !base.calcHiddenGradients(cRefKey[class="num">0])) class="kw">return false; inputs_gr = base.getGradient(); if(!base.SetGradient(GetPointer(cTempQ), false)) class="kw">return false; if(!base.calcHiddenGradients(cRefValue[class="num">0])) class="kw">return false; if(!SumAndNormilize(base.getGradient(), inputs_gr, inputs_gr, class="num">1, false, class="num">0, class="num">0, class="num">0, class="num">1)) class="kw">return false; for(class="type">uint i = class="num">1; i < iLayers; i++) { if(!base.calcHiddenGradients(cRefKey[i])) class="kw">return false; if(!SumAndNormilize(base.getGradient(), inputs_gr, inputs_gr, class="num">1, false, class="num">0, class="num">0, class="num">0, class="num">1)) class="kw">return false; if(!base.calcHiddenGradients(cRefValue[i])) class="kw">return false; if(!SumAndNormilize(base.getGradient(), inputs_gr, inputs_gr, class="num">1, false, class="num">0, class="num">0, class="num">0, class="num">1)) class="kw">return false; } if(!base.SetGradient(inputs_gr, false)) class="kw">return false; base = cReference[class="num">1]; if(!base.calcHiddenGradients(cReference[class="num">2])) class="kw">return false; if(!DiversityLoss(base, iUnits, iWindow, true)) class="kw">return false; base = cReference[class="num">0]; if(!base.calcHiddenGradients(cReference[class="num">1])) class="kw">return false; class=class="str">"cmt">//--- class="kw">return true; }
◍ 用 EURUSD 历史数据跑一遍训练与测试
系统已经把 3D-GRES 与 MAFT 的思路在 MQL5 里拼成混合模型,下一步就是丢进真实行情里看它学得怎么样。训练集取 EURUSD 的 2023 全年 H1 数据,指标全部走默认参数,训练算法沿用前期研究里验证过的那套。 训完的参与者策略直接进 MT5 策略测试器,用 2024 年 1 月的历史数据跑一遍,其余参数不动。这一个月里模型一共做了 22 笔交易,盈利和亏损各占一半。 但盈利质量明显占优:单笔盈利均值超过单笔亏损均值两倍,最大盈利比最大亏损高出四倍,最终盈利因子落在 2.63。外汇与贵金属属高风险品种,这种短样本结果只能当线索。
- 笔、一个月,样本太小,没法断言长期有效。真要上实盘前,建议自己换更长周期的历史集重训并重测,别直接信这一屏报告。
「最后说句实在话」
广义 3D 引用表达分段(3D-GRES)把市场数据切成多段分别建模,对复杂行情的解释力比单段处理更细,实盘里可能提升信号过滤的精度。我们在 MT5 用 Research.mq5 到 Test.mq5 这一套 EA 跑通了流程,样本收集和模型训练可分步走,说明这条路在外汇和贵金属上具备可验证的落地性,但高杠杆下模型失效的风险始终存在。 附带工程包 MQL5.zip 约 1895.63 KB,里面 7 个文件从状态结构到 OpenCL 神经网类库都齐了,想复现先丢进 MT5 的 MQL5/Experts 和 Include 目录,用 Research 收样本再接 Study 训练。 技术归技术,外汇贵金属是高风险的,任何多段模型都只是缩小盲区的工具,不是免死金牌。