首页 > 其他分享 >Backtrader 数据篇

Backtrader 数据篇

时间:2022-10-05 14:55:41浏览次数:46  
标签:Backtrader self lines datetime print date close 数据

Backtrader 数据篇

上一篇已经学习了整个框架的大概划分模块,对于 Backtrader 这框架有了一个大概的认识,这篇将学习这框架基石--数据流程。

下面将会一一解答关于这框架 数据方面的疑问
怎么将数据填充到框架种?
数据组织形式是怎么样?
怎么访问数据?
在回测的过程种,数据流是以怎么形式传递?
怎么扩展其他回测指标?

数据填充

在简介篇,已经知道所有的模块有大脑统一控制管理,数据模块也不例外,所以首先要实例化 Cerebro ,然后往这 Cerebro 塞数据,再统一调度管理。

下面数据是以 dataframe 数据格式为例的介绍,当然 backtrader 也支持其他数据规范的格式,都差不多。

backtrader 把规范的数据包装成了 Data Feeds ,其实就是一个回测数据集合管理类。数据可以添加一个或者多个股票数据。

如何填充数据?

只需要指定数据源,回测时间段,即可添加多个股票数据源。

参数描述
dataname 数据源
fromdate 回测开始时间
todate 回测结束时间

示例代码


# 股票查询开始和结束时间
start_query = '2022-01-01'
end_query = '2022-09-01'
# 回测开始和结束时间
start_date = datetime.datetime(2022, 7, 10)
end_date = datetime.datetime(2022, 8, 10)
cerebro = bt.Cerebro()
# 添加几个股票数据
codes = [
    '300015',
    '300347',
    '300760',
    '603127',
    '600438'
]
# 添加多个股票回测数据
for code in codes:
    data = sdb.stock_daily(code, start_query, end_query)
    data.index.names = ['datetime']
    date_feed = bt.feeds.PandasData(dataname=data, fromdate=start_date, todate=end_date)
    cerebro.adddata(date_feed, name=code)
    print('添加股票数据:code: %s' % code)

注意:查询的数据时间段与回测时间段是分开的,最终数据流是以回测时间段测试数据。

参数 name 是这张表的表名。 self.datas[0]._name 可以打印表名。

存储方式

把每个股票数据看作为一张表,其实就是一张指标维度和时间维度的表,self.datas 就是集合了多个股票的数据集,形成了一个三维数据源,分别是: 数据表维度、时间维度、指标维度。

如上图所示,Data Feeds 种的 self.datas 数据类型是 list. 每个元素是一张包含时间维度和指标维度的股票数据表。

数据表维度

该维度其实就是 list 集合,集合了所有添加进来了股票数据,每个股票数据都有时间维度和指标维度构成的数据表。
self.datas[N]

指标维度

该维度是回测时使用的指标,除了常用指标还可以自定义指标。
self.datas[N].lines.xxx[M]

参数

字段类型描述
datetime float 日期,如果打印日期,
用datetime.date[0]
open float 开盘价
high float 最高价
low float 最低价
close float 收盘价
volume float 成交量
openinterest float 持仓量,一般没使用
其他扩展指标 其他 自定义或扩展指标,列如 pe 、pb

所有的指标

self.data.lines.getlinealiases()

控制台
>> lines ('close', 'low', 'high', 'open', 'volume', 'openinterest', 'datetime')

时间维度

时间维度其实是回测时间段,fromdate ~ todate 之间。
self.data[N].lines.datetime.date(M)

数据索引

self.datas 数据类型是 list

  1. 下标索引:self.datas[N],其中 N 为 0 到 N-1 时,是正向,N 为 -1 到 -N 时为反向
  2. 缩写索引,self.dataN ,注意不是 datas 。N 为 0 到 N-1。
  3. 表名索引,self.getdatabyname('name'),其中 name 为导入数据时 adddata(date_feed, name=code) 时设置的表名。
  4. 第一个数据集索引,self.datas[0] 等价 self.data0 等价 self.data

注意:self.datas 和 self.data 的区别,self.datas 是数据集合 list. self.data 是第 0 个数据。self.dataN 的访问是没有 s 的。

self.datas[N].lines

