
简介一份基于Python的机器学习股价预测源码面向毕业设计、期末大作业及课程设计场景适合有一定Python基础、希望快速搭建完整预测项目的新手。代码覆盖线性回归、LSTM、ARIMA、KNN等多种模型并附带注释、依赖列表与可运行环境说明可直接部署使用。压缩包共31个文件以Python脚本、图像结果、CSV数据、HTML可视化页面及Excel表格为主包含预测主程序、回测工具、数据绘图等模块脚本与数据分离目录结构清晰便于按模块阅读和二次开发整体仅1.45MB轻量易用。已有372人学习项目经过严格调试功能完整且界面直观可作为课程报告或毕设展示的高分参考包含真实股票样例数据便于立即复现。读者可从中获得多模型对比思路、时间序列处理方式、数据可视化技巧及股价预测完整流程尤其适合需要快速产出可演示成果的学习者。1. 把多模型股价预测一次跑通这份源码项目能直接改造成你的毕设如果一个做毕设的人把 LSTM、ARIMA、KNN 全塞进一个项目还能跑出图和 HTML 报告那导师很难挑出毛病。我拆这份“Python实现机器学习股价预测源码LR、LSTM、ARIMA、KNN”时第一反应是它把机器学习课程里的常见算法都落了地有 AMZN.csv 真实历史股价有 models.py 统一封装有 backtest.py 回测连每日资金情况图和持有期收益率情况图都做成了 HTML 看板装好依赖就能复现。这份资源适合三类人正在选毕设题目的本科生想抄一个高分期末大作业的计算机与金融交叉方向学生以及想快速验证“机器学习在价格预测上到底能不能用”的量化入门者。它不解决“稳定赚钱”它解决“把多模型预测流程完整跑通并讲清楚每个模型在什么条件下成立”。项目文件里代码和注释齐全依赖写在 requirements.txt。下面按“数据准备→模型→回测→避坑”的顺序拆开每个环节给出可抄走的代码和参数你照着改就能变成自己的项目。2. 数据准备从 AMZN.csv 到可训练序列的三道工序数据决定模型上限。无论后面跑 LR 还是 LSTM喂进去的序列不对结果全是废物。AMZN.csv 是亚马逊的历史日线行情第一件事是确认字段、清理缺失、把价格序列变成模型能吃的结构。2.1 读入数据与字段取舍import pandas as pd df pd.read_csv(AMZN.csv, parse_dates[Date], index_colDate) df df[[Open, High, Low, Close, Volume]].dropna() df[Close] df[Close].astype(float) df.to_csv(AMZN_clean.csv)这段做的事情很朴素把 Date 列解析成 datetime 并设为索引只保留日线交易最常用的五个字段去掉缺失行。项目里后续的预测目标基本围绕 Close 展开因为收盘价是策略信号和回测结算的基准Volume 保留下来是给 LR、KNN 这类需要特征工程的方法当输入LSTM 和 ARIMA 阶段通常只用 Close。提示如果 CSV 里第一列明明是日期读进来却是字符串parse_dates 会静默失败索引变成字符串索引。读完后立刻执行df.index看一眼类型别急着往下跑。为什么不直接用 Adj Close项目里 linearRegression.png、LSTM.png、knn.png 等验证图画的都是原始价格用除权调整价反而要向答辩老师解释“预测的是复权后价格”。短期研究用 Close 更直观长期策略回测才需要换 Adj Close这个分寸你自己掌握。2.2 平稳性检验与差分ARIMA 的门槛ARIMA 要求序列平稳所以模型还没开始先过 ADF 检验这道门。我一般这样写from statsmodels.tsa.stattools import adfuller def check_stationarity(series, nameClose): stat, p_value, usedlag, nobs, crit, icbest adfuller(series, autolagAIC) print(f{name}: ADF stat{stat:.4f}, p-value{p_value:.4f}) return p_value 0.05 print(check_stationarity(df[Close])) df[diff1] df[Close].diff() clean_diff df[diff1].dropna() print(check_stationarity(clean_diff, diff1))判断标准很简单p-value 小于 0.05 时拒绝“存在单位根”的原假设序列才算平稳。原始价格几乎必然不平稳一阶差分后通常通过。如果原始序列 p-value 在 0.4 左右一阶差分后掉到 0.001 以下那 ARIMA 的 d 直接定 1一阶差分还不稳才考虑二阶。项目里 trend.png、decompose.png、deterministicProcess.png 就是这阶段的可视化trend.png 看原始趋势decompose.png 做趋势和残差分解deterministicProcess.png 对应确定性趋势处理。另外注意autocorrelation.png 和 partial_auto.png 必须在差分后的序列上画画在原始价格上会把不平稳的假自相关当真这是答辩时常见的低级错误。2.3 归一化与滑窗切分喂给 LSTM 前必须改的格式深度学习不吃原始价格。我习惯用 MinMaxScaler 把价格压到 [0,1]再用 60 天滑窗构造样本import numpy as np from sklearn.preprocessing import MinMaxScaler scaler MinMaxScaler(feature_range(0, 1)) scaled scaler.fit_transform(df[[Close]]) def make_windows(data, window60): X, y [], [] for i in range(window, len(data)): X.append(data[i-window:i, 0]) y.append(data[i, 0]) return np.array(X), np.array(y) X, y make_windows(scaled, window60) split int(len(X) * 0.8) X_train, X_test X[:split], X[split:] y_train, y_test y[:split], y[split:]三个参数你改的时候要有依据window60 表示用过去 60 个交易日预测下一个交易日这是日线预测最常见的设置接近三个月交易信息split0.8 意味着前 80% 训练、后 20% 样本外验证feature_range(0,1) 配合 LSTM 的 tanh 激活函数输入输出处于同一量纲。这里要特别强调顺序scaler 只能在训练集上 fit再分别 transform 训练集和测试集绝不能在整个序列上 fit 完再切分。这是本项目中数据泄漏的第一来源也是最容易毁掉可信度的地方。注意时间序列数据严禁随机 shuffle。一旦打乱顺序等于把未来信息泄漏给过去训练曲线会好看到假。项目里 LSTM.png、knn.png 的验证曲线就是用这个正确流程跑出来的。预测阶段记得反归一化把预测值还原成真实价格再和实际收盘价对比predictions_inv scaler.inverse_transform(predicted.reshape(-1, 1)) actual_inv scaler.inverse_transform(y_test.reshape(-1, 1))3. 模型实战LR、KNN、ARIMA、LSTM 在 AMZN 价格上的预测与参数选型models.py 是本项目核心四类模型按复杂程度递进。我的建议是别一上来就死磕 LSTM先把 LR 跑通再逐个叠加。3.1 LR先做一个能解释的基准确模型LR 的定位是基线。任何机器学习项目先跑一个最简单的模型看看可解释的下限在哪复杂模型值不值得上才有依据。代码大致长这样from sklearn.linear_model import LinearRegression from sklearn.metrics import mean_squared_error df_feat df.copy() for lag in range(1, 6): df_feat[flag_{lag}] df_feat[Close].shift(lag) df_feat[ma5] df_feat[Close].rolling(5).mean() df_feat df_feat.dropna() X df_feat[[lag_1, lag_2, lag_3, lag_4, lag_5, ma5]] y df_feat[Close] split_idx int(len(X) * 0.8) X_train, X_test X.iloc[:split_idx], X.iloc[split_idx:] y_train, y_test y.iloc[:split_idx], y.iloc[split_idx:] lr LinearRegression().fit(X_train, y_train) pred_lr lr.predict(X_test) print(LR RMSE:, np.sqrt(mean_squared_error(y_test, pred_lr)))滞后特征 shift(lag) 的意思是拿前 1 到前 5 天的收盘价当自变量ma5 是 5 日均线这六个特征在量化里属于最不容易被质疑的一类。你换成 lag10 或者加入涨跌幅LR 的 RMSE 变化很小这说明价格短期预测的线性信息就这么多别指望 LR 创造奇迹。3.2 KNN相似历史模式的近邻投票KNN 在价格预测里的逻辑是找到历史上与最近 60 天走势最像的片段用那几段后面的真实走势做预测本质是“历史重演”。这也是项目里 KNN 和 LSTM 共用滑窗结构的原因。from sklearn.neighbors import KNeighborsRegressor from sklearn.preprocessing import StandardScaler X2 X_train.reshape(X_train.shape[0], -1) X2_test X_test.reshape(X_test.shape[0], -1) sc StandardScaler().fit(X2) knn KNeighborsRegressor(n_neighbors5, weightsdistance, metriceuclidean) knn.fit(sc.transform(X2), y_train) pred_knn knn.predict(sc.transform(X2_test))n_neighbors5 是默认值权重选 distance 让距离近的样本影响更大。KNN 的经典特征是预测曲线总比真实走势慢半拍因为输出是历史近邻的平均而历史模式永远来自过去。项目里 knn.png 呈现的正是这种滞后形态——这不算 bug是方法本身的特性答辩时主动讲出来反而是加分项。3.3 ARIMA从 ACF/PACF 定阶到三参数配置ARIMA 的 order(p,d,q) 中d 已经在数据准备阶段通过 ADF 检验定了剩下 p、q 靠自相关图 autocorrelation.png 和偏自相关图 partial_auto.png 来读from statsmodels.graphics.tsaplots import plot_acf, plot_pacf from statsmodels.tsa.arima.model import ARIMA import matplotlib.pyplot as plt plot_acf(clean_diff, lags30) plot_pacf(clean_diff, lags30) plt.show() model ARIMA(df[Close], order(1, 1, 2)) result model.fit() forecast_arima result.forecast(steps10)读图规则自相关图拖尾、偏自相关图一阶后截尾p 取 1反过来自相关图截尾、偏自相关图拖尾q 取截尾阶数都拖尾就用 ARIMA(1,1,1) 起步。项目里的 periodogram.png 是周期图辅助确认是否存在月度或年度周期性供后面的 Prophet 阶段设置季节周期。如果觉得手工定阶麻烦pmdarima 的 auto_arima 能自动搜索候选组合但毕设答辩老师大概率会问“p、q 怎么来的”所以图谱判断必须会。另注意 statsmodels 0.12 之后的接口从 statsmodels.tsa.arima_model 挪到了 statsmodels.tsa.arima.model老教程的 import 方式会直接 ImportError。3.4 LSTM滑窗序列进循环网络LSTM 是项目重头戏models.py 里这段是整个项目代码最长、最容易翻车的段落from tensorflow.keras.models import Sequential from tensorflow.keras.layers import LSTM, Dense, Dropout from tensorflow.keras.callbacks import EarlyStopping X_train_lstm X_train.reshape(X_train.shape[0], X_train.shape[1], 1) X_test_lstm X_test.reshape(X_test.shape[0], X_test.shape[1], 1) model Sequential() model.add(LSTM(50, activationtanh, return_sequencesTrue, input_shape(60, 1))) model.add(Dropout(0.2)) model.add(LSTM(50, activationtanh)) model.add(Dropout(0.2)) model.add(Dense(1)) model.compile(optimizeradam, lossmse) model.fit(X_train_lstm, y_train, epochs50, batch_size32, validation_split0.1, callbacks[EarlyStopping(monitorval_loss, patience5)])几个参数值得说透。第一层 LSTM 的 return_sequencesTrue 是必须的否则输出维度直接塌到一维第二层 LSTM 接不上input_shape(60,1) 里的 60 必须和滑窗 window 一致。units50 是隐层维度太小学不到形态太大容易在小数据集上过拟合。epochs50 配 EarlyStopping 是经验组合patience5 表示验证集 loss 连续 5 轮不降就停避免在训练集上死磕。Dropout(0.2) 是给时间序列模型降过拟合用的20% 的神经元随机失活。提示TensorFlow 和 Keras 的版本匹配一直是重灾区。建议 Python 3.83.10TensorFlow 装 2.10 附近的版本Keras 跟着 TensorFlow 走不要单独 pip install keras 升到新版否则 LSTM 层启动时会报一堆 shape 诡异的错误。训练完预测后别忘了反归一化再把 LSTM、LR、KNN、ARIMA 四条曲线画在一张图上对比这就是项目里 LSTM.png、linearRegression.png、arima.png、knn.png 的多模型对比图。3.5 Prophet把趋势和季节性拆开看待Prophet 是带趋势和季节性的时间序列库项目里 prophet.png、prophet1.png、prophet2.png 说明作者把它也纳入了对比。代码from prophet import Prophet df_prophet df.reset_index()[[Date, Close]].rename( columns{Date: ds, Close: y}) model_p Prophet(daily_seasonalityTrue) model_p.fit(df_prophet) future model_p.make_future_dataframe(periods30) forecast_p model_p.predict(future) model_p.plot(forecast_p)Prophet 强制要求两列固定命名 ds 和 y。daily_seasonalityTrue 是日频交易数据的常见设置。Prophet 对缺失值和异常值宽容适合快速输出一张带置信区间的预测图在答辩 PPT 里视觉效果比 LSTM 的曲线更友好。4. 回测与可视化backtest.py 的资金曲线逻辑与 ECharts 报告生成预测归预测导师一定会追问“预测准了然后呢”backtest.py 负责把预测转化成资金曲线draw_line.py 负责把结果变成图表和报告。4.1 回测逻辑与资金曲线def backtest(prices, signals, initial_cash100000, fee_rate0.001): cash initial_cash position 0 curve [] for i, price in enumerate(prices): if signals[i] 1 and position 0: # 看多信号用全部现金买入 position (cash * (1 - fee_rate)) / price cash 0 elif signals[i] -1 and position 0: # 看空信号清仓 cash position * price * (1 - fee_rate) position 0 curve.append(cash position * price) return curve这段代码对应项目里每日资金情况图.html 的数据来源。signals 来自前面模型的预测结果常见做法是预测明日涨幅超过 0.5% 就持多头低于阈值就空仓。fee_rate0.001 是单边手续费假设A 股佣金加印花税大致在这个量级。资金曲线最终值除以初始资金减 1就是持有期收益率对应项目里的持有期收益率情况图.html。回测参数建议按这个默认表起步别一上来就调阈值追求高收益那是自欺欺人。参数默认值含义initial_cash100000初始资金fee_rate0.001单边交易成本buy_threshold0.005预测涨幅超过 0.5% 买入signal_type1 / -1看多/看空信号4.2 从 matplotlib 到 ECharts 报告draw_line.py 做两件事先用 matplotlib 把静态对比图存进 images 目录再用 echarts.min.js 生成交互式 HTML。项目里这些文件各有用途文件作用类型backtest.py资金曲线与收益率计算核心回测逻辑forecast.py加载模型做样本外预测调用 models.pymodels.pyLR/KNN/ARIMA/LSTM/Prophet 统一封装模型库draw_line.pymatplotlib 画图与 HTML 生成报告出口每日资金情况图.html资金曲线看板交互页面持有期收益率情况图.html持有期收益看板交互页面echarts.min.js前端图表库本地静态资源各月股票队列.xlsx按月输出持仓队列Excel 汇总个股持有情况分析.csv持仓明细CSV 数据ECharts 生成 HTML 的核心是模板字符串把数据塞进 JS 数组import json template script srcecharts.min.js/script div idchart stylewidth:100%;height:600px;/div script var chart echarts.init(document.getElementById(chart)); chart.setOption({ xAxis: { type: category, data: %s }, yAxis: { type: value }, series: [{ type: line, data: %s }] }); /script % (json.dumps(dates), json.dumps(curve)) with open(每日资金情况图.html, w, encodingutf-8) as f: f.write(template)这样做的好处是 HTML 双击就能打开不依赖后端服务答辩时在老师电脑上演示零成本。你只需要替换 dates 和 curve 两个数组页面结构不用动。项目里把预测结果按月汇总成各月股票队列.xlsx、按持仓明细导出成个股持有情况分析.csv也是为了让答辩展示时既有图又有数据表。5. 避坑与排查数据泄漏、LSTM 不收敛、ARIMA 直线预测的五个真实翻车现场这个项目调试到能跑通中间会撞上不少坑。我按“现象→原因→解决”写你自己跑的时候直接对号入座。5.1 回测收益 90%实盘一买就亏数据泄漏现象训练集 RMSE 很低回测资金曲线近乎完美但把模型放到最近一年数据上预测收益变负。原因最常见两类。要么 MinMaxScaler 在整条序列上 fit把测试集的统计信息泄漏进了训练要么滑窗特征里混了当天收盘价预测目标又是当天收盘价模型等于抄答案。AMZN.csv 是单一序列时间切分一旦错位后 20% 的“测试集”其实早被归一化看过了。解决scaler.fit 永远只吃 X_trainX_test 只调用 transform构造特征时统一用 shift(lag)至少 shift(1) 起步。我在 2.3 小节特意把顺序写成“先切分再 fit”就是为这条兜底。5.2 LSTM loss 不降预测图是一条水平直线现象训练几十轮val_loss 卡在 0.01 附近不动预测曲线画出来是一条直线跟不上真实价格波动。原因LSTM 用 tanh 激活输入不归一化或归一化范围不对梯度会直接消失另一个常见原因是网络把目标学成了序列均值退化成常数预测。解决确认用 MinMaxScaler 且范围 [0,1]总样本太少时把第一层 units 从 50 降到 20并加 Dropoutepochs 不用硬拉到 200EarlyStopping 会让训练停在验证集最好的位置。如果还是一条直线检查反归一化时是不是拿错了 scaler。5.3 ARIMA 预测出来是水平线现象result.forecast(steps10) 给出的未来 10 天几乎在同一条水平线上。原因差分阶数定高了。一阶差分后 ADF 已经通过又顺手做了二阶差分ARIMA 把序列当成了纯随机游走预测收敛到历史均值另一种情况是序列本身接近随机游走ARIMA 对短期走势确实没有预测力。解决d 只取让 ADF p-value 刚好小于 0.05 的最小阶数预测前看 autocorrelation.png若自相关在一阶后已截尾说明可预测的信息确实很少。这个结果不是 bug是数据特性。答辩时如实说“该序列近似随机游走ARIMA 只能给出均值参考”比硬解释曲线更合格。5.4 KNN 预测曲线整体滞后一天现象预测值和真实值走势一致但整体向右平移了一天RMSE 不小图画出来却很好看。原因KNN 的输出是历史近邻片段的真实后续值而历史片段全部来自过去预测天然滞后如果特征里混入当日 Close模型输出等于把今天的价格搬到明天。解决特征只保留 lag_1 到 lag_5 和 ma5目标 y 用下一交易日 Close确保特征时间和目标时间错开。知道这个特性后KNN 更适合做方向判断而非精确价格预测——比如预测明天涨跌而不是明天价格是多少。5.5 复现时的 Python 与依赖版本冲突现象requirements.txt 装完import statsmodels 报错或者 import tensorflow 后 LSTM 层初始化失败。原因statsmodels 老接口 arima_model 在新版被移除TensorFlow 2.10 之后 Keras 版本绑定更紧单独升级 Keras 会引发层定义冲突Python 3.11 对旧版 TensorFlow 的兼容性并不理想。解决建独立虚拟环境然后 pip install -r requirements.txt。如果仍报 ARIMA import 错误把代码改为from statsmodels.tsa.arima.model import ARIMAorder 参数不变。环境问题优先于调参问题先锁版本再谈模型。6. 最后一道检查滚动回测与多模型集成的一点经验预测模型跑通之后导师最常问的一句话是“你凭什么相信它在未来也有效”我现在的做法是放弃单次切分改成滚动回测这也是多模型项目里我最想保留的验证方法。具体操作固定一个 180 天的训练窗口每预测完 5 天就把真实数据纳入训练集再往前推一步整个过程重复 10 次def rolling_eval(df, model_fn, train_len180, step5): errs [] for start in range(train_len, len(df) - step, step): train df.iloc[start - train_len:start] test df.iloc[start:start step] pred model_fn(train, test) errs.append(mean_squared_error(test[Close], pred)) return np.mean(errs)rolling_eval 的意义是把模型在全历史样本上的表现拆成 10 个小段分别验证任何一段失效都会被平均吃掉单次 80/20 切分时偶尔碰上的运气区间不会哄骗你。train_len180 对应半年左右的交易日step5 是一周跨度配 LSTM 时建议 step 加大到 20否则训练成本太高。有了滚动验证的误差还能顺手做一件实测有效的事多模型集成。把 LR、KNN、ARIMA、LSTM 的预测值按各自近期 RMSE 倒数为权重做加权平均结果不会差于最差模型。原因很简单四种模型的信息侧重点不同——ARIMA 吃线性自相关KNN 吃相似形态LSTM 吃非线性依赖LR 吃基础线性关系彼此是互补的。从那以后我每次跑完这种多模型项目都强制走一遍滚动回测再打印四个模型的误差做加权。预测股价本来就是一件反直觉的事能做的就是让每一步误差都摊开在眼前别让数据泄漏和版本冲突这种低级问题埋掉真正有价值的结果。希望帮到你。本文还有配套的精品资源点击获取