您应当知道的 MQL5 向导技术(第 22 部分):条件化生成式对抗网络(cGAN)(基础篇)
📘

您应当知道的 MQL5 向导技术(第 22 部分):条件化生成式对抗网络(cGAN)(基础篇)

第 1/2 篇

「用 cGAN 在 MT5 里条件化生成行情样本」

MQL5 向导从 2025 年 2 月发布的第 22 部分技术起,支持条件化生成式对抗网络(cGAN)作为交易系统构建模块。它和早期纯 GAN 的区别在于:生成器接收的不是随机噪声,而是带标签的市场状态向量,使产出样本能对应特定波动 regime。 在外汇与贵金属这类高杠杆品种上,用 cGAN 扩充历史片段存在过拟合风险,生成的样本只能作为策略压力测试素材,不能当作未来分布保证。 实际落地时,可在 MT5 的 MQL5 向导中勾选 cGAN 模块,指定条件维度(如 ATR 分位、趋势方向),向导会调用对应头文件完成条件嵌入。验证方式很简单:生成后比对条件标签与样本统计特征是否一致。

◍ cGAN 凭什么比普通 GAN 更适合价格序列

条件化生成式对抗网络(cGAN)和普通 GAN 的核心差别,在于生成器的输入是不是随机噪声。普通 GAN 里生成器吃随机数据,硬凑出判别器分不出真假的输出;cGAN 则把某种结构化数据喂进生成器,让判别器去判断「数据—标签」配对是真还是编的。 放到金融场景,普通 GAN 那种纯随机输入对预测几乎没用——你没法让模型从一团噪声里学出 EURUSD 的下一根 K 线。cGAN 的思路是把独立行情数据(比如一段已发生的波动)送进生成器,判别器拿到「行情片段 + 对应标签」的配对,去甄别这标签是真实走势还是模型伪造的。 原文作者用两张结构图对比了两种设置:GAN 的生成器输出直接灌给判别器,cGAN 则是判别器同时接收独立数据和各自标签的配对。图像领域 GAN 因算力消耗表现不如 CNN 或 ViT,但在合成与增强上仍有价值;外汇与贵金属属高风险品种,用这类模型做序列预测前,建议先在 MT5 用历史数据跑通配对逻辑再谈实盘。

在 MT5 里搭 cGAN 的网络骨架

cGAN 的生成器和判别器都可直接复用多层感知器基类,只暴露两个核心方法:前向的 Forward() 与反向的 Backward()。类构造器负责接设置,另有内务函数做权重存盘、设训练目标和读前向结果,足够跑通原型。 生成器损失按 −log(D(G(z∣y)∣y)) 计算:D 是判别器输出,G 是生成器输出,z 为独立噪声,y 为条件标签或预测数据。该值通常是向量,维度取决于输出大小,在前向通过后作为误差权重喂回反向传播。 Backward() 被重载为接受判别器输出的变体,两个重载都调一个 Back() 复用旧反向传播主体,减少重复代码。这样训练生成器时既逼近下一根收盘价变化,也倾向骗过判别器;判别器则反向优化,更准地区分真假样本。 若改用 Python(TensorFlow)搭同类网络,需逐行加层、自定义更强但脱离 MT5 环境,还要靠 ONNX 等适配器把权重导回 MQL5。实盘或部署期训练时,这种来回适配可能变得笨重。 下面这段是 Backward 重载的关键片段,默认学习率 0.05,输出层误差用 -1.0*MathLog(判别器输出)*(目标-输出) 做 GAN 专属修正: // 网络反向传播入口,按梯度下降更新权重与偏置 void Cgan::Backward(vector<double> &DiscriminatorOutput, double LearningRate = 0.05) { // 目标与输出维度必须一致,否则打印错误并返回 if(target.Size() != output.Size()) { printf(__FUNCSIG__ + " Target & output size should match. "); return; } // 权重矩阵数组大小必须等于隐藏层数+1 if(ArraySize(weights) != hidden_layers + 1) { printf(__FUNCSIG__ + " weights matrix array size should be: " + IntegerToString(hidden_layers + 1)); return; } ... // 更新输出层权重与偏置(GAN 唯一改动点) vector _output_error = -1.0*MathLog(DiscriminatorOutput)*(target - output); //solo modification for GAN Back(_output_error, LearningRate); }

