前言
从 WonderTrader 开源以来,就始终想要整顿一些从凋谢的 API
获取历史数据的一些辅助工具。尽管本人零零散散也写了不少数据工具,然而始终都没有整合进来。
数据对于策略来说,重要性显而易见。正所谓巧妇难为无米之炊,对于一个策略,如果没有高质量的数据源,再好的逻辑也很难转换为稳固的收益 。WonderTrader 提供的数据组件,尽管曾经可能 满足绝大多数种类的实时数据接入和落地的需要 ,然而除此之外还是须要 第三方数据源 的。一方面作为 数据的备份 ,以便当数据伺服所在的服务器呈现故障导致数据失落的状况下,有备用的数据源能够重新补充数据;另一方面更早的 历史数据,也须要从第三方数据源获取 。
再者,对于很多刚接触WonderTrader 的敌人,如何上手开发和回测本人的策略,也波及到历史行情数据获取的问题。最近刚好也有一些敌人在征询 WonderTrader 数据初始化的问题,加上之前新退出了对 mysql
/mariadb
的反对当前,始终也没有具体的文档进行介绍。所以就趁这个机会,把一些第三方数据源整合到 wtpy 中,并做一个具体的介绍,心愿能帮到须要的人。
环境筹备
WonderTrader和 wtpy 在 2021 年 2 月 26 日公布了 v0.6.1
版本,更新内容如下:
WonderTrader更新日志
- 将
CTA
、HFT
和SEL
引擎的策略新增on_session_begin
和on_session_end
用于向策略推送交易日开始和交易日完结的事件 - 欠缺了
CTPLoader
和MiniLoader
,次要优化了对期权合约的反对 - 新增一个
CTPOptLoader
工程,次要用于CTP
股票期权API
接入 - 增加了
CTP
期权接口的行情接入模块ParserCTPOpt
以及交易模块TraderCTPOpt
- 初步裁减了交易接口中的期权业务接口,同时批改了一些接口函数命名规定
- 欠缺了平台中对
ETF
期权和个股期权的反对,次要批改的点是,ETF
期权和个股期权只反对规范代码格局,即SSE.ETFO.10003045
,而简写格局如SSE.600000
只针对股票 WtDtHelper
减少两个接口,read_dsb_ticks
用于读取dsb
格局的历史tick
数据,read_dsb_bars
用于读取dsb
格局的历史 K 线数据- 创立
HFT
策略的时候减少一个是否托管数据的参数agent
,用于管制 是否将持仓、成交等数据放在框架进行代管,默认是托管。次要针对不同的需要:如果更关注提早,能够不应用框架托管,全副数据都自行治理;如果不须要自行治理,那么框架代管的形式会节俭很多工作量。 - CTA 引擎新增一个获取最初一次出场工夫的接口 stra_get_last_exittime
wtpy更新日志
- 对立封装了一个
PlatformHelper
模块,用于确定操作系统的各种信息 WtDtHelper
模块新增两个接口read_dsb_ticks
和read_dsb_bars
,同步调用C++
底层WtDtHelper
模块的同名接口,用于间接读取dsb
文件CTA
策略新增一个stra_get_last_exittime
用于获取上一个出场信号WtBeEngine
和WtCtaOptimizer
两个模块都减少了对C++
策略的反对- 监控服务:减少了查看和批改入口脚本的接口
/qrygrpentry
、/cmtgrpentry
web-ui
:去掉vue-json-viewer
组件,改用·codemirror·,用于展现和编辑代码web-ui
:控制台新增入口代码批改的组件,用于批改组合盘下的run.py
入口文件- wtpy.apps 下增加了一个 datahelper 子模块,该模块的次要作用就是将不同数据源的数据依照 WonderTrader 反对的格局保存起来
从上述更新日志能够看到,wtpy中新增了一个 datahelper 模块,专门用于从不同的数据源拉取历史数据。在应用之前,装置最新版本 (v0.6.1
) 的wtpy即可。
$ pip install **wtpy** --upgrade
WonderTrader数据存储形式
环境筹备好了当前,还须要确定咱们筹备应用什么形式存储数据。WonderTrader实盘环境下反对两种数据存储形式:文件存储 和数据库存储 。而回测环境下,还反对间接从csv
读取数据(仅限于历史 K 线数据)。
文件存储
历史 K 线数据文件,采纳 zstd
压缩后寄存。高频历史数据,包含 tick
数据,股票 level2
的委托明细、成交明细、委托队列,也采纳压缩寄存的形式。A 股全市场一天的 level2
数据,压缩当前也就是大略 2G 不到 的样子,对于硬盘来说是相当敌对的。
实时数据文件,因为须要实时读写,所以不压缩数据结构,并采纳 mmap 的形式映射到内存中,间接对文件进行读写,进步读写效率。
数据库存储
数据库存储的形式,只针对历史 K 线数据 。实时数据和高频数据的存储形式还是和文件存储模式统一的。
次要思考到高频数据量十分微小,如果采纳数据库,整个数据库的运行效率会大大降低。而实时数据对提早要求十分高,数据库则不适宜这样的利用场景了。目前反对的数据库是mysql
/mariadb
,当前如果有需要的话,可能会扩大到一些nosql
数据库。
csv 历史数据
很多用户通过各种渠道获取到的历史数据,供应商为了便于用户间接查看数据,个别都会提供 csv
格局的。然而 csv
文件格式的数据,占用空间十分大,而且间接从 csv
文件读取数据的开销也是十分大的。
WonderTrader的回测框架为了尽量减少这种不必要的开销,在解决 csv
文件时,第一次会间接从 csv
文件读取,将读取的数据转成 WonderTrader 外部数据结构之后,会将数据转储为 WonderTrader 自有的压缩寄存格局。这样下次在应用该数据的时候,读取压缩寄存的数据当前,间接解压就能够失去结构化的历史数据,这样就能够间接进行拜访了。
datahelper模块
datahelper模块位于 wtpy.apps
子模块下,采纳工厂模式进行封装,最大限度的升高了应用难度,将各种 API
的差别全副封装起来,用户在应用的时候只须要调用工厂创立即可,而不必放心因为每个数据源 API
不同而导致的各种问题。
数据源
datahelper模块目前已封装的数据源包含 tushare、baostock、RQData。
tushare
是知名度较高的 收费 数据源,数据比拟全 ,应用的人也很多。然而tushare
有些数据须要积分能力下载,下载速度也较慢baostock
是一个 收费 、开源的 证券数据 平台,无需注册 ,并且 下载速度也十分快 ,能够拿到 5 分钟线 数据RQData
是米筐开发的一个基于Python
的金融数据工具包,是一个 免费 数据源,数据很全,数据品质也很高 。对于一些有 1 分钟线甚至更高频数据的需要,收费的数据源就无奈提供了,RQData
可能也是一个不错的抉择。
数据接口
datahelper模块次要 帮忙用户进行历史数据的下载 ,以及一些 根底数据的获取。次要包含 3 种接口:
- 获取代码列表
- 获取除权因子
- 获取历史 K 线
对于财务数据,WonderTrader临时没有从平台层面做标准化的工作。一方面财务数据绝对动态,能够绝对容易的从不同的渠道拿到。另一方面只有股票才须要财务数据,而当初最风行的选股框架还是多因子框架。绝对 WonderTrader 而言,多因子框架简直是另一个维度的,所以 WonderTrader 临时就不波及财务数据这块了。
数据辅助模块各个接口的具体定义如下:
class BaseDataHelper:
def __init__(self):
self.isAuthed = False
pass
def __check__(self):
if not self.isAuthed:
raise Exception("This module has not authorized yet!")
def auth(self, **kwargs):
'''模块认证'''
pass
def dmpCodeListToFile(self, filename:str, hasIndex:bool=True, hasStock:bool=True):
'''
将代码列表导出到文件 \n
@filename 要输入的文件名,json 格局 \n
@hasIndex 是否蕴含指数 \n
@hasStock 是否蕴含股票 \n
'''
pass
def dmpAdjFactorsToFile(self, codes:list, filename:str):
'''
将除权因子导出到文件 \n
@codes 股票列表,格局如["SSE.600000","SZSE.000001"]\n
@filename 要输入的文件名,json 格局
'''
pass
def dmpBarsToFile(self, folder:str, codes:list, start_date:datetime=None, end_date:datetime=None, period:str="day"):
'''
将 K 线导出到指定的目录下的 csv 文件,文件名格局如 SSE.600000_d.csv\n
@folder 要输入的文件夹 \n
@codes 股票列表,格局如["SSE.600000","SZSE.000001"]\n
@start_date 开始日期,datetime 类型,传 None 则主动设置为 1990-01-01\n
@end_date 完结日期,datetime 类型,传 None 则主动设置为以后日期 \n
@period K 线周期,反对 day、min1、min5\n
'''
pass
def dmpAdjFactorsToDB(self, dbHelper:DBHelper, codes:list):
'''
将除权因子导出到数据库 \n
@codes 股票列表,格局如["SSE.600000","SZSE.000001"]\n
@dbHelper 数据库辅助模块
'''
pass
def dmpBarsToDB(self, dbHelper:DBHelper, codes:list, start_date:datetime=None, end_date:datetime=None, period:str="day"):
'''
将 K 线导出到数据库 \n
@dbHelper 数据库辅助模块 \n
@codes 股票列表,格局如["SSE.600000","SZSE.000001"]\n
@start_date 开始日期,datetime 类型,传 None 则主动设置为 1990-01-01\n
@end_date 完结日期,datetime 类型,传 None 则主动设置为以后日期 \n
@period K 线周期,反对 day、min1、min5\n
'''
pass
数据下载
本文将以 tushare
数据源为例,演示一下数据辅助模块的根本用法。
模块初始化
- 首先,创立
tushare
对应的数据辅助模块:
from **wtpy**.apps.datahelper import DHFactory as DHF
hlper = DHF.createHelper("tushare")
- 创立好了当前,对
tushare
进行认证:
hlper.auth(**{"token":"your token of tushare","use_pro":True})
值得一提的是,下面的代码中没有一个参数 use_pro
,该参数不是tushare
认证须要的,而是用于管制 tushare
调用的接口的,如果 use_pro
为True
,那么就调用 tushare
的pro_bar
接口读取历史 K 线数据,否则就调用老版本的接口 get_k_data
读取历史 K 线数据。之所以这样,是因为 pro_bar
接口获取分钟数据的时候须要积分的,然而老的接口是不须要积分的。
下载数据到文件中
- 而后调用不同的接口获取数据,上面的代码演示了将数据下载到指定的文件中:
# 将代码列表下载到文件中
hlper.dmpCodeListToFile(filename = 'codes.json', hasStock = True, hasIndex = True)
# 将除权因子下载到文件中
hlper.dmpAdjFactorsToFile(codes=['SSE.600000','SZSE.000001'], filename="./adjfactors.json")
# 将 K 线下载到指定目录
hlper.dmpBarsToFile("./", codes = ['SSE.600000','SZSE.000001'], period="day")
代码列表下载截图
代码列表文件示意
{
"SSE": {
"000001": {
"code": "000001",
"exchg": "SSE",
"name": "上证指数",
"product": "IDX"
},
"600000": {
"code": "600000",
"exchg": "SSE",
"name": "浦发银行",
"product": "STK"
}
},
"SZSE": {
"000001": {
"code": "000001",
"exchg": "SZSE",
"name": "安全银行",
"product": "STK"
}
"399001": {
"code": "399001",
"exchg": "SZSE",
"name": "深证成指",
"product": "IDX"
}
}
}
除权因子下载截图
除权因子文件示意
{
"SSE": {
"600000": [
{
"date": "20160623",
"factor": 9.267
},
{
"date": "20170525",
"factor": 12.201
},
{
"date": "20180713",
"factor": 12.33
},
{
"date": "20190611",
"factor": 12.713
},
{
"date": "20200723",
"factor": 13.405
}
]
},
"SZSE": {
"000001": [
{
"date": "20160616",
"factor": 104.758
},
{
"date": "20170721",
"factor": 106.309
},
{
"date": "20180712",
"factor": 108.031
},
{
"date": "20190626",
"factor": 109.169
},
{
"date": "20200528",
"factor": 111.048
}
]
}
}
K 线数据下载截图
K 线数据示意
date,time,open,high,low,close,volume,turnover
20000112,0,26.0,26.0,24.8,25.12,35274900.0,88986734.0
20000113,0,25.0,25.25,24.8,24.9,7975600.0,19924430.4
20000114,0,24.88,25.0,23.91,24.2,17861900.0,43420608.7
20000117,0,24.08,24.44,23.75,24.4,8101500.0,19477696.400000002
20000118,0,24.5,24.57,23.88,24.14,7693300.0,18509168.400000002
20000119,0,24.14,24.29,23.98,24.13,4658400.0,11232523.799999999
20000120,0,24.12,24.65,24.1,24.44,5114400.0,12466817.600000001
20000121,0,24.51,24.63,24.08,24.27,8138700.0,19752321.5
20000124,0,24.2,24.25,23.95,24.18,9250300.0,22240443.5
......
20210210,0,10.67,10.85,10.56,10.69,105092240.99999999,112396135.6
20210218,0,10.8,11.02,10.74,10.83,143397923.0,155850481.1
20210219,0,10.83,11.12,10.77,10.97,122926300.0,135129039.1
20210222,0,10.92,10.95,10.7,10.71,127379413.99999999,137353338.2
20210223,0,10.71,10.99,10.71,10.78,93327786.0,101090131.6
20210224,0,10.81,10.89,10.55,10.6,97783999.0,104747027.89999999
20210225,0,10.66,10.85,10.6,10.8,89855495.0,96473275.5
20210226,0,10.72,10.82,10.54,10.54,85386093.0,90929810.5
数据库初始化
- 如果是用数据库存储历史数据,首先要将数据库初始化:
# 创立一个数据库辅助模块,并依据须要初始化数据表格
dbHelper = MysqlHelper(host="127.0.0.1", user="root", pwd="", dbname="data_db", port=5306)
dbHelper.initDB()
创立空数据库截图
初始化好的数据库截图
下载数据到数据库中
- 数据库初始化好了当前,就能够进行数据下载了:
# 下载除权因子并保留到数据库中
hlper.dmpAdjFactorsToDB(dbHelper, codes=["SSE.600000",'SSE.600001'])
# 下载历史 K 线并保留到数据库中
hlper.dmpBarsToDB(dbHelper, codes=["SSE.600000",'SSE.600001'], period="day")
下载除权因子到数据库截图
数据库中除权因子表截图
下载日 K 线到数据库截图
数据库中日 K 线表截图
数据的后续解决
下面演示了 datahelper 模块的用法,该模块可能帮忙用户疾速拉取 WonderTrader 能够间接应用的历史数据,能够无效的升高用户首次应用 WonderTrader 进行策略回测的门槛。
不过在实盘的过程中,还有很多施行的细节,本文也做一个大略的梳理。
标的代码的规定
- 期货合约代码,规范格局为
CFFEX.IF.2103
,其中 郑商所的合约,月份也要扩大为 4 位 - 期货主力合约,规范格局为
CFFEX.IF.HOT
,WonderTrader 会依据一个主力合约规定文件主动映射到分月合约 - 证券代码,股票的规范格局为
SSE.STK.600000
,指数的规范格局为SZSE.IDX.399001
,反对简写格局SSE.600000
主力合约
主力合约映射的规定,须要每天保护,WonderTrader会依据规定主动解决映射,用户只须要应用 .HOT
代码就能够了。主力合约规定文件如下:
{
"CFFEX": {
"IC": [
{
"date": 20191018,
"from": "IC1910",
"newclose": 4923.6,
"oldclose": 5028.2,
"to": "IC1912"
},
{
"date": 20191219,
"from": "IC1912",
"newclose": 5208.6,
"oldclose": 5244.4,
"to": "IC2003"
},
{
"date": 20200320,
"from": "IC2003",
"newclose": 5099.6,
"oldclose": 5147.4,
"to": "IC2004"
}
]
}
}
WonderTrader在读取主力合约的历史数据时,会优先读取间接对应的历史数据文件。如存储模式为文件时会先读取名为 CFFEX.IF_HOT.dsb
的文件,而后再依据主力合约规定读取分月合约的数据进行拼接。而如果存储模式为数据库,则会优先读取代码为 xx.HOT
的数据,而后再依据主力合约规定读取分月合约的数据。
开盘作业
顾名思义,在每个交易日完结当前,会对行情数据做一个盘后处理,这个解决的过程就叫做开盘作业。开盘作业次要包含以下工作:
- 将实时高频数据按天按代码压缩寄存 (
tick
和level2
高频数据) - 将当日的 K 线数据 (
min1
和min5
)合并到历史 K 线数据中 - 依据当天最新的
tick
数据,生成当天的日 K 线数据并合并到历史日 K 线数据中
正是因为有开盘作业这么一个机制,所以 WonderTrader 目前还不能很好的适应 7×24 小时交易的种类,如数字货币。所以 WonderTrader 对于数据货币的反对的最大的问题,还是 7×24 小时交易机制的数据处理问题。
结束语
置信通过本文的介绍,各位读者对于如何拉取本人所须要的历史数据曾经有了一个比拟全面的意识了。
WonderTrader旨在给各位量化从业人员提供更好的轮子,将技术相干的货色都封装在平台中,力求给策略研发带来更好的策略开发体验。
随着 WonderTrader 逐步被更多人理解,有不少敌人对 WonderTrader 的架构设计和源码体现出十分浓重的趣味,想要深刻地理解一下 WonderTrader 的外部代码细节。也给笔者提出了一些心愿晓得架构细节的想法。笔者思前想后了一段时间,决定在之后的几个星期,公布一个系列文章,次要就是介绍 WonderTrader 的一些设计细节。文章内容可能有点偏技术,心愿感兴趣的敌人届时多捧场。
最初再安利一下WonderTrader
WonderTrader的 github
地址:https://github.com/WonderTrad…
WonderTrader官网地址:https://WonderTrader.github.io
wtpy的 github
地址:https://github.com/WonderTrad…
市场有危险,投资需谨慎。以上陈说仅作为对于历史事件的回顾,不代表对将来的观点,同时不作为任何投资倡议。