FEATURED · 精选文章

LSTM股价预测:从开源代码到参数调优和回测验证

发布时间 / 2026/9/16 1:57:51
来源 / 创域科博编辑部
栏目 / 资讯中心
LSTM股价预测:从开源代码到参数调优和回测验证 简介这是一个聚焦LSTM长短期记忆网络在股价预测中应用的代码包适合刚接触时序预测的开发者也适合用深度学习完成量化分析实验的学生。项目完整覆盖股价预测全流程历史数据读取、归一化、滑动窗口构造特征、模型搭建、训练与可视化评估并附带空气质量等多组CSV示例数据方便对比不同序列长度与特征组合的效果。压缩包共153个文件约5.49MB其中89个Python脚本负责数据预处理、模型训练及绘图28个CSV文件提供训练样本与测试数据其余为日志、配置、检查点及h5模型权重可直接加载推理目录结构清楚便于按模块学习。目前已有90人浏览学习既可作为入门LSTM的动手教程也能用于课程设计、竞赛复现或后续研究的扩展基础。1. LSTM股价预测开源可执行代码能跑通不等于参数能用从 GitHub 上随便找一个星标过千的 LSTM 股价预测开源项目装完依赖直接跑大概率看到一条完美贴合的曲线训练 loss 降到万分之几测试集预测和真实收盘价几乎重叠。换一只股票、换一段行情再跑问题就暴露了——预测曲线比真实曲线慢一拍前一天涨模型第二天才跟。这不是代码写错了而是 LSTM 时间序列预测的固有特性开源代码能跑通只代表语法和流程正确不代表参数对这个数据集成立。下面把「LSTM学习可执行代码」和「开源的基于LSTM的股价预测代码」这两类需求合并成一条可复现路径先看懂开源代码里滑动窗口、归一化、张量形状这些约定再跑通最小可执行脚本然后按顺序调 time_step、units、dropout最后用 walk-forward 回测和基准模型判断结果可不可信。第一次接触 lstm 时间序列预测 python 的新手可以直接照抄代码跑过开源项目的熟手也能在参数边界和验证手法上找到自己的盲区。2. 看懂LSTM股价预测代码的输入输出约定滑动窗口、归一化与张量形状2.1 从RNN到LSTM神经网络门控机制为什么适合股价序列股价数据本质是带噪声的非平稳时间序列今天的收盘价和 30 天前的收盘价之间存在弱相关但普通循环神经网络在反向传播时梯度要穿过多个时间步连乘序列一长梯度就消失模型记不住 20 天前的信息。LSTM 神经网络的解决办法是在循环单元内部加一条细胞状态通道配合遗忘门、输入门、输出门三个门控结构让信息可以选择性写入、保留或丢弃。用一句人话概括遗忘门决定昨天的记忆还要不要输入门决定今天的新信息值不值得记输出门决定把当前记忆的哪一部分暴露给下一层。这种机制让 LSTM 在中等长度的金融序列上比普通 RNN 更能同时捕捉趋势延续和均值回归两类模式。需要强调LSTM 并不保证预测盈利它只是把时间依赖关系建模得更充分。这是所有开源股价预测代码的理论基础也是你判断哪里能改、哪里不能动的出发点——模型结构里的 return_sequences、units、dropout 都可以调但门控机制本身不要去动。2.2 滑动窗口把一维价格序列改造成监督学习样本LSTM 的输入要求是三维张量 (样本数, 时间步长, 特征数)原始 CSV 里的收盘价是一维序列所以要先切成固定长度窗口。开源代码里最常见的做法是 time_step30用第 1 到第 30 天收盘价预测第 31 天再用第 2 到第 31 天预测第 32 天窗口每次滑一步。改造后样本数从 n 变成 n - time_step - 1逻辑上等价于给每个样本配一个未来一天的标签。time_step样本数1000天数据模型能看到的历史适用场景10989两周短线波动噪声大30969一个半月开源项目默认值折中最优60939一个季度趋势型行情120879半年长周期样本损失明显窗口越大每个样本携带的历史信息越多但样本总数越少训练集不足时模型方差变大。开源项目默认 30 不是拍脑袋是记忆长度和样本量的折中。构造窗口有一个隐蔽陷阱有的代码用 train_test_split 随机打乱再切分这对时间序列是错的随机划分等于让模型看到未来信息测试集指标虚高。注意学习阶段可以容忍随机切分做回测验证时务必按时间顺序切分否则 RMSE 没有任何参考意义。2.3 MinMax归一化与反归一化开源代码最容易漏掉的对称设计LSTM 内部用 tanh 和 sigmoid 激活函数输入数值过大梯度容易饱和所以几十到几百元的原始价格不能直接喂进去。常见做法是用 MinMaxScaler 缩放到 [0,1] 区间。真正的坑在 fit 的对象很多开源入门代码对全量数据 fit_transform学习场景问题不大但在严格的时间序列验证里scaler 见过未来数据的最大值和最小值等于把测试集信息泄漏给训练过程。# 错误全量数据一起fit未来信息泄漏 scaler MinMaxScaler().fit(all_prices) # 正确只用训练集fit再transform训练集和测试集 scaler MinMaxScaler().fit(train_prices) train_scaled scaler.transform(train_prices) test_scaled scaler.transform(test_prices)逻辑说明MinMaxScaler 会记录训练阶段的最小值和最大值测试集用同一个 scaler transform保证测试数据落在训练分布内且没有让模型先看到测试集的统计量。预测完成后必须用同一个 scaler 的 inverse_transform 把结果还原成价格单位这就是对称设计——先缩进去再从同一个对象里缩放回来。另一类常见错误是特征维度不一致有人把 close、volume 五个特征一起归一化训练输入形状是 (time_step, 5)预测时只给一个 close维度对不上直接报错。改特征时数据管道和模型输入要同步改这是把开源代码改造成自己数据时最常翻车的地方。3. 本地跑通LSTM股价预测可执行代码从CSV到预测曲线的完整Python脚本3.1 依赖安装与数据准备先保证环境能跑选型上的建议TensorFlow 2.x 已经把 Keras 内置为 tf.keras不需要单独装 keras 包Python 用 3.9 到 3.11配合 tensorflow 2.10 以上版本比较稳。最小依赖如下pip install numpy pandas scikit-learn tensorflow matplotlib akshareakshare 是开源数据接口库用来拉 A 股日线数据不想装它的话直接用本地 CSV 即可。装完后验证 import 正常再进入下一步。数据源方面我一般建议先手上有 CSV格式包含 date、open、high、low、close、volume 六列任何行情软件都能导出。想自动拉数据时用 akshareimport akshare as ak df ak.stock_zh_a_hist(symbol000001, perioddaily, start_date20190101, end_date20231231, adjustqfq) df df[[日期, 开盘, 收盘, 最高, 最低, 成交量]] df.columns [date, open, close, high, low, volume] df.to_csv(stock.csv, indexFalse)参数说明symbol 是股票代码perioddaily 表示日线adjustqfq 是前复权避免除权除息造成价格跳空。akshare 的字段名会随上游数据源调整跑不通时先打印 df.head() 看列名再改映射别在列名上死磕。拿到 CSV 后按日期升序读入这是后续所有步骤的前提——时间序列的样本顺序一旦乱了切分和验证全是错的。3.2 构造滑动窗口样本并用MinMaxScaler归一化下面的 make_dataset 函数是开源 LSTM 股价预测代码里最标准的切片逻辑直接抄下来改成自己的数据就能用import numpy as np import pandas as pd from sklearn.preprocessing import MinMaxScaler df pd.read_csv(stock.csv, parse_dates[date]).sort_values(date) prices df[close].values.reshape(-1, 1) scaler MinMaxScaler(feature_range(0, 1)) scaled scaler.fit_transform(prices) def make_dataset(data, time_step30): X, y [], [] for i in range(len(data) - time_step - 1): X.append(data[i:i time_step, 0]) # 第 i 到 itime_step-1 天 y.append(data[i time_step, 0]) # 第 itime_step 天作为标签 return np.array(X), np.array(y) time_step 30 X, y make_dataset(scaled, time_step) print(X.shape, y.shape) # 例如 (940, 30) (940,)逻辑说明循环从第 0 位滑到 len(data) - time_step - 1每次取 time_step 长度的窗口作为 X窗口后一天的价格作为 y把无监督的价格序列变成监督学习样本。reshape(-1, 1) 是因为 MinMaxScaler 要求二维输入。打印的形状里940 971 天数据 - 30 天窗口 - 1 个标签位对得上就说明预处理正确对不上就回头检查排序和时间步。3.3 搭建两层LSTM模型并训练return_sequences是关键参数训练集和测试集按时间顺序切分前 80% 训练、后 20% 测试然后 reshape 成 Keras 要求的三维张量split int(len(X) * 0.8) X_train, X_test X[:split], X[split:] y_train, y_test y[:split], y[split:] X_train X_train.reshape(-1, time_step, 1) X_test X_test.reshape(-1, time_step, 1) from tensorflow.keras.models import Sequential from tensorflow.keras.layers import LSTM, Dense, Dropout from tensorflow.keras.callbacks import EarlyStopping model Sequential([ LSTM(50, return_sequencesTrue, input_shape(time_step, 1)), Dropout(0.2), LSTM(50, return_sequencesFalse), Dropout(0.2), Dense(1) ]) model.compile(optimizeradam, lossmse) early_stop EarlyStopping(monitorval_loss, patience10, restore_best_weightsTrue) history model.fit(X_train, y_train, batch_size64, epochs100, validation_split0.1, callbacks[early_stop], verbose1)参数说明第一层 LSTM 的 return_sequencesTrue返回每个时间步的完整隐藏状态序列第二层才能继续沿时间维度处理最后一层 return_sequencesFalse只返回最后一步的输出接 Dense(1) 输出下一日收盘价。Dropout(0.2) 随机丢弃 20% 的神经元连接抑制过拟合。batch_size64 是每次梯度更新用的样本数epochs100 是最大训练轮数EarlyStopping 在验证 loss 连续 10 轮不下降时提前停止restore_best_weightsTrue 会把模型回滚到验证 loss 最低的一轮。如果这里报维度错误检查 reshape 的最后一维是否和 LSTM 输入特征数一致。3.4 预测、反归一化与绘图先看滞后现象再谈准确率训练完成后测试集预测和真实值都要用同一个 scaler 还原成价格pred model.predict(X_test) pred_price scaler.inverse_transform(pred) true_price scaler.inverse_transform(y_test.reshape(-1, 1)) import matplotlib.pyplot as plt plt.figure(figsize(12, 5)) plt.plot(true_price, labelreal) plt.plot(pred_price, labellstm_predict) plt.legend() plt.title(LSTM stock close price prediction) plt.show() rmse np.sqrt(np.mean((pred_price - true_price) ** 2)) print(fRMSE: {rmse:.2f})这段代码最容易踩的坑是忘记 inverse_transform导致预测曲线全程压在 0 到 1 区间跟真实价格完全对不上。另一个典型现象是预测曲线整体比真实曲线滞后一天尤其在转折点——LSTM 学到的是昨天的价格是最强的特征所以明天的预测约等于今天价格加一个小的修正项。看到这种图不用慌先记录 RMSE去第四章调参数最后用第五章的基准对比确认模型到底有没有预测能力。4. 开源LSTM股价预测代码的必调参数time_step、units、dropout谁先动4.1 先定time_step窗口长度决定记忆范围与样本数量time_step 是第一个要动的参数它决定模型能回头看多少天也决定训练样本量。默认 30 对日线数据基本合理但要根据数据长度调整数据只有 500 天时把 time_step 设 60样本掉到 439 个训练集只剩 350 个模型很容易过拟合数据超过 2000 天时30 窗口又会浪费长周期趋势信息。我一般按总样本量决策少于 1000 天用 20 到 301000 到 3000 天用 30 到 60更长才考虑 90 以上。改 time_step 时有三处必须同步make_dataset 的参数、input_shape 的第一维、预测时喂给模型的数据窗口长度。开源代码里最隐蔽的 bug 是只改了前两处训练正常预测时报维度错误。提示改完 time_step 后先打印 X.shape确认第二维等于你设置的窗口长度再往下跑训练。4.2 units与层数模型容量和过拟合的平衡units 是每个 LSTM 层的神经元数量。股价数据信噪比低网络不是越大越好。主流开源代码里 50 到 128 是常见区间层数一层到两层最多三层以上在日线级别数据上基本只增加训练时间不提升泛化。判断标准是训练 loss 和验证 loss 的差距差距持续扩大是过拟合优先加 Dropout 而不是降 units两者都在高位下不去才是容量不足再加 units。第一层和第二层 units 可以不同常见搭配是 (64, 32) 或 (50, 50)。units 调大后 batch_size 也要跟着调否则训练速度和显存都吃不消。CPU 机器建议从 32 起步先跑一个 epoch 看耗时再决定要不要升配。4.3 dropout、batch_size、epochs与早停四个联动参数一起调这四个参数联动性强分开调容易顾此失彼。dropout 控制随机丢弃比例0.1 到 0.3 是常见区间股价预测这种低信噪比任务从 0.2 起步比较稳。batch_size 影响梯度估计稳定性64 是日线数据的安全默认值数据量大可上 128数据量小用 32。epochs 不要拍脑袋定 50配合 EarlyStopping 设 100 到 150让训练在验证 loss 不再下降时自动停。参数新手默认值调参范围过拟合征兆time_step3010~90训练loss降但验证loss涨units5032~128训练loss趋近0验证loss高位徘徊dropout0.20.1~0.4验证loss波动大batch_size6432~128训练曲线震荡epochs100早停50~200训练loss降验证loss回升调参顺序建议先固定 time_step 和 units把 dropout、batch_size、早停组合跑通再回来调 time_step动了 units 就重新检查 dropout。一次只动一个参数每次记录 RMSE同时改三四个的话你根本不知道是哪个改动起了作用。4.4 评价指标RMSE之外必须验证方向准确率开源代码里最常见的评价语句是model.evaluate(X_test, y_test)返回的 mse 是绝对值指标。价格从 50 涨到 200 的股票 RMSE3 可能已经很准价格在 5 到 10 之间波动的股票 RMSE3 完全不能用。所以 RMSE 只能在同标的、同时间段内比较参数优劣不能跨股票比较。更接近交易场景的指标是方向准确率——预测涨跌方向和真实涨跌方向一致的比例direction_acc np.mean(np.sign(pred_price[1:] - pred_price[:-1]) np.sign(true_price[1:] - true_price[:-1])) print(fDirection accuracy: {direction_acc:.2%})逻辑说明np.sign 把每天的差分映射成 1、0、-1再逐位比较预测方向和真实方向是否一致均值就是方向准确率。如果长期在 50% 附近打转说明模型只拟合了绝对价格水平对涨跌没有预测力这时候调参救不回来要做第五章的验证和基准对比。5. LSTM股价预测结果上线前的回测验证walk-forward与基准对比5.1 用walk-forward滚动验证替代一次性切分一次性 80/20 切分的最大问题是结果依赖那 20% 测试期的行情——如果测试期恰好是单边上涨所有模型看起来都很准。更稳的做法是 walk-forward 滚动验证先用第 1 到第 500 天训练预测第 501 到第 520 天再把训练集扩到第 520 天预测后面 20 天滚到数据末尾。每步预测拼接起来算整体误差才有统计意义。实现时把第三章的 fit 包一层循环每轮重新创建模型重新 fit MinMaxScaler避免上一轮状态泄漏到下一轮。5.2 给LSTM配两个基准naive预测和线性回归不做基准对比的回测没有意义。第一个基准是 naive 预测即明天的价格等于今天的价格直接把真实收盘价整体平移一天。这个基准极难打败因为股价接近随机游走。第二个基准是带滑动窗口的线性回归用同样窗口构造特征、预测同一目标。把 LSTM、naive、线性回归画在同一张图上如果 LSTM 的 RMSE 只比 naive 低 2% 到 3%基本可以判断模型只是拟合了价格惯性没有额外信息方向准确率上LSTM 也至少要稳定超过 52% 到 53%才值得进入下一步。5.3 一个提升参数对比可靠性的技巧固定种子多次训练LSTM 初始化带随机性同一份代码跑两次 RMSE 可能差 10%。判断参数好坏之前先设np.random.seed(42)和tf.random.set_seed(42)每个配置至少训练三次取 RMSE 均值和标准差再比较。标准差比均值更能说明模型稳定性——平均 RMSE 低但三次结果忽高忽低的参数组合换一段行情就会失效不值得采用。本文还有配套的精品资源点击获取
RELATED — 相关阅读

相关资讯

LATEST — 最新资讯

最新发布

TODAY — 本日精选

新闻

WEEKLY — 本周精选

新闻

MONTHLY — 本月精选

新闻