首页 > 其他分享 >VeighNa进阶EP01:TuShare数据源接入

VeighNa进阶EP01:TuShare数据源接入

时间:2022-09-19 16:14:17浏览次数:95  
标签:TuShare 进阶 Exchange 数据源 symbol exchange ts tushare str

前言

上次我们介绍了一下vnpy量化框架的搭建,今天我们来说说TuShare数据源的接入。因为公司之前一直是从一些金融网站或者证券服务商获取的,公司最近决定改变策略通过TuShare获取。其实在VeighNa开源网站上官方也提供了一些数据服务商。本着能白嫖绝不花钱的准则,就试着接入下。接下来我们开始进入正题吧

账号注册

  1. 通过TuShare官网进入,注册并登陆个人账户,进入个人主页

    image-20220919151510855)

  2. 积分查询与获取

    新用户的积分是100,通过更新个人资料,可以增加20的积分

    image-20220919151510855

  3. 积分其他获取方式

    • 分享

      通过分享推荐链接,成功注册一个有效用户(指真正会使用tushare数据的用户)可获得50积分,虚假用户带来的积分会被定期回收!

    • 捐助(付费)

      通过捐助社区捐助一定的金额可提高个人的积分。捐助积分与频次关系图如下:

      积分数 每分钟频次 每天总量上限 可以访问的接口 捐助(元)
      120 50 8000次 股票基础信息、股票非复权日线行情,其他接口无法调取 0
      2000以上 200 100000次/个API tushare.pro 60%的API可以调取,可参考每个接口的积分要求 200
      5000以上 500 常规数据无上限 tushare.pro 90%的API可以调取,可参考每个接口的积分要求 500
      10000以上 1000 常规数据无上限,特色数据300次每分钟 特色数据权限,包括盈利预测数据、每日筹码和胜率、筹码分布、券商每月金股等数据 1000
      15000以上 1000 特色数据无总量限制 特色数据专属权限 1500

      10000积分以上可以有更高的API频次和权限,比如股票特色数据

      此外,分钟和港美股数据权限不在积分范畴内,各类分钟单独开权限

      类型 包含数据 历史起始 捐助(元) 频次
      沪深A股 1、5、15、30、60分钟 2009年 1000 每分钟500次,每次8000行数据,总量不限制
      期货 同上 2010年 1000 同上
      期权 同上 2010年 2000,包含股指和商品期权 同上
      港股 日线 全历史 1000 每分钟500次,每次3000行,总量不限制
      美股 日线,包含估值指标、换手率等 全股票全历史 1000 每分钟500次,每次6000行,总量不限制
      数字货币 1~60分钟 2020年开始 1000 每分钟500次,每次8000行,总量不限制
      新闻资讯 快讯、长篇新闻、新闻联播、公司公告 3年以上 1000 每分钟400次,总量不限制
    • 高校师生,确认身份后,可以免费获得2000积分(根据实际情况可以调整)

    • 参与社区贡献,比如提交数据问题、参与数据贡献、编写文章发给群主或积分管理员

  4. 接口调用与测试

    在本地编写Python测试脚本

    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)
    

    image-20220919151510855

  5. 接入vnpy

    • 安装

      pip install vnpy_tushare
      
    • vnpy项目根目录下创建vnpy_tushare\__init__.py

    import importlib_metadata
    
    from .tushare_datafeed import TushareDatafeed as Datafeed
    
    
    try:
        __version__ = importlib_metadata.version("vnpy_tushare")
    except importlib_metadata.PackageNotFoundError:
        __version__ = "dev"
    
    • vnpy_tushare\tushare_datafeed.py
    from datetime import timedelta, datetime
    from typing import Dict, List, Optional
    from copy import deepcopy
    
    import pandas as pd
    from pandas import DataFrame
    import tushare as ts
    from tushare.pro.client import DataApi
    
    from vnpy.trader.setting import SETTINGS
    from vnpy.trader.datafeed import BaseDatafeed
    from vnpy.trader.constant import Exchange, Interval
    from vnpy.trader.object import BarData, HistoryRequest
    from vnpy.trader.utility import round_to, ZoneInfo
    
    # 数据频率映射
    INTERVAL_VT2TS: Dict[Interval, str] = {
        Interval.MINUTE: "1min",
        Interval.HOUR: "60min",
        Interval.DAILY: "D",
    }
    
    # 股票支持列表
    STOCK_LIST: List[Exchange] = [
        Exchange.SSE,
        Exchange.SZSE,
        Exchange.BSE,
    ]
    
    # 期货支持列表
    FUTURE_LIST: List[Exchange] = [
        Exchange.CFFEX,
        Exchange.SHFE,
        Exchange.CZCE,
        Exchange.DCE,
        Exchange.INE,
    ]
    
    # 交易所映射
    EXCHANGE_VT2TS: Dict[Exchange, str] = {
        Exchange.CFFEX: "CFX",
        Exchange.SHFE: "SHF",
        Exchange.CZCE: "ZCE",
        Exchange.DCE: "DCE",
        Exchange.INE: "INE",
        Exchange.SSE: "SH",
        Exchange.SZSE: "SZ",
    }
    
    # 时间调整映射
    INTERVAL_ADJUSTMENT_MAP: Dict[Interval, timedelta] = {
        Interval.MINUTE: timedelta(minutes=1),
        Interval.HOUR: timedelta(hours=1),
        Interval.DAILY: timedelta()
    }
    
    # 中国上海时区
    CHINA_TZ = ZoneInfo("Asia/Shanghai")
    
    
    def to_ts_symbol(symbol, exchange) -> Optional[str]:
        """将交易所代码转换为tushare代码"""
        # 股票
        if exchange in STOCK_LIST:
            ts_symbol: str = f"{symbol}.{EXCHANGE_VT2TS[exchange]}"
        # 期货
        elif exchange in FUTURE_LIST:
            if exchange is not Exchange.CZCE:
                ts_symbol: str = f"{symbol}.{EXCHANGE_VT2TS[exchange]}".upper()
            else:
                for count, word in enumerate(symbol):
                    if word.isdigit():
                        break
    
                year: str = symbol[count]
                month: str = symbol[count + 1:]
                if year == "9":
                    year = "1" + year
                else:
                    year = "2" + year
    
                product: str = symbol[:count]
                ts_symbol: str = f"{product}{year}{month}.ZCE".upper()
        else:
            return None
    
        return ts_symbol
    
    
    def to_ts_asset(symbol, exchange) -> Optional[str]:
        """生成tushare资产类别"""
        # 股票
        if exchange in STOCK_LIST:
            if exchange is Exchange.SSE and symbol[0] == "6":
                asset: str = "E"
            elif exchange is Exchange.SZSE and symbol[0] == "0" or symbol[0] == "3":
                asset: str = "E"
            else:
                asset: str = "I"
        # 期货
        elif exchange in FUTURE_LIST:
            asset: str = "FT"
        else:
            return None
    
        return asset
    
    
    class TushareDatafeed(BaseDatafeed):
        """TuShare数据服务接口"""
    
        def __init__(self):
            """"""
            self.username: str = SETTINGS["datafeed.username"]
            self.password: str = SETTINGS["datafeed.password"]
    
            self.inited: bool = False
    
        def init(self) -> bool:
            """初始化"""
            if self.inited:
                return True
    
            ts.set_token(self.password)
            self.pro: Optional[DataApi] = ts.pro_api()
            self.inited = True
    
            return True
    
        def query_bar_history(self, req: HistoryRequest) -> Optional[List[BarData]]:
            """查询k线数据"""
            if not self.inited:
                self.init()
    
            symbol: str = req.symbol
            exchange: Exchange = req.exchange
            interval: Interval = req.interval
            start: datetime = req.start.strftime("%Y-%m-%d %H:%M:%S")
            end: datetime = req.end.strftime("%Y-%m-%d %H:%M:%S")
    
            ts_symbol: str = to_ts_symbol(symbol, exchange)
            if not ts_symbol:
                return None
    
            asset: str = to_ts_asset(symbol, exchange)
            if not asset:
                return None
    
            ts_interval: str = INTERVAL_VT2TS.get(interval)
            if not ts_interval:
                return None
    
            adjustment: timedelta = INTERVAL_ADJUSTMENT_MAP[interval]
    
            try:
                d1: DataFrame = ts.pro_bar(
                    ts_code=ts_symbol,
                    start_date=start,
                    end_date=end,
                    asset=asset,
                    freq=ts_interval
                )
            except IOError:
                return []
    
            df: DataFrame = deepcopy(d1)
    
            while True:
                if len(d1) != 8000:
                    break
                tmp_end: str = d1["trade_time"].values[-1]
    
                d1 = ts.pro_bar(
                    ts_code=ts_symbol,
                    start_date=start,
                    end_date=tmp_end,
                    asset=asset,
                    freq=ts_interval
                )
                df = pd.concat([df[:-1], d1])
    
            bar_keys: List[datetime] = []
            bar_dict: Dict[datetime, BarData] = {}
            data: List[BarData] = []
    
            # 处理原始数据中的NaN值
            df.fillna(0, inplace=True)
    
            if df is not None:
                for ix, row in df.iterrows():
                    if row["open"] is None:
                        continue
    
                    if interval.value == "d":
                        dt: str = row["trade_date"]
                        dt: datetime = datetime.strptime(dt, "%Y%m%d")
                    else:
                        dt: str = row["trade_time"]
                        dt: datetime = datetime.strptime(dt, "%Y-%m-%d %H:%M:%S") - adjustment
    
                    dt = dt.replace(tzinfo=CHINA_TZ)
    
                    turnover = row.get("amount", 0)
                    if turnover is None:
                        turnover = 0
    
                    open_interest = row.get("oi", 0)
                    if open_interest is None:
                        open_interest = 0
    
                    bar: BarData = BarData(
                        symbol=symbol,
                        exchange=exchange,
                        interval=interval,
                        datetime=dt,
                        open_price=round_to(row["open"], 0.000001),
                        high_price=round_to(row["high"], 0.000001),
                        low_price=round_to(row["low"], 0.000001),
                        close_price=round_to(row["close"], 0.000001),
                        volume=row["vol"],
                        turnover=turnover,
                        open_interest=open_interest,
                        gateway_name="TS"
                    )
    
                    bar_dict[dt] = bar
    
            bar_keys: list = bar_dict.keys()
            bar_keys = sorted(bar_keys, reverse=False)
            for i in bar_keys:
                data.append(bar_dict[i])
    
            return data
    
    • 使用

      在VeighNa中使用TuShare时,需要在全局配置中填写以下字段信息:

      名称 含义 必填 举例
      datafeed.name 名称 tushare
      datafeed.username 用户名 token
      datafeed.password 密码 c3a110417f08f26d2c221edc0c50d4a8a5001502eea89cf5
  6. 测试

    • 查看配置项

      image-20220919151510855

      这里的数据库选择默认的sqlite

    • 填写参数

      周期没有tick级的

      image-20220919151510855

    • 下载数据

      image-20220919151510855

      数据库查询

      image-20220919151510855

    • 开始回测

      image-20220919151510855

