xtquant.xtdata

取行情、财务等数据的相关接口

   1# coding=utf-8
   2"""
   3取行情、财务等数据的相关接口
   4"""
   5
   6import os, sys
   7import time
   8import traceback
   9import json
  10
  11from . import xtbson as bson
  12from . import xtdata_config
  13
  14from .IPythonApiClient import IPythonApiClient as RPCClient
  15
  16__all__ = [
  17    'subscribe_quote'
  18    , 'subscribe_whole_quote'
  19    , 'unsubscribe_quote'
  20    , 'run'
  21    , 'get_market_data'
  22    , 'get_local_data'
  23    , 'get_full_tick'
  24    , 'get_divid_factors'
  25    , 'get_l2_quote'
  26    , 'get_l2_order'
  27    , 'get_l2_transaction'
  28    , 'download_history_data'
  29    , 'get_financial_data'
  30    , 'download_financial_data'
  31    , 'get_instrument_detail'
  32    , 'get_instrument_type'
  33    , 'get_trading_dates'
  34    , 'get_sector_list'
  35    , 'get_stock_list_in_sector'
  36    , 'download_sector_data'
  37    , 'add_sector'
  38    , 'remove_sector'
  39    , 'get_index_weight'
  40    , 'download_index_weight'
  41    , 'get_holidays'
  42    , 'get_trading_calendar'
  43    , 'get_trade_times'
  44    #, 'get_industry'
  45    #, 'get_etf_info'
  46    #, 'get_main_contract'
  47    #, 'download_history_contracts'
  48    , 'download_cb_data'
  49    , 'get_cb_info'
  50]
  51
  52def try_except(func):
  53    def wrapper(*args, **kwargs):
  54        try:
  55            return func(*args, **kwargs)
  56        except Exception:
  57            exc_type, exc_instance, exc_traceback = sys.exc_info()
  58            formatted_traceback = ''.join(traceback.format_tb(exc_traceback))
  59            message = '\n{0} raise {1}:{2}'.format(
  60                formatted_traceback,
  61                exc_type.__name__,
  62                exc_instance
  63            )
  64            # raise exc_type(message)
  65            print(message)
  66            return None
  67
  68    return wrapper
  69
  70
  71CLIENT = None
  72
  73from os.path import abspath, dirname
  74__curdir = dirname(abspath(__file__))
  75
  76__rpc_config = __curdir + '/xtdata.ini'
  77__xtdata_config = __curdir + '/xtdata.ini'
  78
  79from .IPythonApiClient import rpc_init
  80__rpc_init_status = rpc_init(__rpc_config)
  81if __rpc_init_status < 0:
  82    print(f'rpc初始化失败,配置文件:{__rpc_config}')
  83
  84def load_global_config():
  85    res = {}
  86
  87    base_path = os.path.join(os.environ["USERPROFILE"], ".xtquant")
  88    if xtdata_config.client_guid:
  89        full_path = os.path.join(base_path, xtdata_config.client_guid)
  90        if os.path.isfile(os.path.join(full_path, "xtdata.cfg")):
  91            config = json.load(open(os.path.join(full_path, "xtdata.cfg"), "r", encoding = "utf-8"))
  92            res[config.get('port', 58610)] = config
  93    else:
  94        for file in os.listdir(base_path):
  95            full_path = os.path.join(base_path, file)
  96
  97            try:
  98                os.remove(os.path.join(full_path, "running_status"))
  99            except PermissionError:
 100                if os.path.isfile(os.path.join(full_path, "xtdata.cfg")):
 101                    config = json.load(open(os.path.join(full_path, "xtdata.cfg"), "r", encoding = "utf-8"))
 102                    res[config.get('port', 58610)] = config
 103            except Exception as e:
 104                pass
 105    return res
 106
 107def get_client():
 108    global CLIENT
 109    if not CLIENT:
 110        CLIENT = RPCClient('client_xtdata', __xtdata_config)
 111
 112        try:
 113            configs = load_global_config()
 114            configs = sorted(configs.items(), key = lambda x:x[0])
 115            for port, config in configs:
 116                CLIENT.set_remote_addr('localhost', port)
 117                CLIENT.reset()
 118                succ, errmsg = CLIENT.connect_ex()
 119                if succ:
 120                    init_data_dir()
 121                    break
 122        except Exception as e:
 123            pass
 124
 125        if not CLIENT.is_connected():
 126            CLIENT.load_config(__xtdata_config)
 127            CLIENT.reset()
 128
 129    if not CLIENT.is_connected():
 130        succ, errmsg = CLIENT.connect_ex()
 131        if succ:
 132            init_data_dir()
 133        else:
 134            raise Exception("无法连接行情服务!")
 135    return CLIENT
 136
 137def reconnect(ip = 'localhost', port = None):
 138    global CLIENT
 139    CLIENT = None
 140    if not CLIENT:
 141        if port == None:
 142            CLIENT = get_client()
 143        else:
 144            CLIENT = RPCClient('client_xtdata', __xtdata_config)
 145            CLIENT.set_remote_addr(ip, port)
 146            CLIENT.reset()
 147            succ, errmsg = CLIENT.connect_ex()
 148            if succ:
 149                init_data_dir()
 150
 151    if not CLIENT.is_connected():
 152        succ, errmsg = CLIENT.connect_ex()
 153        if succ:
 154            init_data_dir()
 155        else:
 156            raise Exception("无法连接行情服务!")
 157    return
 158
 159default_data_dir = '../userdata_mini/datadir'
 160data_dir = default_data_dir
 161
 162def init_data_dir():
 163    global data_dir
 164
 165    try:
 166        client = get_client()
 167        data_dir = client.get_data_dir()
 168
 169        if data_dir == "":
 170            data_dir = os.path.join(client.get_app_dir(), default_data_dir)
 171
 172        if data_dir != default_data_dir:
 173            data_dir = os.path.abspath(data_dir)
 174    except Exception as e:
 175        pass
 176
 177    return data_dir
 178
 179debug_mode = 0
 180
 181def create_array(shape, dtype_tuple, capsule, size):
 182    import numpy as np
 183    import ctypes
 184
 185    ctypes.pythonapi.PyCapsule_GetPointer.restype = ctypes.POINTER(ctypes.c_char)
 186    ctypes.pythonapi.PyCapsule_GetPointer.argtypes = [ctypes.py_object, ctypes.c_char_p]
 187    buff = ctypes.pythonapi.PyCapsule_GetPointer(capsule, None)
 188    base_type = size * buff._type_
 189
 190    for dim in shape[::-1]:
 191        base_type = dim * base_type
 192    p_arr_type = ctypes.POINTER(base_type)
 193    obj = ctypes.cast(buff, p_arr_type).contents
 194    obj._base = capsule
 195    return np.ndarray(shape = shape, dtype = np.dtype(dtype_tuple), buffer = obj)
 196
 197from .IPythonApiClient import register_create_nparray
 198register_create_nparray(create_array)
 199
 200def get_industry(industry_name):
 201    '''
 202    获取行业成份股,支持申万行业和证监会行业
 203    :param industry_name: (str)行业名称
 204    :return: list
 205    '''
 206    client = get_client()
 207    return client.get_industry(industry_name)
 208
 209
 210def get_stock_list_in_sector(sector_name):
 211    '''
 212    获取板块成份股,支持客户端左侧板块列表中任意的板块,包括自定义板块
 213    :param sector_name: (str)板块名称
 214    :return: list
 215    '''
 216    client = get_client()
 217    return client.get_stock_list_in_sector(sector_name, 0)
 218
 219
 220def get_index_weight(index_code):
 221    '''
 222    获取某只股票在某指数中的绝对权重
 223    :param index_code: (str)指数名称
 224    :return: dict
 225    '''
 226    client = get_client()
 227    return client.get_weight_in_index(index_code)
 228
 229
 230def get_financial_data(stock_list, table_list=[], start_time='', end_time='', report_type='report_time'):
 231    '''
 232     获取财务数据
 233    :param stock_list: (list)合约代码列表
 234    :param table_list: (list)报表名称列表
 235    :param start_time: (str)起始时间
 236    :param end_time: (str)结束时间
 237    :param report_type: (str) 时段筛选方式 'announce_time' / 'report_time'
 238    :return:
 239        field: list[str]
 240        date: list[int]
 241        stock: list[str]
 242        value: list[list[float]]
 243    '''
 244    client = get_client()
 245    all_table = {
 246        'Balance' : 'ASHAREBALANCESHEET'
 247        , 'Income' : 'ASHAREINCOME'
 248        , 'CashFlow' : 'ASHARECASHFLOW'
 249        , 'Capital' : 'CAPITALSTRUCTURE'
 250        , 'HolderNum' : 'SHAREHOLDER'
 251        , 'Top10Holder' : 'TOP10HOLDER'
 252        , 'Top10FlowHolder' : 'TOP10FLOWHOLDER'
 253        , 'PershareIndex' : 'PERSHAREINDEX'
 254    }
 255
 256    if not table_list:
 257        table_list = list(all_table.keys())
 258
 259    all_table_upper = {table.upper() : all_table[table] for table in all_table}
 260    req_list = []
 261    names = {}
 262    for table in table_list:
 263        req_table = all_table_upper.get(table.upper(), table)
 264        req_list.append(req_table)
 265        names[req_table] = table
 266
 267    data = {}
 268    sl_len = 20
 269    stock_list2 = [stock_list[i : i + sl_len] for i in range(0, len(stock_list), sl_len)]
 270    for sl in stock_list2:
 271        data2 = client.get_financial_data(sl, req_list, start_time, end_time, report_type)
 272        for s in data2:
 273            data[s] = data2[s]
 274
 275    import time
 276    import math
 277    def conv_date(data, key, key2):
 278        if key in data:
 279            tmp_data = data[key]
 280            if math.isnan(tmp_data):
 281                if key2 not in data or math.isnan(data[key2]):
 282                    data[key] = ''
 283                else:
 284                    tmp_data = data[key2]
 285            data[key] = time.strftime('%Y%m%d', time.localtime(tmp_data / 1000))
 286        return
 287
 288    result = {}
 289    import pandas as pd
 290    for stock in data:
 291        stock_data = data[stock]
 292        result[stock] = {}
 293        for table in stock_data:
 294            table_data = stock_data[table]
 295            for row_data in table_data:
 296                conv_date(row_data, 'm_anntime', 'm_timetag')
 297                conv_date(row_data, 'm_timetag', '')
 298                conv_date(row_data, 'declareDate', '')
 299                conv_date(row_data, 'endDate', '')
 300            result[stock][names[table]] = pd.DataFrame(table_data)
 301    return result
 302
 303
 304def get_market_data_ori(
 305    field_list = [], stock_list = [], period = '1d'
 306    , start_time = '', end_time = '', count = -1
 307    , dividend_type = 'none', fill_data = True
 308):
 309    client = get_client()
 310    enable_read_from_local = period in {'1m', '5m', '15m', '30m', '1h', '1d'}
 311    global debug_mode
 312    return client.get_market_data3(field_list, stock_list, period, start_time, end_time, count, dividend_type, fill_data, 'v2', enable_read_from_local, debug_mode)
 313
 314
 315def get_market_data(
 316    field_list = [], stock_list = [], period = '1d'
 317    , start_time = '', end_time = '', count = -1
 318    , dividend_type = 'none', fill_data = True
 319):
 320    '''
 321    获取历史行情数据
 322    :param field_list: 行情数据字段列表,[]为全部字段
 323        K线可选字段:
 324            "time"                #时间戳
 325            "open"                #开盘价
 326            "high"                #最高价
 327            "low"                 #最低价
 328            "close"               #收盘价
 329            "volume"              #成交量
 330            "amount"              #成交额
 331            "settle"              #今结算
 332            "openInterest"        #持仓量
 333        分笔可选字段:
 334            "time"                #时间戳
 335            "lastPrice"           #最新价
 336            "open"                #开盘价
 337            "high"                #最高价
 338            "low"                 #最低价
 339            "lastClose"           #前收盘价
 340            "amount"              #成交总额
 341            "volume"              #成交总量
 342            "pvolume"             #原始成交总量
 343            "stockStatus"         #证券状态
 344            "openInt"             #持仓量
 345            "lastSettlementPrice" #前结算
 346            "askPrice1", "askPrice2", "askPrice3", "askPrice4", "askPrice5" #卖一价~卖五价
 347            "bidPrice1", "bidPrice2", "bidPrice3", "bidPrice4", "bidPrice5" #买一价~买五价
 348            "askVol1", "askVol2", "askVol3", "askVol4", "askVol5"           #卖一量~卖五量
 349            "bidVol1", "bidVol2", "bidVol3", "bidVol4", "bidVol5"           #买一量~买五量
 350    :param stock_list: 股票代码 "000001.SZ"
 351    :param period: 周期 分笔"tick" 分钟线"1m"/"5m" 日线"1d"
 352    :param start_time: 起始时间 "20200101" "20200101093000"
 353    :param end_time: 结束时间 "20201231" "20201231150000"
 354    :param count: 数量 -1全部/n: 从结束时间向前数n个
 355    :param dividend_type: 除权类型"none" "front" "back" "front_ratio" "back_ratio"
 356    :param fill_data: 对齐时间戳时是否填充数据,仅对K线有效,分笔周期不对齐时间戳
 357        为True时,以缺失数据的前一条数据填充
 358            open、high、low、close 为前一条数据的close
 359            amount、volume为0
 360            settle、openInterest 和前一条数据相同
 361        为False时,缺失数据所有字段填NaN
 362    :return: 数据集,分笔数据和K线数据格式不同
 363        period为'tick'时:{stock1 : value1, stock2 : value2, ...}
 364            stock1, stock2, ... : 合约代码
 365            value1, value2, ... : np.ndarray 数据列表,按time增序排列
 366        period为其他K线周期时:{field1 : value1, field2 : value2, ...}
 367            field1, field2, ... : 数据字段
 368            value1, value2, ... : pd.DataFrame 字段对应的数据,各字段维度相同,index为stock_list,columns为time_list
 369    '''
 370    if period in {'1m', '5m', '15m', '30m', '1h', '1d'}:
 371        import pandas as pd
 372        index, data = get_market_data_ori(field_list, stock_list, period, start_time, end_time, count, dividend_type, fill_data)
 373        result = {}
 374        for field in data:
 375            result[field] = pd.DataFrame(data[field], index = index[0], columns = index[1])
 376        return result
 377
 378    return get_market_data_ori(field_list, stock_list, period, start_time, end_time, count, dividend_type, fill_data)
 379
 380
 381def get_market_data_ex_ori(
 382    field_list = [], stock_list = [], period = '1d'
 383    , start_time = '', end_time = '', count = -1
 384    , dividend_type = 'none', fill_data = True
 385):
 386    client = get_client()
 387    enable_read_from_local = period in {'1m', '5m', '15m', '30m', '1h', '1d'}
 388    global debug_mode
 389    return client.get_market_data3(field_list, stock_list, period, start_time, end_time, count, dividend_type, fill_data, 'v3', enable_read_from_local, debug_mode)
 390
 391
 392def get_market_data_ex(
 393    field_list = [], stock_list = [], period = '1d'
 394    , start_time = '', end_time = '', count = -1
 395    , dividend_type = 'none', fill_data = True
 396):
 397    '''
 398    获取历史行情数据
 399    :param field_list: 行情数据字段列表,[]为全部字段
 400        K线可选字段:
 401            "time"                #时间戳
 402            "open"                #开盘价
 403            "high"                #最高价
 404            "low"                 #最低价
 405            "close"               #收盘价
 406            "volume"              #成交量
 407            "amount"              #成交额
 408            "settle"              #今结算
 409            "openInterest"        #持仓量
 410        分笔可选字段:
 411            "time"                #时间戳
 412            "lastPrice"           #最新价
 413            "open"                #开盘价
 414            "high"                #最高价
 415            "low"                 #最低价
 416            "lastClose"           #前收盘价
 417            "amount"              #成交总额
 418            "volume"              #成交总量
 419            "pvolume"             #原始成交总量
 420            "stockStatus"         #证券状态
 421            "openInt"             #持仓量
 422            "lastSettlementPrice" #前结算
 423            "askPrice1", "askPrice2", "askPrice3", "askPrice4", "askPrice5" #卖一价~卖五价
 424            "bidPrice1", "bidPrice2", "bidPrice3", "bidPrice4", "bidPrice5" #买一价~买五价
 425            "askVol1", "askVol2", "askVol3", "askVol4", "askVol5"           #卖一量~卖五量
 426            "bidVol1", "bidVol2", "bidVol3", "bidVol4", "bidVol5"           #买一量~买五量
 427    :param stock_list: 股票代码 "000001.SZ"
 428    :param period: 周期 分笔"tick" 分钟线"1m"/"5m" 日线"1d"
 429    :param start_time: 起始时间 "20200101" "20200101093000"
 430    :param end_time: 结束时间 "20201231" "20201231150000"
 431    :param count: 数量 -1全部/n: 从结束时间向前数n个
 432    :param dividend_type: 除权类型"none" "front" "back" "front_ratio" "back_ratio"
 433    :param fill_data: 对齐时间戳时是否填充数据,仅对K线有效,分笔周期不对齐时间戳
 434        为True时,以缺失数据的前一条数据填充
 435            open、high、low、close 为前一条数据的close
 436            amount、volume为0
 437            settle、openInterest 和前一条数据相同
 438        为False时,缺失数据所有字段填NaN
 439    :return: 数据集,分笔数据和K线数据格式不同
 440        period为'tick'时:{stock1 : value1, stock2 : value2, ...}
 441            stock1, stock2, ... : 合约代码
 442            value1, value2, ... : np.ndarray 数据列表,按time增序排列
 443        period为其他K线周期时:{field1 : value1, field2 : value2, ...}
 444            field1, field2, ... : 数据字段
 445            value1, value2, ... : pd.DataFrame 字段对应的数据,各字段维度相同,index为stock_list,columns为time_list
 446    '''
 447
 448    if period in {'1m', '5m', '15m', '30m', '1h', '1d'}:
 449        ifield = 'time'
 450        query_field_list = field_list if (not field_list) or (ifield in field_list) else [ifield] + field_list
 451        ori_data = _get_market_data_ex_ori_221207(query_field_list, stock_list, period, start_time, end_time, count, dividend_type, fill_data)
 452
 453        import pandas as pd
 454        result = {}
 455
 456        if not ori_data:
 457            return result
 458        stime_fmt = '%Y%m%d' if period == '1d' else '%Y%m%d%H%M%S'
 459        for s, data in ori_data.items():
 460            cols = field_list if field_list else list(data.dtype.names)
 461            sdata = pd.DataFrame(data, columns = cols)
 462            sdata.index = [timetag_to_datetime(t, stime_fmt) for t in data['time']]
 463            result[s] = sdata
 464
 465        return result
 466
 467    import pandas as pd
 468    result = {}
 469
 470    ifield = 'time'
 471    query_field_list = field_list if (not field_list) or (ifield in field_list) else [ifield] + field_list
 472    ori_data = get_market_data_ex_ori(query_field_list, stock_list, period, start_time, end_time, count, dividend_type, fill_data)
 473
 474    fl = field_list
 475    stime_fmt = '%Y%m%d' if period == '1d' else '%Y%m%d%H%M%S'
 476    if fl:
 477        fl2 = fl if ifield in fl else [ifield] + fl
 478        for s in ori_data:
 479            sdata = pd.DataFrame(ori_data[s], columns = fl2)
 480            sdata2 = sdata[fl]
 481            sdata2.index = sdata[ifield]
 482            sdata2.index.name = 'stime'
 483            result[s] = sdata2
 484    else:
 485        for s in ori_data:
 486            sdata = pd.DataFrame(ori_data[s])
 487            sdata.index = [timetag_to_datetime(t, stime_fmt) for t in sdata[ifield]]
 488            sdata.index.name = 'stime'
 489            result[s] = sdata
 490
 491    return result
 492
 493
 494def _get_market_data_ex_ori_221207(
 495    field_list = [], stock_list = [], period = '1d'
 496    , start_time = '', end_time = '', count = -1
 497    , dividend_type = 'none', fill_data = True
 498):
 499    client = get_client()
 500    enable_read_from_local = period in {'1m', '5m', '15m', '30m', '1h', '1d'}
 501    global debug_mode
 502
 503    fi, sdl = client.get_market_data3(field_list, stock_list, period, start_time, end_time, count, dividend_type, fill_data, 'v4', enable_read_from_local, debug_mode)
 504
 505    import numpy as np
 506    return {s: np.frombuffer(b, fi) for s, b in sdl}
 507
 508
 509def _get_market_data_ex_221207(
 510    field_list = [], stock_list = [], period = '1d'
 511    , start_time = '', end_time = '', count = -1
 512    , dividend_type = 'none', fill_data = True
 513):
 514    ifield = 'time'
 515    query_field_list = field_list if (not field_list) or (ifield in field_list) else [ifield] + field_list
 516
 517    if period in {'1m', '5m', '15m', '30m', '1h', '1d'}:
 518        ori_data = _get_market_data_ex_ori_221207(query_field_list, stock_list, period, start_time, end_time, count, dividend_type, fill_data)
 519    else:
 520        ori_data = get_market_data_ex_ori(query_field_list, stock_list, period, start_time, end_time, count, dividend_type, fill_data)
 521
 522    import pandas as pd
 523    result = {}
 524
 525    for s, data in ori_data.items():
 526        cols = field_list if field_list else list(data.dtype.names)
 527        sdata = pd.DataFrame(data, columns = cols)
 528        sdata.index = pd.to_datetime((data['time'] + 28800000) * 1000000)
 529        result[s] = sdata
 530
 531    return result
 532
 533
 534get_market_data3 = _get_market_data_ex_221207
 535
 536
 537def get_local_data(field_list=[], stock_code=[], period='1d', start_time='', end_time='', count=-1,
 538                              dividend_type='none', fill_data=True, data_dir=data_dir):
 539    return None
 540
 541
 542def get_l2_quote(field_list=[], stock_code='', start_time='', end_time='', count=-1):
 543    '''
 544    level2实时行情
 545    '''
 546    client = get_client()
 547    datas = client.get_market_data3(field_list, [stock_code], 'l2quote', start_time, end_time, count, 'none', False, '', False, False)
 548    if datas:
 549        return datas[stock_code]
 550    return None
 551
 552
 553def get_l2_order(field_list=[], stock_code='', start_time='', end_time='', count=-1):
 554    '''
 555    level2逐笔委托
 556    '''
 557    client = get_client()
 558    datas = client.get_market_data3(field_list, [stock_code], 'l2order', start_time, end_time, count, 'none', False, '', False, False)
 559    if datas:
 560        return datas[stock_code]
 561    return None
 562
 563
 564def get_l2_transaction(field_list=[], stock_code='', start_time='', end_time='', count=-1):
 565    '''
 566    level2逐笔成交
 567    '''
 568    client = get_client()
 569    datas = client.get_market_data3(field_list, [stock_code], 'l2transaction', start_time, end_time, count, 'none', False, '', False, False)
 570    if datas:
 571        return datas[stock_code]
 572    return None
 573
 574
 575def get_divid_factors(stock_code, start_time='', end_time=''):
 576    '''
 577    获取除权除息日及对应的权息
 578    :param stock_code: (str)股票代码
 579    :param date: (str)日期
 580    :return: pd.DataFrame 数据集
 581    '''
 582    client = get_client()
 583    datas = client.get_divid_factors(stock_code, start_time, end_time)
 584    import pandas as pd
 585    datas = pd.DataFrame(datas).T
 586    return datas
 587
 588
 589@try_except
 590def getDividFactors(stock_code, date):
 591    client = get_client()
 592    resData = client.get_divid_factors(stock_code, date)
 593    res = {resData[i]: [resData[i + 1][j] for j in
 594                        range(0, len(resData[i + 1]), 1)] for i in range(0, len(resData), 2)}
 595    if isinstance(res, dict):
 596        for k, v in res.items():
 597            if isinstance(v, list) and len(v) > 5:
 598                v[5] = int(v[5])
 599    return res
 600
 601
 602def get_main_contract(code_market):
 603    '''
 604    获取当前期货主力合约
 605    :param code_market: (str)股票代码
 606    :return: str
 607    '''
 608    client = get_client()
 609    return client.get_main_contract(code_market)
 610
 611def datetime_to_timetag(datetime, format = "%Y%m%d%H%M%S"):
 612    if len(datetime) == 8:
 613        format = "%Y%m%d"
 614    timetag = time.mktime(time.strptime(datetime, format))
 615    return timetag * 1000
 616
 617def timetag_to_datetime(timetag, format):
 618    '''
 619    将毫秒时间转换成日期时间
 620    :param timetag: (int)时间戳毫秒数
 621    :param format: (str)时间格式
 622    :return: str
 623    '''
 624    return timetagToDateTime(timetag, format)
 625
 626
 627@try_except
 628def timetagToDateTime(timetag, format):
 629    import time
 630    timetag = timetag / 1000
 631    time_local = time.localtime(timetag)
 632    return time.strftime(format, time_local)
 633
 634
 635def get_trading_dates(market, start_time='', end_time='', count=-1):
 636    '''
 637    根据市场获取交易日列表
 638    : param market: 市场代码 e.g. 'SH','SZ','IF','DF','SF','ZF'等
 639    : param start_time: 起始时间 '20200101'
 640    : param end_time: 结束时间 '20201231'
 641    : param count: 数据个数,-1为全部数据
 642    :return list(long) 毫秒数的时间戳列表
 643    '''
 644    client = get_client()
 645    datas = client.get_trading_dates_by_market(market, start_time, end_time, count)
 646    return list(datas.values())
 647
 648
 649def get_full_tick(code_list):
 650    '''
 651    获取盘口tick数据
 652    :param code_list: (list)stock.market组成的股票代码列表
 653    :return: dict
 654    {'stock.market': {dict}}
 655    '''
 656    client = get_client()
 657    resp_json = client.get_full_tick(code_list)
 658    return json.loads(resp_json)
 659
 660
 661def subscribe_callback_wrapper(callback):
 662    import traceback
 663    def subscribe_callback(datas):
 664        try:
 665            if type(datas) == bytes:
 666                datas = bson.BSON.decode(datas)
 667            callback(datas)
 668        except:
 669            print('subscribe_quote callback error:', callback)
 670            traceback.print_exc()
 671    return subscribe_callback
 672
 673
 674def subscribe_quote(stock_code, period='1d', start_time='', end_time='', count=0, callback=None):
 675    '''
 676    订阅股票行情数据
 677    :param stock_code: 股票代码 e.g. "000001.SZ"
 678    :param start_time: 开始时间,格式YYYYMMDD/YYYYMMDDhhmmss/YYYYMMDDhhmmss.milli,e.g."20200427" "20200427093000" "20200427093000.000"
 679        若取某日全量历史数据,时间需要具体到秒,e.g."20200427093000"
 680    :param end_time: 结束时间 同“开始时间”
 681    :param count: 数量 -1全部/n: 从结束时间向前数n个
 682    :param period: 周期 分笔"tick" 分钟线"1m"/"5m" 日线"1d"
 683    :param callback:
 684        订阅回调函数onSubscribe(datas)
 685        :param datas: {stock : [data1, data2, ...]} 数据字典
 686    :return: int 订阅序号
 687    '''
 688    if callback:
 689        callback = subscribe_callback_wrapper(callback)
 690
 691    meta = {'stockCode': stock_code, 'period': period}
 692    region = {'startTime': start_time, 'endTime': end_time, 'count': count}
 693
 694    client = get_client()
 695    return client.subscribe_quote(bson.BSON.encode(meta), bson.BSON.encode(region), callback)
 696
 697
 698def subscribe_l2thousand(stock_code, gear_num = 0, callback = None):
 699    '''
 700    订阅千档盘口
 701    '''
 702    if callback:
 703        callback = subscribe_callback_wrapper(callback)
 704
 705    meta = {'stockCode': stock_code, 'period': 'l2thousand'}
 706    region = {'thousandGearNum': gear_num, 'thousandDetailGear': 0, 'thousandDetailNum': 0}
 707
 708    client = get_client()
 709    return client.subscribe_quote(bson.BSON.encode(meta), bson.BSON.encode(region), callback)
 710
 711
 712def subscribe_whole_quote(code_list, callback=None):
 713    '''
 714    订阅全推数据
 715    :param code_list: 市场代码列表 ["SH", "SZ"]
 716    :param callback:
 717        订阅回调函数onSubscribe(datas)
 718        :param datas: {stock1 : data1, stock2 : data2, ...} 数据字典
 719    :return: int 订阅序号
 720    '''
 721    if callback:
 722        callback = subscribe_callback_wrapper(callback)
 723
 724    client = get_client()
 725    return client.subscribe_whole_quote(code_list, callback)
 726
 727
 728def unsubscribe_quote(seq):
 729    '''
 730    :param seq: 订阅接口subscribe_quote返回的订阅号
 731    :return:
 732    '''
 733    client = get_client()
 734    return client.unsubscribe_quote(seq)
 735
 736
 737def run():
 738    '''阻塞线程接收行情回调'''
 739    import time
 740    client = get_client()
 741    while True:
 742        time.sleep(3)
 743        if not client.is_connected():
 744            raise Exception('行情服务连接断开')
 745            break
 746    return
 747
 748
 749def get_sector_list():
 750    '''
 751    获取板块列表
 752    :return: (list[str])
 753    '''
 754    client = get_client()
 755    return client.get_sector_list()
 756
 757
 758def add_sector(sector_name, stock_list):
 759    '''
 760    增加自定义板块
 761    :param sector_name: 板块名称 e.g. "我的自选"
 762    :param stock_list: (list)stock.market组成的股票代码列表
 763    '''
 764    client = get_client()
 765    return client.add_sector(sector_name, stock_list, 1)
 766
 767
 768def remove_sector(sector_name):
 769    '''
 770    删除自定义板块
 771    :param sector_name: 板块名称 e.g. "我的自选"
 772    '''
 773    client = get_client()
 774    return client.add_sector(sector_name, [], -1)
 775
 776
 777def get_instrument_detail(stock_code):
 778    '''
 779    获取合约信息
 780    :param stock_code: 股票代码 e.g. "600000.SH"
 781    :return: dict
 782        ExchangeID(str):合约市场代码, InstrumentID(str):合约代码, InstrumentName(str):合约名称, ProductID(str):合约的品种ID(期货), ProductName(str)合约的品种名称(期货),
 783        CreateDate(int):上市日期(期货), OpenDate(int):IPO日期(股票), ExpireDate(int):退市日或者到期日, PreClose(double):前收盘价格, SettlementPrice(double):前结算价格,
 784        UpStopPrice(double):当日涨停价, DownStopPrice(double):当日跌停价, FloatVolume(double):流通股本, TotalVolume(double):总股本, LongMarginRatio(double):多头保证金率,
 785        ShortMarginRatio(double):空头保证金率, PriceTick(double):最小变价单位, VolumeMultiple(int):合约乘数(对期货以外的品种,默认是1),
 786        MainContract(int):主力合约标记,1、2、3分别表示第一主力合约,第二主力合约,第三主力合约, LastVolume(int):昨日持仓量, InstrumentStatus(int):合约停牌状态,
 787        IsTrading(bool):合约是否可交易, IsRecent(bool):是否是近月合约,
 788    '''
 789    client = get_client()
 790    inst = client.get_instrument_detail(stock_code)
 791    if not inst:
 792        return None
 793    field_list = [
 794            'ExchangeID'
 795            , 'InstrumentID'
 796            , 'InstrumentName'
 797            , 'ProductID'
 798            , 'ProductName'
 799            , 'CreateDate'
 800            , 'OpenDate'
 801            , 'ExpireDate'
 802            , 'PreClose'
 803            , 'SettlementPrice'
 804            , 'UpStopPrice'
 805            , 'DownStopPrice'
 806            , 'FloatVolume'
 807            , 'TotalVolume'
 808            , 'LongMarginRatio'
 809            , 'ShortMarginRatio'
 810            , 'PriceTick'
 811            , 'VolumeMultiple'
 812            , 'MainContract'
 813            , 'LastVolume'
 814            , 'InstrumentStatus'
 815            , 'IsTrading'
 816            , 'IsRecent'
 817        ]
 818    ret = {}
 819    for field in field_list:
 820        ret[field] = inst.get(field)
 821
 822    exfield_list = [
 823            'ProductTradeQuota'
 824            , 'ContractTradeQuota'
 825            , 'ProductOpenInterestQuota'
 826            , 'ContractOpenInterestQuota'
 827        ]
 828    inst_ex = inst.get('ExtendInfo', {})
 829    for field in exfield_list:
 830        ret[field] = inst_ex.get(field)
 831
 832    def convNum2Str(field):
 833        if field in ret and isinstance(ret[field], int):
 834            ret[field] = str(ret[field])
 835    convNum2Str('CreateDate')
 836    convNum2Str('OpenDate')
 837    return ret
 838
 839
 840def get_etf_info(stockCode):
 841    '''
 842    获取etf申赎清单
 843    :param stockCode: ETF代码 e.g. "159811.SZ"
 844    :return: dict
 845        etfCode(str):ETF代码, etfExchID(str):ETF市场, prCode(str):基金申赎代码,
 846        stocks(dict):成分股
 847            key: 成分股代码 e.g. "000063.SZ"
 848            value: dict
 849                componentExchID(str):成份股市场代码, componentCode(str):成份股代码, componentName(str):成份股名称, componentVolume(int):成份股数量
 850    '''
 851    client = get_client()
 852    return client.get_etf_info(stockCode)
 853
 854
 855def download_index_weight():
 856    '''
 857    下载指数权重数据
 858    '''
 859    client = get_client()
 860    client.down_index_weight()
 861
 862
 863def download_history_contracts():
 864    '''
 865    下载过期合约数据
 866    '''
 867    client = get_client()
 868    client.down_history_contracts()
 869
 870
 871class TimeListBuilder:
 872    def __init__(self):
 873        # param
 874        self.period = 3600000
 875        self.open_list = None  # [['093000', '113000'], ['130000', '150000']]
 876
 877        # build up
 878        self.cur_date = 0
 879        self.date_offset = 3600000 * 8
 880        self.day_time_list = []
 881        self.cur_index = 0
 882
 883    def init(self):
 884        if not self.open_list: return False
 885        if self.period <= 0: return False
 886
 887        for scope in self.open_list:
 888            hour, minute, second = self.parse_time(scope[0])
 889            start = (((hour * 60) + minute) * 60 + second) * 1000
 890            hour, minute, second = self.parse_time(scope[1])
 891            end = (((hour * 60) + minute) * 60 + second) * 1000
 892            t = start + self.period
 893            while t <= end:
 894                self.day_time_list.append(t)
 895                t += self.period
 896        self.cur_index = 0
 897
 898        if not self.day_time_list: return False
 899        return True
 900
 901    def parse_time(self, ft):
 902        ft = int(ft)
 903        second = ft % 100
 904        ft = int((ft - second) / 100)
 905        minute = ft % 100
 906        ft = int((ft - minute) / 100)
 907        hour = ft % 100
 908        return hour, minute, second
 909
 910    def get(self):
 911        if self.day_time_list:
 912            return self.cur_date + self.day_time_list[self.cur_index]
 913        else:
 914            return self.cur_date
 915
 916    def next(self):
 917        self.cur_index += 1
 918        if self.cur_index >= len(self.day_time_list):
 919            self.cur_date += 86400000
 920            self.cur_index = 0
 921
 922    def locate(self, t):
 923        day_time = t % 86400000
 924        self.cur_date = t - day_time - self.date_offset
 925        self.cur_index = 0
 926        for i in range(len(self.day_time_list)):
 927            te = self.day_time_list[i]
 928            if t < te:
 929                self.cur_index = i
 930                break
 931
 932
 933class MergeData:
 934    def __init__(self):
 935        # param
 936        self.period = 3600000
 937        self.open_list = None  # [['093000', '113000'], ['130000', '150000']]
 938        self.merge_func = None
 939
 940        # build up
 941        self.timer = None
 942
 943        # result
 944        self.time_list = []
 945        self.data_list = []
 946
 947    def init(self):
 948        self.timer = TimeListBuilder()
 949        self.timer.open_list = self.open_list
 950        self.timer.period = self.period
 951        self.timer.init()
 952
 953    def push(self, t, data):
 954        if self.time_list:
 955            te = self.time_list[-1]
 956            if t <= te:
 957                self.data_list[-1] = self.merge_func(self.data_list[-1], data)
 958            else:
 959                self.timer.next()
 960                te = self.timer.get()
 961                self.time_list.append(te)
 962                self.data_list.append(data)
 963        else:
 964            self.timer.locate(t)
 965
 966            te = self.timer.get()
 967            self.time_list.append(te)
 968            self.data_list.append(data)
 969
 970
 971def merge_data_sum(data1, data2):
 972    return data1 + data2
 973
 974
 975def merge_data_max(data1, data2):
 976    return max(data1, data2)
 977
 978
 979def merge_data_min(data1, data2):
 980    return min(data1, data2)
 981
 982
 983def merge_data_first(data1, data2):
 984    return data1
 985
 986
 987def merge_data_last(data1, data2):
 988    return data2
 989
 990
 991def merge_data(time_list, data_list, period, open_list, field):
 992    merge_func = {}
 993    merge_func['open'] = merge_data_first
 994    merge_func['high'] = merge_data_max
 995    merge_func['low'] = merge_data_min
 996    merge_func['close'] = merge_data_last
 997    merge_func['volume'] = merge_data_sum
 998    merge_func['amount'] = merge_data_sum
 999