索引方式
日期:self.datas[N].lines.datetime.date(N) 其他:self.datas[N].lines.其他字段名(open、high、low、close、volume)[N]

注意:datetime 是以 float 数据类型存储,访问是需要借助 xxx.date(N) 函数进行转换。

示例

# 访问第一个数据表的 close 指标的索引 0
self.data[0].lines.close[0]

切片方式

self.data1.lines.close.get(ago=N, size=M))
参数描述
ago 索引开始位置
size 切片大小

返回值:array 数组 [close[N-(M-1)],...,close[N-1],close[N]]
如果 N - (M - 1) <1,返回空数组 []。
列如:N = 3 ,M = 4,返回 [].

策略中的数据流

回测长度:N = self.data.buflen()

索引下标 0 的含义

索引下标 0 在 init() 函数和 next() 函数是不一样的,在 init() 函数中索引 0 是代表回测时间 todate ,在 next() 函数中 索引 0 是代表当前回测的时间。

init()函数中的数据流

在 init() 函数中,索引 0 是 todate ,索引 1 是 fromdate. 支持 正向和反向访问的两种方式。

  • 正向索引的索引下标为 1、2 ... N
  • 反向索引下标为 0 、-1、-2 ... -(N-1).

其中,对应下标值是相同

正向索引反向索引
0 N
1 -(N-1)
2 -(N-2)
... ...
N-1 -1
N 0

next()函数中的数据流

在 next() 函数中,索引 0 永远是当前的时间节点,索引 0 随着以时间维度的循环,不停的移动。backtrader 是已经回测过的了,forward 是还没有回测到的。

自定义读取数据

如果你觉得每次都要设置这么多参数来告知指标位置很麻烦,那你也可以重新自定义数据读取函数,自定义的方式就是继承数据加载类 GenericCSVData、PandasData 再构建一个新的类,然后在新的类里统一设置参数:

class My_PandasData(bt.feeds.PandasData):
    params = (
        ('fromdate', datetime.datetime(2019, 1, 2)),
        ('todate', datetime.datetime(2021, 1, 28)),
        ('nullvalue', 0.0),
        ('dtformat', ('%Y-%m-%d')),
        ('datetime', 0),
        ('time', -1),
        ('high', 3),
        ('low', 4),
        ('open', 2),
        ('close', 5),
        ('volume', 6),
        ('openinterest', -1)
    )

新增指标

backtrader 除了提供基本的指标外('close', 'low', 'high', 'open', 'volume', 'openinterest', 'datetime'),还提供给用户自定义扩展。例如:macd,pe,pb等等指标。

如何扩展?

  1. 继承 bt.feeds.PandasData 类,定义新指标。
  2. 数据源扩展新指标对应的列,并初始化新指标值。

示例

# 继承
class PandasData_more(bt.feeds.PandasData):
    lines = ('pe', 'pb',)  # 要添加的线
    # 设置 line 在数据源上的列位置
    params = (
        ('pe', -1),
        ('pb', -1),
    )

# 数据源新增列
# 股票查询开始和结束时间
start_query = '2022-01-01'
end_query = '2022-09-01'
# 回测开始和结束时间
start_date = datetime.datetime(2022, 7, 11)
end_date = datetime.datetime(2022, 8, 10)
cerebro = bt.Cerebro()
# 添加几个股票数据
codes = [
    '300015',
    '300347',
    '300760',
    '603127',
    '600438'
]
# 添加多个股票回测数据
for code in codes:
    data = sdb.stock_daily(code, start_query, end_query)
    data.index.names = ['datetime']
    # 新增指标列
    data['pe'] = 3
    data['pb'] = 4
    date_feed = PandasData_more(dataname=data, fromdate=start_date, todate=end_date)
    cerebro.adddata(date_feed, name=code)
    print('添加股票数据:code: %s' % code)

cerebro.addstrategy(TestStrategy)
cerebro.run()

常用函数手册

