机器学习量化投资入门:LightGBM股价预测与回测实战源码解析
2026/9/23 22:53:38 网站建设 项目流程

简介:这份Python源码面向具备一定编程基础的量化投资学习者与金融数据分析从业者,围绕机器学习在金融市场预测中的应用展开,帮助读者理解如何从K线价格信息中挖掘规律并构建自动化交易决策流程。资源包共15个文件,以5个py脚本为核心,涵盖数据获取、特征工程、模型训练与回测等模块,另含6张png图表用于展示决策树预测涨幅、最大回撤与K线走势等结果,配合txt说明、md文档与gitignore配置,整体约737KB,结构紧凑便于快速上手。源码采用LightGBM梯度提升决策树模型,兼顾训练速度与预测精度,适合处理高维金融数据。目前已有221人学习下载,读者可借此掌握从数据收集、特征提取到模型测试的完整量化策略实现思路,并参考回测与可视化结果评估模型泛化能力,为后续策略优化提供可复用的代码框架。

1. 从一份能跑起来的机器学习量化源码说起

很多人第一次接触量化投资,都是从「用机器学习预测股价」这个念头开始的。想法很直接:把历史 K 线喂给模型,让它学出涨跌规律,然后自动给出买卖信号。但真动手时,八成会卡在同一个地方——数据怎么对齐、特征怎么构造、模型输出怎么变成可执行的策略,这三步任何一步断了,代码就只是一堆跑不通的脚本。这份ai_quant_demo就是冲着这个断点来的:它把数据获取、特征工程、LightGBM 训练、回测评估串成了一条完整链路,目录里有data.pyfeature.pymodel.pybacktest.pymain.py五个核心模块,外加stock_list.txt股票池和requirements.txt依赖清单。适合有 Python 基础、想跑通第一个机器学习量化原型的从业者,也适合拿它当骨架改造成自己策略的人。下面我按实际拆包的顺序,把每个文件干什么、参数怎么设、哪里容易翻车讲清楚。

2. 拆开源码包:五个模块的分工与数据流

2.1 目录结构与模块职责

拿到压缩包解压后,根目录下是这些内容:

文件/目录作用
main.py入口,串联数据、特征、模型、回测
data.py通过 tushare 拉取历史行情
feature.py从 K 线派生技术指标特征
model.pyLightGBM 训练与预测
backtest.py简单回测与绩效统计
stock_list.txt股票池代码列表
requirements.txt依赖版本
img/回测结果图表输出目录

这个划分是典型的「数据-特征-模型-评估」四段式,好处是每一段都能单独替换。比如你想把 LightGBM 换成 XGBoost,只动model.py就行;想换数据源,只改data.py。我一般会先通读main.py,因为它决定了整个调用顺序和参数传递方式,其他文件都是被它调用的。

2.2 数据获取:tushare token 与股票池

data.py依赖 tushare 获取 A 股历史行情。tushare 需要注册后拿到 token,源码里对应的配置在tushare_token.png那张截图里能看到位置。常见做法是把 token 写进环境变量或单独的配置文件,不要硬编码进data.py,否则上传代码时容易泄露。

# data.py 核心逻辑示意 import tushare as ts import pandas as pd def get_stock_data(code, start_date, end_date, token): ts.set_token(token) # 设置 token,建议从环境变量读取 pro = ts.pro_api() df = pro.daily(ts_code=code, # 股票代码,格式如 000001.SZ start_date=start_date, # 起始日期 YYYYMMDD end_date=end_date) # 结束日期 YYYYMMDD df = df.sort_values('trade_date') # 按交易日升序,后续特征依赖顺序 return df

这里三个参数要留意:ts_code必须带交易所后缀(.SZ/.SH),只写六位数字会报错;start_dateend_date格式是YYYYMMDD字符串,不是日期对象;返回的 DataFrame 默认按日期降序,必须sort_values升序,否则后面算均线、算收益率全是反的。stock_list.txt里存的就是一批ts_codemain.py会逐行读取后循环调用。

2.3 特征工程:从 K 线到模型输入

feature.py是整个项目里最值得细看的部分。原始行情只有开高低收和成交量,模型没法直接理解「趋势」,需要派生特征。源码里围绕 K 线构造了若干技术指标,常见的有均线、涨跌幅、振幅、量比这几类。