1000    md = MergeData()
1001    md.period = period
1002    md.open_list = open_list
1003    md.merge_func = merge_func[field.lower()]
1004    md.init()
1005
1006    for i in range(len(time_list)):
1007        md.push(time_list[i], data_list[i])
1008
1009    return md.time_list, md.data_list
1010
1011
1012def download_history_data(stock_code, period, start_time='', end_time=''):
1013    '''
1014    :param stock_code: 股票代码 e.g. "000001.SZ"
1015    :param period: 周期 分笔"tick" 分钟线"1m"/"5m" 日线"1d"
1016    :param start_time: 开始时间,格式YYYYMMDD/YYYYMMDDhhmmss/YYYYMMDDhhmmss.milli,e.g."20200427" "20200427093000" "20200427093000.000"
1017        若取某日全量历史数据,时间需要具体到秒,e.g."20200427093000"
1018    :param end_time: 结束时间 同上,若是未来某时刻会被视作当前时间
1019    :return: bool 是否成功
1020    '''
1021    client = get_client()
1022    client.supply_history_data(stock_code, period, start_time, end_time)
1023
1024
1025supply_history_data = download_history_data
1026
1027
1028def download_history_data2(stock_list, period, start_time='', end_time='', callback=None):
1029    '''
1030    :param stock_code: 股票代码 e.g. "000001.SZ"
1031    :param period: 周期 分笔"tick" 分钟线"1m"/"5m" 日线"1d"
1032    :param start_time: 开始时间,格式YYYYMMDD/YYYYMMDDhhmmss/YYYYMMDDhhmmss.milli,e.g."20200427" "20200427093000" "20200427093000.000"
1033        若取某日全量历史数据,时间需要具体到秒,e.g."20200427093000"
1034    :param end_time: 结束时间 同上,若是未来某时刻会被视作当前时间
1035    :return: bool 是否成功
1036    '''
1037    client = get_client()
1038
1039    status = [False, 0, 1, '']
1040    def on_progress(data):
1041        try:
1042            finished = data['finished']
1043            total = data['total']
1044            done = (finished >= total)
1045            status[0] = done
1046            status[1] = finished
1047            status[2] = total
1048
1049            try:
1050                callback(data)
1051            except:
1052                pass
1053
1054            return done
1055        except:
1056            status[0] = True
1057            status[3] = 'exception'
1058            return True
1059
1060    client.supply_history_data2(stock_list, period, start_time, end_time, on_progress)
1061
1062    import time
1063    try:
1064        while not status[0] and client.is_connected():
1065            time.sleep(0.1)
1066    except:
1067        if status[1] < status[2]:
1068            client.stop_supply_history_data2()
1069        traceback.print_exc()
1070    if not client.is_connected():
1071        raise Exception('行情服务连接断开')
1072    if status[3]:
1073        raise Exception('下载数据失败:' + status[3])
1074    return
1075
1076
1077def download_financial_data(stock_list, table_list=[], start_time='', end_time=''):
1078    '''
1079    :param stock_list: 股票代码列表
1080    :param table_list: 财务数据表名列表,[]为全部表
1081        可选范围:['Balance','Income','CashFlow','Capital','Top10FlowHolder','Top10Holder','HolderNum','PershareIndex', 'PerShare']
1082    :param start_time: 开始时间,格式YYYYMMDD,e.g."20200427"
1083    :param end_time: 结束时间 同上,若是未来某时刻会被视作当前时间
1084    '''
1085    client = get_client()
1086    if not table_list:
1087        table_list = ['Balance','Income','CashFlow','Capital','Top10FlowHolder','Top10Holder','HolderNum','PershareIndex', 'PerShare']
1088
1089    for stock_code in stock_list:
1090        for table in table_list:
1091            client.supply_history_data(stock_code, table, start_time, end_time)
1092
1093
1094def download_financial_data2(stock_list, table_list=[], start_time='', end_time='', callback=None):
1095    '''
1096    :param stock_list: 股票代码列表
1097    :param table_list: 财务数据表名列表,[]为全部表
1098        可选范围:['Balance','Income','CashFlow','Capital','Top10FlowHolder','Top10Holder','HolderNum','PershareIndex', 'PerShare']
1099    :param start_time: 开始时间,格式YYYYMMDD,e.g."20200427"
1100    :param end_time: 结束时间 同上,若是未来某时刻会被视作当前时间
1101    '''
1102    client = get_client()
1103    if not table_list:
1104        table_list = ['Balance','Income','CashFlow','Capital','Top10FlowHolder','Top10Holder','HolderNum','PershareIndex', 'PerShare']
1105
1106    data = {}
1107    data['total'] = len(table_list) * len(stock_list)
1108    finish = 0
1109    for stock_code in stock_list:
1110        for table in table_list:
1111            client.supply_history_data(stock_code, table, start_time, end_time)
1112
1113            finish = finish + 1
1114            try:
1115                data['finished'] = finish
1116                callback(data)
1117            except:
1118                pass
1119
1120            if not client.is_connected():
1121                raise Exception('行情服务连接断开')
1122                break
1123
1124
1125def get_instrument_type(stock_code):
1126    '''
1127    判断证券类型
1128    :param stock_code: 股票代码 e.g. "600000.SH"
1129    :return: dict{str : bool} {类型名:是否属于该类型}
1130    '''
1131    client = get_client()
1132    return client.get_stock_type(stock_code)
1133
1134get_stock_type = get_instrument_type
1135
1136
1137def download_sector_data():
1138    '''
1139    下载行业板块数据
1140    '''
1141    client = get_client()
1142    client.down_all_sector_data()
1143
1144def get_holidays():
1145    '''
1146    获取节假日列表
1147    :return: 8位int型日期
1148    '''
1149    client = get_client()
1150    return [str(d) for d in client.get_holidays()]
1151
1152def get_trading_calendar(market, start_time = '', end_time = '', tradetimes = False):
1153    '''
1154    获取指定市场交易日历
1155    :param market: str 市场
1156    :param start_time: str 起始时间 '20200101'
1157    :param end_time: str 结束时间 '20201231'
1158    :param tradetimes: bool 是否包含日内交易时段
1159    :return:
1160    '''
1161    holidays_list = get_holidays()   # 19900101格式的数字
1162    import datetime
1163    now = datetime.datetime.combine(datetime.date.today(), datetime.time())
1164    last = datetime.datetime(now.year + 1, 1, 1)
1165
1166    client = get_client()
1167    trading_list = list(client.get_trading_dates_by_market(market, start_time, end_time, -1).keys())
1168
1169    if start_time == '' and trading_list:
1170        start_time = trading_list[0]
1171    start = datetime.datetime.strptime(start_time, "%Y%m%d")
1172
1173    if end_time == '':
1174        end_time = now.strftime("%Y%m%d")
1175    end = min(datetime.datetime.strptime(end_time, "%Y%m%d"), last)
1176
1177       # 时间戳毫秒
1178    if not trading_list:
1179        return []
1180
1181    if not tradetimes:
1182        ret_list = trading_list
1183        while now < end:
1184            now += datetime.timedelta(days=1)
1185            if datetime.datetime.isoweekday(now) not in [6, 7]:
1186                ft = (now.strftime("%Y%m%d"))
1187                if ft not in holidays_list:
1188                    ret_list.append(ft)
1189        return ret_list
1190    else:
1191        ret_map = {}
1192        trading_times = get_trade_times(market)
1193        new_trading_times_prev = []  #21-24
1194        new_trading_times_mid = []  #0-3
1195        new_trading_times_next = [] #9-15
1196
1197        for tt in trading_times:
1198            t0 = tt[0]
1199            t1 = tt[1]
1200            t2 = tt[2]
1201            try:
1202                if t1 <= 0:
1203                    new_trading_times_prev.append([t0 + 86400, t1 + 86400, t2])
1204                elif 0 <= t0 and t1 <= 10800:
1205                    new_trading_times_mid.append(tt)
1206                elif t0 <= 0 and t1 <= 10800:
1207                    new_trading_times_prev.append([t0 + 86400, 86400, t2])
1208                    new_trading_times_mid.append([0, t1, t2])
1209                else:
1210                    new_trading_times_next.append(tt)
1211            except:
1212                pass
1213
1214        end = end + datetime.timedelta(days=1)
1215        import copy
1216        prev_open_flag = False
1217        while start < end:
1218            weekday = datetime.datetime.isoweekday(start)
1219            ft = start.strftime("%Y%m%d")
1220            if weekday not in [6, 7]:
1221                if ft not in holidays_list:
1222                    ret_map[ft] = []
1223                    if prev_open_flag:
1224                        ret_map[ft].extend(new_trading_times_mid)  # 早盘
1225                    ret_map[ft].extend(new_trading_times_next)
1226                    if weekday != 5:
1227                        if (start + datetime.timedelta(days=1)).strftime("%Y%m%d") not in holidays_list:
1228                            ret_map[ft].extend(new_trading_times_prev)
1229                    else:
1230                        if (start + datetime.timedelta(days=3)).strftime("%Y%m%d") not in holidays_list:
1231                            ret_map[ft].extend(new_trading_times_prev)
1232                    prev_open_flag = True
1233                else:
1234                    prev_open_flag = False
1235            start += datetime.timedelta(days=1)
1236        return ret_map
1237
1238def get_trade_times(stockcode):
1239    '''
1240    返回指定市场或者指定股票的交易时段
1241    :param stockcode:  市场或者代码.市场  例如 'SH' 或者 '600000.SH'
1242    :return: 返回交易时段列表,第一位是开始时间,第二位结束时间,第三位交易类型   (2 - 开盘竞价, 3 - 连续交易, 8 - 收盘竞价, 9 - 盘后定价)
1243    '''
1244    stockcode_split = stockcode.split('.')
1245    if len(stockcode_split) == 2:
1246        ins_dl = get_instrument_detail(stockcode)
1247        product = ins_dl['ProductID']
1248        stock = stockcode_split[0]
1249        market = stockcode_split[1]
1250        default = 0
1251    else:
1252        market = stockcode
1253        product = ""
1254        stock = ""
1255        default = 1
1256
1257    trader_time = {}
1258    try:
1259        with open(os.path.join(data_dir, '..', 'config', 'tradetimeconfig2.json'), 'r') as f:
1260            trader_time = json.loads(f.read())
1261    except:
1262        pass
1263
1264    ret = []
1265    import re
1266    for tdm in trader_time:
1267        if tdm['default'] == default and tdm['market'] == market:
1268            if tdm['product'] == [] and tdm['type'] == "":
1269                ret = tdm['tradetime'] #默认为product为空的 默认值
1270            if tdm['type'] != "" and re.match(tdm['type'], stock):
1271                ret = tdm['tradetime']
1272                break
1273            if product != "" and product in tdm['product']:
1274                ret = tdm['tradetime']
1275                break
1276
1277    import datetime
1278    def convert(t):
1279        if t == "240000" or t == "-240000":
1280            return 0
1281        if t[0] == '-':
1282            parc = datetime.datetime.strptime(t, "-%H%M%S")
1283            t = datetime.timedelta(hours=-parc.hour, minutes=-parc.minute)
1284        else:
1285            parc = datetime.datetime.strptime(t, "%H%M%S")
1286            t = datetime.timedelta(hours=parc.hour, minutes=parc.minute)
1287        return int(t.total_seconds())
1288    ret = [[convert(timepair[0]), convert(timepair[1]), int(timepair[2])] for timepair in ret]
1289    return ret
1290
1291def is_stock_type(stock, tag):
1292    client = get_client()
1293    return client.is_stock_type(stock, tag)
1294
1295def download_cb_data():
1296    client = get_client()
1297    return client.down_cb_data()
1298    
1299def get_cb_info(stockcode):
1300    client = get_client()
1301    return client.get_cb_info(stockcode)
1302    
1303gmd = get_market_data
1304gmd2 = get_market_data_ex
1305gmd3 = get_market_data3
1306gld = get_local_data
1307t2d = timetag_to_datetime
1308gsl = get_stock_list_in_sector
def subscribe_quote( stock_code, period='1d', start_time='', end_time='', count=0, callback=None):
675def subscribe_quote(stock_code, period='1d', start_time='', end_time='', count=0, callback=None):
676    '''
677    订阅股票行情数据
678    :param stock_code: 股票代码 e.g. "000001.SZ"
679    :param start_time: 开始时间,格式YYYYMMDD/YYYYMMDDhhmmss/YYYYMMDDhhmmss.milli,e.g."20200427" "20200427093000" "20200427093000.000"
680        若取某日全量历史数据,时间需要具体到秒,e.g."20200427093000"
681    :param end_time: 结束时间 同“开始时间”
682    :param count: 数量 -1全部/n: 从结束时间向前数n个
683    :param period: 周期 分笔"tick" 分钟线"1m"/"5m" 日线"1d"
684    :param callback:
685        订阅回调函数onSubscribe(datas)
686        :param datas: {stock : [data1, data2, ...]} 数据字典
687    :return: int 订阅序号
688    '''
689    if callback:
690        callback = subscribe_callback_wrapper(callback)
691
692    meta = {'stockCode': stock_code, 'period': period}
693    region = {'startTime': start_time, 'endTime': end_time, 'count': count}
694
695    client = get_client()
696    return client.subscribe_quote(bson.BSON.encode(meta), bson.BSON.encode(region), callback)

