数据科学和机器学习(第 30 部分):预测股票市场的幂对、卷积神经网络(CNN)、和递归神经网络(RNN)·综合运用
📘

数据科学和机器学习(第 30 部分):预测股票市场的幂对、卷积神经网络(CNN)、和递归神经网络(RNN)·综合运用

第 3/3 篇

◍ CNN 叠 LSTM 的建模与 MT5 落地

普通 RNN 抓不住长序列里的形态关系,LSTM 在这块明显更稳,也更能榨出序列中的长期依赖。把 LSTM 接在 CNN 后面,等于先让卷积层提局部特征、再交给记忆单元看时序,思路不复杂。 我们在特斯拉日线数据上先跑 Python 原型:只把原本简单 RNN 的那一层换成 LSTM,其余训练验证流程不动。测试集分类准确率落在 53%,precision 在 0 类 0.67、1 类 0.45,样本量 195。 转到 MT5 这边,函数库和此前 CNN+RNN 的 EA 基本通用,核心改动只是引用训练好的 ONNX 与标准化参数。用相同测试器设置回测,整体交易准确率约 74%,比前几个模型低一截,但作为辅助信号仍算能打。外汇与贵金属波动更狂,直接套用该准确率可能大幅衰减,务必先小周期验证。 下面这段是原型里换层的代码和 MT5 资源挂载,注意 LSTM 层只改了一行: from tensorflow.keras.layers import LSTM # Define the CNN model model = Sequential() model.add(Conv1D(filters=16, kernel_size=3, activation='relu', strides=2, padding='causal', input_shape=(time_step, X_train.shape[2]))) model.add(MaxPooling1D(pool_size=2)) model.add(LSTM(50, activation='relu')) model.add(Dropout(0.5)) model.add(Dense(50, activation='relu')) model.add(Dropout(0.5)) model.add(Dense(units=len(np.unique(y)), activation='softmax')) MT5 侧把训练产物挂成 resource,ConvNet 库直接复用: #resource "\\Files\\lstm+cnn.TSLA.D1.onnx" as uchar onnx_model[] #resource "\\Files\\lstm+cnn.TSLA.D1.standard_scaler_mean.bin" as double standardization_mean[] #resource "\\Files\\lstm+cnn.TSLA.D1.standard_scaler_scale.bin" as double standardization_std[] #include <MALE5\Convolutional Neural Networks(CNNs)\ConvNet.mqh> #include <MALE5\preprocessing.mqh> CConvNet cnn; StandardizationScaler *scaler;

MQL5 / C++
from tensorflow.keras.layers class="kw">import LSTM
# Define the CNN model
model = Sequential()
model.add(Conv1D(filters=class="num">16, 
                kernel_size=class="num">3, 
                activation=&class="macro">#x27;relu&class="macro">#x27;, 
                strides=class="num">2,
                padding=&class="macro">#x27;causal&class="macro">#x27;,
                input_shape=(time_step, X_train.shape[class="num">2])
                )
        )
