第18节 自定义裁判决策交易
2017年10月13日
第20节 A股全市场回测
2017年10月13日

第19节 数据源

作者: 阿布

阿布量化版权所有 未经允许 禁止转载

abu量化系统github地址(欢迎+star)

本节ipython notebook

abupy除了之前章节讲解示例时使用的内置沙盒数据外,也内置了几个数据源,支持实时获取美股,A股,港股,期货和比特币等类型数据,内置的数据源仅供学习使用,abupy提供了接入外部数据源的接口和规范,本节的示例将讲解内置数据源的切换,以及接入用户外部的数据源的接口规范。

1. 数据模式的切换

使用g_data_fetch_mode可以查看当前的数据模式:

abupy.env.g_data_fetch_mode
<EMarketDataFetchMode.E_DATA_FETCH_NORMAL: 0>

默认使用模式为E_DATA_FETCH_NORMAL,NORMAL的意义是默认优先从缓存中获取,如果缓存中不存在,再访问网络,尝试从网络获取,除此之外还有一些优化,比如虽然缓存中的数据也无法满足要求,但是缓存索引纪录今天已经尝试从网络获取,这种情况下也不再访问网络。

更多详情请阅读ABuDataSource代码

E_DATA_FETCH_FORCE_NET为强制使用网络进行数据更新,一般不推荐使用,如果切换了数据源,或者缓存中的数据存在问题的情况下会使用:

abupy.env.g_data_fetch_mode = EMarketDataFetchMode.E_DATA_FETCH_FORCE_NET
ABuSymbolPd.make_kl_df('usBIDU').tail()

E_DATA_FETCH_FORCE_LOCAL为强制从缓存获取,实际上在做回测的时候,使用的一般都是这种模式,因为比如编写了一个策略进行回测结果度量,通常情况下需要反复的修改策略,重新进行回测,强制使用缓存的好处是:

  1. 保证使用的数据集没有发生变化,度量结果有可比性
  2. 提高回测运行效率,特别是针对全市场回测
  3. 分类数据获取和回测,方便问题排除
abupy.env.g_data_fetch_mode = EMarketDataFetchMode.E_DATA_FETCH_FORCE_LOCAL
ABuSymbolPd.make_kl_df('usBIDU').tail(1)

下面把数据获取模式恢复为默认的E_DATA_FETCH_NORMAL:

abupy.env.g_data_fetch_mode = EMarketDataFetchMode.E_DATA_FETCH_NORMAL

2. 数据存储的切换

默认的缓存数据存储模式为hdf5,如下所示:

abupy.env.g_data_cache_type
<EDataCacheType.E_DATA_CACHE_HDF5: 0>

可以通过g_data_cache_type切好其它存贮模式,如下使用csv进行数据存贮:

abupy.env.g_data_cache_type = EDataCacheType.E_DATA_CACHE_CSV
ABuSymbolPd.make_kl_df('usTSLA').tail()

3. 数据源的切换

如下显示当前的数据源g_market_source为百度数据源:

abupy.env.g_market_source
<EMarketSourceType.E_MARKET_SOURCE_bd: 0>

如下想要获取比特币的数据,但是输出显示百度的数据源不支持比特币:

ABuSymbolPd.make_kl_df('btc')
Exception kline_pd symbol:btc e:BDApi don't support tc_COIN:btc!

切换数据源为火币数据源,即可正常获取数据,如下:

abupy.env.g_market_source = EMarketSourceType.E_MARKET_SOURCE_hb_tc
ABuSymbolPd.make_kl_df('btc').tail()

类似,下面想要获取期货鸡蛋的数据,但是输出显示火币的数据源不支持期货市场:

ABuSymbolPd.make_kl_df('jd0')
Exception kline_pd symbol:jd0 e:HBApi don't support futures_cn_DCE:JD0!

切换数据源为新浪期货数据源,即可正常获取数据,如下:

abupy.env.g_market_source = EMarketSourceType.E_MARKET_SOURCE_sn_futures
ABuSymbolPd.make_kl_df('jd0').tail()

4. 全市场数据的更新

在之前的章节使用abu.run_loop_back进行交易回测,使用的都是沙盒数据,如果需要使用实时数据,特别是回测交易多的情况下,比如全市场测试,推荐在使用abu.run_loop_back进行回测前先使用abu.run_kl_update将数据进行更新。