订阅股票行情数据

Parameters
  • stock_code: 股票代码 e.g. "000001.SZ"
  • start_time: 开始时间,格式YYYYMMDD/YYYYMMDDhhmmss/YYYYMMDDhhmmss.milli,e.g."20200427" "20200427093000" "20200427093000.000" 若取某日全量历史数据,时间需要具体到秒,e.g."20200427093000"
  • end_time: 结束时间 同“开始时间”
  • count: 数量 -1全部/n: 从结束时间向前数n个
  • period: 周期 分笔"tick" 分钟线"1m"/"5m" 日线"1d"
  • callback: 订阅回调函数onSubscribe(datas) :param datas: {stock : [data1, data2, ...]} 数据字典
Returns

int 订阅序号

def subscribe_whole_quote(code_list, callback=None):
713def subscribe_whole_quote(code_list, callback=None):
714    '''
715    订阅全推数据
716    :param code_list: 市场代码列表 ["SH", "SZ"]
717    :param callback:
718        订阅回调函数onSubscribe(datas)
719        :param datas: {stock1 : data1, stock2 : data2, ...} 数据字典
720    :return: int 订阅序号
721    '''
722    if callback:
723        callback = subscribe_callback_wrapper(callback)
724
725    client = get_client()
726    return client.subscribe_whole_quote(code_list, callback)

