
简介这是一份基于机器学习算法的股票市场价格分析与预测完整源码项目面向计算机、人工智能、大数据、数学、电子信息等专业正在做课程设计、期末大作业或毕业设计的学生也适合有一定Python与机器学习基础的开发者参考。压缩包共2个文件包括1个Python主脚本和1个环境依赖说明整体仅45KB结构精简便于快速阅读和调试。代码经过严格调试下载即可运行覆盖股票历史数据读取、特征工程、模型训练、价格预测与结果评估等典型环节可帮助读者系统理解机器学习在金融数据分析中的落地流程随附的依赖清单则能快速搭建运行环境。目前已有298人学习下载适合作为量化分析、智能投顾等课程项目的实施模板也可在此源码基础上做二次开发与算法调优用于复现实验或扩展新模型。1. 股票价格分析及预测的源码包先弄清楚它能干什么、不能干什么拿到一个名为「基于机器学习算法的股票市场股票价格的分析及预测源码.zip」的压缩包大多数人的第一反应是解压、跑通、看曲线然后期待它第二天就能告诉你买哪只。我的建议是反过来先花半天把包里的文件结构、数据流和模型假设摸清楚再决定要不要投入时间。这个方向本身不玄学——用历史行情训练模型预测未来价格走势是量化研究里最经典的入门课题核心链路就五步数据获取、特征构造、模型训练、评估回测、参数调优。源码包的价值不在于「预测准不准」而在于它把这条链路完整落地了你能在上面改数据、换模型、调参数逐步理解每个环节的边界。适合谁适合有 Python 基础、想用机器学习做量化分析但不知道从哪下手的从业者也适合想快速搭建一个可复现的股价预测基线的开发人员。不适合谁不适合指望它稳定盈利的人——后面你会看到模型的准确率和策略的收益之间隔着一条巨大的鸿沟。2. 解压后先做三件事文件摸底、环境复现、跑通最小预测2.1 源码包结构摸底先分清哪些是核心代码哪些是依赖和数据拿到 zip 后的第一个动作不是找 main.py而是先列目录。常见做法是解压后执行tree命令或者直接用编辑器打开看文件树。一个规范的股票预测源码包通常包含这几类内容数据获取脚本如get_data.py、data_loader.py负责从行情接口拉取历史 K 线特征工程模块如features.py负责把原始 OHLCV 转成技术指标模型定义与训练脚本如train.py、model.py包含模型结构和训练入口预测与回测脚本如predict.py、backtest.py配置文件如config.yaml、params.json存放参数依赖清单requirements.txt和说明文档README.md。如果包里有多个.ipynb后缀的 notebook大概率是分步骤讲解的教程型代码如果以.py为主则是工程化风格。我一般会先打开requirements.txt看依赖版本再打开README.md确认作者标注的数据源。注意一点很多源码包的行情数据是硬编码了日期范围的直接跑可能会因为数据源更新而报错这部分后面会细说。2.2 环境复现用虚拟环境隔离依赖别污染系统 Python股票预测项目最常见的依赖组合是pandas、numpy、scikit-learn、matplotlib如果涉及深度学习还会有tensorflow或pytorch。不同的包版本之间冲突很常见尤其是 numpy 和 pandas 的版本搭配。我建议用conda或者python -m venv建独立环境。# 创建并激活虚拟环境Windows 用户把 source 换成 activate python -m venv stock_pred_env source stock_pred_env/bin/activate # 安装依赖如果国内网络慢可以换镜像源 pip install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple # 如果 requirements.txt 缺失手动安装最小依赖集 pip install pandas numpy scikit-learn matplotlib逻辑说明虚拟环境的核心作用是把项目的依赖隔离在独立目录里避免和系统里其他项目的包互相干扰。换镜像源是为了在下载大体积依赖包时更稳定这个在国内环境几乎是必做的。参数说明python -m venv后面跟的是环境名称可以自己改-r参数指定依赖清单文件路径-i参数指定 pip 下载源。装完依赖后先跑一个最小的数据加载脚本确认.csv数据文件能正常读入。很多源码包会附带一份样本数据通常是以000001.csv或类似格式命名的历史日线数据。如果包里没有数据文件就需要自己去行情接口拉——这是后面章节的重点。2.3 跑通最小预测从 30 行代码里验证数据流是通的不要一上来就跑完整的训练脚本先构造一个「读数据 → 切分 → 训练 → 预测」的最小闭环。这个闭环只需要几十行代码但能把环境、数据、模型接口这三个最容易出问题的环节全部验证一遍。我一般会用 scikit-learn 的线性回归做基线。import pandas as pd from sklearn.model_selection import train_test_split from sklearn.linear_model import LinearRegression from sklearn.metrics import mean_squared_error # 读取历史行情数据按日期升序排列 df pd.read_csv(data/000001.csv, parse_dates[date]) df df.sort_values(date) # 构造最简单的特征用前 N 天收盘价预测下一天收盘价 df[prev_close] df[close].shift(1) df[prev_volume] df[volume].shift(1) df df.dropna() X df[[prev_close, prev_volume]] y df[close] # 按时间顺序切分避免随机切分造成未来数据泄漏 split_idx int(len(df) * 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:] model LinearRegression() model.fit(X_train, y_train) y_pred model.predict(X_test) print(MSE:, mean_squared_error(y_test, y_pred))逻辑说明这个脚本的核心逻辑是用「昨天的收盘价和成交量」去预测「今天的收盘价」。shift(1)是时序数据里最基本的操作——把整列向下移动一行让第 N 行的特征对应第 N1 行的标签。注意切分用的是按位置切片而不是train_test_split的默认随机切分这是时序预测里最容易踩的坑后面会专门展开。参数说明split_idx是训练集和测试集的分界点这里取 80% 作为训练集、20% 作为测试集你可以根据数据总长度调整但要保证训练集在时间上先于测试集。mse是均方误差输出越小说明预测值和真实值的偏差越小。这个最小闭环跑通后说明数据链路和模型接口都没问题可以进入特征工程环节。3. 特征工程把行情数据变成机器学习能理解的语言3.1 为什么直接喂原始 OHLCV 效果差特征分布和尺度问题很多新手会直接把开盘价、收盘价、最高价、最低价、成交量这五列扔进模型结果训练出来的模型在测试集上一团糟。原因有两个层面。第一原始价格序列是高度非平稳的——今天的收盘价和一年前的收盘价不在一个量级上模型很难从这样的数据里学到稳定的规律。第二价格和成交量的尺度差异极大大部分机器学习算法尤其是基于距离或梯度的模型会天然偏向数值大的特征导致成交量几乎不起作用。解决思路是构造相对特征和比率特征而不是使用绝对价格。比如「当日涨跌幅」代替「当日收盘价」「当日成交量相对 5 日均量的倍数」代替「当日成交量」。这样处理之后特征分布更稳定模型也更有可能捕捉到市场的相对变化。这个思路是所有股价预测特征工程的基础不管后面用什么模型都适用。3.2 技术指标计算手动实现比调库更可控技术指标是股票预测特征工程的主体。常见的指标包括移动平均线 MA、指数移动平均线 EMA、相对强弱指数 RSI、MACD 等。很多源码包会直接调用ta或ta-lib这类现成库但我的建议是手动用 pandas 实现一遍因为这样你能精确控制窗口大小和计算细节遇到异常数据时也更容易排查。import pandas as pd import numpy as np def add_technical_features(df, ma_windows[5, 10, 20]): 为日线数据添加常用技术指标特征 # 均线指标用滚动窗口计算注意 min_periods 避免前期数据为 NaN for w in ma_windows: df[fma_{w}] df[close].rolling(windoww, min_periodsw).mean() # 价格相对均线的偏离度用于捕捉短期偏离 df[fclose_ma_{w}_ratio] df[close] / df[fma_{w}] - 1 # 涨跌幅特征pct_change 计算的是与前一日的相对变化率 df[return_1d] df[close].pct_change() df[return_5d] df[close].pct_change(periods5) # 成交量相对均值倍数捕捉放量异动 df[volume_ma_5] df[volume].rolling(window5, min_periods5).mean() df[volume_ratio] df[volume] / df[volume_ma_5] # RSI 指标14 日窗口的相对强弱常见区间是 30~70 delta df[close].diff() gain delta.clip(lower0).rolling(window14, min_periods14).mean() loss (-delta.clip(upper0)).rolling(window14, min_periods14).mean() rs gain / loss df[rsi_14] 100 - (100 / (1 rs)) return df df add_technical_features(pd.read_csv(data/000001.csv, parse_dates[date])) print(df.tail())逻辑说明这段代码计算了三类特征。均线类特征看的是价格趋势和偏离程度close_ma_w_ratio大于 0 说明收盘价高于均线偏离越大越可能回调。涨跌幅特征看的是短中期动量return_5d捕捉的是 5 日累计变化。成交量相对倍数volume_ratio用于识别放量——如果某天量能是 5 日均值的 2 倍以上通常意味着市场情绪有明显变化。RSI 是经典的动量指标值大于 70 通常认为超买小于 30 认为超卖。参数说明ma_windows是均线窗口列表通常取 5、10、20、60 这几个常用周期。RSI 的窗口 14 是 Wilder 提出的默认值也是行业通用配置不建议随意改因为不同周期算出来的 RSI 对超买超卖的判断标准会变。min_periods参数的意思是窗口内至少有多少个有效值才计算防止数据前期产生大量 NaN。所有特征都要求从历史数据里计算不能使用未来信息——这一点在有 NaN 的时期尤其要注意。3.3 数据集切分与归一化时序顺序是硬约束特征构造完成后下一步是切分数据集并对特征做归一化。这里有一个很容易被忽略的细节归一化必须只在训练集上计算均值和方差然后用同样的参数去转换测试集否则测试集的信息会通过统计量泄漏到训练过程中。这个错误非常隐蔽——结果看起来不错其实是因为模型「见过」了测试集的分布。from sklearn.preprocessing import StandardScaler # 先按时间切分再归一化 feature_cols [c for c in df.columns if c not in [date, close, target]] X df[feature_cols].values.astype(np.float32) y df[close].values.astype(np.float32) split_idx int(len(df) * 0.8) X_train, X_test X[:split_idx], X[split_idx:] y_train, y_test y[:split_idx], y[split_idx:] # 关键点只 fit 训练集测试集用 transform scaler StandardScaler() X_train_scaled scaler.fit_transform(X_train) X_test_scaled scaler.transform(X_test)逻辑说明fit_transform会在训练集上计算每个特征的均值和标准差然后做标准化——标准化后的数据均值为 0、标准差为 1。测试集只调用transform用的是训练集统计出来的同一组参数这样测试集的信息不会参与模型训练前的任何计算。参数说明StandardScaler是标准化器也可以用MinMaxScaler做归一化到 [0,1] 区间。模型是线性类如线性回归、逻辑回归时标准化可以加速收敛并提升数值稳定性模型是树类如随机森林、XGBoost时对尺度不敏感可以跳过这步。另外这里的X用np.float32是为了节省内存如果你的数据量很大或者使用深度学习模型这个习惯能显著减少内存占用。4. 模型选择与训练从单模型到对比实验的完整路径4.1 选型逻辑先跑树模型和线性基线再决定要不要上 LSTM股票价格预测里最常见的模型有三类线性回归/岭回归、随机森林/XGBoost 这类树模型、LSTM 这类循环神经网络。我的经验是不要一上来就上 LSTM——它训练慢、调参复杂、结果不稳定而且在小数据集上往往打不过树模型。先把线性基线和树模型跑通拿到一个「不那么差」的结果再用这个结果作为参照去评估 LSTM 是否值得投入。选型的主要依据是数据规模和特征类型。数据量在几千条级别时树模型通常是最好的选择它对非线性关系有不错的拟合能力对异常值也有一定鲁棒性。数据量在几万条以上并且你愿意花时间调参时LSTM 才有比较优势——它能建模更长的时序依赖但代价是训练时间和调参难度都大幅上升。另外树模型不需要特征归一化这对新手更友好。4.2 随机森林训练关键参数和防止数据泄漏的细节随机森林是学股价格预测里最常用的树模型因为它的默认参数就能跑出还算稳定的结果而且不容易过拟合。下面是一段完整的训练脚本包含了时序切分、训练和评估。from sklearn.ensemble import RandomForestRegressor from sklearn.metrics import mean_squared_error, mean_absolute_error import numpy as np # 构造标签把「未来 5 日后的收盘价」作为目标而不是明日收盘价 df[target] df[close].shift(-5) df df.dropna() feature_cols [c for c in df.columns if c not in [date, close, target]] X df[feature_cols].values.astype(np.float32) y df[target].values.astype(np.float32) # 按时间顺序切分训练集是过去 80%测试集是未来 20% split_idx int(len(df) * 0.8) X_train, X_test X[:split_idx], X[split_idx:] y_train, y_test y[:split_idx], y[split_idx:] # 随机森林回归模型 model RandomForestRegressor( n_estimators300, # 树的数量越大越稳定但越慢 max_depth8, # 限制深度防止过拟合 min_samples_leaf5, # 叶子节点最少样本数 random_state42, # 固定随机种子保证可复现 n_jobs-1 # 使用所有 CPU 核心 ) model.fit(X_train, y_train) y_pred model.predict(X_test) print(RMSE:, np.sqrt(mean_squared_error(y_test, y_pred))) print(MAE:, mean_absolute_error(y_test, y_pred)) # 特征重要性输出 Top 10用于后续特征筛选 importances sorted(zip(feature_cols, model.feature_importances_), keylambda x: x[1], reverseTrue) for feat, imp in importances[:10]: print(f{feat}: {imp:.4f})逻辑说明这里把预测目标从「明天收盘价」改成了「5 天后收盘价」这是股票预测里常见的做法——预测未来 5 日的价格比预测次日更具实操意义而且标签中的短期噪声更少。shift(-5)表示把收盘价往上移 5 行这样当前行的特征对应 5 天后的目标值。参数说明n_estimators300是随机森林中决策树的数量增加这个值会提升模型的稳定性和精度但训练时间也会线性增长超过一定数量后收益递减。max_depth8限制树的深度防止单棵树过度拟合训练数据中的噪声。min_samples_leaf5要求叶子节点至少包含 5 个样本这个参数是控制过拟合最有效的旋钮之一取值越大模型越保守。random_state42固定随机种子保证每次运行结果一致这在做对比实验时是必须的。4.3 LSTM 训练什么时候值得上以及它的三个不稳定因素LSTM 在股价预测中的角色比较特殊——它在很多公开案例里表现亮眼但复现时经常翻车。常见的原因有三个权重初始化导致的随机性、学习率设置不当导致的训练震荡、以及序列长度对预测效果的高度敏感。如果你已经跑通了树模型并且对结果不满意可以考虑用 LSTM 做对比。下面是一个最小实现import tensorflow as tf import numpy as np def build_sequences(features, target, seq_len10): 把特征矩阵转换成监督学习序列格式 X_seq, y_seq [], [] for i in range(seq_len, len(features)): X_seq.append(features[i - seq_len:i]) y_seq.append(target[i]) return np.array(X_seq), np.array(y_seq) # 先用 4.2 节中的 X_train_scaled 构造序列数据 X_train_seq, y_train_seq build_sequences(X_train_scaled, y_train, seq_len10) X_test_seq, y_test_seq build_sequences(X_test_scaled, y_test, seq_len10) model tf.keras.Sequential([ tf.keras.layers.LSTM(64, activationtanh, input_shape(10, X_train_scaled.shape[1])), tf.keras.layers.Dropout(0.2), tf.keras.layers.Dense(1) ]) # Adam 优化器加均方误差损失 model.compile(optimizertf.keras.optimizers.Adam(learning_rate5e-4), lossmse) # 训练 50 个 epoch加早停防止过拟合 history model.fit(X_train_seq, y_train_seq, epochs50, batch_size64, validation_split0.1, callbacks[tf.keras.callbacks.EarlyStopping(patience5, restore_best_weightsTrue)], verbose0) print(训练完成最终验证损失:, history.history[val_loss][-1])逻辑说明LSTM 要求输入形状是(样本数, 时间步数, 特征数)所以需要先把二维特征矩阵转换成三维序列数据。build_sequences函数的作用就是构建时间窗口——用过去 10 天的特征预测当天的目标值seq_len就是这个窗口的大小。Dropout层在每次训练时随机丢弃一部分神经元的输出是一种防止过拟合的正则化手段。参数说明seq_len10是时间窗口长度这个参数非常敏感。窗口太短模型看不到足够的趋势背景窗口太长训练数据量骤减且引入了过多过期信息。learning_rate5e-4是 Adam 优化器的学习率太大会导致损失震荡太小则收敛极慢。EarlyStopping(patience5)表示验证集损失连续 5 个 epoch 不下降就停止训练并恢复到验证集表现最好的权重。LSTM 对随机种子敏感如果两次训练结果差异较大先固定tf.random.set_seed()的种子再跑。5. 避坑与排查时序预测里最容易翻车的 5 个问题5.1 数据泄漏随机切分导致测试集信息混入训练集现象模型在测试集上的 RMSE 低得惊人看起来预测几乎完美但拿到新数据上就完全失灵。原因用了train_test_split的默认随机切分模式而不是按时间顺序切分。随机切分会让训练集里混入未来数据模型学到了「未来信息」测试集自然表现好。这是时序预测中最典型的黑匣子问题——结果越好越要警惕。解决统一按时间顺序切分。也就是在train_test_split中显式传入shuffleFalse或者像前面代码那样直接用位置切片X[:split_idx]和X[split_idx:]。检查一下你源码包里的切分代码有没有设置shuffleFalse。5.2 归一化参数泄漏scaler 对全量数据 fit 了现象标准化之后发现训练集和测试集的均值都趋近于 0标准差都趋近于 1模型的测试集表现虚高。原因把完整数据集交给了scaler.fit_transform()导致标准化时使用了测试集的均值和方差。测试集的分布信息通过标准化参数间接参与了训练。解决严格分离——训练集上fit_transform测试集只transform。如果用了流水线Pipeline确保它是在训练集上fit的。一个简单的检查方法打印scaler.mean_如果这个均值是全量数据的均值而非仅训练集的说明泄漏了。5.3 前视偏差特征或标签里包含了未来信息现象特征重要性排序中某个特征如未来收益或当天收盘价的权重异常高模型表现好得不真实。原因构造特征或标签时使用了未来数据。常见错误是把pct_change计算后的结果直接当特征而这个计算结果包含了当天和未来的关系或者在构造标签时用了shift(-1)但又没删掉最后几行导致 NaN 被填充成了其他值。解决每一次特征构造都只使用截至当前日期的数据。检查代码里所有shift的符号——shift(1)用昨天的数据是安全的shift(-1)用于构造未来标签是安全的但务必确认标签列不会在后续被当成特征使用。我在每次构造完特征后都会打印数据的最后 5 行确认没有「未来值泄漏」到特征列中。5.4 标签噪声过大直接预测收盘价导致模型学不到模式现象模型训练结束后训练集损失很低但测试集损失极高并且预测曲线整体滞后于真实曲线一天。原因股票价格的每日变动里包含大量噪声直接用原始收盘价做回归目标模型的损失函数被这些噪声主导。预测曲线滞后是因为模型学到的「最优策略」就是沿用昨天的价格——这在数学上是最小化均方误差的保守选择。解决更换预测目标。常见做法是预测未来 N 日的涨跌幅未来 5 日收盘价 / 当前收盘价 - 1或者把回归问题转成分类问题——预测未来 5 日是否上涨。分类问题对噪声的容忍度更高在实盘参考中也有更明确的交易含义。5.5 指标失真只看 RMSE 会掩盖方向准确率低的问题现象模型 RMSE 看起来很小但实际判断涨跌方向预测值和真实值同号的准确率只有 50% 左右跟抛硬币差不多。原因RMSE 衡量的是数值误差但股价预测的实际价值在于方向判断。一个模型可以预测值整体偏保守、数值误差不大但对涨跌方向完全没有判断力——这对交易没有参考意义。解决同时观察方向准确率指标。计算方法是对比np.sign(y_pred[1:] - y_pred[:-1])和np.sign(y_test[1:] - y_test[:-1])的相同比例。在后续回测章节我会用方向准确率作为核心评估指标。6. 滚动预测与样本外验证把模型真正用进交易日的最后一步6.1 为什么固定切分不够用滚动窗口模拟真实交易的迭代节奏固定切分的弊端在于它只模拟了一次「训练完就不更新」的流程而真实交易中你需要每周或每月用新数据重新训练模型。滚动预测也叫 walk-forward validation是更接近实战的验证方式每次用过去 N 天的数据训练预测未来 M 天然后把窗口向前推进 M 天继续训练和预测。这种方式的优势是更真实地评估模型在持续更新场景下的表现。import numpy as np from sklearn.ensemble import RandomForestRegressor def walk_forward_validate(df, feature_cols, train_days250, pred_days5): 滚动预测验证每次训练 250 天预测未来 5 天 predictions, actuals [], [] total len(df) for start in range(0, total - train_days, pred_days): train_end start train_days predict_end min(train_end pred_days, total) train_df df.iloc[start:train_end] test_df df.iloc[train_end:predict_end] model RandomForestRegressor(n_estimators200, max_depth6, min_samples_leaf5, random_state42) model.fit(train_df[feature_cols], train_df[target]) pred model.predict(test_df[feature_cols]) predictions.extend(pred) actuals.extend(test_df[target].values) return np.array(predictions), np.array(actuals) y_pred_wf, y_true_wf walk_forward_validate(df, feature_cols) direction_acc np.mean(np.sign(y_pred_wf) np.sign(y_true_wf)) print(滚动预测方向准确率:, direction_acc)逻辑说明这个循环的核心逻辑是「训练区间向前滑动」。每次用最近 250 个交易日的数据训练一个随机森林然后预测接下来 5 个交易日的收盘价目标值每跑完一段就把窗口整体前移 5 天。这种模拟方式还原了实际使用模型时的节奏——你不会用半年前训练的模型去预测今天而是每周用最新数据重新训练。参数说明train_days250大约是 A 股一年的交易日数量这是比较常见的训练窗口长度太短模型学不到足够的市场阶段太长则包含太多旧逻辑。pred_days是预测步长和标签构造时的shift(-5)保持一致。方向准确率direction_acc的含义是预测值与真实值同号的比例——这个值超过 0.55 基本算具备参考价值0.6 以上在趋势明显的时间段是有意义的。6.2 从预测到可用性一个判断模型是否值得投入的检查清单完成了滚动验证之后你已经知道模型的真实水平了。我的习惯是把下面几条全部过一遍再决定这个源码包值不值得投入第一方向准确率是否稳定超过 0.52。注意不是看平均而是看分段稳定性——如果某些时间段准确率很高、某些时间段落回 0.5 以下说明模型只在特定行情里有效。第二预测的涨跌幅中位数是否接近 0。如果模型预测的涨跌幅中位数显著偏正说明模型整体在喊多这种偏差在实盘中会带来系统性风险。第三模型的预测是否对输入特征敏感。可以做一个简单的敏感性测试把最新的特征值稍微扰动一点看预测值是否剧烈变化。如果微小扰动导致预测大幅波动说明模型对噪声敏感实盘参考价值有限。第四交易成本是否被纳入考量。即使方向准确率有 60%扣掉双边手续费和滑点后实际收益可能仍然为负——这是预测模型和交易策略之间最容易被忽略的差距。6.3 实战中的两个小技巧保存模型快照与记录预测日志最后一个建议当你对某个模型配置满意之后务必把模型文件和预测结果存档。我用到的保存方式是joblib.dump(model, model_rf_300_depth8_20240101.pkl)文件名里带上模型参数和训练日期。另外一个被很多人忽略的细节是记录每次预测的日志包括日期、输入特征快照、预测值、模型版本。这看起来繁琐但当你几个月后回头复盘某次预测为什么偏差巨大时日志是唯一能还原现场的证据。我吃过没做日志的亏——训练效果很好的模型在换数据后劣化因为没有记录当时的特征取值排查了半天也不知道是数据问题还是模型问题。从那以后预测日志就是我量化实验里的标配了。希望这些复盘习惯能让你在这个方向少走弯路。本文还有配套的精品资源点击获取