标签:TuShare,进阶,Exchange,数据源,symbol,exchange,ts,tushare,str
From: https://www.cnblogs.com/misso/p/16707990.html

相关文章

  • 十四、MySQL进阶
    (一)索引索引:数据库的性能调优;提升数据库的工作效率。1、索引分类(逻辑分类)1、主键索引:主键索引是一种唯一性索引,即不允许为空以及值重复2、唯一性索引:在创建表的时候加上......
  • webpack5进阶
    介绍本章节主要介绍Webpack高级配置。所谓高级配置其实就是进行Webpack优化,让我们代码在编译/运行时性能更好~我们会从以下角度来进行优化:提升开发体验提升打......
  • 算法竞赛进阶指南 0x22 深度优先搜索
    AcWing165.小猫爬山翰翰和达达饲养了N只小猫,这天,小猫们要去爬山。经历了千辛万苦,小猫们终于爬上了山顶,但是疲倦的它们再也不想徒步走下山了(呜咕>_<)。翰翰和达达只好......
  • JAVA进阶--网络通信--2022年9月15日
    第一节  网络编程1、什么是网络编程网络编程可以让程序与网络上的其他设备中的程序进行数据交互2、网络通信基本模式常见的通信模式有如下......
  • 【Meetup预告】OpenMLDB+37手游:一键查收实时特征计算场景案例及进阶使用攻略
    2022年9月24日(周六)上午10:00-12:00,开源机器学习数据库OpenMLDB第六期Meetup将通过线上直播的形式展开。活动背景提供生产级实时数据及特征开发全栈解决方案的开源学......
  • 高级前端进阶(六)
    最近有个需求,就是上传图片的时候,图片过大,需要压缩一下图片再上传。需求虽然很容易理解,但要做到,不是那么容易的。这里涉及到的知识有点多,不多说,本篇博客有点重要呀!一、......
  • 报表进阶--参数面板添加
    有时候我们并不需要看所有的数据,比如在销量表中,我们只想看”华北“地区的数据,这个时候我们就需要一个控件能帮助我们过滤掉其他的地区数据。这里我们就要从sql开始设置......
  • 学习 pyrhon进阶 魔法函数 持续更新
        delstu#手动回收对象stu当右键运行py文件的时候当做脚本文件运行运行结束后会回收变量  结果 ......
  • ElasticSearch进阶:各种ES查询在Java中的实现
    注:本文摘自:https://mp.weixin.qq.com/s/7vEy-vN8JV3o6sAh6HFohA   本文基于elasticsearch7.13.2版本,es从7.0以后,发生了很大的更新。7.3以后,已经不推荐使用Transpo......
  • [第二章 web进阶]XSS闯关-1
    定义:跨站脚本(Cross_SiteScripting,简称为XSS或跨站脚本或跨站脚本攻击)是一种针对网站应用程序的安全漏洞攻击技术,是代码注入的一种。它允许恶意用户将代码注入网页,其他......