订阅全推数据

Parameters
  • code_list: 市场代码列表 ["SH", "SZ"]
  • callback: 订阅回调函数onSubscribe(datas) :param datas: {stock1 : data1, stock2 : data2, ...} 数据字典
Returns

int 订阅序号

def unsubscribe_quote(seq):
729def unsubscribe_quote(seq):
730    '''
731    :param seq: 订阅接口subscribe_quote返回的订阅号
732    :return:
733    '''
734    client = get_client()
735    return client.unsubscribe_quote(seq)
Parameters
  • seq: 订阅接口subscribe_quote返回的订阅号
Returns
def run():
738def run():
739    '''阻塞线程接收行情回调'''
740    import time
741    client = get_client()
742    while True:
743        time.sleep(3)
744        if not client.is_connected():
745            raise Exception('行情服务连接断开')
746            break
747    return

阻塞线程接收行情回调

def get_market_data( field_list=[], stock_list=[], period='1d', start_time='', end_time='', count=-1, dividend_type='none', fill_data=True):
316def get_market_data(
317    field_list = [], stock_list = [], period = '1d'
318    , start_time = '', end_time = '', count = -1
319    , dividend_type = 'none', fill_data = True
320):
321    '''
322    获取历史行情数据
323    :param field_list: 行情数据字段列表,[]为全部字段
324        K线可选字段:
325            "time"                #时间戳
326            "open"                #开盘价
327            "high"                #最高价
328            "low"                 #最低价
329            "close"               #收盘价
330            "volume"              #成交量
331            "amount"              #成交额
332            "settle"              #今结算
333            "openInterest"        #持仓量
334        分笔可选字段:
335            "time"                #时间戳
336            "lastPrice"           #最新价
337            "open"                #开盘价
338            "high"                #最高价
339            "low"                 #最低价
340            "lastClose"           #前收盘价
341            "amount"              #成交总额
342            "volume"              #成交总量
343            "pvolume"             #原始成交总量
344            "stockStatus"         #证券状态
345            "openInt"             #持仓量
346            "lastSettlementPrice" #前结算
347            "askPrice1", "askPrice2", "askPrice3", "askPrice4", "askPrice5" #卖一价~卖五价
348            "bidPrice1", "bidPrice2", "bidPrice3", "bidPrice4", "bidPrice5" #买一价~买五价
349            "askVol1", "askVol2", "askVol3", "askVol4", "askVol5"           #卖一量~卖五量
350            "bidVol1", "bidVol2", "bidVol3", "bidVol4", "bidVol5"           #买一量~买五量
351    :param stock_list: 股票代码 "000001.SZ"
352    :param period: 周期 分笔"tick" 分钟线"1m"/"5m" 日线"1d"
353    :param start_time: 起始时间 "20200101" "20200101093000"
354    :param end_time: 结束时间 "20201231" "20201231150000"
355    :param count: 数量 -1全部/n: 从结束时间向前数n个
356    :param dividend_type: 除权类型"none" "front" "back" "front_ratio" "back_ratio"
357    :param fill_data: 对齐时间戳时是否填充数据,仅对K线有效,分笔周期不对齐时间戳
358        为True时,以缺失数据的前一条数据填充
359            open、high、low、close 为前一条数据的close
360            amount、volume为0
361            settle、openInterest 和前一条数据相同
362        为False时,缺失数据所有字段填NaN
363    :return: 数据集,分笔数据和K线数据格式不同
364        period为'tick'时:{stock1 : value1, stock2 : value2, ...}
365            stock1, stock2, ... : 合约代码
366            value1, value2, ... : np.ndarray 数据列表,按time增序排列
367        period为其他K线周期时:{field1 : value1, field2 : value2, ...}
368            field1, field2, ... : 数据字段
369            value1, value2, ... : pd.DataFrame 字段对应的数据,各字段维度相同,index为stock_list,columns为time_list
370    '''
371    if period in {'1m', '5m', '15m', '30m', '1h', '1d'}:
372        import pandas as pd
373        index, data = get_market_data_ori(field_list, stock_list, period, start_time, end_time, count, dividend_type, fill_data)
374        result = {}
375        for field in data:
376            result[field] = pd.DataFrame(data[field], index = index[0], columns = index[1])
377        return result
378
379    return get_market_data_ori(field_list, stock_list, period, start_time, end_time, count, dividend_type, fill_data)

