vnpy不使用rqdata,尝试tushare

还没有Tushare账号?注册由此去:官网注册Tushare

本篇为vnpy-tushare-ctp系列文章之一,其他文章请前往:

ubuntu 18.04 安装 vnpy2.0.9 吐血总结

东吴期货CTP自行开发穿透式监管认证指导

一、缘起

为vnpy制作tushare数据接口,实际上是为了日线级别的均线策略。目前的思路是在每天的9:30分时候策略开始生效,读取之前一天的数据,而这些数据可以通过tushare获取存入数据库。读取到数据之后立马就可以进行计算并产生策略信号。

因为rqdata是付费产品,虽然vnpy官方对于rqdata支持比较好,但对于本屌,最好的还是免费产品。

所以新开坑,在vnpy中使用tushare代替rqdata一部分功能,最终达到日线级别的基于tushare的cta策略运行。

在vnpy的源代码中寻找rqdata,找到/vnpy/app/cta_strategy/engine.py中的

    def query_bar_from_rq(
        self, symbol: str, exchange: Exchange, interval: Interval, start: datetime, end: datetime
    ):
        """
        Query bar data from RQData.
        """
        req = HistoryRequest(
            symbol=symbol,
            exchange=exchange,
            interval=interval,
            start=start,
            end=end
        )
        data = rqdata_client.query_history(req)

这就是cta_strategy调用rqdata的直接入口了。

设想,在这个类中,可以通过另外增加一个参数的方式,从上层指导:到底数据取得是通过米筐还是通过tushare。

二、实现

2.1 tushare获取数据

要想用起tushare,必先获取token。在官网社区注册后到“个人主页”->“接口token”获取。另外,要想获取期货日线数据,现在需要至少200积分。小白有一百,填上个人信息再拉两个人头,积分到达220,就可以用了。

在Ubuntu系统下,安装好的miniconda可以让你舒舒服服地用上python,安装配置过程见前文《ubuntu 18.04 安装 vnpy2.0.9 吐血总结》,此处略过。用pip安装好tushare之后,还要再装一个lxml库,还有bs4,接下来开始写文件读取数据。

import tushare as ts
ts.set_token('你的token')
pro = ts.pro_api()
df = pro.fut_daily(ts_code='CU1811.SHF', start_date='20180101', end_date='20181113')
print(df)

这个demo运行正常,之后,我们试图将它以正确的姿势写进数据库。

为什么要写进数据库呢,直接在策略里使用tushare读取的数据不是也挺好吗?使用数据库能够将数据获取与使用分离,可以日后单独将数据获取做得更健壮。

2.2 vnpy的sqlite

vnpy在2020年1月20日正在写这篇文章的时候的最新版本是vnpy-2.0.9,默认的数据库是sqlite3。连接到sqlite,需要找到vnpy的设置文件,用find命令找到了在/hom/han目录下的.vntrader文件夹,在这个文件夹下有vnpy的设置文件(各种.json)和sqlite文件database.db。

sqlite是一个无需配置的轻量数据库,默认情况下连密码都不需要的。我们直接在.vntrader下打开一个终端,运行

sqlite3 database.db

即可打开数据库,之后用.tables命令查看数据库的表,查到有两个,分别是dbbardata和dbtickdata,继续查询表的内容:

select * from dbbardata

终端输出了数据,类似

3878|rb1910|SHFE|2019-10-15 00:00:00|d|7260.0|0.0|3610.0|3650.0|3550.0|3650.0

这样的形式。我们可以把数据的形式弄得好看一点,继续使用命令.header on和.mode column,再次查询表,得到下面的输出:

继续在稍高的层次上操作数据库,下面是从vnpy社区中找到的数据调用分析图:

2.3 在回测引擎中找到数据库插入位置

在更上层的vnpy的app层面,对数据库的调用可以在/app/cta_backtester/engine.py中找到。在run_downloading中,先找到合约,再寻找它在原有数据库中存不存在,如果存在,则直接main_engine.query_history(req, contract.gateway_name),否则就要去米筐那里取数据data = rqdata_client.query_history(req)。取到数据之后进行存储

database_manager.save_bar_data(data)

进行操作就应该在这里把rqdata的语句用tushare加以补充。