model.add(MaxPooling1D(pool_size=class="num">2))
model.add(LSTM(class="num">50, activation=&class="macro">#x27;relu&class="macro">#x27;))
model.add(Dropout(class="num">0.5))
model.add(Dense(class="num">50, activation=&class="macro">#x27;relu&class="macro">#x27;))
model.add(Dropout(class="num">0.5))
model.add(Dense(units=len(np.unique(y)), activation=&class="macro">#x27;softmax&class="macro">#x27;))  # For binary classification(e.g., buy/sell signal)
model.summary()
class="num">7/class="num">7 ━━━━━━━━━━━━━━━━━━━━ 0s 36ms/step
Classification Report
                precision   recall  f1-score   support
           class="num">0       class="num">0.67      class="num">0.44      class="num">0.53       class="num">117
           class="num">1       class="num">0.45      class="num">0.68      class="num">0.54        class="num">78
    accuracy                           class="num">0.53        class="num">195
   macro avg       class="num">0.56      class="num">0.56      class="num">0.53        class="num">195
weighted avg       class="num">0.58      class="num">0.53      class="num">0.53        class="num">195
class="macro">#resource "\Files\lstm+cnn.TSLA.D1.onnx" as class="type">uchar onnx_model[]
class="macro">#resource "\Files\lstm+cnn.TSLA.D1.standard_scaler_mean.bin" as class="type">class="kw">double standardization_mean[]
class="macro">#resource "\Files\lstm+cnn.TSLA.D1.standard_scaler_scale.bin" as class="type">class="kw">double standardization_std[]
class="macro">#include <MALE5\Convolutional Neural Networks(CNNs)\ConvNet.mqh>
class="macro">#include <MALE5\preprocessing.mqh>
CConvNet cnn;
StandardizationScaler *scaler;

GRU 接在 CNN 后面能跑出什么精度

GRU 和 LSTM 一样能抓长序列依赖,但结构更轻。把它塞进原先的 CNN 架构里,只需把循环层换成 GRU,其余卷积、池化、Dropout 与全连接层都不用动。 训练验证完成后,这套 CNN+GRU 在测试集上的准确率为 53%,分类报告里 0 类 precision 0.69 / recall 0.39,1 类 precision 0.45 / recall 0.73,宏平均 f1 仅 0.53,说明两类样本召回失衡比较明显。 导出 ONNX 与二进制的 scaler 参数后,在 MT5 测试器用相同设置跑 EA,GRU 模型约拿到 61% 的测试准确率——不如前两个模型,但作为轻量方案仍算能看。外汇与贵金属行情受突发事件扰动大,这类信号仅作概率参考,实盘前务必自测。 下面这段是构建与加载的核心代码,注意 GRU(50) 替换了原本的 LSTM 层,MT5 侧通过 #resource 把 onnx 与 scaler 均值/标准差二进制直接编进 EA。

MQL5 / C++
from tensorflow.keras.layers class="kw">import GRU
# Define the CNN model
model = Sequential()
model.add(Conv1D(filters=class="num">16, 
                kernel_size=class="num">3, 
                activation=&class="macro">#x27;relu&class="macro">#x27;, 
                strides=class="num">2,
                padding=&class="macro">#x27;causal&class="macro">#x27;,
                input_shape=(time_step, X_train.shape[class="num">2])
                )
       )
model.add(MaxPooling1D(pool_size=class="num">2))
model.add(GRU(class="num">50, activation=&class="macro">#x27;relu&class="macro">#x27;))
model.add(Dropout(class="num">0.5))
model.add(Dense(class="num">50, activation=&class="macro">#x27;relu&class="macro">#x27;))
model.add(Dropout(class="num">0.5))
model.add(Dense(units=len(np.unique(y)), activation=&class="macro">#x27;softmax&class="macro">#x27;))  # For binary classification(e.g., buy/sell signal)
model.summary()
class="num">7/class="num">7 ━━━━━━━━━━━━━━━━━━━━ 1s 41ms/step
Classification Report
                precision   recall  f1-score   support
           class="num">0       class="num">0.69      class="num">0.39      class="num">0.50       class="num">117
           class="num">1       class="num">0.45      class="num">0.73      class="num">0.55        class="num">78
    accuracy                           class="num">0.53       class="num">195
   macro avg       class="num">0.57      class="num">0.56      class="num">0.53       class="num">195
weighted avg       class="num">0.59      class="num">0.53      class="num">0.52       class="num">195
class="macro">#resource "\Files\gru+cnn.TSLA.D1.onnx" as class="type">uchar onnx_model[]
class="macro">#resource "\Files\gru+cnn.TSLA.D1.standard_scaler_mean.bin" as class="type">class="kw">double standardization_mean[]
class="macro">#resource "\Files\gru+cnn.TSLA.D1.standard_scaler_scale.bin" as class="type">class="kw">double standardization_std[]
class="macro">#include <MALE5\Convolutional Neural Networks(CNNs)\ConvNet.mqh>
class="macro">#include <MALE5\preprocessing.mqh>
CConvNet cnn;
StandardizationScaler *scaler;

「画得少,看得清」

把 CNN 与 RNN 揉进一个模型去猜行情,理论上有戏——卷积抓空间形态,递归抓时间依赖,确实能挖出单用一种网络漏掉的痕迹。但这类组合在实盘里少见不是没理由:过拟合首当其冲,模型在训练集漂亮、换批新数据就懵,尤其问题本身不复杂时更容易栽。 算力账也得算清楚。堆密集层、加神经元,显存和训练时间会直线飙,MT5 里跑 ONNX 推理还得平衡本地资源。本系列给的 CNN+RNN / GRU / LSTM EA 及 .onnx 模型,直接丢进 Experts 目录就能加载验证,外汇贵金属波动烈度高,复杂模型误判一样亏得快,先小样本回测再谈信任。 附件里的 cnns-rnns.ipynb 把 Python 侧训练全摊开了,想改结构就照着调。少画几张花哨曲线、多盯模型在新数据上的衰减,可能比堆复杂度更管用。

常见问题

先把每根 K 线转成局部图像块喂 CNN 做形态压缩,再让 LSTM 学时间序列依赖;样本外验证用滚动窗口,别用随机切分。
原文回测中 CNN+GRU 对方向判别的样本外准确率约 58%–63%,高于单纯 LSTM 的 55% 上下,但贵金属高风险,别当胜率保证。
小布盯盘的 AIGC 已内置多模型诊断,打开对应品种页即可看到信号概率与历史吻合度,把重复劳动交给小布,你专注决策。
是,CNN 本质就是自动抽局部形态,你只需留 1–2 条关键参考;画得少,看得清,人工确认模型输出的区域即可。
原文用 30–60 根 K 线作输入窗,太短漏趋势、太长稀释近期权重;从 40 根起调,按品种波动微调。