获取历史行情数据

Parameters
  • field_list: 行情数据字段列表,[]为全部字段 K线可选字段: "time" #时间戳 "open" #开盘价 "high" #最高价 "low" #最低价 "close" #收盘价 "volume" #成交量 "amount" #成交额 "settle" #今结算 "openInterest" #持仓量 分笔可选字段: "time" #时间戳 "lastPrice" #最新价 "open" #开盘价 "high" #最高价 "low" #最低价 "lastClose" #前收盘价 "amount" #成交总额 "volume" #成交总量 "pvolume" #原始成交总量 "stockStatus" #证券状态 "openInt" #持仓量 "lastSettlementPrice" #前结算 "askPrice1", "askPrice2", "askPrice3", "askPrice4", "askPrice5" #卖一价~卖五价 "bidPrice1", "bidPrice2", "bidPrice3", "bidPrice4", "bidPrice5" #买一价~买五价 "askVol1", "askVol2", "askVol3", "askVol4", "askVol5" #卖一量~卖五量 "bidVol1", "bidVol2", "bidVol3", "bidVol4", "bidVol5" #买一量~买五量
  • stock_list: 股票代码 "000001.SZ"
  • period: 周期 分笔"tick" 分钟线"1m"/"5m" 日线"1d"
  • start_time: 起始时间 "20200101" "20200101093000"
  • end_time: 结束时间 "20201231" "20201231150000"
  • count: 数量 -1全部/n: 从结束时间向前数n个
  • dividend_type: 除权类型"none" "front" "back" "front_ratio" "back_ratio"
  • fill_data: 对齐时间戳时是否填充数据,仅对K线有效,分笔周期不对齐时间戳 为True时,以缺失数据的前一条数据填充 open、high、low、close 为前一条数据的close amount、volume为0 settle、openInterest 和前一条数据相同 为False时,缺失数据所有字段填NaN
