当前位置: 首页 > wzjs >正文

濮阳网站建设推广网站自助搭建

濮阳网站建设推广,网站自助搭建,做眼镜网站草图有什么原则,中国科技日报官网Backtrader从0到1——Data Feeds【入门篇】 0. 前言1. 数据源访问2. 添加CSV格式数据3. 参数持久化4. 添加Pandas数据5. 总结 0. 前言 所谓Data Feeds,翻译过来就是数据推送。 笔者在学习Data Feeds模块时,发现官网上很多部分的代码都过分冗余&#xff…

Backtrader从0到1——Data Feeds【入门篇】

  • 0. 前言
  • 1. 数据源访问
  • 2. 添加CSV格式数据
  • 3. 参数持久化
  • 4. 添加Pandas数据
  • 5. 总结


0. 前言


所谓Data Feeds,翻译过来就是数据推送。

笔者在学习Data Feeds模块时,发现官网上很多部分的代码都过分冗余,并且真正有实际应用意义的内容也不多。本文将着重介绍CSV格式文件的加载方式,以及pandas数据的加载方式。

笔者在加载这些数据时,已经形成了一套自己的体系,包括CSV文件内容格式,如何读取,以及自定义CSV类型参数持久化,都有自己的一套规范。希望大家在学习时,也能形成一套自己的使用体系。

学习完本文,将保证你能熟练的将CSV数据加载进Backtrader,处理不同级别时间的数据也将不是问题。

有一些提升部分,如低级别数据的聚合,本文将不会涉及,如有需要,也可以出一篇高级篇,专门介绍一下。这部分内容可用于搭建更复杂的交易系统(如多级别联动),但是对于单周期级别上的策略,就有点画蛇添足了。

话不多说,让我们进入Data Feeds的世界!!!


1. 数据源访问


通过Backtrader从0到1——第一个回测策略的学习,我们已经能将数据源lines添加进Cerebro实例中了。在策略中访问数据源有如下几种方式:

1. 访问lines

  • self.datas[i]表示访问插入的第ilines
  • self.data等价于self.data0等价于self.datas[0],表示访问插入的第一个lines,是一种便捷访问方式。

2. 访问lines中的特定line,也是特定列(以访问第一个lines中的line为例)

  • self.datas[0].列名,就可以拿到对应的列。一个列就是一个bar,一个line,它的indexBacktrader中特有的(上篇文章讲过)。

2. 添加CSV格式数据


1. 准备CSV数据

  • 这里选择从akshare中拉取豆油的30分钟k线数据。并保存为CSV格式。
import akshare as ak# 获取螺纹钢主力合约 1 分钟数据(代码格式:交易所_品种主力,如 "SHFE.rb主力")
df = ak.futures_zh_minute_sina(symbol="Y0",  	 # 合约代码period="30",      # 1/5/15/30/60 分钟
)print(df.head())
df.to_csv('SoybeanOil.csv', index=False)
  • 查看CSV文件:

在这里插入图片描述

  • 可以看到拿到的数据一共有7列,其中hold是持仓量,还有一个翻译是openinterest
  • pd.to_csv时,切记带上index=True选项,不然你将看到8列数据,带一列自增索引。
  • 今后我们的CSV文件格式,就按图片上来,需要有一行标题行,一行中数据以逗号隔开。第一列是datetime,第二列是open,以此类推。(当然,文件中到底有没有标题行,以什么为分割符,都可以在读取时通过参数来控制,这里我统一认为文件要带标题行,以,为分割符,即是为了规范,也是为了好看)。

2. 加载CSV文件进Cerebro

  • 使用bt.feeds.GenericCSVData()方法,加载数据,保证加载的列和CSV文件中的列一一对应(这里只是为了规范一点,好看一点,不是语法要求):
