【python量化】基于backtrader的深度学习模型量化回测框架

2023-05-16

ef62b04b52e268f4e43005fe72c1936f.png

写在前面

在本文中,我们将介绍使用PyTorch构建一个深度学习模型,并将其集成到backtrader回测框架中。具体地,我们将使用PyTorch来实现一个长短期记忆神经网络(LSTM)模型,并将其应用于股票价格预测。由于backtrader目前没有原生支持深度学习的模块,因此我们需要自己先实现一个深度学习模型,对其先进行训练与测试,然后将保存的模型与backtrader集成,以便进行回测。

1

前言

Backtrader是一个开源的Python框架,用于快速设计、测试和部署交易策略。它是基于向量化的计算方法,提供了丰富的工具和数据结构,可以方便地进行回测和交易策略的开发。使用Backtrader,可以轻松地获取、处理和分析金融市场数据,编写和优化交易策略,并进行可视化和回测。Backtrader提供了许多内置的交易指标和模拟交易器,可以帮助快速测试和评估不同的策略。如果想进一步了解Backtrader可以通过其官方网站(https://www.backtrader.com/),获取Backtrader的api文档进行学习。

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库获取股票历史数据,并对数据进行预处理

2. 深度学习模型模块:使用PyTorch创建一个基本的LSTM模型,通过滑动窗口的形式对股票历史数据进行训练以及测试,然后将训练好的模型进行保存,以便于回测框架的调用。

3. 量化策略模块:基于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模型进行测试,模型也没有进行进一步的调优,为了使模型具有更好的预测效果,以下是一些可能提高LSTM模型效果的方法:更改网络结构:增加层数或者增加隐藏单元数可以提高LSTM模型的表达能力。但是,太多的层数或者隐藏单元数也可能导致过拟合,所以需要在训练集和测试集上做出合理的选择。加入正则化:LSTM模型也可以使用L2正则化等方法来避免过拟合。加入更多的特征:除了开盘价之外,也可以考虑加入其他的特征,例如最高价、最低价、成交量等,以提高模型的表达能力。调整超参数:可以通过网格搜索等方法来寻找最佳的超参数组合,例如学习率、batch size、滑动窗口大小等。用到的LSTM模型代码如下:

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中加载保存的模型,然后在next中每次收盘时对模型进行调用。需要注意的是这里通过滑动窗口的形式进行预测,所以定义了一个counter变量用来计算是否收集到了足够的数据。之后将窗口的数据进行归一化输入模型,并根据模型的预测结果来决定下一个交易的交易行为。这里的交易规则简单的定为,如果预测未来会上涨且没有仓位就在下一交易日开盘买入,如果预测未来会下跌且持有仓位就在下一交易日开盘卖出。回测时本金10000,每次交易只进行一手,佣金设置为万五。

# 构建策略
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()

策略运行效果

首先,对模型进行训练跟测试,经过多个epoch的迭代,训练的模型在测试集实现了66%的分类准确性。

Finished Training
Accuracy of the model on the test data: 66.3157894736842%

之后调用backtrader回测引擎进行回测。回测结果的可视化如下图所示,可以看出每次交易一手,回测结束后的资金是11686.92,前期有多次亏损,中间模型捕捉到了一次大的上涨趋势,后面也是多次正的收益。

631a32584265cdca771370f9d8f637f8.png

4

总结

本文构建的交易策略使用了深度学习模型来构建交易信号,并通过backtrader框架实现量化回测。相比传统技术分析方法,使用深度学习模型可以更好地利用历史数据的信息,丰富交易策略。同时,使用backtrader框架可以简化回测的流程,自动化交易决策,并且提供丰富的可视化工具,方便用户进行回测结果的分析和优化。这个框架只是简单将backtrader框架用于深度学习模型的历史回测,所以还有很多可以改进的地方,例如加入过滤条件,进行样本外测试,更换其他模型,引入更多特征等。总之,本文基于backtrader提供了一种基于深度学习构建回测框架的思路,感兴趣的读者可以基于此框架,对更多深度学习、机器学习模型进行测试。

本文内容仅仅是技术探讨和学习,并不构成任何投资建议。

获取完整代码与数据以及其他历史文章完整源码与数据可加入《人工智能量化实验室》知识星球。

cccf34326660650e715bb0636fcaac66.png

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

add0b3747d02641862ae90d8f88af7af.png

加入人工智能量化实验室知识星球,您可以获得:(1)定期推送最新人工智能量化应用相关的研究成果,包括高水平期刊论文以及券商优质金融工程研究报告,便于您随时随地了解最新前沿知识;(2)公众号历史文章Python项目完整源码;(3)优质Python、机器学习、量化交易相关电子书PDF;(4)优质量化交易资料、项目代码分享;(5)跟星友一起交流,结交志同道合朋友。(6)向博主发起提问,答疑解惑。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

【python量化】基于backtrader的深度学习模型量化回测框架 的相关文章

随机推荐

  • stm32的复位电路问题

    现在比较流行的复位方式是这样的 xff1a 但我们都知道对于结构紧凑型硬件来说 xff0c 多一个电阻都是没必要的 在没有手动复位需求的场合 xff0c 能不能删掉按键与R24 xff0c 仅保留104电容 xff1f 通过阅读stm32
  • 外设驱动库开发笔记21:BME680环境传感器驱动

    环境传感器是一类我们很常用的传感器 它可以方便我们获取压力 温度 湿度以及空气质量等数据 在这一篇中 xff0c 我们将分析 BME680 环境传感器的功能 xff0c 并设计和实现 BME680 环境传感器的驱动 1 功能概述 BME68
  • 外设驱动库开发笔记45:MS4515DO压力传感器驱动

    很多时候我们需要检测流量和压力这些参数 xff0c 比如我们要检测大气压 xff0c 或者通过测量差压来获得输送流体的流量等 xff0c 都需要用到压力传感器 这一篇我们就来讨论MS4515DO压力传感器的数据获取 1 功能概述 MS451
  • 一个好看的CSS样式表格

    一个好看的CSS样式表格 自动换整行颜色的CSS样式表格 xff08 需要用到JS xff09 自动换整行颜色的CSS样式表格源代码 自动换整行颜色的CSS样式表格 xff08 需要用到JS xff09 这个CSS表格会自动切换每一行的颜色
  • docker删除镜像

    docker要删除镜像 xff0c 先要删除依赖它的容器 1 删除容器 docker ps 查看正在运行的容器 docker ps a 查看所有容器 docker rm container id 删除容器 2 删除镜像 docker ima
  • FreeRTOS如何结束和重新启动调度程序

    大多数主机或桌面系统 xff08 比如Linux xff0c Mac或Windows xff09 都有一个正常的用例 xff0c 你可以在早上启动操作系统 xff0c 然后在晚上关闭它 xff0c 然后你就离开机器 嵌入式系统是不同的 xf
  • [显存被占满,程序无法运行问题]ResourceExhaustedError (see above for traceback): OOM when allocating tensor

    最近在实验室的服务器上跑tensorflow程序 xff0c 一直都没有报错 xff0c 但是今天却突然报错 xff0c 而且出错提示显示的内容从未见到过 xff0c 错误提示如下 xff1a 错误提示资源耗尽 xff0c 无法分配tens
  • 解读神经网络十大误解,再也不会弄错它的工作原理(转载自机器之心)

    神经网络是机器学习算法中最流行和最强大的一类 在计量金融中 xff0c 神经网络常被用于时间序列预测 构建专用指标 算法交易 证券分类和信用风险建模 它们也被用于构建随机过程模型和价格衍生品 尽管神经网络有这些用处 xff0c 但它们却往往
  • 树莓派 Raspberry Pi VNC屏幕无法显示、软键盘、摄像头实时图传、固定IP等环境配置

    目录 1 VNC屏幕无法显示 2 树莓派软键盘安装 3 摄像头实时图传配置 xff0c 可用于图像监控系统 4 安装VIM与固定IP 1 VNC屏幕无法显示 在树莓派终端 xff0c 输入 sudo raspi config 选择接口配置
  • 在Jetson上配置RealSense相机驱动

    1 下载源码 https github com IntelRealSense librealsense span class token builtin class name cd span librealsense scripts set
  • aruco marker使用笔记

    在英伟达Jetson Xaiver开发板上配置 SDK环境 opencv 4 1 1 CUDA 10 2 1 git clone https github com pal robotics aruco ros 2 复制到catkin ws
  • catkin_make命令

    catkin make是在catkin工作区中构建代码的便捷工具 catkin make遵循catkin工作区的标准布局 xff0c 如REP 128中所述 用法 假设您的catkin工作区位于 catkin ws中 xff0c 则应始终在
  • docker容器中运行界面程序

    Docker比较常用的场景是 运行无界面的后台服务 或者 运行Web服务 不过有时出于个人的喜好或特定的需求 xff0c 我们会希望在Docker中运行带图形界面的应用程序 将容器中的图形界面展示到外部的一般性思路 xff1a 目前Unix
  • linux录屏

    Linux下好用的录屏软件是kazam录屏后视频处理软件kdenlive根据剪辑好的视频撰写解说词 xff0c 使用讯飞配音app将解说词文字转换为语音mp3将语音与视频通过kdenlive软件合成在一起 xff0c 完美的演示视频诞生了
  • 【python】conda和pip安装库之间的区别

    conda 首先 xff0c conda是一个通用的包管理器 xff0c 意思是什么语言的包都可以用其进行管理 xff0c 自然也就包括Python了 在安装Anaconda或者Miniconda时 xff0c 会对conda进行一同安装
  • OpenHarmony-Overview_zh

    OpenHarmony开源项目 项目介绍 OpenHarmony是开放原子开源基金会 xff08 OpenAtom Foundation xff09 旗下开源项目 xff0c 定位是一款面向全场景的开源分布式操作系统 OpenHarmony
  • 【python量化】用时间卷积神经网络(TCN)进行股价预测

    写在前面 下面这篇文章首先主要简单介绍了目前较为先进的时间序列预测方法 时间卷积神经网络 xff08 TCN xff09 的基本原理 xff0c 然后基于TCN的开源代码 xff0c 手把手教你如何通过时间卷积神经网络来进行股价预测 xff
  • 【python量化】将Transformer模型用于股票价格预测

    写在前面 下面的这篇文章主要教大家如何搭建一个基于Transformer的简单预测模型 xff0c 并将其用于股票价格预测当中 原代码在文末进行获取 1 Transformer模型 Transformer 是 Google 的团队在 201
  • 解读:基于GCN的股票预测模型

    前言 xff1a 自ICLR2017首次提出图卷积神经网络 xff08 GCN xff09 的概念 xff0c 该模型在节点分类 边预测等任务上表现出了出色的性能 在传统因子选股模型中 xff0c 常常将股票视为独立的个体 xff0c 但事
  • 【python量化】基于backtrader的深度学习模型量化回测框架

    写在前面 在本文中 xff0c 我们将介绍使用PyTorch构建一个深度学习模型 xff0c 并将其集成到backtrader回测框架中 具体地 xff0c 我们将使用PyTorch来实现一个长短期记忆神经网络 xff08 LSTM xff