Returns

数据集,分笔数据和K线数据格式不同 period为'tick'时:{stock1 : value1, stock2 : value2, ...} stock1, stock2, ... : 合约代码 value1, value2, ... : np.ndarray 数据列表,按time增序排列 period为其他K线周期时:{field1 : value1, field2 : value2, ...} field1, field2, ... : 数据字段 value1, value2, ... : pd.DataFrame 字段对应的数据,各字段维度相同,index为stock_list,columns为time_list

def get_local_data( field_list=[], stock_code=[], period='1d', start_time='', end_time='', count=-1, dividend_type='none', fill_data=True, data_dir='../userdata_mini/datadir'):
538def get_local_data(field_list=[], stock_code=[], period='1d', start_time='', end_time='', count=-1,
539                              dividend_type='none', fill_data=True, data_dir=data_dir):
540    return None
def get_full_tick(code_list):
650def get_full_tick(code_list):
651    '''
652    获取盘口tick数据
653    :param code_list: (list)stock.market组成的股票代码列表
654    :return: dict
655    {'stock.market': {dict}}
656    '''
657    client = get_client()
658    resp_json = client.get_full_tick(code_list)
659    return json.loads(resp_json)

获取盘口tick数据

Parameters
  • code_list: (list)stock.market组成的股票代码列表
Returns

dict {'stock.market': {dict}}

def get_divid_factors(stock_code, start_time='', end_time=''):
576def get_divid_factors(stock_code, start_time='', end_time=''):
577    '''
578    获取除权除息日及对应的权息
579    :param stock_code: (str)股票代码
580    :param date: (str)日期
581    :return: pd.DataFrame 数据集
582    '''
583    client = get_client()
584    datas = client.get_divid_factors(stock_code, start_time, end_time)
585    import pandas as pd
586    datas = pd.DataFrame(datas).T
587    return datas

获取除权除息日及对应的权息

Parameters
  • stock_code: (str)股票代码
  • date: (str)日期
Returns

pd.DataFrame 数据集

def get_l2_quote(field_list=[], stock_code='', start_time='', end_time='', count=-1):
543def get_l2_quote(field_list=[], stock_code='', start_time='', end_time='', count=-1):
544    '''
545    level2实时行情
546    '''
547    client = get_client()
548    datas = client.get_market_data3(field_list, [stock_code], 'l2quote', start_time, end_time, count, 'none', False, '', False, False)
549    if datas:
550        return datas[stock_code]
551    return None

level2实时行情

def get_l2_order(field_list=[], stock_code='', start_time='', end_time='', count=-1):
554def get_l2_order(field_list=[], stock_code='', start_time='', end_time='', count=-1):
555    '''
556    level2逐笔委托
557    '''
558    client = get_client()
559    datas = client.get_market_data3(field_list, [stock_code], 'l2order', start_time, end_time, count, 'none', False, '', False, False)
560    if datas:
561        return datas[stock_code]
562    return None

level2逐笔委托

def get_l2_transaction(field_list=[], stock_code='', start_time='', end_time='', count=-1):
565def get_l2_transaction(field_list=[], stock_code='', start_time='', end_time='', count=-1):
566    '''
567    level2逐笔成交
568    '''
569    client = get_client()
570    datas = client.get_market_data3(field_list, [stock_code], 'l2transaction', start_time, end_time, count, 'none', False, '', False, False)
571    if datas:
572        return datas[stock_code]
573    return None

