RNN外汇时间序列预测:从序列记忆到Python建模基础(基础篇)
(1/3)· 多数交易者用独立样本喂模型,却忽略价格本是前后纠缠的序列,本文补上RNN认知底座
「用 RNN 给外汇序列建模前先看清数据底座」
在 MT5 里做外汇时间序列预测,RNN 不是直接把收盘价丢进去就能跑。EURUSD 的 H1 收盘价序列在 2020—2024 年样本内年化波动率约 8.3%,序列非平稳,直接训练会让梯度在长周期里被早期噪声稀释。 先对价格做对数差分得到收益率序列,再按滚动窗口(如 window=30 根 H1 K 线)构造监督学习样本。这样网络输入维度固定,且弱化了量纲漂移。注意外汇与贵金属杠杆高,模型输出只是概率倾向,实盘前必须在 MT5 策略测试器用穿出验证(walk-forward)而不是单次回测。 小布盯盘的做法是先用 Python 抽 EURUSD H1 数据,归一化到 [-1,1] 再交 RNN;MT5 端只负责把模型推理结果映射成信号。这样能避开 MQL5 张量运算弱的短板。
◍ RNN 在 MT5 里的落地路径
想把循环神经网络(RNN)真正用进外汇或贵金属策略,第一步不是调参,而是先把数据变成序列。MT5 导出的收盘价、成交量若直接丢进模型,网络学不到时间依赖;必须按窗口长度重排成监督学习样本,这一步决定后续 EA 是否只是拟合噪声。 原文给出的技术链路很直接:用 Python 造序列数据 → 训练回归或分类 RNN → 存成 ONNX → 进 MT5 策略测试器跑 EA。其中 ONNX 是绕开 MQL5 原生不支持深度学习的关键桥,没有它,RNN 只能停留在研究端。 外汇与贵金属杠杆高、跳空频繁,RNN 在回测里看到的连续序列,实盘可能因流动性断裂而失效。建议先拿 EURUSD 的 H1 数据跑通回归 RNN,观察测试器里样本外误差是否稳定低于 0.0003,再考虑上实盘信号过滤。
RNN 与 RNNs 家族的边界在哪
循环神经网络(RNNs)是一类专门吃序列数据的人工神经网络,用来从时间序列、语言或视频流里抓前后依赖的模式。传统前馈网络默认每个输入独立无关,而 RNN 会把上一步的隐藏状态带进下一步,因此能识别序列里的结构。 这里有个术语坑得先厘清:本文里单独说「循环神经网络」时,特指最简单的 simple RNN 那种基础模型;而写「循环神经网络(RNNs)」是泛指整个家族,包含 simple RNN、LSTM、GRU 等变体。混用会直接读歪后续内容。 要在 MT5 里真正跑通这类模型,你得先有 Python 基础、懂 MQL5 调用 ONNX 的接口,以及会写 Python 机器学习训练脚本。三者缺一个,后面的实盘验证都落不了地。
「RNN的序列记忆为什么撑不过长句子」
循环神经网络靠「序列记忆」把前一个时间步的信息喂给后一个时间步,逻辑上很像人边听边组织语句。底层仍是前馈网络首尾相接,当前节点能拿到前一节点的状态,从而基于历史理解当下。 拿聊天机器人理解「what time is it now?」举例:单词被切成时间步依次送入。t=0、t=1 时末节点里几乎看不到信息;走到 what、time 这两个词时,它们在最终节点里已经几乎消失。这种随步数拉长而丢前文的现象就是短期记忆。 根子在反向传播。RNN 走的是随时间反向传播(BPTT),梯度按时间步往回传时会指数级缩小。梯度本是用来调权重和偏置的,梯度小意味着早期层调不动、学不进去,这就是梯度消失。实测里,简单 RNN 在上面的句子上只能靠「is it ?」半句瞎猜,what、time 直接被忽略。 外汇与贵金属的行情序列往往上百根 K 线,简单 RNN 这种短时记忆基本不可用,误判概率偏高。后来出的 LSTM 和 GRU 用「门」机制缓解这个问题,能抓长期依赖,下篇再拆。
◍ RNN 怎么靠隐藏状态记住行情节奏
循环网络和前馈网络最大的区别,是隐藏层自己跟自己连了一条回路。这条回路让时间步 t 的隐藏状态 h_t 能携带之前所有步的残影,相当于给价格序列装了一段短期记忆。 具体计算上,h_t = σ(W_x·x_t + W_h·h_{t-1} + b_h)。W_x 管当前输入,W_h 管上一刻的记忆,b_h 是偏置,σ 多用 tanh 或 ReLU。输出层再拿 o_t = W_o·h_t + b_o 算出这一步的预测值。 训练时把所有时间步的损失加起来:L = Σ L_t,再用随时间反向传播(BPTT)算梯度。隐藏偏置的总梯度是各步 ∂L/∂h_t 经激活导数链式求和,权重 W_h、W_x 同理累计后丢进 Adam 这类优化器更新。 简单 RNN 对超长周期建模力不从心,但抓近几十根 K 线的依赖还够用。外汇与贵金属杠杆高、跳空频繁,用其辅助决策前务必在 MT5 用历史数据回测,实盘仅作概率参考而非方向保证。
用 Keras 搭一个回归型 RNN 只需几行
在 Python 里用 Keras 写循环神经网络,核心就是 Sequential 堆叠层,编译也就一行。下面这段是面向回归任务的 RNN,输出层只挂 1 个节点、末层用 ReLU,和前馈网络里讲过的输出设计思路一致。 之所以选 RNN 而不是普通树模型,是因为它自带时间步记忆,对之前整理过的外汇时间序列更友好。我们拿同一份数据,把它和早先的 LightGBM 放一起比一比,性能差异可能帮你判断哪类模型更适合这类行情序列。外汇与贵金属波动剧烈,任何模型输出都只是概率倾向,实盘前务必在 MT5 回测环境交叉验证。 [CODE] import tensorflow as tf from tensorflow.keras.models import Sequential #import sequential neural network layer from sklearn.preprocessing import StandardScaler from tensorflow.keras.layers import SimpleRNN, Dense, Input from keras.callbacks import EarlyStopping from sklearn.preprocessing import MinMaxScaler from keras.optimizers import Adam reg_model = Sequential() reg_model.add(Input(shape=(time_step, x_train.shape[1]))) # input layer reg_model.add(SimpleRNN(50, activation='sigmoid')) #first hidden layer reg_model.add(Dense(50, activation='sigmoid')) #second hidden layer reg_model.add(Dense(units=1, activation='relu')) # final layer adam_optimizer = Adam(learning_rate = 0.001) reg_model.compile(optimizer=adam_optimizer, loss='mean_squared_error') # Compile the model reg_model.summary() [/CODE] 代码逐行拆解:导入 tensorflow 并简称为 tf,作为后端;Sequential 用来线性堆叠网络层;StandardScaler 与 MinMaxScaler 都引入了,实际训练前需二选一做归一;SimpleRNN 与 Dense、Input 是层构件;EarlyStopping 可防过拟合;Adam 优化器学习率设 0.001。 网络结构:输入形状依赖 time_step 与特征维度;首隐层 50 个 sigmoid 循环单元;再接 50 个 sigmoid 全连接;末层单节点 ReLU 出回归值;用 Adam 配均方误差编译,summary() 直接打印参数量,方便你核对规模。
class="kw">import tensorflow as tf from tensorflow.keras.models class="kw">import Sequential class="macro">#class="kw">import sequential neural network layer from sklearn.preprocessing class="kw">import StandardScaler from tensorflow.keras.layers class="kw">import SimpleRNN, Dense, Input from keras.callbacks class="kw">import EarlyStopping from sklearn.preprocessing class="kw">import MinMaxScaler from keras.optimizers class="kw">import Adam reg_model = Sequential() reg_model.add(Input(shape=(time_step, x_train.shape[class="num">1]))) # input layer reg_model.add(SimpleRNN(class="num">50, activation=&class="macro">#x27;sigmoid&class="macro">#x27;)) class="macro">#first hidden layer reg_model.add(Dense(class="num">50, activation=&class="macro">#x27;sigmoid&class="macro">#x27;)) class="macro">#second hidden layer reg_model.add(Dense(units=class="num">1, activation=&class="macro">#x27;relu&class="macro">#x27;)) # final layer adam_optimizer = Adam(learning_rate = class="num">0.001) reg_model.compile(optimizer=adam_optimizer, loss=&class="macro">#x27;mean_squared_error&class="macro">#x27;) # Compile the model reg_model.summary()