ARTICLE DETAIL

资讯详情

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

机器学习预测股价:LR、LSTM、ARIMA、KNN全流程源码实战

机器学习预测股价:LR、LSTM、ARIMA、KNN全流程源码实战 简介一份围绕LR、LSTM、ARIMA、KNN等多种机器学习算法的股价预测项目源码与文档说明主要面向毕业设计、期末大作业及课程设计场景也可供对金融数据建模感兴趣的Python开发者参考。包内共31个文件包含5个Python脚本、17张结果图表、2个HTML可视化页面、2个CSV数据文件、1个Excel表格及说明文档等压缩包整体仅1.45MB结构清晰便于快速部署与二次修改。源码涉及模型训练、未来预测、回测评估和走势绘图提供每日资金情况、持有期收益率等交互式图形并附有运行依赖清单与说明文档降低上手门槛。目前已有117人浏览学习项目自带详细注释与文档经严格调试可直接运行并配备历史股价数据与月度股票队列等数据文件可支撑多模型对比实验适合作为课程高分项目或毕设基础框架使用。1. 机器学习方法预测股价一份能跑通全流程的源码包做股价预测的机器学习项目最怕的不是模型不work而是数据、训练、回测、可视化散落在不同脚本里拼不起来。这份基于 LR、LSTM、ARIMA、KNN 的预测源码包恰好把全流程串好了从 AMZN.csv 的数据读取到 models.py 里四个模型的训练再到 backtest.py 的回测和 draw_line.py 的绘图最终输出每日资金情况图和持有期收益率图两个 HTML 报告。我拆完第一感受是它适合两类人——准备期末大作业或毕设的学生需要一份能答辩、有对比实验的完整工程刚入门时间序列预测的开发者则需要一个看得见完整链路的参考实现。下文我会按数据准备、模型训练、回测可视化、踩坑排查的顺序逐步拆。2. 先看清项目骨架AMZN.csv 到可训练样本的处理流程2.1 数据文件与依赖清单动手前先盘清家底解压后第一件事不是跑代码而是对照文件清单确认你要碰的东西。这份项目核心文件就这几个AMZN.csv是原始行情数据models.py里封装了四类模型forecast.py负责生成预测结果backtest.py做回测draw_line.py把所有结果画成图myutils.py是公共工具函数。requirements.txt定了依赖版本范围建议新建虚拟环境后先装依赖再跑。python -m venv venv source venv/bin/activate # Windows 下用 venv\Scripts\activate pip install -r requirements.txt依赖安装这一步的坑比较常见如果你本机之前装过 TensorFlow 或 PyTorch再装项目依赖时容易出现版本冲突。我一般会先看requirements.txt里的 pandas 和 numpy 版本把和现有环境冲突的包单独用pip install --upgrade处理而不是一次性全装。装完后跑一句python -c import pandas, sklearn, statsmodels; print(ok)验证核心库能否同时导入。2.2 清洗与窗口构建把时间序列切成监督学习样本AMZN.csv是亚马逊的日线数据字段通常包含 Open、High、Low、Close、Volume 和 Date。模型不会直接吃原始价格序列需要先做两步删除缺失值和构建滑动窗口特征。这一步在myutils.py里被封装成了函数核心逻辑是先按日期排序再用前 N 天的收盘价构造特征矩阵预测目标则是第 N1 天的收盘价。import pandas as pd import numpy as np def create_window_data(df, window10, target_colClose): data df[target_col].values X, y [], [] for i in range(len(data) - window): X.append(data[i:i window]) y.append(data[i window]) return np.array(X), np.array(y)这个窗口大小window是最敏感的超参数之一。取 5 意味着用一周交易日预测下一天取 20 则是用一个月。我试下来这份数据AMZN 日线窗口取 10 到 15 之间比较稳太短模型抓不住趋势惯性太长会把久远的价格噪音也带进来。特征矩阵X的形状是(样本数, window)LSTM 输入还需要 reshape 成(样本数, window, 1)这个后面讲模型时再展开。2.3 平稳性检验与分解ARIMA 和 LSTM 的预处理差异项目 images 目录里有一组trend.png、seasonal.png、decompose.png、autocorrelation.png、partial_auto.png对应的是时间序列分解和 ACF/PACF 分析图。ARIMA 模型要求输入序列平稳所以要先做差分而 LSTM 是神经网络虽然不要求严格平稳但归一化这一步逃不掉。from statsmodels.tsa.stattools import adfuller def check_stationarity(series): result adfuller(series.dropna()) print(fADF Statistic: {result[0]:.4f}) print(fp-value: {result[1]:.4f}) return result[1] 0.05如果p-value大于 0.05说明序列非平稳常见做法是做一阶差分再看一遍。注意差分后预测出来的价格要还原成原始量纲否则你画出来的预测曲线和真实股价对不上——这个我在避坑章节会单独提。3. LR、LSTM、ARIMA、KNN 四模型训练models.py 里的参数与调法3.1 线性回归做基线确定性趋势项的意义线性回归在股价预测里常被当成基线模型。它假设收盘价与时间存在线性关系虽然真实股价显然不只受时间影响但作为对比基准非常合适——如果 LSTM 连 LR 都跑不过那一定是数据或训练流程出了问题。models.py里 LR 的实现一般是把时间索引和滞后特征拼在一起做普通最小二乘拟合。from sklearn.linear_model import LinearRegression def train_linear_regression(X_train, y_train): model LinearRegression() model.fit(X_train, y_train) return modelLinearRegression没有什么需要调的超参数唯一值得注意的是特征要不要做标准化。因为 LR 对特征尺度敏感如果特征里既有时间序号数值可能上千又有收盘价数值可能几百建议用StandardScaler先做缩放。这份项目里 AMZN 的价格区间不算极端但不缩放会导致时间序号权重异常偏大模型退化成只看第几天的傻瓜预测器。3.2 LSTM 时间步与归一化样本外预测的常见陷阱LSTM 部分是这个项目的重头戏。在models.py里它通常使用 Keras 或 PyTorch 实现核心是两层 LSTM 加一个 Dense 输出层。需要特别注意两点输入数据必须归一化到 0-1 区间通常用MinMaxScaler训练时拿来做测试的样本必须用训练集的 scaler 做变换不能用全量数据拟合 scaler。from keras.models import Sequential from keras.layers import LSTM, Dense, Dropout def build_lstm_model(window10, units64): model Sequential() model.add(LSTM(unitsunits, return_sequencesTrue, input_shape(window, 1))) model.add(Dropout(0.2)) model.add(LSTM(unitsunits // 2, return_sequencesFalse)) model.add(Dense(1)) model.compile(optimizeradam, lossmse) return modelunits64是 LSTM 隐层维度Dropout(0.2)防止过拟合。这里的 1 指的是input_shape(window, 1)中的最后一个维度即每个时间步只输入收盘价这一个特征。如果要改进可以把这个维度扩充到多特征——下文会单独讲。3.3 ARIMA 定阶ACF、PACF 与差分次数怎么定ARIMA 的三个参数(p, d, q)在这份项目里不是猜出来的images/autocorrelation.png和partial_auto.png就是用来定阶的看 ACF 图的拖尾和 PACF 图的截尾位置确定 p 和 qd由差分次数决定一般差分到平稳为止。from statsmodels.tsa.arima.model import ARIMA def train_arima(train_series, order(5, 1, 2)): model ARIMA(train_series, orderorder) fitted model.fit() return fitted这个order(5, 1, 2)是一个比较保守的初始值。如果你不想看 ACF/PACF 图可以用pmdarima库自动搜索最佳阶数但要注意自动搜索在大样本上很慢。实际跑的时候我建议先用adfuller确认差分次数再定 p、q否则模型容易报收敛警告或者预测结果是一条平线。3.4 KNN 相似模式匹配距离度量和特征缩放KNN 在股价预测里的思路和分类任务不同它不是预测涨跌类别而是在历史数据里找与当前窗口最相似的 K 个片段用它们的下一日价格加权平均作为预测值。models.py里 KNN 通常用sklearn.neighbors.KNeighborsRegressor实现默认距离度量是欧氏距离。from sklearn.neighbors import KNeighborsRegressor from sklearn.preprocessing import StandardScaler def train_knn(X_train, y_train, k5): scaler StandardScaler() X_train_scaled scaler.fit_transform(X_train) model KNeighborsRegressor(n_neighborsk, weightsdistance) model.fit(X_train_scaled, y_train) return model, scalern_neighborsk取 5 是经验值weightsdistance表示距离近的邻居权重更高。这个模型最大的坑是特征缩放——如果 X 没标准化价格绝对值大的特征会完全支配距离计算KNN 找出来的最近邻其实是假的。scaler要跟着模型一起返回预测时对新的 X 先 transform 再 predict。4. 回测与可视化backtest.py、draw_line.py 与 HTML 报告怎么用4.1 回测流程滚动窗口与持有期收益计算backtest.py做的事是把训练好的模型放到历史数据上模拟交易计算如果按照模型信号操作能赚多少。这份项目的回测逻辑是滚动窗口式的先用前一段数据训练预测下一段然后窗口向前移动再训练再预测。这种做法的好处是更接近真实场景缺点是很慢。python backtest.py --model lstm --window 10 --hold_days 5--hold_days 5表示每次按照模型信号买入后持有 5 个交易日再结算。回测结果会写进个股持有情况分析.csv里面记录每次买入的价格、卖出价格、持有天数和收益率。我自己跑的时候会重点看两个指标胜率盈利次数占总交易次数比例和累计收益率。如果胜率低于 50% 但累计收益为正说明盈利的交易赚得比亏损的交易多策略依然可用。4.2 绘图与输出每日资金图和持有期收益率图draw_line.py负责把预测结果和回测结果可视化生成每日资金情况图.html和持有期收益率情况图.html。这两个 HTML 文件依赖echarts.min.js本质上是把计算结果用 ECharts 的折线图渲染出来方便你在浏览器里交互查看。python draw_line.py --input 个股持有情况分析.csv --output reports/这里有个容易忽视的点HTML 引用的echarts.min.js是相对路径如果生成的报告文件移动位置图表会空白。解决方案要么保证echarts.min.js和 HTML 在同一目录要么把 JS 文件内嵌进 HTML。我一般是先跑生成脚本再统一把 reports 目录拷到别处展示所以会确认一下 JS 路径是相对路径还是绝对路径。4.3 各月股票队列与个股持有分析的联动各月股票队列.xlsx是按月份切分的股票池清单回测脚本会依据它决定每个月操作哪只股票。个股持有情况分析.csv则是逐笔交易的明细两者配合起来可以分析某个月选出的股票是否在整段回测区间里表现稳定还是只靠某几笔大额盈利拉高了整体收益。import pandas as pd df pd.read_csv(个股持有情况分析.csv) monthly_return df.groupby(df[买入日期].str[:7])[收益率].sum() print(monthly_return)这段代码按买入日期的月份汇总收益率能快速看出策略在哪几个月亏钱、哪几个月赚钱。如果某个月收益率异常高建议回去看那个月的行情——大概率是单边上涨行情模型的预测方向刚好踩对了不代表策略本身有普适性。5. 运行避坑与排查五个真实翻车场景5.1 LSTM 预测曲线整体滞后现象LSTM 预测结果和真实价格曲线形状很像但整体向右平移了一两天看着就像昨天的预测。原因模型被训练成了用前 N 天价格近似预测下一天而股价日线数据本身有强自相关模型学到的其实是明天的价格约等于今天于是输出天然滞后一个周期。解决不要用原始价格作为预测目标改预测收益差或涨跌方向或者用未来 K 天的均值做平滑目标。我在跑这份源码时用diff()做一阶差分后训练 LSTM滞后现象明显缓解。5.2 ARIMA 报 LinAlgError / SVD 不收敛现象model.fit()报 LinAlgError: SVD did not converge 或者提示参数估计不收敛。原因输入序列非平稳或者数据量太少协方差矩阵奇异。尤其是直接拿原始收盘价做 ARIMA 而没做差分时必报。解决先跑adfuller确认平稳性不平稳就做一阶差分另外把数据量控制在 500 条以上太短的序列不适合 ARIMA 的参数估计。5.3 KNN 预测结果接近历史均值现象KNN 预测出来每天都是一个几乎不变的值曲线在图上是一条扁平的线。原因特征没做标准化欧氏距离被价格绝对值主导窗口形状的影响被淹没了——找出来的是价格接近的邻居而非走势接近的邻居。解决训练前对窗口特征做StandardScaler拟合并保存 scaler预测时对新数据同步做 transform不要每次重新 fit。5.4 回测收益和行情对不上现象回测显示累计收益率很高但和同期的实际股价涨幅对不上看起来赚得不真实。原因大概率是数据泄漏——归一化时用了全量数据的 min/max或者窗口构建时无意中使用了未来信息。解决严格按时间顺序切训练集和测试集测试集不参与任何 fit。检查窗口构建代码里索引是否向前偏移确保第 i 行的特征只包含 i 之前的数据。5.5 HTML 报告打开是空白现象浏览器打开每日资金情况图.html只有白屏控制台里报 ReferenceError: echarts is not defined。原因HTML 文件通过相对路径引用echarts.min.js但后者不在同目录或路径层级不对。解决把echarts.min.js放到 HTML 同级目录下或者把整个项目目录文件夹作为一个整体移动不要单独拷贝 HTML 文件。6. 进阶技巧把四个模型的预测结果做集成投票6.1 信号翻转与投票机制单个模型预测总会有各自的系统性偏差ARIMA 偏向短期均值回归LSTM 容易滞后KNN 在趋势行情里反应迟钝。把这些预测结果转成涨跌信号再按多数投票决定最终方向能消掉一部分单模型偏差。具体做法是把四段预测结果做差分差值大于 0 记作看多信号 1小于 0 记作看空信号 -1然后逐日叠加投票。import numpy as np signals np.sign(np.diff(lstm_pred)) \ np.sign(np.diff(arima_pred)) \ np.sign(np.diff(knn_pred)) \ np.sign(np.diff(lr_pred)) final_signal np.where(signals 0, 1, np.where(signals 0, -1, 0))这里signals的取值范围是 -4 到 4final_signal是最终方向大于 0 做多小于 0 暂避。做集成之后再去跑backtest.py对比集成策略和单模型的累计收益曲线往往能看到回撤变小、胜率更稳定。6.2 给特征加维度如果你觉得单用收盘价太单薄可以在create_window_data里把窗口特征扩成多列收盘价、成交量、最高最低价差、5 日收益率。LSTM 的input_shape从(window, 1)变成(window, 4)其他模型把二维窗口数据reshape后直接训练改动路径是现成的不用动生成报告的逻辑。6.3 验证方法验证时千万别只看总收益率——把它和同期买入持有策略对比跑不赢买入持有就说明模型预测没有提供增量信息。我把每次回测结果记录成一张表模型名称、累计收益、最大回撤、胜率、交易次数用这五列对比比单看一条收益曲线靠谱得多。我记得第一次跑 KNN 集成时以为投票后胜率肯定上去结果回测出来收益反而变低了。查了半天发现是投票把方向矛盾的日子全部归零跳过刚好错过了一段上涨——集成不是过滤信号是降低单一方向的依赖。从那以后我每次做模型对比都强制走一遍单模型基准 → 集成 → 对照买入持有的验证流程四步缺一不可。这个项目的价值就在于此四种模型从数据到回测全链路跑通改参数、换特征、加集成都有下手点希望你也能从中找到自己的实验方向。本文还有配套的精品资源点击获取
返回列表