level2逐笔成交

def download_history_data(stock_code, period, start_time='', end_time=''):
1013def download_history_data(stock_code, period, start_time='', end_time=''):
1014    '''
1015    :param stock_code: 股票代码 e.g. "000001.SZ"
1016    :param period: 周期 分笔"tick" 分钟线"1m"/"5m" 日线"1d"
1017    :param start_time: 开始时间,格式YYYYMMDD/YYYYMMDDhhmmss/YYYYMMDDhhmmss.milli,e.g."20200427" "20200427093000" "20200427093000.000"
1018        若取某日全量历史数据,时间需要具体到秒,e.g."20200427093000"
1019    :param end_time: 结束时间 同上,若是未来某时刻会被视作当前时间
1020    :return: bool 是否成功
1021    '''
1022    client = get_client()
1023    client.supply_history_data(stock_code, period, start_time, end_time)
Parameters
  • stock_code: 股票代码 e.g. "000001.SZ"
  • period: 周期 分笔"tick" 分钟线"1m"/"5m" 日线"1d"
  • start_time: 开始时间,格式YYYYMMDD/YYYYMMDDhhmmss/YYYYMMDDhhmmss.milli,e.g."20200427" "20200427093000" "20200427093000.000" 若取某日全量历史数据,时间需要具体到秒,e.g."20200427093000"
  • end_time: 结束时间 同上,若是未来某时刻会被视作当前时间
Returns

bool 是否成功

def get_financial_data( stock_list, table_list=[], start_time='', end_time='', report_type='report_time'):
231def get_financial_data(stock_list, table_list=[], start_time='', end_time='', report_type='report_time'):
232    '''
233     获取财务数据
234    :param stock_list: (list)合约代码列表
235    :param table_list: (list)报表名称列表
236    :param start_time: (str)起始时间
237    :param end_time: (str)结束时间
238    :param report_type: (str) 时段筛选方式 'announce_time' / 'report_time'
239    :return:
240        field: list[str]
241        date: list[int]
242        stock: list[str]
243        value: list[list[float]]
244    '''
245    client = get_client()
246    all_table = {
247        'Balance' : 'ASHAREBALANCESHEET'
248        , 'Income' : 'ASHAREINCOME'
249        , 'CashFlow' : 'ASHARECASHFLOW'
250        , 'Capital' : 'CAPITALSTRUCTURE'
251        , 'HolderNum' : 'SHAREHOLDER'
252        , 'Top10Holder' : 'TOP10HOLDER'
253        , 'Top10FlowHolder' : 'TOP10FLOWHOLDER'
254        , 'PershareIndex' : 'PERSHAREINDEX'
255    }
256
257    if not table_list:
258        table_list = list(all_table.keys())
259
260    all_table_upper = {table.upper() : all_table[table] for table in all_table}
261    req_list = []
262    names = {}
263    for table in table_list:
264        req_table = all_table_upper.get(table.upper(), table)
265        req_list.append(req_table)
266        names[req_table] = table
267
268    data = {}
269    sl_len = 20
270    stock_list2 = [stock_list[i : i + sl_len] for i in range(0, len(stock_list), sl_len)]
271    for sl in stock_list2:
272        data2 = client.get_financial_data(sl, req_list, start_time, end_time, report_type)
273        for s in data2:
274            data[s] = data2[s]
275
276    import time
277    import math
278    def conv_date(data, key, key2):
279        if key in data:
280            tmp_data = data[key]
281            if math.isnan(tmp_data):
282                if key2 not in data or math.isnan(data[key2]):
283                    data[key] = ''
284                else:
285                    tmp_data = data[key2]
286            data[key] = time.strftime('%Y%m%d', time.localtime(tmp_data / 1000))
287        return
288
289    result = {}
290    import pandas as pd
291    for stock in data:
292        stock_data = data[stock]
293        result[stock] = {}
294        for table in stock_data:
295            table_data = stock_data[table]
296            for row_data in table_data:
297                conv_date(row_data, 'm_anntime', 'm_timetag')
298                conv_date(row_data, 'm_timetag', '')
299                conv_date(row_data, 'declareDate', '')
300                conv_date(row_data, 'endDate', '')
301            result[stock][names[table]] = pd.DataFrame(table_data)
302    return result

获取财务数据

Parameters
  • stock_list: (list)合约代码列表
  • table_list: (list)报表名称列表
  • start_time: (str)起始时间
  • end_time: (str)结束时间
  • report_type: (str) 时段筛选方式 'announce_time' / 'report_time'
Returns
field: list[str]
date: list[int]
stock: list[str]
value: list[list[float]]
def download_financial_data(stock_list, table_list=[], start_time='', end_time=''):
1078def download_financial_data(stock_list, table_list=[], start_time='', end_time=''):
1079    '''
1080    :param stock_list: 股票代码列表
1081    :param table_list: 财务数据表名列表,[]为全部表
1082        可选范围:['Balance','Income','CashFlow','Capital','Top10FlowHolder','Top10Holder','HolderNum','PershareIndex', 'PerShare']
1083    :param start_time: 开始时间,格式YYYYMMDD,e.g."20200427"
1084    :param end_time: 结束时间 同上,若是未来某时刻会被视作当前时间
1085    '''
1086    client = get_client()
1087    if not table_list:
1088        table_list = ['Balance','Income','CashFlow','Capital','Top10FlowHolder','Top10Holder','HolderNum','PershareIndex', 'PerShare']
1089
1090    for stock_code in stock_list:
1091        for table in table_list:
1092            client.supply_history_data(stock_code, table, start_time, end_time)
Parameters
  • stock_list: 股票代码列表
  • table_list: 财务数据表名列表,[]为全部表 可选范围:['Balance','Income','CashFlow','Capital','Top10FlowHolder','Top10Holder','HolderNum','PershareIndex', 'PerShare']
  • start_time: 开始时间,格式YYYYMMDD,e.g."20200427"
  • end_time: 结束时间 同上,若是未来某时刻会被视作当前时间
def get_instrument_detail(stock_code):
778def get_instrument_detail(stock_code):
779    '''
780    获取合约信息
781    :param stock_code: 股票代码 e.g. "600000.SH"
782    :return: dict
783        ExchangeID(str):合约市场代码, InstrumentID(str):合约代码, InstrumentName(str):合约名称, ProductID(str):合约的品种ID(期货), ProductName(str)合约的品种名称(期货),
784        CreateDate(int):上市日期(期货), OpenDate(int):IPO日期(股票), ExpireDate(int):退市日或者到期日, PreClose(double):前收盘价格, SettlementPrice(double):前结算价格,
785        UpStopPrice(double):当日涨停价, DownStopPrice(double):当日跌停价, FloatVolume(double):流通股本, TotalVolume(double):总股本, LongMarginRatio(double):多头保证金率,
786        ShortMarginRatio(double):空头保证金率, PriceTick(double):最小变价单位, VolumeMultiple(int):合约乘数(对期货以外的品种,默认是1),
787        MainContract(int):主力合约标记,1、2、3分别表示第一主力合约,第二主力合约,第三主力合约, LastVolume(int):昨日持仓量, InstrumentStatus(int):合约停牌状态,
788        IsTrading(bool):合约是否可交易, IsRecent(bool):是否是近月合约,
789    '''
790    client = get_client()
791    inst = client.get_instrument_detail(stock_code)
792    if not inst:
793        return None
794    field_list = [
795            'ExchangeID'
796            , 'InstrumentID'
797            , 'InstrumentName'
798            , 'ProductID'
799            , 'ProductName'
800            , 'CreateDate'
801            , 'OpenDate'
802            , 'ExpireDate'
803            , 'PreClose'
804            , 'SettlementPrice'
805            , 'UpStopPrice'
806            , 'DownStopPrice'
807            , 'FloatVolume'
808            , 'TotalVolume'
809            , 'LongMarginRatio'
810            , 'ShortMarginRatio'
811            , 'PriceTick'
812            , 'VolumeMultiple'
813            , 'MainContract'
814            , 'LastVolume'
815            , 'InstrumentStatus'
816            , 'IsTrading'
817            , 'IsRecent'
818        ]
819    ret = {}
820    for field in field_list:
821        ret[field] = inst.get(field)
822
823    exfield_list = [
824            'ProductTradeQuota'
825            , 'ContractTradeQuota'
826            , 'ProductOpenInterestQuota'
827            , 'ContractOpenInterestQuota'
828        ]
829    inst_ex = inst.get('ExtendInfo', {})
830    for field in exfield_list:
831        ret[field] = inst_ex.get(field)
832
833    def convNum2Str(field):
834        if field in ret and isinstance(ret[field], int):
835            ret[field] = str(ret[field])
836    convNum2Str('CreateDate')
837    convNum2Str('OpenDate')
838    return ret

获取合约信息

Parameters
  • stock_code: 股票代码 e.g. "600000.SH"
Returns

dict ExchangeID(str):合约市场代码, InstrumentID(str):合约代码, InstrumentName(str):合约名称, ProductID(str):合约的品种ID(期货), ProductName(str)合约的品种名称(期货), CreateDate(int):上市日期(期货), OpenDate(int):IPO日期(股票), ExpireDate(int):退市日或者到期日, PreClose(double):前收盘价格, SettlementPrice(double):前结算价格, UpStopPrice(double):当日涨停价, DownStopPrice(double):当日跌停价, FloatVolume(double):流通股本, TotalVolume(double):总股本, LongMarginRatio(double):多头保证金率, ShortMarginRatio(double):空头保证金率, PriceTick(double):最小变价单位, VolumeMultiple(int):合约乘数(对期货以外的品种,默认是1), MainContract(int):主力合约标记,1、2、3分别表示第一主力合约,第二主力合约,第三主力合约, LastVolume(int):昨日持仓量, InstrumentStatus(int):合约停牌状态, IsTrading(bool):合约是否可交易, IsRecent(bool):是否是近月合约,

def get_instrument_type(stock_code):
1126def get_instrument_type(stock_code):
1127    '''
1128    判断证券类型
1129    :param stock_code: 股票代码 e.g. "600000.SH"
1130    :return: dict{str : bool} {类型名:是否属于该类型}
1131    '''
1132    client = get_client()
1133    return client.get_stock_type(stock_code)