函数描述
self.data.buflen() 回测总长度
len(self.data) 已经处理的数据位置
self.data.lines.getlinealiases() 指标列表
bt.Strategy.init() 一次调用,策略初始化函数
计算指标值,买卖信号等耗时操作
bt.Strategy.next() 多次调用,策略回测调用函数
循环所有的回测时间段
self.datas[N].lines.datetime.date(N) 日期索引
self.datas[N].lines.close.date(N) 指标close索引
self.getdatabyname('name') 表名索引,表名建议以code命名
self.dataT.lines.close.get(ago=N, size=M)) 切片函数
bt.num2date() 时间 datatime 格式将其转为“xxxx-xx-xx xx:xx:xx”这种形式

测试示例

import datetime

import backtrader as bt

import stock_db as sdb


class PandasData_more(bt.feeds.PandasData):
    lines = ('pe', 'pb',)  # 要添加的线
    # 设置 line 在数据源上的列位置
    params = (
        ('pe', -1),
        ('pb', -1),
    )


class My_PandasData(bt.feeds.PandasData):
    params = (
        ('fromdate', datetime.datetime(2019, 1, 2)),
        ('todate', datetime.datetime(2021, 1, 28)),
        ('nullvalue', 0.0),
        ('dtformat', ('%Y-%m-%d')),
        ('datetime', 0),
        ('time', -1),
        ('high', 3),
        ('low', 4),
        ('open', 2),
        ('close', 5),
        ('volume', 6),
        ('openinterest', -1)
    )


class TestStrategy(bt.Strategy):
    # 可选,设置回测的可变参数:如移动均线的周期
    # params = (
    #     (..., ...),  # 最后一个“,”最好别删!
    # )

    def log(self, txt, dt=None):
        """
        可选,构建策略打印日志的函数:可用于打印订单记录或交易记录等
        :param txt:
        :param dt:
        :return:
        """
        dt = dt or self.datas[0].datetime.date(0)
        print('%s,%s' % (dt.isoformat(), txt))

    def __init__(self):
        """
        必选,初始化属性、计算指标等
        """

        print(type(self.datas[0].lines.datetime[0]))
        print(type(self.datas[0].lines.volume[0]))
        self.count = 0
        print("------------- init 中的索引位置-------------")
        print('lines', self.data1.lines.getlinealiases())
        print('datas type', type(self.datas))
        print("0 索引:", 'datetime', self.datas[1].lines.datetime.date(0), 'close', self.data1.lines.close[0])
        print('-1 索引:', 'datetime', self.data1.lines.datetime.date(-1), 'close', self.data1.lines.close[-1])
        print('-2 索引:', 'datetime', self.data1.lines.datetime.date(-2), 'close', self.data1.lines.close[-2])
        print('1 索引: ', 'datetime', self.data1.lines.datetime.date(1), 'close', self.data1.lines.close[1])
        print('2 索引: ', 'datetime', self.data1.lines.datetime.date(2), 'close', self.data1.lines.close[2])
        print('从 0 开始往前取3天的收盘价:', self.data1.lines.close.get(ago=0, size=3))
        print("从-1开始往前取3天的收盘价:", self.data1.lines.close.get(ago=3, size=3))
        print("从-2开始往前取3天的收盘价:", self.data1.lines.close.get(ago=-2, size=3))
        print("回测的总长度:", self.data.buflen())
        pass

    def notify_order(self, order):
        """
        可选,打印订单信息
        :param order:
        :return:
        """
        pass

    def notify_trade(self, trade):
        """
        可选,打印交易信息
        :param trade:
        :return:
        """
        pass

    def next(self):
        """
        必选,编写交易策略逻辑
        :return:
        """
        print(f"------------- next 的第{self.count + 1}次循环 --------------")
        print('当前节点(今日): ', 'datetime', self.data1.lines.datetime.date(0), 'close', self.data1.lines.close[0])
        print("往前推1天(昨日):", 'datetime', self.data1.lines.datetime.date(-1), 'close', self.data1.lines.close[-1])
        print("往前推2天(前日)", 'datetime', self.data1.lines.datetime.date(-2), 'close', self.data1.lines.close[-2])
        print("前日、昨日、今日的收盘价:", self.data1.lines.close.get(ago=0, size=3))
        # print("往后推1天(明日):", 'datetime', self.data1.lines.datetime.date(1), 'close', self.data1.lines.close[1])
        # print("往后推2天(明后日)", 'datetime', self.data1.lines.datetime.date(2), 'close', self.data1.lines.close[2])
        print("已处理的数据点:", len(self.data))
        print("回测的总长度:", self.data.buflen())
        self.count += 1
        pass