# feature.py 特征构造示意 import pandas as pd import numpy as np def build_features(df): df = df.copy() df['pct_chg'] = df['close'].pct_change() # 日收益率 df['ma5'] = df['close'].rolling(5).mean() # 5 日均线 df['ma20'] = df['close'].rolling(20).mean() # 20 日均线 df['ma_ratio'] = df['ma5'] / df['ma20'] # 均线比,衡量短期强弱 df['amplitude'] = (df['high'] - df['low']) / df['close'] # 振幅 df['vol_ratio'] = df['vol'] / df['vol'].rolling(5).mean() # 量比 df['label'] = (df['close'].shift(-1) > df['close']).astype(int) # 次日涨跌标签 df = df.dropna() # 去掉滚动窗口产生的空值 return df

逻辑上,前几行是特征,最后一行label是预测目标——用次日收盘价是否高于当日来定义涨跌,这是二分类问题。参数上,rolling(5)rolling(20)的窗口可以改,短窗口对波动更敏感但噪声大,长窗口更平滑但滞后。shift(-1)是把未来一天的价格挪到当前行,构造标签时必须这么做,但要注意:特征里绝对不能包含任何shift(-n)的列,否则就是未来函数,回测收益会虚高到离谱。dropna()会删掉前 20 行(因为 ma20 需要 20 个数据点),这是正常的。

2.4 模型训练:LightGBM 的参数与输出

model.py用 LightGBM 做二分类。LightGBM 是基于梯度提升的决策树算法,训练快、内存占用低,适合这种表格型特征。源码里img/决策树预测股价涨幅.png展示的就是模型输出的预测概率分布。

# model.py 训练与预测示意 import lightgbm as lgb from sklearn.model_selection import train_test_split from sklearn.metrics import accuracy_score def train_model(df, feature_cols): X = df[feature_cols] # 特征列 y = df['label'] # 标签列 X_train, X_test, y_train, y_test = train_test_split( X, y, test_size=0.2, shuffle=False) # 时间序列不能随机打乱 model = lgb.LGBMClassifier( n_estimators=100, # 树的数量 learning_rate=0.05, # 学习率 max_depth=5, # 树深度,控制过拟合 num_leaves=31) # 叶子数 model.fit(X_train, y_train) pred = model.predict(X_test) print('accuracy:', accuracy_score(y_test, pred)) return model

关键参数有三个:n_estimators是树的数量,太小欠拟合、太大过拟合;learning_rate是每棵树的学习步长,通常 0.01 到 0.1 之间;max_depthnum_leaves共同控制模型复杂度,深度越大越容易记住训练集的噪声。最容易被忽略的是train_test_split里的shuffle=False——时间序列数据必须按时间顺序切分,随机打乱会让未来数据混进训练集,这是量化里最经典的血泪坑之一。

3. 跑通全流程:从环境配置到回测出图

3.1 环境准备与依赖安装

先把 Python 环境弄干净。建议用虚拟环境,避免和系统里其他包的版本打架。

# 创建并激活虚拟环境 python -m venv venv source venv/bin/activate # Windows 用 venv\Scripts\activate # 安装依赖 pip install -r requirements.txt

requirements.txt里通常锁定了 tushare、lightgbm、pandas、numpy、matplotlib 这几个包的版本。如果安装 lightgbm 时报编译错误,常见原因是缺少 C++ 编译环境,Windows 上装 Visual Studio Build Tools,macOS 上xcode-select --install一般能解决。装完后用python -c "import lightgbm"验证一下,不报错再往下走。

3.2 配置 token 与股票池

tushare 的 token 需要去官网注册后获取,源码截图tushare_token.png标了填写位置。我一般会新建一个config.py或者直接用环境变量:

# 推荐做法:从环境变量读取,不写死在代码里 import os TOKEN = os.environ.get('TUSHARE_TOKEN')

stock_list.txt里每行一个股票代码,格式要和data.py里的ts_code一致。初次跑建议只留两三只股票,减少数据拉取时间和接口调用次数,跑通后再扩池。

3.3 执行 main.py 与结果解读

配置好后直接运行入口:

python main.py

main.py会依次调用数据获取、特征构造、模型训练、回测,最后把图表输出到img/目录。img/里有几张图值得对照看:k_chart.png是原始 K 线,柱状图.png可能是特征重要性或收益分布,最大回撤.png是回测期间的回撤曲线,炒股界面.png是策略信号的可视化。回测部分backtest.py一般会算累计收益、最大回撤、胜率这几个指标。最大回撤是量化里比收益率更重要的风险指标,它告诉你策略在最差情况下会亏多少,如果回撤超过 30%,实盘基本拿不住。

3.4 回测结果的正确读法

回测跑出来的收益率不能直接信。先看三件事:一是回测区间够不够长,只跑半年数据的结论没有意义;二是交易成本有没有算进去,源码里的简单回测可能没扣手续费和滑点,实盘会吃掉一部分收益;三是有没有未来函数,前面提到的shuffle=False和特征里不能有未来数据,这两点必须逐行检查。我见过太多回测年化 50% 的策略,一上实盘就亏,问题基本都出在这三处。

