量化回归测试平台 设计,python量化交易策略回测
欢迎各位!我们为大家带来量化回归测试平台的设计与Python量化交易策略回测的详细解析,请大家耐心阅读并深入了解一下这个平台吧!


写在前面
在本文中, 我们将详细介绍如何利用PyTorch构建深度学习模型, 并将其整合进backtrader回测框架中。随后, 我们将开发一个基于长短期记忆神经网络(LSTM)的模型, 用于股票价格预测c语言和python有什么区别。由于目前backtrader框架尚未提供内置支持深度学习功能, 我们必须先开发并训练测试该模型, 才能完成与backtrader的整合工作以实现有效的回测功能。
1
前言
作为开源Python框架的一个强大工具箱, Backtrader旨在帮助开发者高效地构建,测试并部署复杂的金融量化策略.该框架采用向量化计算引擎,内置了大量实用的数据分析工具,能够便捷地实现回测功能并辅助实施交易策略开发.通过该框架,平台能够自动完成市场数据收集与整理,并支持开发多样化的量化模型.此外, Backtrader还集成了众多预装的技术指标以及模拟交易平台,使用者可以通过其官方网站(https://www.backtrader.com/)深入探索这些功能并获取详尽的技术文档以提升自身能力
2
环境配置
本地环境:
Python 3.7
IDE:Pycharm
库版本:
numpy 1.18.1
pandas 1.0.3
sklearn 0.22.2
matplotlib 3.2.1
torch 1.10.1
tushare 1.2.60
backtrader 1.9.76.123
3
代码实现
总体设计
为了以深度学习模型为基础构建该backtrader回测框架而存在, 我们可以将其划分为若干功能模块
1. 数据获取模块:使用tushare库获取股票历史数据,并对数据进行预处理
深度学习模型模块:基于PyTorch构建一个基础型LSTM网络模型;随后利用滑动窗口的方式对股票历史数据实施训练与检验;随后将训练完成后的模型保存下来;以便后续回测框架能够顺利调用该模型。
量化交易模块:利用Backtrader框架开发一个基于长短期记忆网络模型(LSTM)的简单交易系统。该系统每天收盘时会调用训练好的LSTM模型来判断未来一段时间内的价格走势是否会上涨,在预测结果为上涨时于次日开盘价买入,在预测结果为下跌时于次日开盘价卖出。
数据获取
我们计划开发一个函数用于获取股票历史数据,请在代码中替换tushare API token至YOUR_API_TOKEN位置。随后可以调用get_stock_data函数以获取特定股票的历史数据,并将这些数据保存至本地存储。例如我们可以选择招商银行过去两年的数据作为示例。
def get_stock_data(code, start_date, end_date, token):
ts.set_token(token)
pro = ts.pro_api()
df = pro.daily(ts_code=code, start_date=start_date, end_date=end_date)
df = df.sort_values(by="trade_date", ascending=True) # 对数据进行排序,以便滑动窗口操作
df.set_index("trade_date", inplace=True)
return df
stock_code = "600036.SH"
start_date = "20200101"
end_date = "20220101"
api_token = "YOUR_API_TOKEN"
data = get_stock_data(stock_code, start_date, end_date, api_token)
data.to_csv('./data.csv')
print(data.head())
模型实现
在本研究中采用了基础型的LSTM架构用于验证其预测能力。该模型仅作为基准配置运行而未进行优化调参。为了进一步提升预测效果以下是一些可行的改进方向:首先可考虑对网络架构进行优化以增强其学习能力:适当提升网络深度或扩大隐层神经元数量即可使模型具备更强的表现力;但需注意过多增加可能引发过拟合现象因此建议在训练集与测试集间进行合理权衡;其次可采用正则化技术如L2范数正则化等方法来有效防止过拟合问题;此外还可以考虑引入更多辅助特征以丰富输入信息例如利用最高价最低价成交量等指标来进行预测;最后可通过系统化的参数搜索来确定最佳的超参数配置从而达到最优模型效果。
class SimpleLSTM(nn.Module):
def __init__(self, input_size, hidden_size, num_layers, num_classes, dropout_rate=0.2):
super(SimpleLSTM, self).__init__()
self.hidden_size = hidden_size
self.num_layers = num_layers
self.rnn = nn.RNN(input_size, hidden_size, num_layers, batch_first=True)
self.fc1 = nn.Linear(hidden_size, hidden_size)
self.relu = nn.ReLU()
self.dropout = nn.Dropout(dropout_rate)
self.bn = nn.BatchNorm1d(hidden_size)
self.fc2 = nn.Linear(hidden_size, num_classes)
self.sigmoid = nn.Sigmoid()
def forward(self, x):
h0 = torch.zeros(self.num_layers, x.size(0), self.hidden_size)
out, _ = self.rnn(x, h0)
out = self.fc1(out[:, -1, :])
out = self.relu(out)
out = self.dropout(out)
out = self.bn(out)
out = self.fc2(out)
out = self.sigmoid(out)
return out
随后,在划分数据集的过程中
def create_dataset(stock_data, window_size):
X = []
y = []
scaler = MinMaxScaler()
stock_data_normalized = scaler.fit_transform(stock_data.values.reshape(-1, 1))
for i in range(len(stock_data) - window_size - 2):
X.append(stock_data_normalized[i:i + window_size])
if stock_data.iloc[i + window_size + 2] > stock_data.iloc[i + window_size - 1]:
y.append(1)
else:
y.append(0)
X, y = np.array(X), np.array(y)
X = torch.from_numpy(X).float()
y = torch.from_numpy(y).long()
return X, y, scaler
随后,在将数据划分为训练集和测试集后,并对构建好的模型进行持续优化与验证,并将经过严格训练后的最优模型参数保存下来以便后续在backtrader策略中调用
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
train_data = TensorDataset(X_train, y_train)
train_loader = DataLoader(train_data, batch_size=32, shuffle=True)
model = SimpleLSTM(input_size, hidden_size, num_layers, num_classes)
criterion = nn.CrossEntropyLoss()
optimizer = torch.optim.Adam(model.parameters(), lr=1e-4)
num_epochs = 200
# 训练模型
for epoch in range(num_epochs):
for i, (batch_X, batch_y) in enumerate(train_loader):
outputs = model(batch_X)
loss = criterion(outputs, batch_y)
optimizer.zero_grad()
loss.backward()
optimizer.step()
if (epoch + 1) % 10 == 0:
print(f'Epoch [{epoch + 1}/{num_epochs}], Loss: {loss.item():.4f}')
print('Finished Training')
torch.save(model.state_dict(), 'lstm_model.pth')
model.eval()
with torch.no_grad():
correct = 0
total = 0
test_data = TensorDataset(X_test, y_test)
test_loader = DataLoader(test_data, batch_size=32, shuffle=False)
for batch_X, batch_y in test_loader:
outputs = model(batch_X)
_, predicted = torch.max(outputs.data, 1)
total += batch_y.size(0)
correct += (predicted == batch_y).sum().item()
print(f'Accuracy of the model on the test data: {100 * correct / total}%')
backtrader策略实现
为实现backtrader策略的构建,在Strategy类中导入保存下来的模型文件,并在每次收盘时自动调用该模型进行预测。值得注意的是,在此过程中我们采用了滑动窗口的技术来获取时间序列数据,并引入一个计数器变量用于判断是否积累了足够的历史数据。随后将这些数据经归一化处理后输入至模型中进行训练,并根据模型输出结果制定相应的交易决策规则:如果预测未来价格将上涨且当前未持有头寸,则于下一交易日开盘买入;若预测价格将下跌且当前持有头寸,则于下一交易日开盘卖出。在此设定下,我们的交易策略采用如下方式:如果预测未来会上涨且没有仓位就在下一交易日开盘买入;如果预测未来会下跌且持有仓位就在下一交易日开盘卖出。回测时本金10000元人民币(RMB),每次交易仅进行一手合约操作(lot),手续费设置为万分之五(0.0005%)。
# 构建策略
class LSTMStrategy(bt.Strategy):
def __init__(self):
self.data_close = self.datas[0].close
self.model = SimpleLSTM(input_size, hidden_size, num_layers, num_classes)
self.model.load_state_dict(torch.load('lstm_model.pth'))
self.model.eval()
self.scaler = scaler
self.counter = 1
def next(self):
if self.counter < window_size:
self.counter += 1
return
previous_close_prices = [self.data_close[-i] for i in range(0, window_size)]
X = torch.tensor(previous_close_prices).view(1, window_size, -1).float()
X = self.scaler.transform(X.numpy().reshape(-1, 1)).reshape(1, window_size, -1)
prediction = self.model(torch.tensor(X).float())
max_vals, max_idxs = torch.max(prediction, dim=1)
predicted_prob, predicted_trend = max_vals.item(), max_idxs.item()
if predicted_trend == 1 and not self.position: # 上涨趋势
self.order = self.buy() # 买入股票
elif predicted_trend == 0 and self.position: # 如果预测不是上涨趋势且持有股票,卖出股票
self.order = self.sell()
# Load test data
test_data = pd.read_csv('data.csv', index_col=0, parse_dates=True)
# Create a cerebro entity
cerebro = bt.Cerebro(runonce=False)
# Add data to cerebro
data = bt.feeds.PandasData(
dataname=test_data,
datetime=None,
open=1,
high=2,
low=3,
close=4,
volume=8,
openinterest=-1)
cerebro.adddata(data)
# Add strategy to cerebro
cerebro.addstrategy(LSTMStrategy)
# 本金10000,每次交易100股
cerebro.broker.setcash(10000)
cerebro.addsizer(bt.sizers.FixedSize, stake=100)
# 万五佣金
cerebro.broker.setcommission(commission=0.0005)
# Print out the starting conditions
print('Starting Portfolio Value: %.2f' % cerebro.broker.getvalue())
# Run over everything
cerebro.run()
# Print out the final result
print('Final Portfolio Value: %.2f' % cerebro.broker.getvalue())
# Plot the result
cerebro.plot()
策略运行效果
在训练过程中,在对模型进行训练和测试后,在经过多次迭代过程中,在测试集上达到了66%的分类准确率。
Finished Training
Accuracy of the model on the test data: 66.3157894736842%
随后使用backtrader回测引擎执行回测操作。通过图形化界面观察回测结果可以看到每次交易仅投入一手资金最终累计资金达到11686.92美元在初期阶段出现了多笔亏损记录然而在中间阶段模型成功捕捉到一次显著的上涨行情后续交易中持续实现了盈利收益

4
总结
本文开发了一种交易策略,并利用深度学习模型生成交易信号;此外,在量化回测方面采用了backtrader框架。相比于传统技术分析方法的优势在于其能够更充分地提取历史数据中的信息,并通过深度学习模型丰富了交易策略的内容。同时,在backtrader框架的应用上实现了回测流程的简化以及自动化交易决策功能,并提供了丰富的可视化工具以辅助分析与优化回测结果。值得注意的是,在当前的研究中仅将backtrader框架用于其历史数据的回测工作;因此仍存在诸多改进空间:例如可引入过滤条件以提升筛选效率、进行样本外测试以验证模型稳定性、尝试替代其他类型的模型以及整合更多元化的特征指标等建议。综上所述,在现有研究的基础上本文提供了一种基于深度学习构建量化回测框架的方法;对于熟悉backtrader框架的技术研究者而言这种思路具有一定的参考价值
本文内容仅仅是技术探讨和学习,并不构成任何投资建议。
访问详细代码及数据集以及更多历史文章的数据资源,请加入《人工智能量化实验室》知识星球。

《人工智能量化实验室》知识星球

加入人工智能量化实验室知识星球后,您将获得以下丰富资源:
1)定期更新高质量的前沿研究报告(包括高水平期刊论文及券商金融工程研究报告),方便您随时掌握最新研究动态;
2)享有丰富的Python项目源码库;
3)可下载优质电子书《Python量化交易实战》;
4)获得高质量的量化交易案例及代码分享;
5)参与专业社群交流活动;
6)享受专属答疑服务。