# 股票查询开始和结束时间
start_query = '2022-01-01'
end_query = '2022-09-01'
# 回测开始和结束时间
start_date = datetime.datetime(2022, 7, 11)
end_date = datetime.datetime(2022, 8, 10)
cerebro = bt.Cerebro()
# 添加几个股票数据
codes = [
    '300015',
    '300347',
    '300760',
    '603127',
    '600438'
]
# 添加多个股票回测数据
for code in codes:
    data = sdb.stock_daily(code, start_query, end_query)
    data.index.names = ['datetime']
    # 新增指标列
    data['pe'] = 3
    data['pb'] = 4
    date_feed = PandasData_more(dataname=data, fromdate=start_date, todate=end_date)
    cerebro.adddata(date_feed, name=code)
    print('添加股票数据:code: %s' % code)

cerebro.addstrategy(TestStrategy)
cerebro.run()
# cerebro.plot()

if __name__ == '__main__':
    pass

写于 2022 年 10 月 05 日 14:24:59

 

标签:Backtrader,self,lines,datetime,print,date,close,数据
From: https://www.cnblogs.com/sykent/p/16755577.html

相关文章

  • db2 数据库的目录
    1、数据库的目录1、数据库目录用于存储数据库的信息,如表空间、表、容器等信息2、创建位置取决于创建数据库时指定的数据库路径3、分区全局目录结构:db_path/instance_name/NO......
  • 超长时间序列数据可视化的6个技巧
    时间序列是由表示时间的x轴和表示数据值的y轴组成,使用折线图在显示数据随时间推移的进展时很常见。它在提取诸如趋势和季节性影响等信息方面有一些好处。但是在处理超长的......
  • 数据组中的矩阵两个对角线的和(优化版)
    #include<stdio.h>intmain(){ intMAP[4][4]={12,11,14,15, 21,22,23,24, 65,55,66,77, 87,98,51,32}; inti,j; intsu......
  • 买手机或者数据线的小建议
    商家总会在顾客不注意的地方进行成本缩减。比如一些手机接口会是2.0版本,这些都要买的时候询问,2.0的就不可以连接显示屏或者网上买一些充电线,无论贵还是便宜都要问一下。......
  • 【学习笔记】数据库用户管理和备份
    数据库用户管理和备份 用户管理可视化管理用navicat可视化管理软件进行用户的添加删除和权限的管理新建用户连接用户  sql命令操作对用户的......
  • 对稀有飞机数据集进行多属性物体检测:使用YOLOv5的实验过程
    编译:ronghuaiyang(AI公园)导读如何使用物体的多个特征来提升物体检测的能力,使用YOLOv5进行多属性物体检测的实验。我们发布了RarePlanes数据集和基线实验的结果。今天,我们试图......
  • 数据离散化
    定义:把无穷大集合中的若干个元素映射为有限集合以便于统计的方法。当数据之间差值很大,即使排完序后,两个数之间仍有很大的差值,不适合直接用下标表示,这样会导致数组开的过大......
  • Springboot 之 Mybatis-plus 多数据源
    简介Mybatis-puls多数据源的使用,采用的是官方提供的dynamic-datasource-spring-boot-starter包的@DS注解,具体可以参考官网:https://gitee.com/baomidou/dynamic-dataso......
  • SAP UI5 应用元数据文件 manifest.json 的加载和解析原理讲解试读版
    一套适合SAPUI5初学者循序渐进的学习教程本专栏计划的文章数在​​300​​​篇左右,到​​2022年9月22日​​​为止,目前已经更新了​​133​​​篇,专栏完成度为​​......
  • 将容器中(数组、集合)的数据串成字符串
    开发工具VC7(VS2002)核心代码用到MFC,测试代码用到stl本代码功能,将容器中(数组、集合)的数据串成字符串核心代码和扩展代码往往不是一个人完成的。扩展代码和使用也很可能......