4. 避坑与排查:量化原型最容易翻车的地方

4.1 未来函数导致回测虚高

现象:回测收益率高得离谱,年化动辄翻倍,但逻辑上说不通。原因:特征里混入了未来数据,或者train_test_split没有按时间切分,模型在训练时「偷看」了测试集。解决:检查feature.py里所有列,凡是用了shift(-n)的只能作为标签,不能作为特征;确认train_test_splitshuffle=False;回测时严格按时间推进,不能用全量数据训练后再回测全量区间。

4.2 tushare 接口调用失败

现象data.py报错,提示 token 无效或接口权限不足。原因:token 没设置、过期,或者当前账号积分不够调用daily接口。解决:确认 token 已正确写入且未过期;tushare 部分接口需要积分,新账号先看官方文档确认权限;拉取频率过高会触发限流,循环拉多只股票时加time.sleep间隔。

4.3 标签定义与特征窗口不匹配

现象:模型准确率一直在 50% 附近,跟随机猜没区别。原因:标签定义的是次日涨跌,但特征窗口太长(比如用了 60 日均线),短期预测和长期特征对不上。解决:标签预测周期和特征窗口要匹配,预测次日就用短窗口特征(5 日、10 日),预测一周就用中窗口;另外检查dropna()后样本量还剩多少,样本太少模型学不到东西。

4.4 回测未扣交易成本

现象:回测收益为正,实盘一跑就亏。原因backtest.py里只算了价格变动,没扣手续费、印花税和滑点。解决:在回测逻辑里加入单边手续费(约万分之三)和印花税(卖出千分之一),滑点按成交价的千分之一到千分之二估算;高频策略里交易成本能吃掉大部分利润,必须算。

4.5 过拟合与参数调优的边界

现象:训练集准确率 80%,测试集只有 52%。原因:模型太复杂,把训练集的噪声也学进去了。解决:降低max_depthnum_leaves,增大learning_rate配合减少n_estimators;用交叉验证而不是单次切分来评估;特征数量也要控制,不是越多越好,无关特征会加剧过拟合。

5. 把原型改成自己的策略:特征扩展与模型验证

跑通默认流程后,真正有价值的是把它改成你自己的东西。第一步是扩特征。源码里只用了均线、振幅、量比这几类,你可以加 MACD、RSI、布林带宽度,甚至把大盘指数收益率作为外部特征拼进来。加特征时记住一个原则:每个新特征都要能说出它为什么可能有用,说不出来就别加,否则只是给过拟合添砖加瓦。

第二步是换标签。默认标签是次日涨跌二分类,你可以改成预测未来 N 日收益率,然后做回归;也可以改成三分类(涨、平、跌),把小幅波动归为「平」,减少噪声。标签一变,整个评估逻辑都要跟着调,分类看准确率和 AUC,回归看 IC 和 Rank IC。

第三步是验证方法升级。单次train_test_split说服力不够,常见做法是滚动窗口验证:用前 3 年训练、第 4 年测试,然后窗口往后滑一年,重复多次,看策略在不同年份的表现是否稳定。如果某一年特别好、某一年特别差,说明策略对市场环境依赖太强,实盘风险大。

# 滚动窗口验证示意 def walk_forward(df, train_years=3, test_years=1): results = [] start = df['trade_date'].min() while True: train_end = start + pd.DateOffset(years=train_years) test_end = train_end + pd.DateOffset(years=test_years) train = df[(df['trade_date'] >= start) & (df['trade_date'] < train_end)] test = df[(df['trade_date'] >= train_end) & (df['trade_date'] < test_end)] if len(test) == 0: break model = train_model(train, feature_cols) results.append(evaluate(model, test)) start = start + pd.DateOffset(years=1) # 窗口每次滑动一年 return results

这段逻辑的核心是「训练集永远在测试集之前」,每次窗口滑动一年,模拟真实交易中只能用到历史信息的情形。参数train_yearstest_years按你的数据量调整,数据少就缩短窗口,但测试集至少要有几十个交易日才有统计意义。

最后说个我自己的习惯:每次改完特征或参数,我都会先把回测区间切成三段——训练段、验证段、留出段,留出段只在最后看一次,中间反复调参只看验证段。这样能避免「调参调到留出集上」的隐性过拟合。从那以后我每次上新策略,都强制走一遍滚动验证加留出集确认,再小的改动也不跳过。希望这份源码能帮你把第一个机器学习量化原型真正跑起来,少走点我当年踩过的弯路。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询