LSTM外汇预测实战:USDJPY分钟级数据从数据管线到滚动回测
发布时间:2026/9/28 2:07:56来源:尧图网络
简介这份资源是一套基于LSTM网络的外汇预测模型Python实现面向计算机相关专业学生、教师及企业员工可用于深度学习与时间序列分析的学习实践也可作为课程设计、毕业设计或作业的参考方案。压缩包共31个文件约13.41MB包含py脚本、ipynb笔记本、csv汇率数据、模型权重与配置文件等覆盖数据准备、模型训练、测试与预测的完整流程。资源中提供了USDJPY、GBPUSD等外汇对的历史数据以及时间序列处理模块和通用变量定义便于理解LSTM门控机制在汇率预测中的应用。目前已有48人学习下载。通过README.md可了解使用方法与依赖安装读者能掌握数据清洗、标准化、序列切分、模型搭建与评估的完整思路并借鉴多模型预测与训练测试分离的代码组织方式适合作为入门深度学习与金融时间序列的实操素材。1. 拆开这份 LSTM 外汇预测包USDJPY 分钟级数据到底能跑出什么外汇分钟级预测这件事很多人第一反应是「玄学」但真把一份能跑的 LSTM 源码摊在桌上你会发现它解决的其实是很具体的问题把 USDJPY.M1 这种一分钟一根的行情序列喂进带门控的循环网络让它学出下一根 K 线的方向或价格。这份资源就是干这个的——ForexForecast-main.zip里同时给了数据、脚本、训练好的模型和 notebook不是那种只丢一个.py让你自己猜的残缺包。它适合谁计算机专业做毕设、课程设计的学生想找一个「数据齐、能跑通、有训练有测试」的时间序列项目也适合已经会 Python、想看看 LSTM 在外汇这种高噪声序列上怎么落地的人。不适合指望它直接拿去实盘赚钱的——分钟级汇率受消息面冲击极大模型给的是统计规律不是水晶球。下面我按「数据怎么进、模型怎么搭、坑在哪、怎么验证」的顺序把这份包拆开讲清楚。2. 数据管线与文件结构从 CSV 到模型能吃进去的张量2.1 先认清包里每个文件是干嘛的拿到一个陌生源码包我习惯先tree一遍再动手不然改错文件白折腾。这份包的目录结构大致是这样路径作用data/USDJPY.M1-train.csv训练集分钟级 USDJPY 行情data/USDJPY.M1-validate.csv验证集调参和早停用data/USDJPY.M1-test.csv测试集最终评估训练时绝不能碰data/USDJPY.M1.csv全量原始数据切分前的源头prep_and_split.ipynb数据清洗、标准化、切分流程time_series.py时间序列处理的自定义模块common_variables.py全局变量、路径、超参集中定义train_model.ipynb训练主流程test_model.ipynb测试与预测multi_pred_model.ipynb多步/多变量预测models/USDJPY.M1-32-256-14/已保存的模型SavedModel 格式scalers/USDJPY.M1-32-256-14.bin对应的标准化器必须和模型配对这里最关键的一点models和scalers是成对的。模型目录名USDJPY.M1-32-256-14里的数字不是随便起的通常对应「窗口长度-隐藏单元数-特征维度」这类超参组合。你换数据、换窗口就得重新训练并重新生成 scaler不能拿旧 scaler 套新模型。2.2 数据清洗与标准化为什么必须用 scaler 而不是随手除LSTM 对输入尺度非常敏感。汇率价格量纲和收益率、成交量完全不在一个数量级直接喂原始价格梯度会被大数值主导训练要么不收敛要么震荡。所以标准做法是先做标准化再把 scaler 存下来——因为预测阶段要用同一个 scaler 反变换回真实价格。# time_series.py 里常见的标准化与滑窗构造逻辑示意 import numpy as np from sklearn.preprocessing import MinMaxScaler import joblib def build_windows(series, window32): 把一维序列切成 (样本数, 窗口长度, 特征数) 的三维张量 X, y [], [] for i in range(len(series) - window): X.append(series[i:i window]) # 过去 window 根 y.append(series[i window]) # 预测下一根 return np.array(X), np.array(y) # 只用训练集 fit避免验证/测试信息泄漏 scaler MinMaxScaler(feature_range(0, 1)) train_scaled scaler.fit_transform(train_df[[close]]) joblib.dump(scaler, scalers/USDJPY.M1-32-256-14.bin) X_train, y_train build_windows(train_scaled, window32) X_train X_train.reshape((X_train.shape[0], X_train.shape[1], 1))逻辑说明build_windows把时间序列转成监督学习样本window32表示用过去 32 分钟预测第 33 分钟。参数上window越大模型看到的上下文越长但样本数会减少、训练变慢feature_range(0,1)是 MinMax 的常规选择也有人用标准化均值 0 方差 1差别在于对异常值的敏感度。注意scaler 一定要在训练集上fit然后transform验证集和测试集。如果对全量数据一起 fit测试集的信息就泄漏进训练了评估结果会虚高这是时间序列里最常见的翻车点之一。2.3 训练/验证/测试三分时间序列不能随机打乱普通分类任务可以train_test_split(shuffleTrue)但时间序列绝对不行。你把未来某天的数据打乱进训练集模型等于提前看了答案。这份包直接给了三个独立 CSV就是按时间顺序切好的省得你自己切错。# 按时间顺序读取不做 shuffle train_df pd.read_csv(data/USDJPY.M1-train.csv, parse_dates[time]) val_df pd.read_csv(data/USDJPY.M1-validate.csv, parse_dates[time]) test_df pd.read_csv(data/USDJPY.M1-test.csv, parse_dates[time]) # 确认时间不重叠 assert train_df[time].max() val_df[time].min() assert val_df[time].max() test_df[time].min()参数说明parse_dates把时间列解析成 datetime方便后续做时序对齐和可视化。那两行assert是我自己加的保险很多包不写但你复现时最好确认一遍防止数据被二次处理时顺序错乱。3. LSTM 模型搭建与训练门控机制怎么落到 Keras 代码里3.1 为什么是 LSTM 而不是普通 RNN 或 ARIMA普通 RNN 在长序列上会遇到梯度消失几十步之前的输入对当前几乎没影响。LSTM 靠遗忘门、输入门、输出门三个门控决定「哪些旧信息留、哪些新信息进、当前输出多少」本质上是在序列里维护一条受控的记忆通道。外汇分钟序列里价格惯性、短期波动聚集这些模式往往跨越几十根 K 线LSTM 的门控正好对上这个需求。ARIMA/GARCH 这类传统方法强在可解释性和统计假设但对非线性、多因子交互的刻画能力有限。LSTM 不假设线性关系能从数据里自己学代价是需要更多数据和调参。这份包选 LSTM方向是对的但别指望它单靠价格序列就能稳定盈利。3.2 用 Keras 搭一个可训练的 LSTMfrom tensorflow.keras.models import Sequential from tensorflow.keras.layers import LSTM, Dense, Dropout from tensorflow.keras.callbacks import EarlyStopping model Sequential([ LSTM(256, input_shape(32, 1), return_sequencesFalse), # 256 隐藏单元 Dropout(0.2), # 抑制过拟合 Dense(1) # 回归输出下一根价格 ]) model.compile(optimizeradam, lossmse, metrics[mae]) early_stop EarlyStopping(monitorval_loss, patience5, restore_best_weightsTrue) history model.fit( X_train, y_train, validation_data(X_val, y_val), epochs50, batch_size64, callbacks[early_stop], verbose1 ) model.save(models/USDJPY.M1-32-256-14)逻辑说明LSTM(256)对应目录名里的 256隐藏单元越多拟合能力越强但过拟合风险和数据需求也越大。return_sequencesFalse表示只取最后一步输出做预测如果你要做多步预测就得改成True再接更多层。Dropout(0.2)是正则化EarlyStopping在验证损失不再下降时停手并回滚到最优权重这是防止「训练集 loss 一直降、验证集反而涨」的后悔药。参数怎么调batch_size从 32 到 128 都常见小 batch 噪声大但可能泛化更好epochs配合早停设大一点没关系patience5表示连续 5 轮没改善就停数据噪声大时可以放宽到 8~10。3.3 训练完怎么确认模型真的学到了东西训练 loss 下降不代表模型有用。我一般会做两件事一是把预测值反变换回真实价格和测试集画在同一张图上二是算几个朴素基线做对比——比如「直接用上一分钟价格当预测」如果 LSTM 连这个都打不过说明模型没学到有效模式。pred_scaled model.predict(X_test) pred scaler.inverse_transform(pred_scaled) # 反变换回价格 actual scaler.inverse_transform(y_test.reshape(-1, 1)) # 朴素基线用窗口最后一个值当预测 naive X_test[:, -1, 0].reshape(-1, 1) naive scaler.inverse_transform(naive) from sklearn.metrics import mean_absolute_error print(LSTM MAE :, mean_absolute_error(actual, pred)) print(Naive MAE:, mean_absolute_error(actual, naive))如果两者接近说明这份数据在当前特征下可预测性很弱别急着调网络先回去看特征工程——加成交量、加多周期、加技术指标往往比换网络结构更有效。4. 避坑与常见问题排查跑不通多半是这几个原因4.1 现象加载模型报形状不匹配原因input_shape里的窗口长度或特征数和保存模型时不一致或者你改了window却没重训。解决以models目录名里的超参为准common_variables.py里的window、features要和模型对齐改任何一个都要重新训练。4.2 现象预测结果全是同一条直线原因模型塌缩到预测均值通常是学习率过大、训练不充分或者标准化做错比如对全量数据 fit 导致分布偏移。解决先检查 scaler 是否只在训练集 fit再把学习率降到 1e-3 甚至 1e-4观察 loss 是否正常下降。4.3 现象验证 loss 先降后升原因过拟合。分钟级外汇数据噪声极高模型很容易记住训练集的噪声。解决加 Dropout、减小隐藏单元、加 L2 正则或者干脆缩短window减少参数量。早停一定要开。4.4 现象notebook 里 import 自定义模块失败原因time_series.py、common_variables.py不在当前工作目录或.idea里的路径配置残留。解决把 notebook 的工作目录设到项目根目录或在开头sys.path.append(项目根路径)。.idea那堆文件是 IDE 配置换机器直接忽略。4.5 现象测试集 MAE 很小但实盘完全不能用原因测试集和训练集来自同一段市场状态分布接近真实行情换了波动 regime 后模型失效。解决做滚动回测walk-forward每隔一段时间用新数据重训别拿一次性切分的测试结果当长期能力。5. 进阶验证与滚动回测把一次性评估换成走步检验一次性切分的测试集只能告诉你「模型在这段历史上表现如何」但外汇市场的波动结构会变。真正靠谱的验证是滚动回测用前 N 天训练预测接下来一段然后窗口往前滚重新训练再预测。这样得到的指标才接近实盘会遇到的情况。def walk_forward(df, window32, train_size5000, step500): 滚动训练预测返回每段的预测误差 errors [] for start in range(0, len(df) - train_size - step, step): train df.iloc[start:start train_size] test df.iloc[start train_size:start train_size step] # 每个窗口重新 fit scaler避免跨段泄漏 sc MinMaxScaler().fit(train[[close]]) Xtr, ytr build_windows(sc.transform(train[[close]]), window) Xte, yte build_windows(sc.transform(test[[close]]), window) m build_model(window) # 复用同一套结构 m.fit(Xtr, ytr, epochs10, verbose0) pred sc.inverse_transform(m.predict(Xte)) actual sc.inverse_transform(yte.reshape(-1, 1)) errors.append(mean_absolute_error(actual, pred)) return np.mean(errors), np.std(errors)逻辑说明每个滚动窗口都重新fitscaler 和模型杜绝任何跨段信息泄漏。train_size和step是权衡——训练窗口越大越稳但越慢步长越小评估越密但计算量越大。返回的均值和标准差一起看均值低但标准差大说明模型在某些市场状态下会崩稳定性不够。我自己的习惯是任何时间序列模型上线前滚动回测的误差标准差必须小于均值的某个比例否则宁可不用。这份包给的是学习和研究起点真要往实盘方向走滚动回测、特征扩展、风控缺一不可。从那以后我每次拿到新的时序模型都强制先跑一遍 walk-forward 再谈别的指标。希望这份拆解帮到你README 先读数据先对齐再动手改网络。本文还有配套的精品资源点击获取
网站建设高端定制企业官网