ARTICLE DETAIL

资讯详情

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

基于深度学习的量化投资策略实战:从CSV数据到模拟回测的完整工程拆解

基于深度学习的量化投资策略实战:从CSV数据到模拟回测的完整工程拆解 简介这是一份面向高校学生与量化投资初学者的深度学习实战项目包可作为毕业设计、期末大作业或人工智能课程实践参考帮助读者理解如何将神经网络应用于股票价格预测与交易策略开发。压缩包共46个文件约216KB以23个Python源码为核心辅以xml工程配置、csv策略与行情数据、sqlite与db数据库文件、md说明文档及txt依赖清单覆盖数据读取、模型构建、策略执行与模拟交易等环节。项目围绕数据预处理、RNN/LSTM等模型搭建、训练调优及历史回测评估展开代码按分析、深度学习网络、策略、模拟运行等模块分层组织并配有单元测试与依赖说明便于读者梳理完整工程结构、理解量化策略从数据到回测的实现链路。目前已有133人学习下载适合希望打通深度学习与金融量化交叉知识、积累可运行项目经验的读者参考。1. 从一份 600519 的 CSV 说起这套深度学习量化策略包到底能跑出什么很多人第一次接触量化投资都是从一份贵州茅台的日线 CSV 开始的。你手里这个基于深度学习的量化投资策略.zip本质上就是一条从原始行情到模拟交易信号的完整链路data/600519.SH.CSV是原料process/csv2sqlite.py把 CSV 灌进 SQLiteanalysis/stock.py做指标计算DL/network.py搭深度学习网络strategy/Strategy.py把预测转成买卖动作最后simulate_RUN.py跑一遍模拟。它不是一个能直接下单的实盘系统而是一个结构清晰、可拆可改的毕业设计级工程骨架适合做期末大作业、课程设计或者作为你自己策略原型的起点。如果你正卡在“深度学习怎么和量化投资结合”这个点上这份代码能让你少走一段从零搭架子的路。2. 拆开压缩包先看什么目录结构与模块职责2.1 核心文件清单与调用关系拿到一个陌生项目我习惯先看入口文件和依赖而不是急着跑。这个包里main.py和simulate_RUN.py是两个入口前者偏策略执行后者偏模拟回测。requirements.txt决定了你能不能顺利装环境README.md和Sight.md是作者留下的说明先扫一遍能省很多猜的时间。路径职责是否核心main.py策略主执行入口是simulate_RUN.py模拟交易运行入口是ML.py深度学习模型相关逻辑是DL/network.py网络结构定义是DL/GPU.pyGPU 相关配置视环境analysis/stock.py股票数据读取与指标是analysis/draw.py绘图否process/csv2sqlite.pyCSV 转 SQLite是process/SQLFrame.pySQL 数据帧封装是strategy/Strategy.py策略逻辑是strategy/chost.py策略辅助模块视情况data/600519.SH.CSV原始行情数据是tests/单元测试建议看从调用关系看典型链路是csv2sqlite.py把600519.SH.CSV写入data.sqlite或600519.dbstock.py从库里读数据并算特征network.py定义网络ML.py负责训练和预测Strategy.py根据预测生成信号simulate_RUN.py串起来跑模拟。你改任何一环都要顺着这条链往下检查。2.2 环境准备与依赖安装requirements.txt是这个项目能不能跑起来的第一道门槛。深度学习项目最怕的就是版本冲突尤其是 TensorFlow 和 PyTorch 对 Python 版本、CUDA 版本都很敏感。我一般会先建独立虚拟环境再按文件装依赖。python -m venv venv # Windows 激活 venv\Scripts\activate # Linux / macOS 激活 source venv/bin/activate pip install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple第一段建虚拟环境避免污染全局包第二段激活环境Windows 和 Linux 命令不同第三段用国内镜像装依赖速度会快很多。如果requirements.txt里没有锁死版本号装完最好pip freeze requirements_lock.txt存一份方便复现。提示如果安装过程中报某个包找不到对应版本先看它的版本号是不是写死了。常见做法是把该行改成不指定版本让 pip 自己选兼容版本再观察后续是否报错。2.3 数据从 CSV 到 SQLite 的落库过程这个项目没有直接用 pandas 读 CSV 就完事而是多了一步落库说明作者想让数据查询和复用更方便。process/csv2sqlite.py大概率就是干这件事的。你可以先手动跑一遍确认数据能正确进库。import pandas as pd import sqlite3 # 读取 CSV注意编码和日期列 df pd.read_csv(data/600519.SH.CSV, encodingutf-8) # 日期列转成标准格式方便后续按时间索引 df[date] pd.to_datetime(df[date]) # 写入 SQLite表名用 stock_600519 conn sqlite3.connect(data/600519.db) df.to_sql(stock_600519, conn, if_existsreplace, indexFalse) conn.close() print(rows:, len(df), cols:, list(df.columns))这段代码做了三件事读 CSV、转日期、写库。if_existsreplace表示每次覆盖适合反复调试如果你不想丢历史数据改成append。indexFalse避免把 pandas 索引也写进去。跑完打印行列数能快速判断数据有没有读歪。2.4 用 stock.py 做特征与指标计算analysis/stock.py是数据加工层。量化策略里常见的均线、收益率、波动率通常都在这一层算。你可以先单独调用它看看输出长什么样再决定要不要加自己的因子。import pandas as pd def add_features(df): # 收盘价简单收益率 df[ret] df[close].pct_change() # 5 日和 20 日均线 df[ma5] df[close].rolling(5).mean() df[ma20] df[close].rolling(20).mean() # 20 日滚动波动率 df[vol20] df[ret].rolling(20).std() # 去掉前面因滚动窗口产生的空值 df df.dropna().reset_index(dropTrue) return df if __name__ __main__: raw pd.read_csv(data/600519.SH.CSV) feat add_features(raw) print(feat[[date, close, ret, ma5, ma20, vol20]].tail())pct_change()算日收益率rolling(5).mean()算 5 日均线rolling(20).std()算 20 日波动率。dropna()会删掉前 19 行因为均线还没形成。这一步做完你的特征表就可以喂给网络了。参数上均线窗口和波动率窗口都可以改但要注意改完以后样本量会变训练集划分也要跟着调。3. 深度学习模型怎么接进策略网络定义、训练与预测3.1 DL/network.py 里的网络结构怎么读DL/network.py是模型定义文件。量化时序数据常见的选择是 LSTM 或一维 CNN前者擅长捕捉长依赖后者擅长提取局部形态。你打开文件后先看它继承的是哪个框架的模块再看输入输出维度。import torch import torch.nn as nn class LSTMModel(nn.Module): def __init__(self, input_size5, hidden_size64, num_layers2, output_size1): super().__init__() # batch_firstTrue 表示输入形状为 (batch, seq, feature) self.lstm nn.LSTM(input_size, hidden_size, num_layers, batch_firstTrue) self.fc nn.Linear(hidden_size, output_size) def forward(self, x): # out 形状 (batch, seq, hidden) out, _ self.lstm(x) # 只取最后一个时间步的输出做预测 return self.fc(out[:, -1, :])input_size对应你喂进去的特征数量比如 close、ret、ma5、ma20、vol20 就是 5。hidden_size是隐藏层维度越大拟合能力越强但越容易过拟合。num_layers2表示两层 LSTM。out[:, -1, :]取序列最后一步表示用过去一段窗口预测下一个点。如果你改成预测多步output_size要相应调整。3.2 训练循环与损失函数选择ML.py大概率包含训练逻辑。量化里做回归常用 MSE做涨跌分类常用交叉熵。你要先确认标签是什么再决定损失函数。import torch import torch.nn as nn from torch.utils.data import DataLoader, TensorDataset def train_model(model, X, y, epochs50, lr1e-3, batch_size32): # 转成 tensorfloat32 是深度学习默认精度 X_t torch.tensor(X, dtypetorch.float32) y_t torch.tensor(y, dtypetorch.float32).view(-1, 1) loader DataLoader(TensorDataset(X_t, y_t), batch_sizebatch_size, shuffleTrue) criterion nn.MSELoss() optimizer torch.optim.Adam(model.parameters(), lrlr) for epoch in range(epochs): model.train() total_loss 0.0 for xb, yb in loader: optimizer.zero_grad() pred model(xb) loss criterion(pred, yb) loss.backward() optimizer.step() total_loss loss.item() if (epoch 1) % 10 0: print(fepoch {epoch1}, loss {total_loss/len(loader):.6f}) return modelMSELoss适合预测收益率这类连续值。Adam学习率默认 1e-3比较稳。shuffleTrue打乱样本顺序避免模型记住顺序。每 10 轮打印一次 loss方便观察有没有发散。如果 loss 一直不降先检查输入特征有没有归一化再检查标签有没有对齐。3.3 训练集、验证集、测试集怎么切时序数据不能随机打乱切分否则会用到未来信息这是量化里最经典的翻车点之一。正确做法是按时间顺序切。def time_split(X, y, train_ratio0.7, val_ratio0.15): n len(X) train_end int(n * train_ratio) val_end int(n * (train_ratio val_ratio)) return (X[:train_end], y[:train_end], X[train_end:val_end], y[train_end:val_end], X[val_end:], y[val_end:])train_ratio0.7表示前 70% 做训练中间 15% 做验证最后 15% 做测试。这样切出来的测试集在时间上最靠后更接近真实使用场景。如果你用随机切分模型可能在训练时见过未来数据回测结果会虚高实盘就露馅。3.4 预测结果怎么转成买卖信号模型输出的是数值策略需要的是动作。strategy/Strategy.py负责这一步。常见做法是设定阈值预测收益大于某个值就买小于某个值就卖。def signal_from_pred(pred, buy_th0.005, sell_th-0.005): signals [] for p in pred: if p buy_th: signals.append(1) # 买入 elif p sell_th: signals.append(-1) # 卖出 else: signals.append(0) # 持有 return signalsbuy_th和sell_th是阈值单位是预测收益率。阈值太小吃太多噪声太大错过机会。你可以先用 0.005 跑一遍再根据信号数量和回测结果调整。这一步没有标准答案更多是经验和反复试。4. 模拟回测怎么跑simulate_RUN.py 与策略参数4.1 模拟运行的入口与参数simulate_RUN.py是回测入口。它一般会读数据、加载模型、生成信号、模拟买卖、输出收益曲线。你第一次跑建议先把交易成本设为零确认逻辑通不通再加成本。python simulate_RUN.py --data data/600519.db --model DL/model.pth --cash 100000--data指定数据库--model指定模型权重--cash是初始资金。如果脚本不支持命令行参数就打开文件改默认值。跑完看输出目录有没有收益曲线图或交易记录 CSV。4.2 回测指标怎么看回测不是只看总收益。我一般会同时看年化收益、最大回撤、夏普比率和交易次数。总收益高但回撤大实盘很难拿住交易次数过多成本会吃掉利润。指标含义关注点年化收益折算到一年的收益率是否稳定最大回撤从高点到低点的最大亏损能否承受夏普比率单位风险的超额收益越高越好交易次数买卖总次数是否过于频繁胜率盈利交易占比结合盈亏比看这些指标如果脚本没直接输出你可以从交易记录自己算。关键是别只看一个数就下结论。4.3 策略参数调整的边界strategy/Strategy.py和strategyDic/default.strategy.csv里通常有策略参数。改参数之前先想清楚改的是哪一层是特征窗口、模型超参还是买卖阈值。每次只改一个记录结果否则你分不清是哪个改动起了作用。# 示例把均线窗口从 5/20 改成 10/30 df[ma10] df[close].rolling(10).mean() df[ma30] df[close].rolling(30).mean()窗口变大信号更平滑但更滞后窗口变小反应快但噪声多。没有绝对优劣要结合你的持仓周期。改完记得重新训练模型因为输入特征变了。5. 避坑与排查这份代码最容易翻车的几个地方5.1 数据时间对齐问题现象回测收益异常高曲线几乎只涨不跌。原因特征和标签错位用了未来数据。解决检查shift方向确保预测目标在特征之后。常见做法是标签用close.shift(-1)特征用当前及过去数据。5.2 归一化不一致现象训练 loss 正常预测结果离谱。原因训练集和测试集用了不同的归一化参数。解决归一化参数只在训练集上拟合然后应用到验证集和测试集。不要对全量数据一起归一化。5.3 模型过拟合现象训练集 loss 很低验证集 loss 很高。原因模型太复杂或样本太少。解决减小hidden_size、加 dropout、早停或者增加数据量。量化数据本身噪声大过拟合很常见。5.4 SQLite 路径与权限现象跑csv2sqlite.py报找不到文件或无法写入。原因相对路径基于当前工作目录不是脚本所在目录。解决用os.path.dirname(__file__)拼绝对路径或者确认你在项目根目录执行命令。5.5 GPU 与 CPU 切换现象DL/GPU.py相关代码报 CUDA 不可用。原因机器没有 GPU 或驱动不匹配。解决在代码里加device torch.device(cuda if torch.cuda.is_available() else cpu)把模型和数据都.to(device)。没有 GPU 就用 CPU小数据量也能跑。6. 让这套代码真正为你所用从改一个因子到验证一轮回测这份代码最大的价值不是它自带的策略而是它给了你一条可改的链路。你可以从最简单的改动开始在stock.py里加一个动量因子重新训练跑一遍回测看指标有没有变化。然后换一个网络结构比如把 LSTM 换成一维 CNN再跑一遍。每次只改一个变量记录结果这样你才能知道什么有效。# 加一个 10 日动量因子 df[momentum10] df[close] / df[close].shift(10) - 1 df df.dropna().reset_index(dropTrue)这个因子表示过去 10 个交易日的涨跌幅。加完以后input_size要从 5 改成 6训练脚本也要同步改。跑完对比夏普比率和最大回撤如果变好说明动量有信息如果变差可能是过拟合或者因子冗余。验证一轮回测是否可信我一般会做三件事一是把测试集换成不同时间段看结果是否稳定二是把交易成本加上看利润还剩多少三是把参数微调一下看结果是否剧烈变化。如果一改参数结果就天翻地覆说明策略不稳实盘要谨慎。注意回测好看不等于实盘能赚。这份代码是学习骨架不是印钞机。用它理解流程、练手改代码比直接拿去跑实盘更有价值。从那以后我每次拿到一个新的量化代码包都会先跑通数据链路再单独验证模型输出最后才看回测曲线。顺序反了很容易被漂亮的收益图带偏。希望这份拆解能帮到你少踩几个我踩过的坑。本文还有配套的精品资源点击获取
返回列表