data = bt.feeds.GenericCSVData(dataname='SoybeanOil.csv',nullvalue=0.0,  # 空值替换为0.0dtformat=('%Y-%m-%d %H:%M:%S'), # 和csv文件中的日期格式适配datetime=0,     # 指定为第0列open=1,         # 指定为第1列 high=2,          # 以此类推low=3,close=4,volume=5,openinterest=6,timeframe=bt.TimeFrame.Minutes,  # 分钟级数据)
  • 参数详解:
    • dataname:CSV文件路径或或类似文件的对象;
    • datetime:(默认值0)包含日期(或日期时间)字段的列;
    • open(默认值1),high(默认值2),low(默认值3), close(默认值4),volume(默认值5),openinterest (默认值6);
      • open=1为例,表示指定索引(Python索引)为1的列,列名为open
      • 如果传递负值(例如:-1),则表示该字段在CSV数据中不存在。
    • nullvalue:(默认值:float('NaN'))将空值替换为一个值,例如nullvalue=0.0就是将空值替换为0.0;
    • dtformat:(默认值:%Y-%m-%d %H:%M:%S)和CSV文件中日期的格式适配;
    • timeframe:(默认值:TimeFrame.Days)可选项有:Ticks, Seconds, Minutes, Days, Weeks, Months and Years。例子中我们加载的是30分钟级别数据,所以填bt.TimeFrame.Minutes
  • 没有用到的参数:
    • headers:(默认值:True)指示传递的数据是否有初始标题行;
    • separator:(默认: ”,”)指定分隔符。
    • time:(默认值:-1)如果与日期时间字段分开,如:date,time,则需要用该参数指定时间所在列;
    • tmformat:(默认值:%H:%M:%S)令time列的格式和CSV文件中时间的格式适配。
    • compression:(默认值:1)每根柱状图的实际小柱状图数量。仅在数据重采样/回放时用的上。

如果没用用到的参数不理解,特别是compression,没有关系,因为很复杂的场景下(如多级别联动),才会用到。

3. 代码测试,看看数据是否被成功载入了

  • 这里添加的策略很简单,就是将加载的信息,遍历一遍:
import backtrader as btclass MyStrategy(bt.Strategy):def log(self, txt, dt=None):''' Logging function for this strategy'''# 注意要和datetime类型适配,使用datetime(0)表示当前时间dt = dt or self.datas[0].datetime.datetime(0) # dt.isoformat(sep=" ")格式化输出,以空格为date和time的分隔符print('%s, %s' % (dt.isoformat(sep=" "), txt)) def __init__(self):# 为每一列,创建一个barself.dataopen = self.datas[0].open      # 开盘价barself.datahigh = self.datas[0].high      # 最高价barself.datalow = self.datas[0].low        # 最低价barself.dataclose = self.datas[0].close    # 收盘价barself.datavolume = self.datas[0].volume  # 成交量barself.dataopeninterest = self.datas[0].openinterest  # 持仓量bardef next(self):# 打印该行全部信息self.log('open:%.2f, high:%.2f, low:%.2f, close:%.2f, volume:%.2f, openinterest:%.2f'  % (self.dataopen[0], self.datahigh[0], self.datalow[0], self.dataclose[0], self.datavolume[0], self.dataopeninterest[0]))if __name__ == "__main__":data = bt.feeds.GenericCSVData(dataname='SoybeanOil.csv',nullvalue=0.0,  # 空值替换为0.0dtformat=('%Y-%m-%d %H:%M:%S'), # 和csv文件中的日期格式适配datetime=0,     # 指定为第0列open=1,         # 指定为第1列 high=2,          # 以此类推low=3,close=4,volume=5,openinterest=6,timeframe=bt.TimeFrame.Minutes,  # 分钟级数据)cerebro = bt.Cerebro()cerebro.adddata(data)cerebro.broker.setcash(100000)cerebro.broker.setcommission(0.0002)cerebro.addstrategy(MyStrategy)cerebro.run()
  • 输出结果:
2024-12-02 22:00:00, open:8058.00, high:8070.00, low:8050.00, close:8070.00, volume:63069.00, openinterest:340406.00
2024-12-02 22:30:00, open:8070.00, high:8070.00, low:8040.00, close:8052.00, volume:53939.00, openinterest:340349.00 
2024-12-02 23:00:00, open:8050.00, high:8064.00, low:8042.00, close:8062.00, volume:60184.00, openinterest:338767.00 
2024-12-03 09:30:00, open:8062.00, high:8116.00, low:8062.00, close:8086.00, volume:107417.00, openinterest:333335.00
2024-12-03 10:00:00, open:8086.00, high:8096.00, low:8060.00, close:8066.00, volume:54452.00, openinterest:331981.00 
2024-12-03 10:45:00, open:8066.00, high:8086.00, low:8056.00, close:8058.00, volume:63507.00, openinterest:331925.00 
2024-12-03 11:15:00, open:8058.00, high:8070.00, low:8002.00, close:8010.00, volume:95367.00, openinterest:334204.00 
2024-12-03 13:45:00, open:8010.00, high:8038.00, low:8004.00, close:8014.00, volume:42692.00, openinterest:333286.00 
...
  • 可以看到,数据被成功载入了。

今后这段策略代码就可以拿来做测试,看看数据的加载情况。


3. 参数持久化


不难发现,有很多参数都是固定的,或者说我们希望,即使不传参,这个参数也应该有我们规定的默认值。这就要用到参数持久化了。

1. 通过子类化,实现参数持久化

  • 该子类继承bt.feeds.GenericCSVData
import backtrader as btclass MyDatatype(bt.feeds.GenericCSVData):params = (('nullvalue', 0.0),('dtformat', ('%Y-%m-%d %H:%M:%S')),('datetime', 0),('open', 1),('high', 2),('low', 3),('close', 4),('volume', 5),('openinterest', 6),('timeframe', bt.TimeFrame.Days),   # 默认是Day级别k线数据
)
  • 这样一来,我们只需要传很少的参数就可以了:
data = MyDatatype(dataname="SoybeanOil.csv", timeframe=bt.TimeFrame.Minutes)

2. 完整代码测试

import backtrader as bt
from Datatype import MyDatatypeclass MyStrategy(bt.Strategy):def log(self, txt, dt=None):''' Logging function for this strategy'''# 注意要和datetime类型适配,使用datetime(0)表示当前时间dt = dt or self.datas[0].datetime.datetime(0) # dt.isoformat(sep=" ")格式化输出,以空格为date和time的分隔符print('%s, %s' % (dt.isoformat(sep=" "), txt)) def __init__(self):# 为每一列,创建一个barself.dataopen = self.datas[0].open      # 开盘价barself.datahigh = self.datas[0].high      # 最高价barself.datalow = self.datas[0].low        # 最低价barself.dataclose = self.datas[0].close    # 收盘价barself.datavolume = self.datas[0].volume  # 成交量barself.dataopeninterest = self.datas[0].openinterest  # 持仓量bardef next(self):# 打印该行全部信息self.log('open:%.2f, high:%.2f, low:%.2f, close:%.2f, volume:%.2f, openinterest:%.2f'  % (self.dataopen[0], self.datahigh[0], self.datalow[0], self.dataclose[0], self.datavolume[0], self.dataopeninterest[0]))if __name__ == "__main__":# 这里用到了参数持久化data = MyDatatype(dataname="SoybeanOil.csv", timeframe=bt.TimeFrame.Minutes)cerebro = bt.Cerebro()cerebro.adddata(data)cerebro.broker.setcash(100000)cerebro.broker.setcommission(0.0002)cerebro.addstrategy(MyStrategy)cerebro.run()
  • 效果和之前一模一样,但是参数变简洁了,非常Nice!!!

4. 添加Pandas数据


1. 准备数据

import pandas as pdpd.read_csv("SoybeanOil.csv", index_col=0, date_format="'%Y-%m-%d %H:%M:%S'")
  • 看一眼数据的样子:

在这里插入图片描述

  • 对于Pandas数据,尽量保证索引是时间类型,这是Backtrader的要求。

2. 看看部分源码

class PandasData(feed.DataBase):'''The ``dataname`` parameter inherited from ``feed.DataBase`` is the pandasDataFrame'''params = (# datetime 的可能值(必须已经存在)#  None : datetime 是Pandas的索引#  -1 : 自动检测位置,匹配名字相同的列#  >= 0 : 从0开始,不包括索引,匹配Pandas的第几列#  string : 手动传入列名称,进行匹配('datetime', None),# 可能值:#  None : 该列不存在#  -1 : 自动检测位置,匹配名字相同的列#  >= 0 : numeric index to the colum in the pandas dataframe#  string : 手动传入列名称,进行匹配('open', -1),('high', -1),('low', -1),('close', -1),('volume', -1),('openinterest', -1),)
  • Backtrader支持的Pandas数据需要通过PandasData类构造,之后add的也是这个类的实例化对象。
  • 参数的解释已经写在代码注释中了,这里说一下一般的传参方式:
    • datetime参数一般是不传的,让他为默认值None,因为上面准备的Pandas数据索引已经是时间类型了;
    • 剩余六个基本参数,如果该列在Pandas数据中存在,就传它的列索引(不带datetime列,索引从0开始),或者列名;如果不存在就传None。(毕竟都用Pandas了,还是传列名吧,可读性强,可移植性高)。
  • 不同于加载CSV数据,这里不需要再指定timeframe了,因为该信息已经包含在Pandas的datetime索引中了。

3. 完整代码演示

import backtrader as bt
import pandas as pdclass MyStrategy(bt.Strategy):def log(self, txt, dt=None):''' Logging function for this strategy'''# 注意要和datetime类型适配,使用datetime(0)表示当前时间dt = dt or self.datas[0].datetime.datetime(0) # dt.isoformat(sep=" ")格式化输出,以空格为date和time的分隔符print('%s, %s' % (dt.isoformat(sep=" "), txt)) def __init__(self):# 为每一列,创建一个barself.dataopen = self.datas[0].open      # 开盘价barself.datahigh = self.datas[0].high      # 最高价barself.datalow = self.datas[0].low        # 最低价barself.dataclose = self.datas[0].close    # 收盘价barself.datavolume = self.datas[0].volume  # 成交量barself.dataopeninterest = self.datas[0].openinterest  # 持仓量bardef next(self):# 打印该行全部信息self.log('open:%.2f, high:%.2f, low:%.2f, close:%.2f, volume:%.2f, openinterest:%.2f'  % (self.dataopen[0], self.datahigh[0], self.datalow[0], self.dataclose[0], self.datavolume[0], self.dataopeninterest[0]))if __name__ == "__main__":data = pd.read_csv("SoybeanOil.csv", index_col=0, date_format='%Y-%m-%d %H:%M:%S')# 这里Pandas数据中,成交量列名是hold,不是openinterest,需要显示传入,让参数适配data = bt.feeds.PandasData(dataname=data, openinterest='hold')cerebro = bt.Cerebro()cerebro.adddata(data)cerebro.broker.setcash(100000)cerebro.broker.setcommission(0.0002)cerebro.addstrategy(MyStrategy)cerebro.run()
  • 输出:
2024-12-02 22:00:00, open:8058.00, high:8070.00, low:8050.00, close:8070.00, volume:63069.00, openinterest:340406.00
2024-12-02 22:30:00, open:8070.00, high:8070.00, low:8040.00, close:8052.00, volume:53939.00, openinterest:340349.00 
2024-12-02 23:00:00, open:8050.00, high:8064.00, low:8042.00, close:8062.00, volume:60184.00, openinterest:338767.00 
2024-12-03 09:30:00, open:8062.00, high:8116.00, low:8062.00, close:8086.00, volume:107417.00, openinterest:333335.00
2024-12-03 10:00:00, open:8086.00, high:8096.00, low:8060.00, close:8066.00, volume:54452.00, openinterest:331981.00 
2024-12-03 10:45:00, open:8066.00, high:8086.00, low:8056.00, close:8058.00, volume:63507.00, openinterest:331925.00 
2024-12-03 11:15:00, open:8058.00, high:8070.00, low:8002.00, close:8010.00, volume:95367.00, openinterest:334204.00 
2024-12-03 13:45:00, open:8010.00, high:8038.00, low:8004.00, close:8014.00, volume:42692.00, openinterest:333286.00
...

5. 总结


至此,绝大部分的数据加载问题已经难不住我们了。对比这两种数据加载方式,Pandas加载显然比CSV的加载更加灵活,但是CSV加载则更加规范。

本人习惯使用更为规范的CSV加载,即使有现成的Pandas数据,也可以先pd.to_csv()保存成CSV格式,预处理一下,再加载进Backtrader。


http://www.dtcms.com/wzjs/268144.html

相关文章:

  • 事业单位网站设计宁波seo基础入门
  • wordpress网站在哪百度快速排名软件原理
  • 宣传软文案例郑州网站seo技术
  • 网站与网站链接怎么做为什么sem的工资都不高
  • 营销网站建设推广广告制作公司
  • 徐州免费网站建设营销推广seo
  • 网站页面文案优化营商环境发言稿
  • 温州专业微网站制作多少钱上饶seo博客
  • 网站虚拟主机费用品牌营销网站建设
  • 广州网站优化网站建设文案代写收费标准
  • wordpress动漫博客主题免费下载seo排名怎么看
  • 在哪个网站上做实验仪器比较好龙南黄页全部电话
  • 某些网站字号设置样式长尾词在线挖掘
  • 网站建设商业阶段建个人网站的详细步骤
  • 软文自助发布平台系统台州seo公司
  • 人人建站网网页加速器
  • 南宁门户网站建设搜索引擎简称seo
  • 用vs2017做网站东莞网站推广哪里找
  • 如何做公司自己的网站首页自己建网站的详细步骤
  • 做加盟网站哪个最好免费培训机构管理系统
  • 山西建设厅网站2016年3号北京互联网公司排名
  • 旅游景点网站建设现状十大电商代运营公司
  • 营销网站建设步骤爱链接
  • 做网站需要备案么查询网138网站域名
  • 网站外链查询常见的网络营销方法
  • 网页设计的工作电商seo优化是什么
  • 网站建设 软件开发的公司哪家好线上营销有哪些
  • php企业中英文网站源码网站排名优化推广
  • 做网站跟做APP哪个容易简述seo
  • 团购网站设计武汉网站提升排名