仔细地分析vnpy的回测引擎,CtaBacktesterApp可以得到调取数据库操作的途径。我们进行如下操作

from vnpy.event import EventEngine
from vnpy.trader.engine import MainEngine
from vnpy.app.cta_backtester import CtaBacktesterApp
from datetime import datetime

def main():
    event_engine = EventEngine()
    main_engine = MainEngine(event_engine)
    app = CtaBacktesterApp
    main_engine.add_app(app)
    back_engine = main_engine.get_engine("CtaBacktester")
    back_engine.init_engine()
    vt_symbol = "rb1908.SHFE"
    interval = "d"
    start = datetime(2019,6,1)
    end = datetime(2019,8,31)
    back_engine.start_downloading(vt_symbol,interval,start,end)

之后,可以看到sqlite数据库增加了rb1908.SHFE的相关记录,证明调用成功。并且,当我们再次运行同样的程序,发现sqlite并没有把重复的数据再插入,重复数据的担心也可以省了。

三、tushare-vnpy综合

3.1 将tushare获取的数据集成到vnpy中,并且放到数据库里面。经过了很多次调试,暂定如下代码。在/vnpy/trader目录下建立tuquery.py文件,输入以下内容:

import tushare as ts
from vnpy.trader.object import HistoryRequest,BarData
from vnpy.trader.constant import Exchange
from datetime import  datetime
class TushareData:
    def __init__(self):
        ts.set_token('你的token')
        return
    def exchange_bond(self,exchange:Exchange):
        if exchange.value == "SHFE":
            return "SHF"
        elif exchange.value == "CZCE":
            return  "ZCE"
        else :
            return  exchange.value
        
    def tuquery(self,req:HistoryRequest):
        symbol = req.symbol
        exchange = req.exchange
        interval = req.interval
        start = req.start.strftime('%Y%m%d')
        end = req.end.strftime('%Y%m%d')
        tcode = f'{symbol}'+'.'+ self.exchange_bond(exchange)
        pro = ts.pro_api();
        df = pro.fut_daily(ts_code= tcode, start_date= start, end_date= end)
        data: List[BarData] = []

        if df is not None:
            for ix, row in df.iterrows():
                date = datetime.strptime(row.trade_date,'%Y%m%d')
                bar = BarData(
                    symbol=symbol,
                    exchange=exchange,
                    interval=interval,
                    datetime=date,
                    open_price=row["open"],
                    high_price=row["high"],
                    low_price=row["low"],
                    close_price=row["close"],
                    volume=row["amount"],
                    gateway_name="TU"
                )
                print(bar)
                data.append(bar)
        return data

tusharedata = TushareData()

同时在/vnpy/app/cta_backtester目录下找到engine.py,导入包

from vnpy.trader.tuquery import tusharedata

在run_downloading函数下找到“try:”,if……else:这里将原来的

data = rqdata_client.query_history(req)

替换为

tq = tusharedata      
data = tq.tuquery(req)

最后在最顶层的主文件中添加调用代码即可:

vt_symbol = "fg1909.CZCE"
interval = "d"
start = datetime(2019,6,1)
end = datetime(2019,8,1)
back_engine.start_downloading(vt_symbol,interval,start,end)

我们可以看到,最终在sqlite数据库中,得到了使用tushare获取的数据:

至此,我们已经完成了在vnpy中使用tushare作为数据源进行期货日线级别支持。后面的工作即可提取数据并编制策略,留待后面再续……

四、后记

4.1 rqdata后续

新问题出现了,之前我运行程序一直是在学校,而回到家后,学生试用的账号受到了限制,运行出现了如下错误:

rqdatac.share.errors.PermissionDenied: this license is only allowed to access through the education network

这意味着,我们还没有完全绕过rqdata,我们必须再次进行修改,修改的办法就是将/vnpy/app/cta_backtester/engine.py中的init_engine函数的

self.init_rqdata()

注释掉。

4.2 为数据替换顺序

我们最后插入的数据的顺序与之前vnpy默认的日期顺序是反的,可以在tuquery.py中加入一行,将数据顺序调整过来:

df= df.sort_values( by = 'trade_date', ascending= True)

发表评论