十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

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

机器学习量化投资入门:LightGBM股价预测与回测实战源码解析

机器学习量化投资入门:LightGBM股价预测与回测实战源码解析 简介这份Python源码面向具备一定编程基础的量化投资学习者与金融数据分析从业者围绕机器学习在金融市场预测中的应用展开帮助读者理解如何从K线价格信息中挖掘规律并构建自动化交易决策流程。资源包共15个文件以5个py脚本为核心涵盖数据获取、特征工程、模型训练与回测等模块另含6张png图表用于展示决策树预测涨幅、最大回撤与K线走势等结果配合txt说明、md文档与gitignore配置整体约737KB结构紧凑便于快速上手。源码采用LightGBM梯度提升决策树模型兼顾训练速度与预测精度适合处理高维金融数据。目前已有221人学习下载读者可借此掌握从数据收集、特征提取到模型测试的完整量化策略实现思路并参考回测与可视化结果评估模型泛化能力为后续策略优化提供可复用的代码框架。1. 从一份能跑起来的机器学习量化源码说起很多人第一次接触量化投资都是从「用机器学习预测股价」这个念头开始的。想法很直接把历史 K 线喂给模型让它学出涨跌规律然后自动给出买卖信号。但真动手时八成会卡在同一个地方——数据怎么对齐、特征怎么构造、模型输出怎么变成可执行的策略这三步任何一步断了代码就只是一堆跑不通的脚本。这份ai_quant_demo就是冲着这个断点来的它把数据获取、特征工程、LightGBM 训练、回测评估串成了一条完整链路目录里有data.py、feature.py、model.py、backtest.py、main.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_codecode, # 股票代码格式如 000001.SZ start_datestart_date, # 起始日期 YYYYMMDD end_dateend_date) # 结束日期 YYYYMMDD df df.sort_values(trade_date) # 按交易日升序后续特征依赖顺序 return df这里三个参数要留意ts_code必须带交易所后缀.SZ/.SH只写六位数字会报错start_date和end_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_size0.2, shuffleFalse) # 时间序列不能随机打乱 model lgb.LGBMClassifier( n_estimators100, # 树的数量 learning_rate0.05, # 学习率 max_depth5, # 树深度控制过拟合 num_leaves31) # 叶子数 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_depth和num_leaves共同控制模型复杂度深度越大越容易记住训练集的噪声。最容易被忽略的是train_test_split里的shuffleFalse——时间序列数据必须按时间顺序切分随机打乱会让未来数据混进训练集这是量化里最经典的血泪坑之一。3. 跑通全流程从环境配置到回测出图3.1 环境准备与依赖安装先把 Python 环境弄干净。建议用虚拟环境避免和系统里其他包的版本打架。# 创建并激活虚拟环境 python -m venv venv source venv/bin/activate # Windows 用 venv\Scripts\activate # 安装依赖 pip install -r requirements.txtrequirements.txt里通常锁定了 tushare、lightgbm、pandas、numpy、matplotlib 这几个包的版本。如果安装 lightgbm 时报编译错误常见原因是缺少 C 编译环境Windows 上装 Visual Studio Build ToolsmacOS 上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.pymain.py会依次调用数据获取、特征构造、模型训练、回测最后把图表输出到img/目录。img/里有几张图值得对照看k_chart.png是原始 K 线柱状图.png可能是特征重要性或收益分布最大回撤.png是回测期间的回撤曲线炒股界面.png是策略信号的可视化。回测部分backtest.py一般会算累计收益、最大回撤、胜率这几个指标。最大回撤是量化里比收益率更重要的风险指标它告诉你策略在最差情况下会亏多少如果回撤超过 30%实盘基本拿不住。3.4 回测结果的正确读法回测跑出来的收益率不能直接信。先看三件事一是回测区间够不够长只跑半年数据的结论没有意义二是交易成本有没有算进去源码里的简单回测可能没扣手续费和滑点实盘会吃掉一部分收益三是有没有未来函数前面提到的shuffleFalse和特征里不能有未来数据这两点必须逐行检查。我见过太多回测年化 50% 的策略一上实盘就亏问题基本都出在这三处。4. 避坑与排查量化原型最容易翻车的地方4.1 未来函数导致回测虚高现象回测收益率高得离谱年化动辄翻倍但逻辑上说不通。原因特征里混入了未来数据或者train_test_split没有按时间切分模型在训练时「偷看」了测试集。解决检查feature.py里所有列凡是用了shift(-n)的只能作为标签不能作为特征确认train_test_split的shuffleFalse回测时严格按时间推进不能用全量数据训练后再回测全量区间。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_depth和num_leaves增大learning_rate配合减少n_estimators用交叉验证而不是单次切分来评估特征数量也要控制不是越多越好无关特征会加剧过拟合。5. 把原型改成自己的策略特征扩展与模型验证跑通默认流程后真正有价值的是把它改成你自己的东西。第一步是扩特征。源码里只用了均线、振幅、量比这几类你可以加 MACD、RSI、布林带宽度甚至把大盘指数收益率作为外部特征拼进来。加特征时记住一个原则每个新特征都要能说出它为什么可能有用说不出来就别加否则只是给过拟合添砖加瓦。第二步是换标签。默认标签是次日涨跌二分类你可以改成预测未来 N 日收益率然后做回归也可以改成三分类涨、平、跌把小幅波动归为「平」减少噪声。标签一变整个评估逻辑都要跟着调分类看准确率和 AUC回归看 IC 和 Rank IC。第三步是验证方法升级。单次train_test_split说服力不够常见做法是滚动窗口验证用前 3 年训练、第 4 年测试然后窗口往后滑一年重复多次看策略在不同年份的表现是否稳定。如果某一年特别好、某一年特别差说明策略对市场环境依赖太强实盘风险大。# 滚动窗口验证示意 def walk_forward(df, train_years3, test_years1): results [] start df[trade_date].min() while True: train_end start pd.DateOffset(yearstrain_years) test_end train_end pd.DateOffset(yearstest_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(years1) # 窗口每次滑动一年 return results这段逻辑的核心是「训练集永远在测试集之前」每次窗口滑动一年模拟真实交易中只能用到历史信息的情形。参数train_years和test_years按你的数据量调整数据少就缩短窗口但测试集至少要有几十个交易日才有统计意义。最后说个我自己的习惯每次改完特征或参数我都会先把回测区间切成三段——训练段、验证段、留出段留出段只在最后看一次中间反复调参只看验证段。这样能避免「调参调到留出集上」的隐性过拟合。从那以后我每次上新策略都强制走一遍滚动验证加留出集确认再小的改动也不跳过。希望这份源码能帮你把第一个机器学习量化原型真正跑起来少走点我当年踩过的弯路。本文还有配套的精品资源点击获取
返回列表