ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

PSO-LSTM神经网络股票调整收盘价预测Python源码详解

PSO-LSTM神经网络股票调整收盘价预测Python源码详解 简介基于粒子群优化长短期记忆网络的股票调整收盘价预测Python源码适合完成金融数据分析类课程设计或期末大作业的高校学生目标是借助PSO自动寻优LSTM参数实现调整收盘价的单维单步预测。包内共10个文件以Python脚本为核心附带7个csv行情数据文件涵盖BTC-USD、DJI、AAPL等常见标的、1份README说明和1个txt文档整体仅490KB非常轻量。代码注释完整运行流程清晰读者可依据README快速部署也可替换成自己的交易数据观察预测效果。截至目前已有171人学习下载是一份能直接用于答辩演示、具备实际参考价值的完整源码资源。1. PSO-LSTM预测股票调整收盘价这份Python源码能做什么适合谁期末大作业和课程设计里股票预测是最热门也最容易翻车的选题。绝大多数人卡在同一个地方模型跑通了但预测的是原始收盘价分红、拆股一发生数据里全是“假跳变”答辩时被老师一句“你这个序列不平稳怎么解释”问住。这份基于PSO-LSTM神经网络的股票调整收盘价预测Python源码核心价值在于把目标变量换成了调整收盘价Adjusted Close同时用粒子群算法自动搜LSTM的超参数解决了新手调参全靠玄学的问题。压缩包里带了BTC、AAPL、DJI、上证指数等七个CSV数据集主脚本是单维单步MSE预测注释齐全属于那种“下载下来改个路径就能跑”的课程设计资源。适合三类人急着交期末大作业的本科生、想把深度学习预测流程完整走一遍的入门者、以及答辩前想给模型加一两个亮点参数的进阶玩家。2. 为什么是PSO-LSTM调整收盘价这个选题的建模逻辑与参数边界2.1 调整收盘价和原始收盘价的差别预测目标要先选对股票CSV里通常有Open、High、Low、Close、Adj Close、Volume六列。Close是当天收盘的原始价格Adj Close是经过复权处理后的价格已经剔除了分红、送股、拆股对价格连续性的影响。用原始收盘价做预测遇到除权除息日价格会瞬间跳空LSTM会把这个跳空当成真实趋势去学训练出来的loss虚高画出来的预测曲线在除权日附近有明显毛刺。调整收盘价的价值在于价格序列是连续的适合直接做时间序列建模。这也是为什么这份源码把Datasets目录里的数据都落在Adj Close字段上。实际动手时要注意Yahoo Finance下载的数据里Adj Close在靠后位置有的版本是最后一列读CSV时不要用数字索引硬编码直接用列名df[Adj Close]最稳。另外数据文件里如果同时存在Close和Adj Close对比着看一眼能发现两者差异大的日期往往就是发生过分红或拆股的日期这是一个很有用的数据校验技巧。2.2 LSTM凭什么比前馈神经网络更适合预测股票序列前馈神经网络Feedforward Neural Network处理的是固定大小的输入输入和输出之间没有时序依赖。拿过去10天的收盘价预测明天的价格前馈网络的做法是把10个值拼成一个向量塞进去模型完全不知道这10个值的先后顺序第1天的数据和第10天的数据在模型眼里地位相同趋势信息就这么丢了。LSTM通过三个门结构——遗忘门、输入门、输出门——维护一个细胞状态让信息有选择地跨时间步保留或丢弃。股票序列恰好有这种特点过去五天的走势形态往往比某一天的绝对值更重要。PSO-LSTM里的LSTM部分一般用单层或双层LSTM加上全连接输出层输入形状是(batch_size, time_step, feature_dim)这里的feature_dim在单维预测里就是1只喂调整收盘价本身。需要提醒的是LSTM不是神秘的黑匣子它的记忆容量由隐藏层神经元个数决定神经元太少记不住趋势太多则吃训练时间还容易过拟合这个值正是PSO要搜的参数之一。2.3 PSO到底在优化谁三个超参数的搜索空间如果不用PSOLSTM需要手工调的东西很多时间步长、隐藏层神经元数、学习率、批量大小、训练轮数、优化器选择每一个都影响最终MSE。课程设计里时间有限网格搜索动辄几十组实验GPU差一点的机器一天都跑不完。PSO的做法是把一组超参数当成一个“粒子”每个粒子在参数空间里飞行靠个体最优和群体最优更新速度和位置十几轮迭代就能收敛到一组比较合理的参数。在这份单维单步MSE预测脚本里PSO搜索的超参数通常是三个时间步长、LSTM隐藏层神经元数、学习率。粒子群规模一般设10到20迭代次数10到20轮。搜索范围建议按经验值锁定时间步长5到20隐藏层神经元4到64学习率0.0001到0.01。这三个范围太宽会让PSO收敛很慢太窄又等于人工预设了答案。这里的参数设定直接决定了PSO的适应度函数每一次要训练多少个epoch的LSTM评估一次LSTM要几秒到几十秒乘上粒子数和迭代次数就是整个寻参过程的总耗时。跑之前先拿单组参数试一次估算单次LSTM训练时间再反推粒子群规模和迭代次数是控制总耗时的核心办法。2.4 单维单步与MSE这个任务的边界要清楚文件名里写着“单维单步mse预测”这是整个项目的任务定义也是答辩时最容易被追问的地方。单维指只用调整收盘价这一个特征没有引入成交量、技术指标或新闻情绪单步指用过去time_step天的数据预测明天一个点不是多步外推MSE指均方误差既当损失函数又当PSO的适应度函数。这个设置简化了问题让新手能在两小时内跑通全流程但代价是模型的上限受限单维输入本身不含成交量信息遇到缩量上涨的日子预测误差会明显变大。理解这个边界后你可以在答辩里主动说“这是实验基准版本后续可以扩展到多特征输入”这比被老师指出要体面得多。3. 数据集与目录结构七个CSV怎么读、怎么选、怎么对齐3.1 包内文件的主干结构压缩包解开之后顶层是PSO-LSTM-for-Prediction-main目录里面核心内容如下表文件/目录类型作用Datasets/BTC-USD.csv数据比特币日线数据主要用于加密货币价格预测实验Datasets/DJI.csv数据道琼斯工业指数日线数据代表美股大盘Datasets/AAPL.csv数据苹果公司日线数据典型个股样本Datasets/GSPC.csv数据标普500指数日线数据另一个大盘指数Datasets/IXIC.csv数据纳斯达克综合指数日线数据Datasets/000001.SS.csv数据上证指数日线数据A股样本Datasets/Gold_daily.csv数据黄金日线数据贵金属资产会议PSO-LSTM单维单步mse预测.py脚本主程序包含数据读取、滑窗、PSO寻参、LSTM训练与预测README.md文档项目说明我拆包时一般是先看这个文件再动脚本1.txt这个文件我猜测是数据下载说明、来源链接或预处理备注不属于核心代码。动手第一步别急着跑脚本先打开README和那个txt确认数据格式、字段含义以及作者对Python版本的要求。这个习惯能在后续少踩很多坑下面第5章的翻车记录里一半都和数据格式有关。3.2 读入与清洗的标准流程七个CSV的列结构基本一致都是标准OHLCV格式。但不同来源的数据有几个坑日期格式不统一有的是2024-01-01有的是01/01/2024千位分隔符会导致数值被读成字符串表头可能多一个空格或BOM字符。主脚本里的数据读入顺序一般是import pandas as pd import numpy as np from sklearn.preprocessing import MinMaxScaler def load_data(path, usecols[Date, Adj Close]): df pd.read_csv(path, usecolsusecols, parse_dates[Date]) df.dropna(inplaceTrue) # 去掉停牌或缺失行 df.sort_values(Date, inplaceTrue) # 按时间升序防止乱序 return df df load_data(Datasets/AAPL.csv) price df[Adj Close].values.reshape(-1, 1) print(f样本量: {len(price)}, 时间范围: {df[Date].min()} 至 {df[Date].max()})usecols只读需要的列避免内存浪费parse_dates把日期字符串转成时间类型方便后续按时间排序dropna必须有因为有些日期行可能缺失收盘价不去掉会在归一化时算出NaN。sort_values这行最容易被忽略但最重要如果CSV本身是乱序的滑窗样本里出现在“相邻”位置的两个样本实际跨了很长的日期LSTM学到的全是噪声。拿到任何一份股票数据先对时间列排序并打印时间范围是十分钟内必做的操作。3.3 七个数据集怎么选不同资产适合展示不同结论七个数据集覆盖了加密货币、美股个股、美股指数、A股指数和黄金这份资源最值钱的地方之一是可以用同一套代码跑多个市场做横向对比。实验时建议按资产类别选三组AAPL或DJI成熟市场、000001.SSA股、BTC-USD加密货币。这三类资产性质差异明显美股个股机构主导趋势性和均值回复特征比较明显LSTM拟合效果通常最好上证指数受政策影响大波动集聚性强预测误差普遍偏大比特币波动剧烈且存在周期性牛熊切换训练集里如果带上了暴跌段预测曲线会在转折点附近严重滞后。这组对比放进课程设计报告里比单跑一个数据集有说服力得多——它证明了模型不是只在某一支股票上碰巧有效也暴露了模型在不同波动特征下的行为差异。答辩时老师问“为什么选这个数据集”你就可以回答“选择波动性不同的资产做对比检验模型对波动特征的鲁棒性”这一句就能把报告深度拉开一截。4. 核心脚本拆解从CSV到MSE的七步完整流程4.1 整体流程先看在哪个阶段动手改参数Pandas读数据、MinMaxScaler归一化、滑窗切样本、PSO粒子群寻超参数、用最优参数训练LSTM、反归一化、计算MSE并绘图这是典型的七步流程。主脚本的函数划分直接对应这七个阶段找代码时按函数名定位比按行号定位更高效。我第一次拆这类源码时会先用编辑器把函数定义全部列出来大概了解脚本的骨架结构然后从最核心的PSO适应度函数开始读因为这个函数里藏着整个项目的关键逻辑。一个值得注意的细节是归一化在所有数据上进行还是只在训练集上进行。多个源码包我拆下来发现新手写的最多的情况是先对整个序列做MinMaxScaler再切训练测试集。这个写法简单代码短但有一个隐患——测试集的极值信息被提前泄漏给了归一化器评估结果会比真实水平略好。严格的做法是先切再归一化训练集单独fit。大多数课程设计的源码不会抠到这个粒度但答辩时如果你能主动提一句“这里测试集数据参与了归一化会导致结果略乐观”老师会认为你对数据泄漏有认知。4.2 滑窗样本构建时间步长决定LSTM“看几天”LSTM不能直接吃一整段连续序列需要把序列切成固定长度的窗口。窗口长度就是前面说的time_step含义是“用过去N天的收盘价预测第N1天”。滑窗函数的写法通常是def create_sequences(data, time_step): X, y [], [] for i in range(len(data) - time_step): X.append(data[i:i time_step, 0]) # 取连续 time_step 天 y.append(data[i time_step, 0]) # 预测下一天 return np.array(X), np.array(y) time_step 10 # 用过去10个交易日预测第11天 X, y create_sequences(scaled_data, time_step) X X.reshape(X.shape[0], X.shape[1], 1) # LSTM 要求三维输入X的形状是(样本数, time_step, 1)第三维的1代表单维特征。time_step10在交易日历里就是两个自然周这个数值对股票日线数据还算合理。注意最后time_step条数据是没有对应的预测目标的所以滑窗后样本总量是len(data) - time_step这是排查“为什么样本数少了一截”的关键原因。reshape那行很容易写错少了一个维度LSTM会直接报ValueError这也是常见报错之一。time_step的取值对预测效果影响明显取值太小比如3到5模型看到的最近几天噪声太大预测值会紧贴着上一个值走看起来“预测很准”实际上只是滞后搬运取值太大比如30到60模型被过长历史拖累对最近变化的反应变慢在趋势反转处误差变大。PSO把我们手动调这个参数的过程自动化了但要理解搜索结果的合理性PSO给出的time_step如果落在20以上说明这组数据趋势成分较强如果落在5以下说明序列短期波动主导。带着这个理解去看输出你才能真正解释结果而不是只会截个MSE的图。4.3 PSO适应度函数每评估一次就要训练一遍LSTMPSO的适应度函数是整个脚本的计算瓶颈它的任务是给一组超参数time_step、神经元数、学习率训练一个LSTM返回验证集MSE。粒子群算法用这个MSE来比较粒子好坏。简化伪代码如下def fitness(params): step, units, lr params X, y create_sequences(scaled_data, int(step)) split int(len(X) * 0.8) X_train, X_test X[:split], X[split:] y_train, y_test y[:split], y[split:] model Sequential() model.add(LSTM(int(units), activationtanh, input_shape(X.shape[1], 1))) model.add(Dense(1)) model.compile(optimizerAdam(learning_ratelr), lossmse) model.fit(X_train, y_train, epochs20, batch_size32, verbose0) mse model.evaluate(X_test, y_test, verbose0) return mse适应度函数每一次调用都要完整执行“建模型、训练20轮、评估”的流程所以它有多慢PSO整个寻参过程就有多慢。粒子数乘迭代次数就是适应度函数的调用次数20个粒子、15轮迭代就是300次LSTM训练一次训练2秒的话总耗时10分钟可以接受一次训练30秒的话总耗时就是2.5小时做实验前要估算清楚。这里的split是固定比例切分不是随机切分时间序列不能打乱否则未来数据泄漏到训练集中这一点记住即可下面避坑章还会展开。此外每个粒子在搜索空间里的初始位置是随机的但不同参数的量纲差别很大——time_step大概在5到20学习率却小于0.01。如果PSO的速度公式不做归一化处理学习率的搜索会被time_step的数值变化完全压制。处理方式一般是把每个维度分别归一化到0到1区间再搜索解析时再映射回真实范围。源码里的PSO部分如果没做这个处理收敛会异常慢这是一个值得动手检查的细节。4.4 LSTM训练与最终预测反归一化是最后一道坎PSO返回最优参数后脚本会用最优参数重新训练一次LSTM然后对测试集逐点预测。注意这部分采用的是单步滚动预测还是直接多步预测两种方式差别很大直接预测是把测试集前time_step个真实值喂进去一次性输出测试集所有预测点滚动预测则是每预测出一天就把这个预测值拼回输入序列再用它预测下一天。前者在每一步都用了真实历史值误差不会累积看起来总是“贴近真实曲线”后者预测误差会随步数累积曲线会逐渐偏离但更接近真实应用场景。课程设计报告里要写清楚用的是哪一种写不清楚会被判定为实验不严谨。最后模型输出的是归一化后的预测值范围在0到1之间必须用训练时的scaler做逆变换才能得到真正的价格。反归一化这行代码虽然只有一行却是新手最容易忘记的pred_price scaler.inverse_transform(pred_scaled.reshape(-1, 1))这里有个细节如果标准做法是先切分再各自归一化那么预测值要拿训练集的scaler来反变换而不是测试集的scaler。如果拿错了scaler预测曲线整体偏移而且这个偏移在图上看起来不是平移而是被压缩或拉伸很难一眼发现。判断方法很简单——用训练集scaler反变换测试集真实值和CSV里的真实价格对不上就说明scaler用错了。4.5 从下载到首张预测图二十分钟内的实验路径拿到压缩包后为了最快看到效果我的建议是不要直接跑全量PSO先做一个“单组参数冒烟测试”绕过PSO直接用time_step10、units32、lr0.001跑一遍LSTM训练确认数据读取、滑窗、归一化、反归一化和绘图整条链路通畅。确定所有环节都没问题后再打开PSO主流程把粒子数和迭代次数改小比如各设8到10这样总耗时可控。跑完一组后依次完成以下步骤在load_data里把Datasets/AAPL.csv换成Datasets/000001.SS.csv观察两组数据预测效果的差异打开create_sequences里的time_step手动改成5、10、20各跑一遍记录MSE变化理解时间步的作用查看PSO每次迭代打印的Gbest值确认MSE是否在持续下降如果迭代中段就纹丝不动说明搜索范围或PSO参数需要调整。这套路径的优点是每一步只改一个变量出了问题能立刻定位是数据问题、模型问题还是超参数问题。直接一上来就跑完整PSO三百多次LSTM训练跑完才看到结果中途任何一个小报错都要从头来心态很容易崩。5. 避坑排查PSO-LSTM股票预测里最常见的翻车点5.1 归一化泄漏测试集极值提前暴露现象模型在测试集上的MSE很低预测曲线几乎贴着真实曲线走但换一段新数据后效果急剧变差。原因最早我按“全量数据一个scaler”的方式写归一化归一化器看过整个数据集的极值。测试集的最高、最低点在训练阶段已经泄露给了scaler评估结果虚高。解决先切训练集和测试集再在训练集上scaler.fit然后用这个scaler分别transform训练集和测试集。具体改动是把fit_transform拆成fit和transform两步这是一个所有时序预测项目通用的改动。5.2 预测曲线滞后LSTM把上一天的收盘价背下来了现象预测曲线和真实曲线形态一致但整体向右平移一天MSE却不高看起来“很准”。原因时间序列里相邻两天的价格高度相关LSTM学到的其实是“今天的价格和昨天差不多”而不是学懂了趋势。这不是模型作弊而是单维单步预测任务的天然陷阱。任何不用外部特征的纯时间序列预测都会遇到这个问题模型只是在做一个很简单的复制任务。解决看方向准确率而不是只看MSE方向准确率计算的是预测值相对真实值是涨是跌的命中率。如果方向准确率只有50%左右说明模型看起来拟合得漂亮实际毫无预测力。第6章我会给出这个指标的代码。此外把time_step增大到10到20能在一定程度上缓解滞后但无法根除。5.3 PSO寻参耗时爆炸300次LSTM训练跑了一整夜现象PSO循环打印的迭代进度很慢预计总时长超过几小时运行中途电脑风扇狂转停了又不甘心。原因粒子数和迭代次数设置过大加上LSTM训练epoch数偏高每个粒子的单次评估就要几十秒。我见过把粒子数设成50、迭代50次、epoch设成100的写法总训练次数是2500次单机CPU上基本等于跑不完。解决先跑一次单参数训练估算单次适应度评估耗时粒子数控制在10到15迭代次数10到15搜索范围收窄学习率上限0.01、time_step上限20。记住一个经验课程设计场景下总耗时超过1小时就说明参数没控制好直接改成小规模重跑。5.4 对全序列做滑窗时混入了未排序数据现象代码跑完没有报错但预测曲线在测试集后期明显偏离MSE忽高忽低。原因CSV里的日期不是严格升序或者从数据源下载时行序被打乱。滑窗是按行号切片的乱序意味着窗口内的“最近N天”在时间上并不连续。解决在load_data里加一行df.sort_values(Date, inplaceTrue)然后打印df.head()和df.tail()核对首尾日期。对任何股票CSV读入后先排序再操作养成肌肉记忆。同理检查是否有重复日期行用df.drop_duplicates(subset[Date])兜底。5.5 用全量数据归一化后切分测试集信息泄漏进scaler现象和5.1相似但位置不同这次是滑窗之后才切分训练测试集scaler又是在切分前做的。原因切分时机不对归一化和切分的先后顺序遗漏了时间序列的因果约束。时间序列不满足独立同分布假设任何在切分前基于全量数据做的统计变换本质上都是间接泄漏。解决严格顺序是排序、切分、归一化、滑窗。但滑窗会依赖time_step而time_step本身又由PSO搜索这就产生了循环依赖。我一般的做法是先按8:2切分再对训练集滑窗和归一化测试集用同样的scaler变换后滑窗。主脚本如果先滑窗再切分测试集的滑窗构建也应在切分后完成而不是全量切好再切分窗口。5.6 反归一化用错scaler导致预测价格整体偏移现象预测出的价格数值比真实价格高出一截或低出一截但趋势形状保持一致。原因反归一化时用了测试集的scaler而预测值是基于训练集scaler归一化后预测的两套scaler的min和max不同换算回去的绝对价格当然对不上。解决统一用训练集的scaler做反归一化。哪怕一开始用了先全量归一化再切分的简化写法反归一化也要用同一个scaler对象不能重新fit一个。一行代码的事但出错概率极高。5.7 结果不可复现每次跑出来的MSE都不一样现象同一份代码连续跑两次PSO找出的最优参数和最终MSE都不同写报告时不知道填哪个数。原因源脚本里没设随机种子。LSTM权重初始化、PSO初始粒子位置、训练时batch的随机性都会影响结果。解决在脚本开头固定随机种子import random, numpy as np, tensorflow as tf random.seed(42) np.random.seed(42) tf.random.set_seed(42)固定种子后同一环境下次运行结果基本一致。注意PyTorch和Keras的种子设置方式不同如果你的复现环境是PyTorch要额外设置torch.manual_seed。这是我拆了这么多源码包后体会最深的一点种子这行代码是报告数据可复现的基石放在文件开头比放在任何位置都管用。6. 在答辩环节给模型加一个区分度补上方向准确率与滚动预测验证课程设计答辩里MSE常被追问“低了又怎样跟股票投资有什么关系”。这个问题的本质是评价指标脱离业务语义。MSE衡量的是数值拟合误差但投资者真正关心的是涨跌方向。所以我每次拿到这类预测源码做的第一件事就是加一个方向准确率指标。def direction_accuracy(y_true, y_pred): diff_true np.diff(y_true.flatten()) diff_pred np.diff(y_pred.flatten()) correct np.mean((diff_true * diff_pred) 0) return correct acc direction_accuracy(y_test_true, pred_price) print(f方向准确率: {acc:.2%})这段代码的核心逻辑是计算真实序列和预测序列各自的相邻差值两者方向一致就算一次命中。方向准确率高于52%才说明模型在趋势判断上有统计意义低于50%则意味着预测曲线虽然贴合、方向却不如抛硬币需要向老师如实说明。用这个指标重新评估PSO-LSTM的预测结果往往比MSE更诚实。另一个有区分度的做法是滚动验证从训练集末尾取固定窗口训练一次模型预测下一天然后把真实值加入窗口、丢掉最早一天再重复。下面是一个简化的滚动预测示例# 滚动预测示意 for i in range(len(test_data) - time_step): window np.concatenate([train_data, test_data[:i]])[-time_step:] window window.reshape(1, time_step, 1) pred model.predict(window, verbose0) predictions.append(pred[0, 0])滚动验证的每一步只使用截至当前时刻的数据严格模拟真实交易中“今天收盘后用已知信息预测明天”的场景。PSO-LSTM在这里的优势是用寻优后的超参做滚动预测误差不会因参数不匹配而虚增。从那以后我拿到任何一份时间序列预测源码都会强制走一遍这个流程先设固定随机种子再补方向准确率最后跑一次滚动验证——数值和时间对齐方式都对得上再谈效果。这份资源的底子是好的把这几个点补全后它的功能也就真正落到了你手里。希望帮到你。本文还有配套的精品资源点击获取
返回列表