在run_kl_update中会首先强制使用网络数据进行全市场数据更新,在更新完毕后会将全市场的交易数据都写入缓存,再abu.run_loop_back运行回测的时候使用本地数据模式,即实现数据更新与策略回测分离,运行效率提高。

下面通过切换至腾讯数据源,然后进行美股数据全市场更新:

%%time
abupy.env.g_market_source = EMarketSourceType.E_MARKET_SOURCE_tx
abupy.env.g_data_cache_type = EDataCacheType.E_DATA_CACHE_HDF5
abu.run_kl_update(start='2011-08-08', end='2017-08-08', market=EMarketTargetType.E_MARKET_TARGET_US, n_jobs=10)

切换至百度数据源,然后进行A股数据全市场更新:

%%time
abupy.env.g_market_source = EMarketSourceType.E_MARKET_SOURCE_bd
abupy.env.g_data_cache_type = EDataCacheType.E_DATA_CACHE_HDF5
abu.run_kl_update(start='2011-08-08', end='2017-08-08', market=EMarketTargetType.E_MARKET_TARGET_CN, n_jobs=10)

切换至网易数据源,然后进行港股数据全市场更新:

%%time
abupy.env.g_market_source = EMarketSourceType.E_MARKET_SOURCE_nt
abupy.env.g_data_cache_type = EDataCacheType.E_DATA_CACHE_HDF5
abu.run_kl_update(start='2011-08-08', end='2017-08-08', market=EMarketTargetType.E_MARKET_TARGET_HK, n_jobs=10)

切换至新浪期货数据源,然后进行期货数据全市场更新:

%%time
abupy.env.g_market_source = EMarketSourceType.E_MARKET_SOURCE_sn_futures
abupy.env.g_data_cache_type = EDataCacheType.E_DATA_CACHE_HDF5
abu.run_kl_update(start='2011-08-08', end='2017-08-08', market=EMarketTargetType.E_MARKET_TARGET_FUTURES_CN, n_jobs=4)

切换至火币数据源,然后进行比特币,莱特币数据全市场更新:

%%time
abupy.env.g_market_source = EMarketSourceType.E_MARKET_SOURCE_hb_tc
abupy.env.g_data_cache_type = EDataCacheType.E_DATA_CACHE_HDF5
abu.run_kl_update(start='2011-08-08', end='2017-08-08', market=EMarketTargetType.E_MARKET_TARGET_TC, n_jobs=2)

5. 接入外部数据源,股票数据源

abupy中内置的数据源:

  • 美股市场:腾讯数据源,百度数据源,网易数据源,新浪数据源
  • 港股市场:腾讯数据源,百度数据源,网易数据源
  • A股市场: 腾讯数据源,百度数据源,网易数据源
  • 期货市场:新浪期货数据源,新浪国际期货数据源
  • 比特币,莱特币:火币网数据源

这些数据源都只是为用户学习使用,并不能保证数据一直通畅,而且如果用户很在乎数据质量,比如有些数据源会有前复权数据错误问题,有些数据源成交量不准确等问题,那么就需要接入用户自己的数据源。

下面首先示例接入股票类型的数据源,首先实现一个数据源返回数据解析类,如下所示:

@AbuDataParseWrap()
class SNUSParser(object):
    """snus数据源解析类,被类装饰器AbuDataParseWrap装饰"""
    def __init__(self, symbol, json_dict):
        """
        :param symbol: 请求的symbol str对象
        :param json_dict: 请求返回的json数据
        """
        data = json_dict
        # 为AbuDataParseWrap准备类必须的属性序列
        if len(data) > 0:
            # 时间日期序列
            self.date = 
  • for item in data] # 开盘价格序列 self.open =
  • for item in data] # 收盘价格序列 self.close =
  • for item in data] # 最高价格序列 self.high =
  • for item in data] # 最低价格序列 self.low =
  • for item in data] # 成交量序列 self.volume =
  • for item in data]

    上面编写的SNUSParser即为一个数据源返回数据解析类:

    1. 数据源解析类需要被类装饰器AbuDataParseWrap装饰
    2. 完成__init__函数,根据这里的数据json_dict来拆分成self.date,self.open,self.close,self.high,self.low,self.volume

    如本例中每一条json数据的格式为:

    {'d': '2017-08-08', 'o': '102.29', 'h': '102.35', 'l': '99.16', 'c': '100.07', 'v': '1834706'}
    

    init函数目的就是通过拆解网络原始数据形成上述的五个基本序列,之后在类装饰器AbuDataParseWrap中会进行数据的再次加工以及规范标准化处理

    更多详情请阅读源代码ABuDataParser

    备注:这里拆解的过程没有在乎效率,只为好理解过程

    在编写数据解析类后就需要编写个数据源类,如下所示,以新浪美股数据源为例:

    class SNUSApi(StockBaseMarket, SupportMixin):
        """snus数据源,支持美股"""
        K_NET_BASE = "http://stock.finance.sina.com.cn/usstock/api/json_v2.php/US_MinKService.getDailyK?" \
                     "symbol=%s&___qn=3n"
    
        def __init__(self, symbol):
            """
            :param symbol: Symbol类型对象
            """
            super(SNUSApi, self).__init__(symbol)
            # 设置数据源解析对象类
            self.data_parser_cls = SNUSParser
    
        def _support_market(self):
            """声明数据源支持美股"""
            return [EMarketTargetType.E_MARKET_TARGET_US]
    
        def kline(self, n_folds=2, start=None, end=None):
            """日k线接口"""
            url = SNUSApi.K_NET_BASE % self._symbol.symbol_code
            data = ABuNetWork.get(url=url, timeout=(10, 60)).json()
            kl_df = self.data_parser_cls(self._symbol, data).df
            if kl_df is None:
                return None
            return StockBaseMarket._fix_kline_pd(kl_df, n_folds, start, end)
    
        def minute(self, n_fold=5, *args, **kwargs):
            """分钟k线接口"""
            raise NotImplementedError('SNUSApi minute NotImplementedError!')
    

    上面编写的SNUSApi即为一个股票数据源类:

    1. 股票类型数据源类需要继承StockBaseMarket
    2. __init__函数中指定数据源解析类
    3. 数据源类需要混入SupportMixin类,实现_support_market方法,声明支持的市场,本例只支持美股市场
    4. 数据源类需要实现kline接口,完成获取指定symbol的日线数据,将日线数据交给数据源解析类进行处理
    5. 数据源类需要实现分钟k线接口,也可以直接raise NotImplementedError

    下面示例使用,如下通过check_support检测是否支持A股,结果显示False:

    SNUSApi(code_to_symbol('sh601766')).check_support(rs=False)
    
    False
    

    如下通过check_support检测是否支持美股,结果显示True:

    SNUSApi(code_to_symbol('usSINA')).check_support(rs=False)
    
    True
    

    如下通过kline接口获取数据,如下所示:

    SNUSApi(code_to_symbol('usSINA')).kline().tail()
    

    接入SNUSApi至abupy系统中,只需要将数据源类名称直接赋予abupy.env.g_private_data_source:

    abupy.env.g_private_data_source = SNUSApi
    

    下面使用make_kl_df接口获取sh601766数据,显示SNUSApi不支持:

    ABuSymbolPd.make_kl_df('sh601766')
    
    Exception kline_pd symbol:sh601766 e:SNUSApi don't support hs_sh:601766!
    

    下面使用make_kl_df接口获取美股数据, 返回的数据即是通过上面实现的SNUSApi返回的:

    ABuSymbolPd.make_kl_df('usSINA').tail()
    

    6. 接入外部数据源,期货数据源

    下面示例接入期货类型的数据源,首先实现一个数据源返回数据解析类,如下所示:

    @AbuDataParseWrap()
    class SNFuturesParser(object):
        """示例期货数据源解析类,被类装饰器AbuDataParseWrap装饰"""
        # noinspection PyUnusedLocal
        def __init__(self, symbol, json_dict):
            """
            :param symbol: 请求的symbol str对象
            :param json_dict: 请求返回的json数据
            """
            data = json_dict
            # 为AbuDataParseWrap准备类必须的属性序列
            if len(data) > 0:
                # 时间日期序列
                self.date = 
  • for item in data] # 开盘价格序列 self.open =
  • for item in data] # 最高价格序列 self.high =
  • for item in data] # 最低价格序列 self.low =
  • for item in data] # 收盘价格序列 self.close =
  • for item in data] # 成交量序列 self.volume =
  • for item in data]

    上面编写的SNFuturesParser与SNUSParser基本相同:被类装饰器AbuDataParseWrap装饰,实现__init__函数

    如本例中每一条json数据的格式为, 所以通过序号解析对应的值:

    ['2017-08-08', '4295.000', '4358.000', '4281.000', '4345.000', '175570']
    

    在编写数据解析类后就需要编写个数据源类,如下所示,以新浪期货数据源为例:

    class SNFuturesApi(FuturesBaseMarket, SupportMixin):
        """sn futures数据源,支持国内期货"""
    
        K_NET_BASE = "http://stock.finance.sina.com.cn/futures/api/json_v2.php/" \
                     "IndexService.getInnerFuturesDailyKLine?symbol=%s"
    
        def __init__(self, symbol):
            """
            :param symbol: Symbol类型对象
            """
            super(SNFuturesApi, self).__init__(symbol)
            # 设置数据源解析对象类
            self.data_parser_cls = SNFuturesParser
    
        def _support_market(self):
            """声明数据源支持期货数据"""
            return [EMarketTargetType.E_MARKET_TARGET_FUTURES_CN]
    
        def kline(self, n_folds=2, start=None, end=None):
            """日k线接口"""
            url = SNFuturesApi.K_NET_BASE % self._symbol.symbol_code
            data = ABuNetWork.get(url=url, timeout=(10, 60)).json()
            kl_df = self.data_parser_cls(self._symbol, data).df
            if kl_df is None:
                return None
            return FuturesBaseMarket._fix_kline_pd(kl_df, n_folds, start, end)
    

    上面编写的SNFuturesApi即为一个期货数据源类:

    1. 期货类型数据源类需要继承FuturesBaseMarket
    2. __init__函数中指定数据源解析类
    3. 数据源类需要混入SupportMixin类,实现_support_market方法,声明支持的市场,本例只支持期货市场
    4. 数据源类需要实现kline接口,完成获取指定symbol的日线数据,将日线数据交给数据源解析类进行处理

    下面示例使用,如下通过check_support检测是否支持美股,结果显示False:

    SNFuturesApi(code_to_symbol('usSINA')).check_support(rs=False)
    
    False
    

    如下通过check_support检测是否支持期货,结果显示True:

    SNFuturesApi(code_to_symbol('jd0')).check_support(rs=False)
    
    True
    

    接入SNFuturesApi至abupy系统中, 使用make_kl_df接口获取期货鸡蛋连续数据:

    abupy.env.g_private_data_source = SNFuturesApi
    ABuSymbolPd.make_kl_df('jd0').tail()
    

    与期货市场类似的是美股期权市场,abupy同样支持美股期权市场的回测分析等操作,但由于暂时没有合适的可对外的数据源提供,所以暂时无示例,用户也可以在abupy中接入自己的美股期权数据源。

    7. 接入外部数据源,比特币,莱特币数据源

    下面示例接入币类市场数据源,首先实现一个数据源返回数据解析类,如下所示:

    @AbuDataParseWrap()
    class HBTCParser(object):
        """示例币类市场数据源解析类,被类装饰器AbuDataParseWrap装饰"""
        def __init__(self, symbol, json_dict):
            """
            :param symbol: 请求的symbol str对象
            :param json_dict: 请求返回的json数据
            """
            data = json_dict
            # 为AbuDataParseWrap准备类必须的属性序列
            if len(data) > 0:
                # 时间日期序列
                self.date = 
  • for item in data] # 开盘价格序列 self.open =
  • for item in data] # 最高价格序列 self.high =
  • for item in data] # 最低价格序列 self.low =
  • for item in data] # 收盘价格序列 self.close =
  • for item in data] # 成交量序列 self.volume =
  • for item in data] # 时间日期进行格式转化,转化为如2017-07-26格式字符串 self.date = list(map(lambda date: ABuDateUtil.fmt_date(date), self.date))

    上面编写的HBTCParser与上面的数据解析类基本相同:被类装饰器AbuDataParseWrap装饰,实现__init__函数

    如本例中每一条json数据的格式为, 所以通过序号解析对应的值:

    ['20170809000000000', 22588.08, 23149.99, 22250.0, 22730.0, 7425.5134]
    

    所以需要使用ABuDateUtil.fmt_date将时间进行格式转化,下面编写对应的数据源类,如下所示,以火币数据源为例:

    class HBApi(TCBaseMarket, SupportMixin):
        """hb数据源,支持币类,比特币,莱特币"""
    
        K_NET_BASE = 'https://www.huobi.com/qt/staticmarket/%s_kline_100_json.js?length=%d'
    
        def __init__(self, symbol):
            """
            :param symbol: Symbol类型对象
            """
            super(HBApi, self).__init__(symbol)
            # 设置数据源解析对象类
            self.data_parser_cls = HBTCParser
    
        def _support_market(self):
            """只支持币类市场"""
            return [EMarketTargetType.E_MARKET_TARGET_TC]
    
        def kline(self, n_folds=2, start=None, end=None):
            """日k线接口"""
            req_cnt = n_folds * 365
            if start is not None and end is not None:
                # 向上取整数,下面使用_fix_kline_pd再次进行剪裁, 要使用current_str_date不能是end
                folds = math.ceil(ABuDateUtil.diff(ABuDateUtil.date_str_to_int(start),
                                                   ABuDateUtil.current_str_date()) / 365)
                req_cnt = folds * 365
    
            url = HBApi.K_NET_BASE % (self._symbol.symbol_code, req_cnt)
            data = ABuNetWork.get(url=url, timeout=(10, 60)).json()
            kl_df = self.data_parser_cls(self._symbol, data).df
            if kl_df is None:
                return None
            return TCBaseMarket._fix_kline_pd(kl_df, n_folds, start, end)
    
        def minute(self, *args, **kwargs):
            """分钟k线接口"""
            raise NotImplementedError('HBApi minute NotImplementedError!')
    

    上面编写的HBApi即为一个支持比特币,莱特币数据源类:

    1. 期货类型数据源类需要继承TCBaseMarket
    2. __init__函数中指定数据源解析类
    3. 数据源类需要混入SupportMixin类,实现_support_market方法,声明支持的市场,本例只支持币类市场
    4. 数据源类需要实现kline接口,完成获取指定symbol的日线数据,将日线数据交给数据源解析类进行处理
    5. 数据源类需要实现分钟k线接口minute,也可raise NotImplementedError

    下面示例使用,如下通过check_support检测是否支持美股,结果显示False:

    HBApi(code_to_symbol('usSINA')).check_support(rs=False)
    
    False
    

    如下通过check_support检测是否支持比特币,结果显示True:

    HBApi(code_to_symbol('btc')).check_support(rs=False)
    
    True
    

    接入HBApi至abupy系统中, 使用make_kl_df接口获取期货比特币数据:

    abupy.env.g_private_data_source = HBApi
    ABuSymbolPd.make_kl_df('btc').tail()
    

    小结:

    abupy内置的数据源仅供学习使用,abupy提供了接入外部数据源的接口和规范,推荐购买数据源接入使用,特别是在实盘中。

    abu量化文档目录章节

    1. 择时策略的开发
    2. 择时策略的优化
    3. 滑点策略与交易手续费
    4. 多支股票择时回测与仓位管理
    5. 选股策略的开发
    6. 回测结果的度量
    7. 寻找策略最优参数和评分
    8. A股市场的回测
    9. 港股市场的回测
    10. 比特币,莱特币的回测
    11. 期货市场的回测
    12. 机器学习与比特币示例
    13. 量化技术分析应用
    14. 量化相关性分析应用
    15. 量化交易和搜索引擎
    16. UMP主裁交易决策
    17. UMP边裁交易决策
    18. 自定义裁判决策交易
    19. 数据源
    20. A股全市场回测
    21. A股UMP决策
    22. 美股全市场回测
    23. 美股UMP决策

    abu量化系统文档教程持续更新中,请关注公众号中的更新提醒。

    更多阿布量化量化技术文章

    更多关于量化交易相关请阅读《量化交易之路》

    更多关于量化交易与机器学习相关请阅读《机器学习之路》

    更多关于abu量化系统请关注微信公众号: abu_quant

    5 评论

    1. GeneZhao说道:

      from abupy import ABuMarketDrawing
      ImportError: cannot import name ABuEnv

      请问上述错误怎样解决

      • 阿布说道:

        请按照第0节环境搭建搭建运行环境,使用pip安装最简单,但如想进一步继续扩展建议使用github上版本进行二次开发

    2. Colin说道:

      请问有计划直接对接TuShare的数据吗?

    3. juman说道:

      第六部分,期货回测,好像不支持股指和国债,其他三个交易所都支持,请问如何解决?是不是要修改k_net_base参数?

    4. 天蓝说道:

      阿布老师,我想咨询下如何后去外汇数据,例如eurusd的

    发表评论

    电子邮件地址不会被公开。 必填项已用*标注