
简介这份资源面向金融量化初学者与具备一定Python基础的开发者提供一套基于机器学习预测A股走势的完整源码方案帮助读者理解从数据获取到模型回测的全流程。压缩包共12个文件约2.53MB包含6个ipynb交互式笔记、3个csv行情数据、2个py脚本及1个gitignore配置覆盖K线入库、特征工程、FFT滤波、单票回测与LSTM建模等环节。已有307人学习下载适合对照实践。读者可从中获得数据清洗与特征提取思路、小市值结合盈利指标的过滤策略、sklearn单票回测流程以及singlelstm与singlelstm2两版LSTM模型的实现对比便于快速搭建自己的预测实验框架并理解模型评估与调参要点。1. 从一份 A 股走势预测源码说起机器学习到底能预测什么很多人第一次搜「基于机器学习算法实现对A股股票走势预测系统源码」心里想的其实是拿到一份能跑的代码输入历史行情输出明天涨跌。我当年也是这么想的直到把第一版模型跑在真实数据上才发现预测这件事远没有想象中那么直接。A 股有它自己的脾气——涨跌停限制、T1 交易、板块轮动、政策消息面冲击这些都会让一个在教科书数据集上表现不错的机器学习模型到了实盘就变成玄学。所以这篇文章不打算给你画大饼而是把一套可复现的股票走势预测系统拆开数据怎么取、特征怎么造、模型怎么选、回测怎么做、源码结构怎么组织。适合有一定 Python 基础、想认真做一版能跑通全流程的从业者也适合刚入门机器学习、想找一个真实场景练手的人。读完你至少能自己搭出一套从数据到信号到回测的完整链路并且知道哪些地方最容易翻车。2. 数据层A股行情获取与清洗的工程细节2.1 数据源选择与常见接口对比做 A 股预测第一步不是选模型而是搞定数据。市面上常见的数据获取方式有几类一是开源财经数据接口比如 akshare、tushare 这类 Python 库能拿到日线、分钟线、财务指标二是券商提供的量化接口适合有账户的开发者三是自己爬取公开行情页面但这条路维护成本高还容易遇到反爬。我一般会优先用 akshare因为它免费、更新及时、覆盖品种全缺点是接口偶尔会因为上游页面变动而失效需要关注版本更新。数据源覆盖内容优点注意点akshare日线、分钟线、财务、板块免费、接口丰富偶发接口失效需锁定版本tushare日线、财务、指数数据规范、有积分体系部分接口需要积分券商量化接口实时行情、交易延迟低、可实盘需要开户和权限自建爬虫任意公开页面灵活维护成本高、易触发反爬选数据源的核心原则是先保证能稳定拿到复权后的日线数据再考虑分钟级。很多新手一上来就想做高频结果数据质量不过关模型学到的全是噪声。2.2 用 akshare 拉取日线并做前复权处理下面这段代码是我常用的最小拉取模板以贵州茅台为例拉取最近几年的日线数据并做前复权处理。import akshare as ak import pandas as pd # 拉取贵州茅台日线adjustqfq 表示前复权 df ak.stock_zh_a_hist( symbol600519, perioddaily, start_date20190101, end_date20241231, adjustqfq ) # 统一列名方便后续处理 df df.rename(columns{ 日期: date, 开盘: open, 收盘: close, 最高: high, 最低: low, 成交量: volume, 成交额: amount, 涨跌幅: pct_chg }) df[date] pd.to_datetime(df[date]) df df.sort_values(date).reset_index(dropTrue) # 删除停牌日成交量为0和缺失值 df df[df[volume] 0].dropna() print(df.tail())这段代码的关键点有三个adjustqfq必须加否则除权除息会造成价格跳空模型会误以为发生了剧烈波动volume 0用来过滤停牌日排序和重置索引保证后续滚动窗口计算不会错位。参数上start_date和end_date根据你的回测区间调整一般建议至少覆盖一轮完整牛熊比如 2019 到 2024。2.3 数据清洗中容易忽略的三个坑第一个坑是复权方式混用。前复权和后复权算出来的收益率不一样如果你训练用前复权、回测用后复权结果会对不上。第二个坑是停牌和一字板。停牌日没有交易一字板当天成交量极低这些样本如果直接喂给模型会让它学到虚假的规律。第三个坑是幸存者偏差。如果你只拿现在还在上市的股票做训练那些已经退市的股票就被剔除了模型会过于乐观。常见做法是尽量使用包含退市股票的历史成分股数据或者至少在回测时加入退市处理逻辑。3. 特征工程把 K 线变成模型能吃的因子3.1 量价因子的构造逻辑机器学习模型不会自己看懂 K 线你需要把原始行情转换成数值特征。最基础的是量价因子收益率、波动率、成交量变化率、换手率、均线偏离度。这些因子的共同点是计算简单、解释性强而且在 A 股上有一定的短期预测能力。我一般会构造以下几类动量类过去 N 日收益率、过去 N 日最高价距离波动类过去 N 日收益率标准差、真实波幅 ATR量能类成交量 MA5/MA20 比值、换手率变化均线类收盘价与 MA5/MA10/MA20 的偏离度下面是一个批量生成因子的函数示例。import numpy as np def build_features(df, windows[5, 10, 20]): out df.copy() # 日收益率 out[ret] out[close].pct_change() # 动量因子 for w in windows: out[fmom_{w}] out[close].pct_change(w) out[fma_{w}] out[close].rolling(w).mean() out[fbias_{w}] (out[close] - out[fma_{w}]) / out[fma_{w}] out[fvol_{w}] out[ret].rolling(w).std() out[fvol_ratio_{w}] out[volume] / out[volume].rolling(w).mean() # 真实波幅 high_low out[high] - out[low] high_close (out[high] - out[close].shift()).abs() low_close (out[low] - out[close].shift()).abs() out[atr] pd.concat([high_low, high_close, low_close], axis1).max(axis1).rolling(14).mean() # 标签未来一日涨跌1 为涨0 为跌 out[label] (out[close].shift(-1) out[close]).astype(int) out out.dropna().reset_index(dropTrue) return out这里windows控制均线和波动率的回看周期label用未来一日收盘价对比当前收盘价涨为 1、跌为 0。注意最后一行dropna会删掉前面因为滚动窗口产生的空值也会删掉最后一行因为shift(-1)产生的空标签。如果你要做多日预测把shift(-1)改成shift(-n)即可但样本量会相应减少。3.2 标签设计分类还是回归很多人纠结预测涨跌用分类还是回归。我的经验是如果你只关心方向用二分类如果你关心幅度用回归。但 A 股涨跌幅度分布尖峰厚尾回归模型容易被极端值带偏。常见做法是先做分类再用概率输出做仓位管理。比如模型输出上涨概率 0.7你可以据此决定仓位比例。另外标签的阈值也可以调整不一定非要用 0 作为分界可以设定上涨超过 1% 才算正样本这样可以过滤掉微小波动带来的噪声。3.3 特征标准化与时间序列交叉验证特征标准化在树模型里不是必须的但在逻辑回归、SVM、神经网络里很重要。我一般用滚动标准化而不是全局标准化因为全局标准化会用到未来信息。具体做法是对每个时间点只用它之前的数据计算均值和标准差。下面是一个简单的滚动标准化实现。def rolling_zscore(series, window60): mean series.rolling(window).mean() std series.rolling(window).std() return (series - mean) / std # 对部分因子做滚动标准化 for col in [ret, mom_5, vol_5, bias_5]: df[f{col}_z] rolling_zscore(df[col], window60)时间序列交叉验证不能用普通的 KFold因为会泄露未来信息。我一般用TimeSeriesSplit它保证训练集始终在验证集之前。参数n_splits控制切分次数通常设 5 到 10。4. 模型训练从逻辑回归到 LightGBM 的选型与调参4.1 为什么我优先选树模型在 A 股日频预测这个场景里我试过逻辑回归、SVM、随机森林、XGBoost、LightGBM 和简单的 LSTM。结论是树模型综合表现最稳。原因是量价因子之间存在非线性关系和交互效应树模型能自动捕捉这些而逻辑回归需要手动构造交叉项。LSTM 理论上能学时序依赖但数据量不够大时容易过拟合训练也慢。LightGBM 在速度和精度上比较平衡支持缺失值处理还能输出特征重要性方便做因子筛选。4.2 LightGBM 训练与参数设置下面是一个完整的训练流程包含时间序列切分和早停。import lightgbm as lgb from sklearn.model_selection import TimeSeriesSplit from sklearn.metrics import accuracy_score, roc_auc_score feature_cols [c for c in df.columns if c not in [date, label, open, close, high, low, volume, amount, pct_chg]] X df[feature_cols] y df[label] tscv TimeSeriesSplit(n_splits5) auc_scores [] for train_idx, val_idx in tscv.split(X): X_train, X_val X.iloc[train_idx], X.iloc[val_idx] y_train, y_val y.iloc[train_idx], y.iloc[val_idx] model lgb.LGBMClassifier( n_estimators500, learning_rate0.05, max_depth5, num_leaves31, subsample0.8, colsample_bytree0.8, min_child_samples50, reg_alpha0.1, reg_lambda0.1, random_state42 ) model.fit( X_train, y_train, eval_set[(X_val, y_val)], eval_metricauc, callbacks[lgb.early_stopping(50), lgb.log_evaluation(100)] ) pred_prob model.predict_proba(X_val)[:, 1] auc roc_auc_score(y_val, pred_prob) auc_scores.append(auc) print(f验证集 AUC: {auc:.4f}) print(f平均 AUC: {np.mean(auc_scores):.4f})参数说明n_estimators是树的数量配合早停可以防止过拟合learning_rate控制每棵树的学习率0.05 是比较稳的值max_depth和num_leaves共同控制模型复杂度A 股数据噪声大深度不宜超过 6subsample和colsample_bytree做行采样和列采样增强泛化min_child_samples设大一点可以避免模型学到太细的噪声reg_alpha和reg_lambda是 L1/L2 正则。早停的50表示验证集 AUC 连续 50 轮不提升就停止。4.3 特征重要性与因子筛选训练完之后用model.feature_importances_看哪些因子贡献大。我一般会删掉重要性排名后 30% 的因子再重新训练一次往往能提升泛化。但要注意特征重要性高不代表因果性强可能只是过拟合的产物。稳妥做法是结合滚动窗口的稳定性如果一个因子在不同时间段重要性波动很大就要谨慎使用。5. 回测与避坑把信号变成可评估的策略5.1 用 backtrader 做多股回测的最小配置模型输出的是概率要变成可评估的策略需要回测。backtrader 是常用的回测框架支持多股、多策略。下面是一个最小配置示例假设我们已经有了每只股票的预测信号。import backtrader as bt class MLSignalStrategy(bt.Strategy): params ((prob_threshold, 0.6),) def __init__(self): self.signals {} # 外部注入的预测概率 def next(self): for data in self.datas: prob self.signals.get(data._name, 0.5) pos self.getposition(data).size if prob self.params.prob_threshold and pos 0: self.buy(datadata, size100) elif prob 1 - self.params.prob_threshold and pos 0: self.close(datadata) cerebro bt.Cerebro() cerebro.addstrategy(MLSignalStrategy, prob_threshold0.6) # 添加数据、设置初始资金、手续费等 cerebro.broker.setcash(1000000) cerebro.broker.setcommission(commission0.0003) # cerebro.adddata(...) 逐个添加股票数据 # cerebro.run()这段代码的核心逻辑是预测概率超过阈值就买入低于反向阈值就卖出。prob_threshold设 0.6 意味着只在模型比较确定时才动手。手续费0.0003是万三接近真实水平。多股回测时要注意资金分配backtrader 默认按数据顺序处理可能需要自定义仓位管理。5.2 回测中必须检查的四个指标年化收益率和基准指数对比看是否有超额收益最大回撤决定你能不能扛住夏普比率衡量单位风险的收益换手率换手太高手续费会吃掉利润我一般会把这四个指标和沪深300 同期表现放在一起看。如果年化跑不赢指数或者回撤明显更大那这套信号就没有实盘价值。5.3 避坑与常见问题排查现象一回测收益率很高实盘完全不行。原因通常是未来函数。比如用了全局标准化、用了未来数据做特征、或者标签泄露。解决方法是严格按时间切分所有计算只用历史数据。现象二模型在训练集 AUC 0.9验证集只有 0.5。这是典型过拟合。原因可能是特征太多、模型太复杂、样本量太少。解决方法是减少特征、降低模型复杂度、增加正则化、扩大训练数据。现象三回测换手率极高手续费吃掉大部分利润。原因是信号频繁翻转。解决方法是提高预测阈值、加入信号平滑、或者拉长调仓周期。现象四某些股票回测结果特别好换一批就崩。这是过拟合到特定标的。解决方法是做多股组合回测不要单票调参。现象五数据接口突然报错拉不到数据。常见于开源接口上游变动。解决方法是锁定库版本、加异常重试、准备备用数据源。6. 源码组织与进阶让系统能持续迭代一套能持续用的预测系统源码结构比单次模型精度更重要。我一般会按下面的方式组织目录project/ ├── data/ # 原始数据和缓存 ├── features/ # 因子计算脚本 ├── models/ # 训练和预测脚本 ├── backtest/ # 回测配置和结果 ├── config/ # 参数配置文件 └── utils/ # 通用工具函数配置和代码分离这样换参数不用改代码。每次实验记录模型版本、特征版本、回测区间方便复现。进阶用法上可以尝试把多个模型的预测概率做加权集成比如 LightGBM 加逻辑回归加随机森林取平均概率。集成通常能降低方差但提升有限不要指望从 0.55 跳到 0.7。验证方法上我习惯留出一段完全没参与训练和调参的时间做最终测试比如用 2019 到 2022 训练2023 验证调参2024 做最终测试。如果 2024 的表现和验证集差距很大说明模型不稳定。最后说一个我自己的习惯每次觉得模型效果不错的时候先别急着上实盘把回测里的手续费提高一倍、把滑点加上、把涨跌停无法成交的情况模拟进去再看一遍结果。如果这样还能接受再考虑下一步。希望帮到你。本文还有配套的精品资源点击获取