判断证券类型

Parameters
  • stock_code: 股票代码 e.g. "600000.SH"
Returns

dict{str : bool} {类型名:是否属于该类型}

def get_trading_dates(market, start_time='', end_time='', count=-1):
636def get_trading_dates(market, start_time='', end_time='', count=-1):
637    '''
638    根据市场获取交易日列表
639    : param market: 市场代码 e.g. 'SH','SZ','IF','DF','SF','ZF'等
640    : param start_time: 起始时间 '20200101'
641    : param end_time: 结束时间 '20201231'
642    : param count: 数据个数,-1为全部数据
643    :return list(long) 毫秒数的时间戳列表
644    '''
645    client = get_client()
646    datas = client.get_trading_dates_by_market(market, start_time, end_time, count)
647    return list(datas.values())

根据市场获取交易日列表 : param market: 市场代码 e.g. 'SH','SZ','IF','DF','SF','ZF'等 : param start_time: 起始时间 '20200101' : param end_time: 结束时间 '20201231' : param count: 数据个数,-1为全部数据 :return list(long) 毫秒数的时间戳列表

def get_sector_list():
750def get_sector_list():
751    '''
752    获取板块列表
753    :return: (list[str])
754    '''
755    client = get_client()
756    return client.get_sector_list()

获取板块列表

Returns

(list[str])

def get_stock_list_in_sector(sector_name):
211def get_stock_list_in_sector(sector_name):
212    '''
213    获取板块成份股,支持客户端左侧板块列表中任意的板块,包括自定义板块
214    :param sector_name: (str)板块名称
215    :return: list
216    '''
217    client = get_client()
218    return client.get_stock_list_in_sector(sector_name, 0)

获取板块成份股,支持客户端左侧板块列表中任意的板块,包括自定义板块

Parameters
  • sector_name: (str)板块名称
Returns

list

def download_sector_data():
1138def download_sector_data():
1139    '''
1140    下载行业板块数据
1141    '''
1142    client = get_client()
1143    client.down_all_sector_data()

下载行业板块数据

def add_sector(sector_name, stock_list):
759def add_sector(sector_name, stock_list):
760    '''
761    增加自定义板块
762    :param sector_name: 板块名称 e.g. "我的自选"
763    :param stock_list: (list)stock.market组成的股票代码列表
764    '''
765    client = get_client()
766    return client.add_sector(sector_name, stock_list, 1)

增加自定义板块

Parameters
  • sector_name: 板块名称 e.g. "我的自选"
  • stock_list: (list)stock.market组成的股票代码列表
def remove_sector(sector_name):
769def remove_sector(sector_name):
770    '''
771    删除自定义板块
772    :param sector_name: 板块名称 e.g. "我的自选"
773    '''
774    client = get_client()
775    return client.add_sector(sector_name, [], -1)

删除自定义板块

Parameters
  • sector_name: 板块名称 e.g. "我的自选"
def get_index_weight(index_code):
221def get_index_weight(index_code):
222    '''
223    获取某只股票在某指数中的绝对权重
224    :param index_code: (str)指数名称
225    :return: dict
226    '''
227    client = get_client()
228    return client.get_weight_in_index(index_code)

获取某只股票在某指数中的绝对权重

Parameters
  • index_code: (str)指数名称
Returns

dict

def download_index_weight():
856def download_index_weight():
857    '''
858    下载指数权重数据
859    '''
860    client = get_client()
861    client.down_index_weight()

下载指数权重数据

def get_holidays():
1145def get_holidays():
1146    '''
1147    获取节假日列表
1148    :return: 8位int型日期
1149    '''
1150    client = get_client()
1151    return [str(d) for d in client.get_holidays()]

获取节假日列表

Returns

8位int型日期

def get_trading_calendar(market, start_time='', end_time='', tradetimes=False):
1153def get_trading_calendar(market, start_time = '', end_time = '', tradetimes = False):
1154    '''
1155    获取指定市场交易日历
1156    :param market: str 市场
1157    :param start_time: str 起始时间 '20200101'
1158    :param end_time: str 结束时间 '20201231'
1159    :param tradetimes: bool 是否包含日内交易时段
1160    :return:
1161    '''
1162    holidays_list = get_holidays()   # 19900101格式的数字
1163    import datetime
1164    now = datetime.datetime.combine(datetime.date.today(), datetime.time())
1165    last = datetime.datetime(now.year + 1, 1, 1)
1166
1167    client = get_client()
1168    trading_list = list(client.get_trading_dates_by_market(market, start_time, end_time, -1).keys())
1169
1170    if start_time == '' and trading_list:
1171        start_time = trading_list[0]
1172    start = datetime.datetime.strptime(start_time, "%Y%m%d")
1173
1174    if end_time == '':
1175        end_time = now.strftime("%Y%m%d")
1176    end = min(datetime.datetime.strptime(end_time, "%Y%m%d"), last)
1177
1178       # 时间戳毫秒
1179    if not trading_list:
1180        return []
1181
1182    if not tradetimes:
1183        ret_list = trading_list
1184        while now < end:
1185            now += datetime.timedelta(days=1)
1186            if datetime.datetime.isoweekday(now) not in [6, 7]:
1187                ft = (now.strftime("%Y%m%d"))
1188                if ft not in holidays_list:
1189                    ret_list.append(ft)
1190        return ret_list
1191    else:
1192        ret_map = {}
1193        trading_times = get_trade_times(market)
1194        new_trading_times_prev = []  #21-24
1195        new_trading_times_mid = []  #0-3
1196        new_trading_times_next = [] #9-15
1197
1198        for tt in trading_times:
1199            t0 = tt[0]
1200            t1 = tt[1]
1201            t2 = tt[2]
1202            try:
1203                if t1 <= 0:
1204                    new_trading_times_prev.append([t0 + 86400, t1 + 86400, t2])
1205                elif 0 <= t0 and t1 <= 10800:
1206                    new_trading_times_mid.append(tt)
1207                elif t0 <= 0 and t1 <= 10800:
1208                    new_trading_times_prev.append([t0 + 86400, 86400, t2])
1209                    new_trading_times_mid.append([0, t1, t2])
1210                else:
1211                    new_trading_times_next.append(tt)
1212            except:
1213                pass
1214
1215        end = end + datetime.timedelta(days=1)
1216        import copy
1217        prev_open_flag = False
1218        while start < end:
1219            weekday = datetime.datetime.isoweekday(start)
1220            ft = start.strftime("%Y%m%d")
1221            if weekday not in [6, 7]:
1222                if ft not in holidays_list:
1223                    ret_map[ft] = []
1224                    if prev_open_flag:
1225                        ret_map[ft].extend(new_trading_times_mid)  # 早盘
1226                    ret_map[ft].extend(new_trading_times_next)
1227                    if weekday != 5:
1228                        if (start + datetime.timedelta(days=1)).strftime("%Y%m%d") not in holidays_list:
1229                            ret_map[ft].extend(new_trading_times_prev)
1230                    else:
1231                        if (start + datetime.timedelta(days=3)).strftime("%Y%m%d") not in holidays_list:
1232                            ret_map[ft].extend(new_trading_times_prev)
1233                    prev_open_flag = True
1234                else:
1235                    prev_open_flag = False
1236            start += datetime.timedelta(days=1)
1237        return ret_map

获取指定市场交易日历

Parameters
  • market: str 市场
  • start_time: str 起始时间 '20200101'
  • end_time: str 结束时间 '20201231'
  • tradetimes: bool 是否包含日内交易时段
Returns
def get_trade_times(stockcode):
1239def get_trade_times(stockcode):
1240    '''
1241    返回指定市场或者指定股票的交易时段
1242    :param stockcode:  市场或者代码.市场  例如 'SH' 或者 '600000.SH'
1243    :return: 返回交易时段列表,第一位是开始时间,第二位结束时间,第三位交易类型   (2 - 开盘竞价, 3 - 连续交易, 8 - 收盘竞价, 9 - 盘后定价)
1244    '''
1245    stockcode_split = stockcode.split('.')
1246    if len(stockcode_split) == 2:
1247        ins_dl = get_instrument_detail(stockcode)
1248        product = ins_dl['ProductID']
1249        stock = stockcode_split[0]
1250        market = stockcode_split[1]
1251        default = 0
1252    else:
1253        market = stockcode
1254        product = ""
1255        stock = ""
1256        default = 1
1257
1258    trader_time = {}
1259    try:
1260        with open(os.path.join(data_dir, '..', 'config', 'tradetimeconfig2.json'), 'r') as f:
1261            trader_time = json.loads(f.read())
1262    except:
1263        pass
1264
1265    ret = []
1266    import re
1267    for tdm in trader_time:
1268        if tdm['default'] == default and tdm['market'] == market:
1269            if tdm['product'] == [] and tdm['type'] == "":
1270                ret = tdm['tradetime'] #默认为product为空的 默认值
1271            if tdm['type'] != "" and re.match(tdm['type'], stock):
1272                ret = tdm['tradetime']
1273                break
1274            if product != "" and product in tdm['product']:
1275                ret = tdm['tradetime']
1276                break
1277
1278    import datetime
1279    def convert(t):
1280        if t == "240000" or t == "-240000":
1281            return 0
1282        if t[0] == '-':
1283            parc = datetime.datetime.strptime(t, "-%H%M%S")
1284            t = datetime.timedelta(hours=-parc.hour, minutes=-parc.minute)
1285        else:
1286            parc = datetime.datetime.strptime(t, "%H%M%S")
1287            t = datetime.timedelta(hours=parc.hour, minutes=parc.minute)
1288        return int(t.total_seconds())
1289    ret = [[convert(timepair[0]), convert(timepair[1]), int(timepair[2])] for timepair in ret]
1290    return ret

返回指定市场或者指定股票的交易时段

Parameters
  • stockcode: 市场或者代码.市场 例如 'SH' 或者 '600000.SH'
Returns

返回交易时段列表,第一位是开始时间,第二位结束时间,第三位交易类型 (2 - 开盘竞价, 3 - 连续交易, 8 - 收盘竞价, 9 - 盘后定价)

def download_cb_data():
1296def download_cb_data():
1297    client = get_client()
1298    return client.down_cb_data()
def get_cb_info(stockcode):
1300def get_cb_info(stockcode):
1301    client = get_client()
1302    return client.get_cb_info(stockcode)