ARTICLE DETAIL

资讯详情

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

PyTorch LSTM选股模型与Backtrader回测系统构建实战

PyTorch LSTM选股模型与Backtrader回测系统构建实战 简介面向有一定Python基础的量化交易开发者这份47页PDF文档系统讲解如何基于PyTorch与Backtrader构建LSTM股票预测回测系统覆盖从数据到策略评估的完整链路。内容涵盖量化交易与回测框架概述、PyTorch和Backtrader核心特性、LSTM模型原理以及数据收集与预处理包括缺失值与异常值处理、Min-Max/Z-score归一化、技术指标与时间序列特征工程等关键环节随后逐步完成PyTorch环境搭建、LSTM模型构建、训练、评估与调优并集成至Backtrader策略引擎实现手续费与滑点设置、回测流程运行、结果可视化及收益率、夏普比率、最大回撤等指标分析。文档还介绍了网格搜索、随机搜索与遗传算法等参数优化方法以及过拟合问题识别与解决方法。资源共1个PDF文件压缩包大小2.06MB支持目录章节跳转与左侧大纲快速定位目前已有142人浏览学习适合希望掌握深度学习量化建模与回测实践、提升策略研发效率的读者。1. 量化回测框架设计为什么PyTorch和Backtrader是LSTM选股系统的最小可行组合做量化交易的人迟早会撞上同一堵墙单看LSTM预测准确率模型漂亮得能写论文一放进历史数据里跑回测就原形毕露。问题往往不在模型而在回测框架和预测管道根本没对齐。PyTorch负责把LSTM训练成“预测器”Backtrader负责把预测结果变成“可执行的交易逻辑”两套系统各有各的时间轴和数据处理习惯硬接在一起就是灾难现场。这篇文章要解决的就是这个对齐问题。我按自己实际做过的方案把整个链路拆开从环境搭建、LSTM训练、预测结果落入Backtrader事件流到参数校准和常见坑的排查方式。适合两种人——已经用PyTorch练过LSTM但不知道怎么接入回测的以及用Backtrader跑过策略但对神经网络预测接入没把握的。读完你会有一条可以直接动手的完整路径而不是一堆孤立的概念。2. 框架选型和环境搭建PyTorch、Backtrader各自的边界在哪2.1 为什么是这个组合而不是纯Backtrader或纯PyTorchBacktrader本身支持通过SignalStrategy或者自定义Indicators做预测但它不是为神经网络设计的。你想在Backtrader内部直接训练LSTM会遇到几个尴尬限制训练过程没法可视化、batch处理不灵活、GPU加速绕远路。反过来纯PyTorch做交易回测更痛苦——你得自己写撮合逻辑、仓位管理、滑点模型Backtrader里一行cerebro.addbroker就解决的事手写至少要几百行。所以正确分工是PyTorch负责任何跟“预测”有关的部分Backtrader负责任何跟“交易”有关的部分。中间通过一个“预测结果导出—回测消费”的接口衔接而不是在Backtrader内部塞PyTorch代码也不是在PyTorch里模拟撮合。这个边界想清楚后面所有代码结构都会顺很多。我见过有人把LSTM的预测函数注册成Backtrader的Indicator思路没问题但实现上坑多——Backtrader的indicator会在每个bar上重新计算LSTM的推理开销和状态管理会让回测慢到一个无法接受的程度。更好做法是离线批量预测把预测结果存成CSV或者parquet回测时当作外部数据读入。2.2 用conda在本地跑通PyTorchBacktrader的最小环境先交代一下我这套方案的基础环境版本Python 3.10PyTorch 2.xBacktrader 1.9.x。版本不一定最新但组合经过验证能少踩很多兼容性坑。创建一个独立环境避免把系统Python搞乱conda create -n qtlstm python3.10 -y conda activate qtlstm pip install torch --index-url https://download.pytorch.org/whl/cpu pip install backtrader pandas numpy matplotlib scikit-learn说明一下参数选择的原因。Python 3.10是当前生态兼容性最稳的版本PyTorch对3.10的wheel支持最完整CPU版本的PyTorch足够跑日线级别的股票预测LSTM参数量小的时候CPU推理速度完全够用没必要一上来就折腾CUDA。如果你手头有NVIDIA显卡并且已经配好驱动把--index-url后面换成cu118或cu121对应链接即可。Backtrader依赖纯Python生态pandas、numpy、matplotlib是跑回测和画图的标配。sklearn用来做数据标准化和评估指标。安装完成后验证一下导入是否正常# check_imports.py import torch import backtrader as bt import pandas as pd import numpy as np print(PyTorch:, torch.__version__) print(Backtrader:, bt.__version__) print(Pandas:, pd.__version__)注意如果backtrader安装后导入报错先检查Python版本是否高于3.11——Backtrader某些版本在3.11和3.12上有兼容性问题这是最常见的翻车点。直接用3.10最省事。上面的验证代码逻辑很简单导入四个核心库并打印版本号。如果走到这里没报错说明环境搭好了下一步可以开始准备数据和训练模型。2.3 数据源选择和预处理的时间对齐问题股票预测最容易被忽视的是数据对齐。tushare、akshare、baostock都能拿到日线数据但它们返回的DataFrame索引格式、停牌处理逻辑、复权方式都不一样。我的习惯是统一做三步标准化处理# prepare_data.py import pandas as pd def load_stock_data(filepath, date_coltrade_date, price_colclose): df pd.read_csv(filepath) df[date_col] pd.to_datetime(df[date_col]) df df.sort_values(date_col).set_index(date_col) # 只保留回测和预测都需要的列减少内存 df df[[price_col, open, high, low, volume]].dropna() return df def align_trading_dates(df, df_pred): # 关键步骤让预测结果和行情数据的交易日索引完全一致 common_idx df.index.intersection(df_pred.index) df df.loc[common_idx] df_pred df_pred.loc[common_idx] return df, df_pred这段代码解决的是两个问题。load_stock_data把原始数据标准化成按日期升序、以日期为索引的DataFrame同时去掉有缺失值的行——股票停牌日通常表现为NaN直接dropna虽然简单粗暴但在回测场景里是合理的因为Backtrader不擅长处理缺失bar。align_trading_dates是预测和回测衔接的命门LSTM预测结果是单独存的交易日可能因为停牌、数据源差异和行情数据对不上必须取交集否则回测时preduction和price对不上位置策略信号会整体错位。3. LSTM股票预测模型从单特征到多特征的训练管线3.1 LSTM输入结构设计滑窗到底该用多少天LSTM做时间序列预测的基础逻辑是把一段连续的历史观测作为窗口滚动预测未来一个或多个时间步。股票日线数据里预测目标是“下一个交易日的收益”或者“未来N日的收益方向”不是直接预测价格。直接预测价格会遇到非平稳性问题——价格本身的绝对值随时间和公司基本面漂移模型学到的规律很快失效。我的默认做法是预测“未来5个交易日的累计收益率方向”二分类。好处有两个一是避免了回归预测中价格尺度漂移的问题二是5日窗口过滤掉了单日噪音信号更符合交易逻辑。滑窗长度lookback是LSTM最重要的超参数取值直接决定模型能看到多长的历史模式# window_dataset.py import numpy as np import torch from torch.utils.data import Dataset class StockWindowDataset(Dataset): def __init__(self, features, targets, lookback30): self.lookback lookback # features: shape [num_samples, num_features] # targets: shape [num_samples, 1] self.x [] self.y [] for i in range(lookback, len(features)): self.x.append(features[i - lookback:i]) self.y.append(targets[i]) self.x torch.tensor(np.array(self.x), dtypetorch.float32) self.y torch.tensor(np.array(self.y), dtypetorch.float32) def __len__(self): return len(self.x) def __getitem__(self, idx): return self.x[idx], self.y[idx]lookback30意味着用过去30个交易日约一个半月的特征序列预测未来5天方向。这个值不是拍脑袋定的——股票技术分析里的常用周期20日、30日、60日对应的就是月线级别和季线级别的交易节奏30日作为起步值既能捕捉中短期动量又不至于让样本数量砍太多。len(features) - lookback就是有效样本数一个3000个交易日的历史数据lookback设30能得到约2970个样本。Dataset接口是PyTorch的标准数据加载方式这里没直接返回整个数组是为了后面能用DataLoader做batch训练。注意特征矩阵的shape是[batch, lookback, num_features]LSTM要求batch维度在最前面。3.2 特征工程收益率、振幅、成交量变化率怎么组合原始价格序列不能直接喂给LSTM。价格绝对值没有跨股票可比性茅台和农业银行的股价差几十倍预测器会按价格高低学出错误权重。我的特征组合是五维标准化特征# feature_engineering.py import numpy as np import pandas as pd def build_features(df): df df.copy() # 核心特征对数收益率比原始价格更平稳 df[log_ret] np.log(df[close] / df[close].shift(1)) # 振幅日内波动程度 df[amplitude] (df[high] - df[low]) / df[close].shift(1) # 成交量变化率放量缩量的相对信号 df[vol_ratio] df[volume] / df[volume].rolling(5).mean() # 价格相对均线位置趋势偏离度 df[ma20_dist] df[close] / df[close].rolling(20).mean() - 1 # 动量5日累计收益 df[momentum_5] df[close].pct_change(5) df df.replace([np.inf, -np.inf], np.nan).dropna() feature_cols [log_ret, amplitude, vol_ratio, ma20_dist, momentum_5] return df[feature_cols].values, df[close].values逐个解释每个特征为什么有用。log_ret是核心中的核心对数收益率的分布比简单收益率更接近正态假设LSTM的内部状态更新对输入尺度更敏感amplitude的用意是捕捉日内波动放大和缩小的状态切换波动率突变往往是趋势拐点的前兆vol_ratio是相对5日均量的放量倍数1以下缩量、1以上放量数值范围永远在0到几之间不需要额外归一化ma20_dist是价格偏离20日均线的程度偏离过大有均值回归倾向这个特征给LSTM提供了反转信号momentum_5是短周期动量用来捕捉延续性。注意所有滚窗口计算的特征天然会引入NaN必须dropna。如果这里不处理后面LSTM的损失函数会计算出NaN梯度训练loss直接变nan然后整个模型就废了。这五个特征组合的核心思想是每个特征分别捕捉价格行为的一个独立维度——收益率水平、波动强度、量能状态、趋势偏离、动量延续。它们之间相关性较低LSTM学习到的隐藏状态能更丰富地表达市场环境。3.3 PyTorch LSTM训练定义模型、损失函数和训练循环模型结构不用太复杂。股票数据本身的信噪比极低过度复杂的网络只会加速过拟合。我的标准结构是单层LSTM隐藏单元32 全连接层输出2分类logits。先定义模型# lstm_model.py import torch.nn as nn class LSTMPredictor(nn.Module): def __init__(self, input_size5, hidden_size32, num_layers1, num_classes2): super(LSTMPredictor, self).__init__() self.lstm nn.LSTM( input_sizeinput_size, hidden_sizehidden_size, num_layersnum_layers, batch_firstTrue ) self.fc nn.Linear(hidden_size, num_classes) def forward(self, x): # x: [batch_size, seq_len, input_size] lstm_out, (h_n, c_n) self.lstm(x) # 取最后一个时间步的隐藏状态 last_hidden h_n[-1] # [batch_size, hidden_size] out self.fc(last_hidden) return outbatch_firstTrue是PyTorch的常见约定让输入张量的shape清晰直观batch维度在第一维。h_n[-1]取最后一层LSTM的最终隐藏状态这比取lstm_out[:, -1, :]更直接效果等价。hidden_size32对单股票日线数据通常够用如果预测的是3000只股票的多股票系统可以提高到64或128先从这个小规模起步看基线效果。然后训练循环。这里有个关键细节时间序列数据不能随机打乱训练集和验证集否则会引入未来信息泄漏。我直接用时间顺序切分——前80%训练后20%验证# train_lstm.py import torch import torch.nn as nn from torch.utils.data import DataLoader def train_model(features, targets, epochs50, batch_size64, lr1e-3): split int(len(features) * 0.8) train_features, val_features features[:split], features[split:] train_targets, val_targets targets[:split], targets[split:] train_dataset StockWindowDataset(train_features, train_targets, lookback30) val_dataset StockWindowDataset(val_features, val_targets, lookback30) train_loader DataLoader(train_dataset, batch_sizebatch_size, shuffleFalse) val_loader DataLoader(val_dataset, batch_sizebatch_size, shuffleFalse) model LSTMPredictor(input_sizefeatures.shape[1]) criterion nn.CrossEntropyLoss() optimizer torch.optim.Adam(model.parameters(), lrlr) for epoch in range(epochs): model.train() total_loss 0 for x_batch, y_batch in train_loader: # y_batch是连续数值二分类需要转成long型类别索引 y_batch y_batch.long().squeeze() optimizer.zero_grad() logits model(x_batch) loss criterion(logits, y_batch) loss.backward() optimizer.step() total_loss loss.item() # 验证集不做梯度更新 if (epoch 1) % 5 0: model.eval() val_loss 0 with torch.no_grad(): for x_batch, y_batch in val_loader: y_batch y_batch.long().squeeze() logits model(x_batch) val_loss criterion(logits, y_batch).item() print(fEpoch {epoch1}, Train Loss: {total_loss/len(train_loader):.4f}, fVal Loss: {val_loss/len(val_loader):.4f}) return modelshuffleFalse在时间序列里是强制要求。CrossEntropyLoss会让模型学出“未来5天上涨还是下跌”的概率分布输出两个类别上涨/下跌。训练轮数50是比较中庸的设定股票数据波动大训练太久会出现典型的训练loss持续下降但验证loss先降后升——那就是过拟合信号需要early stopping或者调低epochs。模型训练完要做两件事一是保存state_dict二是把预测结果导出成回测阶段能直接读的文件。最保险的预测导出格式是CSV日期作为索引预测值列名标准化# predict_and_save.py def predict_and_save(model, features, dates, lookback30, output_pathpredictions.csv): model.eval() all_preds [] with torch.no_grad(): for i in range(lookback, len(features)): window torch.tensor(features[i - lookback:i], dtypetorch.float32).unsqueeze(0) logits model(window) prob_positive torch.softmax(logits, dim1)[0][1].item() all_preds.append(prob_positive) pred_df pd.DataFrame({ date: dates[lookback:], pred_prob_up: all_preds }) pred_df.to_csv(output_path, indexFalse) print(fSaved {len(pred_df)} predictions to {output_path}) return pred_df这段代码的输出是每个交易日一个pred_prob_up值取值0到1表示模型认为“未来5天上涨”的概率。这个值就是后续Backtrader策略的输入信号。lookback的偏移匹配要特别注意预测结果的第一行对应的是原始数据的第lookback1天日期数组必须同步切片否则预测和行情日期全部错位。4. Backtrader回测接入预测信号如何变成交易指令4.1 策略设计预测概率阈值和仓位管理逻辑把预测信号接入Backtrader的策略类核心思路是自定义一个DataSeries存预测概率然后在next里读这个值、决定买卖。最简单的双阈值策略是预测上涨概率高于0.65做多低于0.35平仓。为什么阈值不对称因为做多的判断要够强才进场而离场的条件可以宽松一些——这能减少假信号的交易次数。下面这个策略类可以直接用# bt_strategy.py import backtrader as bt import pandas as pd class LSTMSignalStrategy(bt.Strategy): params dict( buy_threshold0.65, sell_threshold0.35, stake_pct0.95 # 仓位比例 ) def __init__(self): # 绑定预测概率数据通过data1传入的CSV序列 self.pred_signal self.data1.pred_prob_up self.close_price self.data0.close self.order None def next(self): if self.order: return pred_value self.pred_signal[0] # 当前bar的预测概率 if not self.position: if pred_value self.p.buy_threshold: size int((self.broker.getvalue() * self.p.stake_pct) / self.close_price[0]) self.buy(sizesize) else: if pred_value self.p.sell_threshold: self.close()策略逻辑落在一个最简框架里不持仓时预测概率达到买入阈值就满仓买入持仓时预测概率跌破卖出阈值就清仓。size的计算方式是当前总资产乘以仓位比例除以当前价格换成股数取整。这个策略没有设置止损和止盈为了先跑通框架——直接加止损逻辑会让信号系统的行为复杂化排错变难。等基线回测结果出来后再逐步迭代。4.2 Cerebro回测引擎配置滑点、手续费、初始资金Cerebro是Backtrader的中央控制器所有回测参数在这里设置。跟回测结果可信度最相关的三个配置是滑点、手续费、初始资金。滑点用set_slippage_perc设置百分比滑点手续费通过setcommission设置# run_backtest.py import backtrader as bt import pandas as pd def load_data_with_prediction(stock_csv, pred_csv): df_stock pd.read_csv(stock_csv, index_coltrade_date, parse_datesTrue) df_pred pd.read_csv(pred_csv, index_coldate, parse_datesTrue) # 数据和预测对齐这一步至关重要 df_stock, df_pred align_trading_dates(df_stock, df_pred) return df_stock, df_pred df_stock, df_pred load_data_with_prediction(stock_data.csv, predictions.csv) # 数据源1行情数据 data0 bt.feeds.PandasData(datanamedf_stock) # 数据源2预测概率 data1 bt.feeds.PandasData( datanamedf_pred, openinterestNone, highNone, lowNone, openNone, volumeNone ) cerebro bt.Cerebro() cerebro.adddata(data0) cerebro.adddata(data1) # 第二个数据源通过self.data1访问 cerebro.addstrategy(LSTMSignalStrategy) cerebro.broker.setcash(100000) cerebro.broker.set_slippage_perc(0.001) cerebro.broker.setcommission(commission0.0003, stocklikeTrue) results cerebro.run() cerebro.plot(stylecandlestick, volumeFalse)这段代码里最关键的是data1的构造方式。预测CSV里只有日期和pred_prob_up两列但PandasData默认要求OHLCV全部字段必须把用不到的字段显式设为None。adddata(data1)后策略里self.data0指向行情self.data1指向预测两者通过日期索引自动对齐。set_slippage_perc(0.001)表示成交价比当前bar价格偏移0.1%这是A股日线回测的常用保守值。手续费万三0.0003是双边佣金加印花税的大致水平。4.3 多股回测怎么做循环添加data还是用一次性run单股票回测跑通后自然会想扩展到多只股票。Backtrader支持多数据源同时回测常用做法是把多只股票的预测结果合并成一个多index的DataFrame然后循环添加。这里有个隐藏坑Backtrader的next会在所有数据源都有新bar时触发不同股票停牌导致日期不一致时策略的next执行频率会乱。我一般用两种方案之一。方案A每只股票单独跑回测最后汇总绩效指标。方案B多股票数据源统一对齐到共同的交易日然后用self.datas遍历操作。方案A更稳定也更容易排查——股票A的问题不会污染股票B的结果。方案B的代码更长但更接近真实的多股票组合管理场景。# multi_stock_backtest.py for stock_code in stock_list: df_stock load_stock(stock_code) df_pred load_prediction(stock_code) data0 bt.feeds.PandasData(datanamedf_stock) data1 bt.feeds.PandasData(datanamedf_pred, highNone, lowNone, openNone, volumeNone) cerebro bt.Cerebro() cerebro.adddata(data0) cerebro.adddata(data1) cerebro.addstrategy(LSTMSignalStrategy) cerebro.broker.setcash(100000) cerebro.broker.set_slippage_perc(0.001) cerebro.broker.setcommission(commission0.0003, stocklikeTrue) strat cerebro.run()[0] print(f{stock_code}: Final Value {strat.broker.getvalue():.2f})每只股票都从10万初始资金开始独立回测收益曲线互不影响最后汇总结果做平均。这样可以评估模型在不同股票上的泛化能力——如果某只股票特别赚钱而其他股票普遍亏损说明模型学到的是个股特异性模式而非有效规律实盘意义有限。5. 避坑和排查LSTM回测系统的高频翻车点5.1 数据泄漏用全量数据归一化导致回测虚高现象训练时loss下降正常回测结果收益高得离谱年化50%以上但实盘一跑就崩。原因训练前用全量数据的均值和标准差做标准化验证集和测试集的信息混进了训练过程。尤其你用sklearn的StandardScaler先fit整个数据集再transform这等于让模型提前“看到”了未来数据的分布特征——回测当然漂亮因为未来信息已经偷渡进训练了。解决严格按时间切分先切train/val/test再分别做标准化。scaler只能fit训练集val和test用同一个scaler进行transform。# correct_scaling.py from sklearn.preprocessing import StandardScaler def scale_features(features, split_idx): scaler StandardScaler() train_part features[:split_idx] scaler.fit(train_part) # 只用训练集的统计量 features_scaled scaler.transform(features) # 全量都用训练集的scaler return features_scaled注意这个坑是所有时间序列机器学习项目里最隐蔽的因为它不会报错只会让回测失真。唯一排查方式是看训练loss和验证loss是否存在异常大的差距以及回测结果是否远超该策略的合理基准。血泪经验回测结果过分好先怀疑数据泄漏。5.2 日期错位预测值和行情bar差一天导致信号整体偏移现象回测收益曲线和预测准确率看起来完全对不上甚至盈利策略变成亏损或者买卖点明显滞后一天。原因LSTM预测结果CSV里第一行对应的交易日是lookback1天如果你在导出时没把日期数组同步切片预测值整体向前或向后偏移一天。Backtrader按索引对齐数据日期错位造成的后果就是策略在错误的日子看到错误的信号。解决在预测导出阶段打印pred_df.head()和pred_df.tail()跟原始行情数据对比日期确认预测第一行和最后一行对应的具体交易日。另一个验证方法是用df_pred.index[0]和df_stock.index[lookback]做断言# sanity_check.py assert df_pred.index[0] df_stock.index[lookback], \ fDate mismatch: prediction starts at {df_pred.index[0]}, expected {df_stock.index[lookback]}这段断言救了我不止一次。预测导出的偏移逻辑是整个系统里最容易出bug的地方——不是大影响那种明显错误而是导到回测里看起来很合理、实际完全错位。5.3 过拟合和泛化能力不足训练loss低但验证loss高现象训练集准确率85%以上验证集准确率只有52%左右回测绩效严重依赖特定时间段换一只股票就策略失效。原因LSTM参数过多加上股票数据本身信噪比极低模型记住训练数据中的噪音模式而不是可迁移的市场规律。hidden_size设64、lookback设60、训练100轮能轻松在训练集上达到高准确率但这些都不代表真实预测能力。解决先从最简单模型开始hidden_size16或32lookback20epochs30加入正则化手段——dropout层、权重衰减、早停。验证集loss开始上升时立即停止训练。另外要建立多股票交叉验证流程至少5只不同行业的股票都跑一遍结果均值才可信。5.4 Backtrader参数敏感性滑点手续费导致回测结果跳变现象同样的策略代码把slippage_perc从0.001改成0.002回测年化收益从25%变成10%策略排名完全颠倒。原因LSTM信号本身具备一定频率买卖次数多每次交易成本会被复利放大。预测概率在0.6附近徘徊的策略阈值两头的交易次数差异巨大手续费和滑点成了真正的“alpha终结者”。解决回测阶段做参数敏感性分析滑点和手续费各设三档乐观/中性/悲观看策略在六种组合下的收益分布。如果只有乐观档位赚钱中性档位就亏损这个策略不可用。另外降低交易频率是减少参数敏感性的直接手段——提高买入阈值的代价是信号变少但稳定性上升。6. 验证方法进阶用随机基准和滚动窗口检验LSTM是否真有预测力LSTM预测系统的验证不能只看回测收益曲线还要回答一个更尖锐的问题这个模型是不是真的比“无脑持有”或“随机入场”强我用两个工具来回答这个问题。第一个是随机基准检验。把预测概率列随机打乱保持交易策略逻辑不变回测得到的收益分布作为空假设。如果随机信号也能产生20%的年化收益说明你的策略收益来自交易频率和市场波动而不是LSTM的预测能力。做法是把pred_prob_up列做随机shuffle跑二十次回测得到收益分布再看真实信号的回测收益是否落在分布之外# random_benchmark.py import numpy as np def random_benchmark(stock_df, pred_df, strategy_cls, n_shuffles20): results [] for _ in range(n_shuffles): pred_shuffled pred_df.copy() pred_shuffled[pred_prob_up] np.random.permutation(pred_shuffled[pred_prob_up].values) # 用shuffle后的预测结果跑回测记录收益 final_value run_single_backtest(stock_df, pred_shuffled, strategy_cls) results.append(final_value) return results第二个是滚动窗口检验。固定窗口训练比如用过去3年数据训练LSTM预测未来6个月然后窗口整体后移6个月重新训练再预测下一个6个月。这样模拟的是真实环境下的持续学习方式能看出模型在不同市场阶段的稳定性。如果滚动检验中某段时间预测准确率跌破50%说明那段行情特征跟训练期差异太大模型需要更频繁的再训练。我自己迭代这套系统时养成的习惯是所有验证结果都记录成表格包括模型版本、训练日期范围、预测准确率、回测收益、夏普比率、最大回撤。每次调参后跟基线版本对比而不是凭感觉说“好像好了一些”。量化系统是黑匣子没有纪律的记录你会被自己骗过去。这套PyTorch Backtrader的框架还有一个隐藏优势数据下载、模型训练、回测验证、结果记录可以完全脚本化如果我某天早上打开电脑一条命令就能跑完整个流程。做到这个程度你才算是真正拥有了一个可以持续迭代的量化研究基础设施而不是每次改个参数就得手工操作一遍的玩具。希望这些踩坑经验能帮你少走一段弯路。本文还有配套的精品资源点击获取
返回列表