ARTICLE DETAIL

资讯详情

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

Python量化交易股票预测系统:数据源、模型与回测实践

Python量化交易股票预测系统:数据源、模型与回测实践 简介Python量化交易股票预测系统是一套面向金融量化方向的可运行项目源码适合具有初步Python基础、希望系统学习量化建模与回测的开发者。压缩包共36个文件以35个Python脚本为主另含1个Markdown说明文档整体大小仅136KB轻量化便于快速部署脚本按数据处理、模型训练、回测评估等模块组织并内置mylib工具库与ridgecv预测模块结构清晰、复用性强。目前已有2307人学习/下载可作为量化入门与进阶的参考素材。项目覆盖Pandas数据清洗与聚合、Matplotlib可视化、ARIMA及指数平滑等时间序列分析方法同时演示线性回归、决策树、随机森林、支持向量机等模型的训练和调参流程并涉及移动平均、MACD、RSI等技术指标的特征构造以及止损止盈和仓位控制等风险管理环节。通过阅读和运行这些代码可以较为完整地理解股票预测系统的搭建逻辑在此基础上扩展自己的交易策略与回测框架代码模块划分清晰、注释友好适合结合真实行情数据做二次开发与策略迭代。1. python量化交易股票预测系统先想清楚它到底在预测什么把 python量化交易股票预测系统 拆开看它不是一台能自动印钱的黑色盒子而是一条由数据获取、特征工程、模型训练、回测验证串起来的流水线。很多新手把注意力全押在模型上结果回测里翻车最狠的往往不是LSTM选得不够新而是数据泄露和未来函数。量化预测真正要预测的不是明天的收盘价而是未来N日收益的分布这决定了你该加仓还是减仓。这套系统适合有Python基础、想用代码把选股、预测、回测、风控闭环跑通的个人研究者也适合在同花顺Supermind这类平台前做本地预研。跟着做你能搭出一套最小可用的预测系统并且知道每个参数为什么这么设。2. 数据源与特征工程预测系统的天花板在前端不在模型很多人一上来就调模型却不知道股票预测系统里决定效果上限的是数据质量和特征构造。模型再强喂进去的如果是一堆掺了未来数据或者复权方式错乱的K线回测曲线再漂亮也是假的。这一章先把数据源选型和特征工程讲透最后给一段可以直接跑的Python代码。2.1 数据源选型免费接口与商业源的取舍个人做量化预测最常用的是三套免费数据源akshare、tushare和baostock。它们各有各的脾气不能只认准一个。数据源频次优点主要问题akshare日线/分钟线接口全覆盖股票、基金、期货依赖爬虫接口偶尔升级后就拉不到数据tushare日线/分钟线数据规范积分制后有更多字段新用户积分门槛部分接口调用次数受限baostock日线为主稳定、无需注册适合批量拉历史字段相对少分钟线支持一般我一般会把akshare当成主数据源因为它的字段跟同花顺Supermind风格接近方便后续做对照但同时会在本地落一份缓存避免接口抖动导致程序中断。数据落地时要注意一个容易被忽略的点量化交易数据访问和存储安全加密方案设计不能省。拉下来的行情存在CSV里没问题但涉及api token这类敏感信息一律放到环境变量不要写死在代码里也不要用明文配置文件提交到git仓库。复权方式是个大坑。回测股票收益必须用后复权adjusthfq因为前复权会把当前价格作为基准去调整历史价格导致你看到的“历史低价”包含了未来信息计算出来的收益率失真。简单说后复权是从上市首日往前累加分红除权它不会因为新数据进来而改变旧价格适合做收益计算。用前复权画图表没问题但喂给模型训练就危险了。2.2 特征工程不要只堆K线指标“特征工程决定预测上限”这句话在股票预测系统里体现得比建模更明显。最常见的误用是把MA、MACD、RSI全部堆上去然后丢给XGBoost跑跑完发现特征重要性最高的还是那个没除复权坑的原始价格。正确做法是先想清楚预测目标再围绕目标构造能刻画市场状态的因子。我常用的因子分三类动量类、波动类、流动性类。动量类比如过去5日、20日收益率用来捕捉趋势惯性波动类用过去10日收益标准差代表市场风险流动性类用成交量均值的比值反映资金参与度。网上流传的python量化交易策略代码里最常出现的三因子策略示例其实就是估值、市值和动量三类的简化版它的核心思路不是三个指标有多神而是每个因子都对应一个独立的收益驱动逻辑。做特征计算时必须时刻警惕前视偏差。比如说构造“过去5日均值”你用rolling(5).mean()是对的但如果你为了填充缺失值用了整个序列的均值就把未来信息混进去了。我习惯在每一步操作后想一句当前这个值在第T天收盘时能不能算出来能就安全不能就是数据泄漏。2.3 用Python拉取数据并构造标签下面这段代码用akshare拉取平安银行的日线数据构造出三类特征和两个预测标签。代码可以直接跑但要注意安装依赖pip install akshare pandas。import pandas as pd import akshare as ak # 拉取后复权日线数据指定起始时间 df ak.stock_zh_a_hist(symbol000001, perioddaily, adjusthfq, start_date20150101) # akshare返回的列名是中文统一改成英文 df.columns [date, open, close, high, low, volume, amount, amplitude, pct_change, change, turnover] df[date] pd.to_datetime(df[date]) df df.set_index(date).sort_index() # 收益率与动量特征 df[ret_1d] df[close].pct_change() df[momentum_5d] df[close] / df[close].shift(5) - 1 df[momentum_20d] df[close] / df[close].shift(20) - 1 # 波动率与流动性特征 df[volatility_10d] df[ret_1d].rolling(10).std() df[volume_ratio] df[volume] / df[volume].rolling(20).mean() # 标签未来5日收益以及是否上涨分类用 df[label_reg] df[close].shift(-5) / df[close] - 1 df[label_cls] (df[label_reg] 0).astype(int) # 删除没有标签的末尾数据以及pct_change产生的NaN行 df df.dropna(subset[label_reg, ret_1d]).copy() df df.dropna() print(df[[close, ret_1d, momentum_5d, label_reg, label_cls]].tail())这段代码里有两个关键点。第一个是adjusthfq如果你换成“前复权”后面算出来的收益率在分红除权日附近会偏差几个点模型学到的规律就是假的。第二个是shift(-5)它表示用第T天的所有信息去预测第T5天的收益这正是预测任务的本质第T天收盘后只能用到第T天及之前的信息第T1到第T5的数据在真实世界里还没发生。特征窗口的选择也有讲究。5日和20日是短中期的常用配置如果你的调仓周期是10个交易日标签也要跟着改成shift(-10)否则模型预测的收益周期和你的实际交易周期不匹配。2.4 特征版本管理改一处特征记录一次版本回测到一半发现特征计算错了这是量化研究里最耗时的事。我后来养成一个习惯特征矩阵单独存成一份带数据版本号的中间文件文件名里注明生成日期、数据范围、复权方式和特征列表。比如features_000001_hfq_20250101_20251231_v3.csv每次改特征都重新生成版本而不是覆盖原文件。这样当一个版本的模型出了问题你能快速回到上一版特征重新训练而不是从头排查是数据问题还是代码问题。这个习惯在团队协作里尤其重要能省掉大量“你用的特征怎么和我不一样”的争论。3. 股票预测模型怎么选从线性回归到LSTM先定任务再选结构特征准备好了接下来要决定预测模型。但这个决定不应该是“哪个模型火就用哪个”而是先想清楚你的预测任务到底是什么。股票预测系统里任务定义一旦错了后面的模型再复杂都是在放大错误。3.1 预测任务定义回归还是分类标签窗口怎么定先把目标说清楚我们预测的不是股价点位而是未来N日的收益率或者它的方向。这两种表述决定了你用的是回归模型还是分类模型。回归模型输出一个连续值比如“未来5日收益约3.2%”分类模型输出一个概率比如“未来5日上涨的概率是62%”。从落地角度看分类模型更实用因为预测系统最终要转成交易信号你大概率只需要知道方向和对这个方向的信心而不是一个精确到小数点的收益数值。而且金融收益数据分布厚尾直接用回归模型去拟合极端值会把模型带偏分类把标签变成0/1之后极端值只是样本中的一个“1”影响可控。标签窗口N的选择要和你的交易周期一致。短线做T1标签就用shift(-1)周频调仓标签用shift(-5)月频用shift(-20)。这里最容易犯的错是让预测窗口和持仓周期错配你用5日标签训练模型然后按周频调仓结果模型预测的是5日收益但你的止损止盈却在1天后触发信号和动作对不上。3.2 传统机器学习随机森林与XGBoost做因子合成传统树模型在股票预测里仍然是最值得优先尝试的。原因是它不用做复杂的特征归一化对缺失值天然有一定容忍度而且能捕捉因子之间的非线性关系。三因子策略示例里估值因子和动量因子往往相互制约用线性回归去拟合这种交互效应很吃力换成XGBoost则很容易让模型自己发现组合规律。我用XGBoost时几个参数基本固定max_depth3树深度不要超过4因为金融数据的信噪比很低深树轻易过拟合learning_rate0.05配合200到300棵树subsample0.8和colsample_bytree0.8相当于对样本和特征都做了采样增加鲁棒性。如果你用LightGBM注意把min_data_in_leaf调大一点比如50防止学到小样本里的噪声。训练集和验证集的切分必须按时间顺序。普通机器学习的train_test_split(random_state42)在这里是禁区它会随机打乱时序关系让模型“偷看”到未来。我一般用TimeSeriesSplit保证每一折验证集都在训练集之后。3.3 深度学习LSTM与TCN的输入构造和过拟合深度学习在股票预测上能做但没那么玄。LSTM的卖点在于能学习时间依赖比如“连续三天的缩量下跌之后往往反弹”这类模式需要模型记住前几天的状态。用LSTM时输入张量形状是(样本数, 时间步长, 特征数)。时间步长我习惯取40到60个交易日相当于两到三个月的行情长度。构造LSTM输入时有个隐蔽的坑归一化一定要在时间序列内部做不能对整个样本集做全局标准化。假设你用未来区间的均值和标准差去归一化第T天的特征等于把未来信息灌进去了。正确做法是用训练集的统计量或者用滚动z-score。金融序列非平稳滚动归一化通常更稳定但计算量会大一些。过拟合是深度模型的核心问题。除了常规的dropout和early stopping我还会在最后一个全连接层后接一层高斯噪声给输出加一点扰动效果类似正则化。如果你发现验证集AUC比训练集低很多先别调模型结构回去检查是不是标签泄漏八成是特征里混进了当天收盘价而标签也是当天收盘后生成的。3.4 代码用XGBoost完成时间序列交叉验证下面用上一章构造的特征训练一个XGBoost分类模型重点展示时间序列切分和验证指标。import xgboost as xgb from sklearn.model_selection import TimeSeriesSplit from sklearn.metrics import roc_auc_score # 使用2.3节构造好的df选出特征和标签 features [momentum_5d, momentum_20d, volatility_10d, volume_ratio] X df[features].fillna(0) y df[label_cls] # 用时间序列交叉验证评估模型稳定性 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 xgb.XGBClassifier( n_estimators300, max_depth3, learning_rate0.05, subsample0.8, colsample_bytree0.8, eval_metriclogloss, use_label_encoderFalse ) model.fit(X_train, y_train, eval_set[(X_val, y_val)], verboseFalse) auc roc_auc_score(y_val, model.predict_proba(X_val)[:, 1]) auc_scores.append(auc) print(ffold AUC: {auc:.4f}) print(fmean AUC: {sum(auc_scores) / len(auc_scores):.4f})代码里的TimeSeriesSplit(n_splits5)把数据按时间顺序切成5段前4段训练、每段后面的部分验证顺序绝不打乱。评估指标用AUC而不是准确率因为上涨和下跌样本通常不平衡准确率会被多数类主导AUC能更真实地反映模型排序能力。max_depth3是一个很保守的设置。可能你在训练集上看到AUC达到0.75验证集只有0.55此时把max_depth加到5或许验证集能到0.57但实盘会过拟合。宁可验证集低一点也要求稳。参数subsample0.8和colsample_bytree0.8会带来一定方差但通常让验证集结果更可信。4. 回测系统未来函数与幸存者偏差如何毁掉你的收益曲线模型训练完很多人直接看回测曲线发现曲线斜率漂亮得惊人于是开始幻想实盘。但回测框架和规则一旦写得不对收益曲线就是精心粉饰的假象。这一章专注讲清回测里最影响真实性的三个点。4.1 回测框架选型backtrader、vectorbt还是自研个人搭股票预测系统回测框架常见有三条路backtrader、vectorbt、自研脚本。它们不是替代关系场景不同。框架类型优点缺点backtrader事件驱动贴近实盘撮合逻辑支持复杂下单规则运行慢参数优化不友好vectorbt向量化批量参数扫描极快适合回测上千组参数复杂策略表达绕滑点模型较粗糙自研脚本自定义完全控制买卖细节方便集成预测信号需要自己处理撮合和费用坑多我的经验是如果你只是想验证“预测信号 简单调仓”是否有效自研向量化脚本足够了如果需要测复杂订单类型比如止盈止损、条件单直接用backtrader。vectorbt我一般用来做参数搜索搜出候选参数后再回落到自研脚本或backtrader做精细验证。4.2 手续费、滑点与涨跌停小参数让收益腰斩股票交易里佣金通常在万2.5到万3卖出还额外收千1的印花税加上冲击成本单次双边成本约0.15%。对日频调仓策略一年换手100次成本就有15%。如果回测里忽略这部分年化收益30%的策略到实盘可能只剩10%出头。涨跌停是另一个容易漏掉的规则。涨停时买不进跌停时卖不掉。如果你在回测里简单认为信号触发就能以收盘价成交那么在极端行情里你的资金根本没法执行误差会非常大。处理手段是把当日涨跌停的样本排除在执行标的之外或者强制标记为“无法成交”。T1规则也要在代码里体现当日买入的仓位次日才能卖出。4.3 代码向量化回测如何避免未来函数下面这段代码演示一个最小可用的向量化回测重点看信号和收益如何对齐。import numpy as np # 假设df是2.3节的股票数据label_cls是模型预测1表示未来5日看涨 # 信号生成用前一天收盘后的预测作为今天的持仓方向 df[signal] 0 df[signal] df[pred_cls].shift(1) # pred_cls是模型对当日给出的预测 df.loc[df[signal] 1, signal] 1 df[signal] df[signal].fillna(0) # 策略日收益 持仓信号 * 当日收益率 df[strategy_ret] df[signal] * df[ret_1d] # 交易成本只有信号变化时才产生 trade_days (df[signal] ! df[signal].shift(1)).astype(int) cost 0.0003 0.001 # 佣金万3 印花税千1 df[strategy_ret_net] df[strategy_ret] - cost * trade_days # 累计净值 df[equity] (1 df[strategy_ret_net]).cumprod() print(df[[ret_1d, signal, strategy_ret_net, equity]].tail(10))这里最核心的一行是df[pred_cls].shift(1)。模型在第T天收盘后给出预测但这个预测对应的交易信号最早只能在第T1天使用。如果不shift你等于通灵到第二天再下单回测收益会虚高。成本计算里的trade_days通过信号比较产生只有信号从0变1或1变0时才扣一次费用这比每次都扣费更贴近真实。不过要注意计算用的成交价是当日收盘价真实世界里你大概率是用次日开盘价成交所以在精细回测时策略收益应该改成signal * next_open_return也就是用次日开盘价算当天的收益。这一点不修正你的回测系统依然暗藏未来函数。5. 常见问题与避坑从预测到实盘之间踩过的坑从离线预测到实盘资金中间的距离远比想象中远。我把自己在python量化交易股票预测系统上踩过最典型的四个坑拆开写每个都按现象、原因、解决三步走。5.1 回测曲线很漂亮实盘一进场就连续亏损现象回测年化收益做到50%最大回撤只到8%结果实盘第一个月亏了10%后面几个月也回不来。原因回测里用了未来数据。最常见的两个来源一是用收盘价信号当天收盘价成交二是用了前复权数据。前复权会让历史价格随最新价格调整等于模型训练时看过未来的除权信息。另一个原因是幸存者偏差你只看今天还存活的股票退市和长期停牌的股票在回测里消失了收益被系统性高估。解决强制把信号和成交错开一天成交价用次日开盘价而不是当日收盘价股票池不要只放当前存活的标的要从历史上每天的真实成分股里选。还有回测里把换手成本按双边0.2%加进去如果收益曲线还是很漂亮才值得继续看。5.2 训练集AUC很高验证集也正常实盘预测却完全跑偏现象模型离线测试AUC稳定在0.6以上实盘跑出来胜率跟抛硬币差不多。原因特征分布漂移。市场风格切换时原始的动量因子、波动率因子的统计特征会变化模型在旧分布上学的规律在新分布上失效。比如2021年的核心资产行情和2023年的小盘行情模型偏好完全相反。解决做滚动重新训练而不是一次性训练。每周或每月把最新数据追加到训练集重新训练模型剔除过期样本。同时监控关键特征的均值和标准差如果新数据的特征均值偏离训练集超过两倍标准差就该触发重新训练或暂停信号。最朴素的做法是设置特征漂移报警漂移严重时直接让系统空仓。5.3 数据源接口突然挂掉预测系统变成黑匣子现象某天开盘前发现akshare接口升级行情拉不到程序报错退出当天预测信号全部缺失。原因免费数据源依赖爬虫接口改版或频率限制都是不可控的。我们把程序写得太“脆”没有缓存和重试机制接口一挂整个系统停摆。解决建立本地数据仓库每天收盘后把行情落盘到SQLite或CSV程序启动时先读本地数据再尝试增量更新。拉数据封装成独立函数带重试指数退避连续失败5次就发送告警但不退出当天用缓存数据跑预测。这只是工程层面的修复但能避免信号中断带来的心理焦虑和交易漏单。5.4 资金管理没建模收益率数字失真现象策略每次全仓买入某个月亏损40%平均年化收益看着还行但账户净值已经腰斩。原因只关注单笔预测胜率忽略连续亏损后的仓位控制。这种策略的算术平均收益遇到回撤就失真复利后净值可能为负。很多量化新手把资金管理当成头寸计算其实它应该和预测信号一起被回测。解决用固定分数资金管理。简单做法是每次开仓只用总资金的20%到30%亏损时仓位比例不变但不能加仓。回测里同时输出年化收益、最大回撤和夏普比率不要只看收益。如果最大回撤超过20%就要降低仓位再回测一次。资金管理无法改变单笔胜率但决定了你能否活过连续亏损阶段。6. 进阶技巧滚动训练与弱信号集成给预测系统加一道保险当基础版预测系统能稳定跑过回测后我建议把重心放在两件事上让模型跟上市场以及让多个模型的信号互相约束。6.1 滚动重新训练给模型装上“后悔药”一次性训练模型最大的问题是时间衰减。半年前的样本对明天的行情可能已经没有意义。我的节奏是每个交易日收盘后取出最近250个交易日的数据重新训练一次模型同时按指数衰减给样本加权越近的样本权重越高。这样做一天训练一次听着重但XGBoost在几千行数据上训练只要几十秒完全来得及。6.2 多个模型投票而不是只看一个信号另一个收益在于把树模型、线性模型、LSTM的输出做平均。每个模型在不同行情里各有短板XGBoost对趋势敏感LSTM对短期反转敏感两者平均后通常比任何单一模型更稳。你可以把两个模型的预测概率直接求平均超过0.55就买入低于0.45就空仓中间不动。这个小约束能过滤掉不少模棱两可的信号。我的习惯是每周末复盘一次本周的模型预测和实际走势把预测置信度高但结果错误的样本挑出来看特征分布是否异常。用这种笨办法我比每天都写“策略稳定运行”的日志收获更多。量化预测这条路没有捷径只有不断修正自己的系统边界才敢把更多资金放进去。希望这篇 python量化交易股票预测系统 的落地笔记能帮你少踩几个坑搭出一套自己敢实盘验证的预测系统。本文还有配套的精品资源点击获取
返回列表