MQL5 / C++
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| Backward pass through the neural network to update weights        |
class=class="str">"cmt">//| and biases using gradient descent                                |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">void Cgan::Backward(vector<class="type">class="kw">double> &DiscriminatorOutput, class="type">class="kw">double LearningRate = class="num">0.05)
{  if(target.Size() != output.Size())
   {  printf(__FUNCSIG__ + " Target & output size should match. ");
      class="kw">return;
   }
   if(ArraySize(weights) != hidden_layers + class="num">1)
   {  printf(__FUNCSIG__ + " weights matrix array size should be: " + IntegerToString(hidden_layers + class="num">1));
      class="kw">return;
   }
        ...
class=class="str">"cmt">// Update output layer weights and biases
   vector _output_error = -class="num">1.0*MathLog(DiscriminatorOutput)*(target - output); class=class="str">"cmt">//solo modification for GAN
   Back(_output_error, LearningRate);
}

「给 cGAN 信号类补上生成器与判别器接口」

在 MT5 里写自定义信号类,标准初始化、校验和评估函数只是底子。要做基于多层感知器的条件生成对抗网络,还得挂三个自有函数:GetOutput() 做市场状态判定锚点,SetOutput() 在每轮训练后写回网络权重,Norm() 在前馈前把输入归一化。 生成网络架构先拍板为 7 层——1 个输入层、5 个隐藏层、1 个输出层,参数放在 settings 数组里用来实例化成名为 GEN 的网络对象。它吃前 4 个收盘价变化,吐出第 5 个变化的预测;这 4 个真实变化加 1 个预测配对,就成了判别器 DIS 的输入。 判别器输入是双叠的:要么是全市场来的 5 个连续变化(标 1.0),要么是 4 真实 + 1 生成器预测(标 0.0)。训练后它返回 0.0~1.0 之间的浮点,越接近 1 越像真序列。R 函数投喂真实数据,F 函数投喂假造数据,两者都在 GetOutput 里按柱线调用。 信号类只暴露三个可调参数:学习率 m_learning_rate、训练局次 m_epochs、训练集大小 m_train_set。下面这段 GetOutput 展示了怎么按新柱线加载输入、前馈并训练;R 函数则把真实输出填 1.0 交给判别器。外汇与贵金属波动剧烈,cGAN 预测仅具概率倾向,实盘前务必在策略测试器跑历史校验。

MQL5 / C++
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//|                                                                |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">void CSignalCGAN::GetOutput(class="type">class="kw">double &GenOut, class="type">bool &DisOut)
{  GenOut = class="num">0.0;
   DisOut = false;
   for(class="type">int i = m_epochs; i >= class="num">0; i--)
   {  for(class="type">int ii = m_train_set; ii >= class="num">0; ii--)
      {  vector _in, _out;
         vector _in_new, _out_new, _in_old, _out_old;
         _in_new.CopyRates(m_symbol.Name(), m_period, class="num">8, ii + class="num">1, __GEN_INPUTS);
         _in_old.CopyRates(m_symbol.Name(), m_period, class="num">8, ii + class="num">1 + class="num">1, __GEN_INPUTS);
         _in = Norm(_in_new, _in_old);
         GEN.Set(_in);
         GEN.Forward();
         if(ii > class="num">0)class=class="str">"cmt">// train
         {  _out_new.CopyRates(m_symbol.Name(), m_period, class="num">8, ii, __GEN_OUTPUTS);
            _out_old.CopyRates(m_symbol.Name(), m_period, class="num">8, ii + class="num">1, __GEN_OUTPUTS);
            _out = Norm(_out_new, _out_old);
            
            ...
         }
         else if(ii == class="num">0 && i == class="num">0)
         {
            ...
         }
      }
   }
}
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| Process Real Data in Discriminator                              |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">void CSignalCGAN::R(vector &IN, vector &OUT)
{  vector _out_r, _out_real, _in_real;
   _out_r.Copy(OUT);
   _in_real.Copy(IN);
   Sum(_in_real, _out_r);
   DIS.Set(_in_real);
   DIS.Forward();
   _out_real.Resize(__DIS_OUTPUTS);
   _out_real.Fill(class="num">1.0);
   DIS.Get(_out_real);

常见问题

可用条件化生成式对抗网络按指定标签批量生成对应行情样本,在终端里搭好生成器与判别器接口后直接调用即可。
普通GAN生成不可控,cGAN输入条件标签后能定向产出某类走势,更贴合价格序列的有序特征,样本可用性更高。
小布可对接你的品种页,自动比对生成样本与真实分布差异,提示条件标签设置是否偏离,减少手动试错。
常漏掉给生成器和判别器分别声明条件输入通道,缺了这层信号类补丁,网络只会无差别乱生成。
生成样本仅近似真实分布,外汇高风险下极端跳空难覆盖,实盘前务必留.out-of-sample验证,勿直接信回测。