dataquant 1.1.6__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- dataquant/__init__.py +150 -0
- dataquant/apis/__init__.py +1 -0
- dataquant/apis/base/__init__.py +2 -0
- dataquant/apis/base/api.py +77 -0
- dataquant/apis/info/__init__.py +1 -0
- dataquant/apis/info/api.py +2300 -0
- dataquant/apis/quote/__init__.py +1 -0
- dataquant/apis/quote/api.py +1744 -0
- dataquant/cd/__init__.py +1 -0
- dataquant/cd/api.py +746 -0
- dataquant/hk/__init__.py +1 -0
- dataquant/hk/api.py +1110 -0
- dataquant/ic/__init__.py +1 -0
- dataquant/ic/api.py +158 -0
- dataquant/intl/__init__.py +1 -0
- dataquant/intl/api.py +137 -0
- dataquant/pof/__init__.py +1 -0
- dataquant/pof/api.py +1963 -0
- dataquant/sql/__init__.py +1 -0
- dataquant/sql/api.py +61 -0
- dataquant/utils/__init__.py +5 -0
- dataquant/utils/client.py +192 -0
- dataquant/utils/common.py +23 -0
- dataquant/utils/config.py +29 -0
- dataquant/utils/config.yml +30 -0
- dataquant/utils/connection.py +502 -0
- dataquant/utils/connection_pool.py +67 -0
- dataquant/utils/consts.py +1 -0
- dataquant/utils/convert.py +54 -0
- dataquant/utils/datetime_func.py +77 -0
- dataquant/utils/decorators.py +125 -0
- dataquant/utils/error.py +159 -0
- dataquant/utils/parallel.py +48 -0
- dataquant-1.1.6.dist-info/METADATA +30 -0
- dataquant-1.1.6.dist-info/RECORD +38 -0
- dataquant-1.1.6.dist-info/WHEEL +5 -0
- dataquant-1.1.6.dist-info/entry_points.txt +3 -0
- dataquant-1.1.6.dist-info/top_level.txt +1 -0
dataquant/hk/api.py
ADDED
|
@@ -0,0 +1,1110 @@
|
|
|
1
|
+
# -*- coding: UTF-8 -*-
|
|
2
|
+
|
|
3
|
+
import re
|
|
4
|
+
import os
|
|
5
|
+
import time
|
|
6
|
+
import mmap
|
|
7
|
+
import gevent
|
|
8
|
+
import platform
|
|
9
|
+
import warnings
|
|
10
|
+
import pandas as pd
|
|
11
|
+
from functools import wraps
|
|
12
|
+
import traceback
|
|
13
|
+
import socket
|
|
14
|
+
from concurrent.futures import as_completed, ThreadPoolExecutor
|
|
15
|
+
|
|
16
|
+
from dataquant.apis.base import get_data, get_qdata
|
|
17
|
+
from dataquant.utils.convert import convert_fields, sort_merge_df, sort_merge_df_dic
|
|
18
|
+
from dataquant.utils.datetime_func import get_current_date
|
|
19
|
+
from dataquant.utils.config import read_config
|
|
20
|
+
from dataquant.utils.error import MaxTryExceed, RunTimeError
|
|
21
|
+
|
|
22
|
+
__all__ = [
|
|
23
|
+
# 新增港股新表查询接口;20240606 shenfc
|
|
24
|
+
"get_tick",#快照
|
|
25
|
+
"get_deal",#逐笔成交
|
|
26
|
+
"get_oddlot_order",#碎股
|
|
27
|
+
"get_broker_queue",#经纪商队列
|
|
28
|
+
"get_index_tick",#指数快照
|
|
29
|
+
"get_security_info", #获取港股基本信息
|
|
30
|
+
"get_stk_rstr_fctr" #获取港股复权因子信息
|
|
31
|
+
]
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
# 请求服务端URL
|
|
35
|
+
|
|
36
|
+
#新增港股请求服务端URL
|
|
37
|
+
URL_GET_HKSTK_TICK = 'get_hkstock_snapshot'#快照
|
|
38
|
+
URL_GET_HKSTK_DEAL = 'get_hkstock_tick'#逐笔成交
|
|
39
|
+
URL_GET_HKSTK_ODD = 'get_hkstock_odd'#碎股
|
|
40
|
+
URL_GET_HKSTK_BROKER = 'get_hkstock_broker'#经纪商队列
|
|
41
|
+
URL_GET_HKSTK_INDEX = 'get_hkstock_index'#指数快照
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
# 代码与证券类型映射
|
|
47
|
+
CODE_SECURITY_MAP = {}
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
global CONFIG_PAGE_SIZE, PARALLEL_NUM, PARALLEL_MODE, EXECUTOR, EXECUTOR_INNER, \
|
|
51
|
+
HF_SORT_COLS, KLINED_SORT_COLS, KLINEM_SORT_COLS, PROCESS_MMAP
|
|
52
|
+
|
|
53
|
+
if platform.system().lower() == 'windows':
|
|
54
|
+
PROCESS_MMAP = mmap.mmap(-1, 1, tagname='dataquant_sdk_pid')
|
|
55
|
+
else:
|
|
56
|
+
MMAP_FILE = open('/dev/shm/dataquant_sdk_pid', 'w+b')
|
|
57
|
+
MMAP_FILE.write(b"\x00")
|
|
58
|
+
MMAP_FILE.flush()
|
|
59
|
+
PROCESS_MMAP = mmap.mmap(MMAP_FILE.fileno(), 1, flags=mmap.MAP_SHARED, prot=mmap.PROT_READ | mmap.PROT_WRITE)
|
|
60
|
+
|
|
61
|
+
PROCESS_MMAP.seek(0)
|
|
62
|
+
if PROCESS_MMAP.read() != b'\x31':
|
|
63
|
+
PROCESS_MMAP.seek(0)
|
|
64
|
+
PROCESS_MMAP.write(b"\x00")
|
|
65
|
+
PROCESS_MMAP.flush()
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def reset():
|
|
69
|
+
PROCESS_MMAP.seek(0)
|
|
70
|
+
PROCESS_MMAP.write(b"\x00")
|
|
71
|
+
PROCESS_MMAP.flush()
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def load_basic_info():
|
|
75
|
+
int_param = []
|
|
76
|
+
float_param = []
|
|
77
|
+
|
|
78
|
+
params = {
|
|
79
|
+
"mkt_code_list": ['XHKG'],
|
|
80
|
+
"cols": ['scr_num', 'scr_name', 'scr_abbr', 'scr_code', 'mkt_code', 'scr_clas', 'list_date'],
|
|
81
|
+
"int_param": int_param,
|
|
82
|
+
"float_param": float_param
|
|
83
|
+
}
|
|
84
|
+
result = get_data("get_scr_basc_info", **params)
|
|
85
|
+
global CODE_SECURITY_MAP
|
|
86
|
+
CODE_SECURITY_MAP = result.set_index('scr_num')['scr_clas'].to_dict()
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
reset()
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def load_conf():
|
|
93
|
+
global CONFIG_PAGE_SIZE, PARALLEL_NUM, PARALLEL_MODE, EXECUTOR, EXECUTOR_INNER, \
|
|
94
|
+
HF_SORT_COLS, KLINED_SORT_COLS, KLINEM_SORT_COLS
|
|
95
|
+
CONFIG = read_config()['system']
|
|
96
|
+
CONFIG_PAGE_SIZE = CONFIG.get('page_size')
|
|
97
|
+
PARALLEL_NUM = CONFIG.get("quote_parallel")
|
|
98
|
+
PARALLEL_MODE = CONFIG.get("parallel_mode")
|
|
99
|
+
if PARALLEL_MODE == 'Thread':
|
|
100
|
+
EXECUTOR = ThreadPoolExecutor(max_workers=PARALLEL_NUM)
|
|
101
|
+
EXECUTOR_INNER = ThreadPoolExecutor(max_workers=PARALLEL_NUM)
|
|
102
|
+
elif PARALLEL_MODE == 'Coroutine':
|
|
103
|
+
from gevent import monkey
|
|
104
|
+
monkey.patch_all()
|
|
105
|
+
from gevent.pool import Pool as gPool
|
|
106
|
+
EXECUTOR = gPool(PARALLEL_NUM)
|
|
107
|
+
EXECUTOR_INNER = gPool(PARALLEL_NUM)
|
|
108
|
+
EXECUTOR.submit = EXECUTOR.spawn
|
|
109
|
+
EXECUTOR_INNER.submit = EXECUTOR_INNER.spawn
|
|
110
|
+
HF_SORT_COLS = {
|
|
111
|
+
'hkstock': list(CONFIG.get('quote_hf_hkstock_sort').split(',')),
|
|
112
|
+
}
|
|
113
|
+
KLINED_SORT_COLS = {
|
|
114
|
+
|
|
115
|
+
}
|
|
116
|
+
KLINEM_SORT_COLS = {
|
|
117
|
+
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
load_conf()
|
|
122
|
+
_config = read_config()['system']
|
|
123
|
+
|
|
124
|
+
TWO_STEP_QUERY = False # 20220812 行情请求是否使用分页模式(第一步获取总条数,第二步实际查询)
|
|
125
|
+
ONE_STEP_NUM = 9999999 # 20220812 一步请求的最大请求数量需要很大以覆盖所有情况
|
|
126
|
+
|
|
127
|
+
KLINE_CODE_GROUP = 10
|
|
128
|
+
HF_DAY_DELTA = 1
|
|
129
|
+
HF_CODE_GROUP = 1
|
|
130
|
+
KLINE_DAY_DELTA = 90
|
|
131
|
+
|
|
132
|
+
KLINE_DAY_DELTA_CANDLE_PERIOD = {
|
|
133
|
+
'1m', '1',
|
|
134
|
+
'5m', '2',
|
|
135
|
+
'15m', '3',
|
|
136
|
+
'30m', '4',
|
|
137
|
+
'1h', '5',
|
|
138
|
+
'1d', '6',
|
|
139
|
+
# '1w': '7',
|
|
140
|
+
# '1M': '8',
|
|
141
|
+
# '1y': '9',
|
|
142
|
+
'2h', '11',
|
|
143
|
+
'3h', '12',
|
|
144
|
+
'4h', '13'
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
CANDLE_PERIOD_MAP = {
|
|
149
|
+
'1m': '1',
|
|
150
|
+
'5m': '2',
|
|
151
|
+
'15m': '3',
|
|
152
|
+
'30m': '4',
|
|
153
|
+
'1h': '5',
|
|
154
|
+
'1d': '6',
|
|
155
|
+
'1w': '7',
|
|
156
|
+
'1M': '8',
|
|
157
|
+
'1y': '9',
|
|
158
|
+
'2h': '11',
|
|
159
|
+
'3h': '12',
|
|
160
|
+
'4h': '13'
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
CANDLE_MODE_MAP = {
|
|
165
|
+
None: '0',
|
|
166
|
+
'pre': '1',
|
|
167
|
+
'post': '2'
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
def bind(_socket=None):
|
|
173
|
+
if _socket is None:
|
|
174
|
+
PROCESS_MMAP.seek(0)
|
|
175
|
+
# 共享区域没有数据,则写入对应数据
|
|
176
|
+
if PROCESS_MMAP.read() == b'\x00':
|
|
177
|
+
# 执行绑定操作
|
|
178
|
+
PROCESS_MMAP.seek(0)
|
|
179
|
+
PROCESS_MMAP.write(b'\x31')
|
|
180
|
+
PROCESS_MMAP.flush()
|
|
181
|
+
|
|
182
|
+
# 检验绑定是否成功
|
|
183
|
+
PROCESS_MMAP.seek(0)
|
|
184
|
+
if PROCESS_MMAP.read() == b'\x31':
|
|
185
|
+
return True
|
|
186
|
+
else:
|
|
187
|
+
return False
|
|
188
|
+
|
|
189
|
+
else:
|
|
190
|
+
return False
|
|
191
|
+
else:
|
|
192
|
+
try:
|
|
193
|
+
_socket.bind(('127.0.0.1', _config["bind_port"]))
|
|
194
|
+
return True
|
|
195
|
+
except Exception as ex:
|
|
196
|
+
return False
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
def unbind(_socket=None):
|
|
200
|
+
if _socket is None:
|
|
201
|
+
PROCESS_MMAP.seek(0)
|
|
202
|
+
PROCESS_MMAP.write(b'\x00')
|
|
203
|
+
PROCESS_MMAP.flush()
|
|
204
|
+
else:
|
|
205
|
+
_socket.close()
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
def wait_until_bind(count=10000, time_delta=1.0):
|
|
209
|
+
def decorate(func):
|
|
210
|
+
@wraps(func)
|
|
211
|
+
def wrap(*args, **kwargs):
|
|
212
|
+
# 尝试进行绑定
|
|
213
|
+
bind_method = _config.get("bind_method", "socket")
|
|
214
|
+
if bind_method == 'socket':
|
|
215
|
+
_socket = socket.socket()
|
|
216
|
+
else:
|
|
217
|
+
_socket = None
|
|
218
|
+
cnt = 0
|
|
219
|
+
while True:
|
|
220
|
+
if bind(_socket):
|
|
221
|
+
try:
|
|
222
|
+
return func(*args, **kwargs)
|
|
223
|
+
except:
|
|
224
|
+
print(f"进程{os.getpid()}运行函数报错")
|
|
225
|
+
print(traceback.format_exc())
|
|
226
|
+
raise RunTimeError("运行时报错")
|
|
227
|
+
finally:
|
|
228
|
+
unbind(_socket)
|
|
229
|
+
|
|
230
|
+
else:
|
|
231
|
+
cnt += 1
|
|
232
|
+
if cnt > count:
|
|
233
|
+
raise MaxTryExceed(f"进程{os.getpid()}等待次数超过上线")
|
|
234
|
+
if cnt % 60 == 0:
|
|
235
|
+
print(f"进程{os.getpid()}正常排队查询")
|
|
236
|
+
time.sleep(time_delta)
|
|
237
|
+
return wrap
|
|
238
|
+
return decorate
|
|
239
|
+
|
|
240
|
+
|
|
241
|
+
def quote_single_part(method, params, two_step: bool = TWO_STEP_QUERY):
|
|
242
|
+
init_count = 0 # 初次查询已获取的条数
|
|
243
|
+
init_page = 0 # 初次查询已获取的页数
|
|
244
|
+
total_pages = 0
|
|
245
|
+
df_dic = {}
|
|
246
|
+
|
|
247
|
+
# 两步模式下第一步获取总条数以取得分页
|
|
248
|
+
if two_step:
|
|
249
|
+
# 约定使用0作为条数查询
|
|
250
|
+
params['total_num'] = 0
|
|
251
|
+
init_result = get_qdata(method, **params)
|
|
252
|
+
if str(init_result.get('result_code', '0')) != '0':
|
|
253
|
+
raise Exception('异常代码[%s], 异常信息[%s]' % (init_result['result_code'], init_result['result_msg']))
|
|
254
|
+
if init_result['data'] is not None:
|
|
255
|
+
init_count = len(init_result['data'])
|
|
256
|
+
df_dic[0] = init_result['data']
|
|
257
|
+
total_pages = (init_result['total_num'] + params['page_size'] - 1 - init_count) // params['page_size']
|
|
258
|
+
# 只可能是1或0,表示初次查询是否返回值,否则有问题
|
|
259
|
+
init_page = init_count // params['page_size']
|
|
260
|
+
|
|
261
|
+
if two_step and total_pages > init_page:
|
|
262
|
+
_parts = []
|
|
263
|
+
for i in range(init_page + 1, total_pages + 1):
|
|
264
|
+
params['total_num'] = init_result['total_num']
|
|
265
|
+
params['page_num'] = i
|
|
266
|
+
_part = EXECUTOR_INNER.submit(get_qdata, method=method, **params)
|
|
267
|
+
_parts.append(_part)
|
|
268
|
+
|
|
269
|
+
for _p in as_completed(_parts):
|
|
270
|
+
try:
|
|
271
|
+
if _p is None:
|
|
272
|
+
continue
|
|
273
|
+
elif _p.result() is None:
|
|
274
|
+
continue
|
|
275
|
+
|
|
276
|
+
result_data = _p.result()
|
|
277
|
+
|
|
278
|
+
df_part = result_data['data']
|
|
279
|
+
if len(df_part) > 0:
|
|
280
|
+
df_part.index = df_part.index + (result_data['page_num'] - 1) * params['page_size']
|
|
281
|
+
df_dic[result_data['page_num']] = df_part
|
|
282
|
+
|
|
283
|
+
except Exception as ex:
|
|
284
|
+
raise Exception("并发处理异常,异常函数[%s]" % method)
|
|
285
|
+
df = sort_merge_df_dic(df_dic)
|
|
286
|
+
else:
|
|
287
|
+
# 一步模式请求所有数据
|
|
288
|
+
params['total_num'] = ONE_STEP_NUM
|
|
289
|
+
params['page_size'] = ONE_STEP_NUM
|
|
290
|
+
result = get_qdata(method, **params)
|
|
291
|
+
if str(result.get('result_code', '0')) != '0':
|
|
292
|
+
raise Exception('异常代码[%s], 异常信息[%s]' % (result['result_code'], result['result_msg']))
|
|
293
|
+
df = result['data']
|
|
294
|
+
ret = {'method': method, 'params': params, 'data': df, }
|
|
295
|
+
return ret
|
|
296
|
+
|
|
297
|
+
|
|
298
|
+
def get_exchange_calendar(mkt_code, strt_date='19900101', end_date=None, trdy_flag=None, cols=None, rslt_type=0):
|
|
299
|
+
"""
|
|
300
|
+
获取交易所交易日日历,包括:上海证券交易所,深圳证券交易所等。
|
|
301
|
+
|
|
302
|
+
"""
|
|
303
|
+
|
|
304
|
+
int_param = []
|
|
305
|
+
float_param = []
|
|
306
|
+
if cols:
|
|
307
|
+
int_param = list(set([]).intersection(set(convert_fields(cols))))
|
|
308
|
+
float_param = list(set([]).intersection(set(convert_fields(cols))))
|
|
309
|
+
else:
|
|
310
|
+
cols = ['mkt_code', 'busi_date', 'trdy_flag']
|
|
311
|
+
|
|
312
|
+
if mkt_code:
|
|
313
|
+
params = {
|
|
314
|
+
"mkt_code": mkt_code,
|
|
315
|
+
"strt_date": strt_date,
|
|
316
|
+
"end_date": end_date,
|
|
317
|
+
"trdy_flag": trdy_flag,
|
|
318
|
+
"cols": cols,
|
|
319
|
+
"rslt_type": rslt_type,
|
|
320
|
+
"int_param": int_param,
|
|
321
|
+
"float_param": float_param
|
|
322
|
+
}
|
|
323
|
+
return get_data("get_exch_trd_cldr", **params)
|
|
324
|
+
else:
|
|
325
|
+
warnings.warn("函数[get_exchange_calendar]的参数(mkt_code)为必填项")
|
|
326
|
+
return None
|
|
327
|
+
|
|
328
|
+
|
|
329
|
+
|
|
330
|
+
|
|
331
|
+
def _async_get_hf_data(func, scr_num_list, start_time, end_time, columns, code_type):
|
|
332
|
+
"""
|
|
333
|
+
异步获取高频数据
|
|
334
|
+
"""
|
|
335
|
+
# future和hkstock默认用的单日起止时间
|
|
336
|
+
day_end_time = '235959'
|
|
337
|
+
day_start_time = '000000'
|
|
338
|
+
|
|
339
|
+
scr_num_list = regroup_scr_nums(scr_num_list, HF_CODE_GROUP)
|
|
340
|
+
|
|
341
|
+
if HF_DAY_DELTA > 0:
|
|
342
|
+
# 获取交易日
|
|
343
|
+
if start_time[: 8] == end_time[: 8]:
|
|
344
|
+
trading_day = [start_time[: 8]]
|
|
345
|
+
else:
|
|
346
|
+
#20240606 新增港股交易日判斷
|
|
347
|
+
if code_type == "hkstock" :
|
|
348
|
+
df = get_exchange_calendar('XHKG', start_time[: 8], end_time[: 8], trdy_flag=1)
|
|
349
|
+
if df is None:
|
|
350
|
+
df = get_exchange_calendar('XHKG', trdy_flag=1).tail(1)
|
|
351
|
+
else:
|
|
352
|
+
df = get_exchange_calendar('XSHG', start_time[: 8], end_time[: 8], trdy_flag=1)
|
|
353
|
+
if df is None:
|
|
354
|
+
df = get_exchange_calendar('XSHG', trdy_flag=1).tail(1)
|
|
355
|
+
trading_day = df['busi_date'].tolist()
|
|
356
|
+
|
|
357
|
+
params_list = []
|
|
358
|
+
_futures = []
|
|
359
|
+
if HF_DAY_DELTA > 0:
|
|
360
|
+
day_delta = HF_DAY_DELTA if HF_DAY_DELTA < len(trading_day) else len(trading_day)
|
|
361
|
+
_start_date_list = trading_day[::day_delta]
|
|
362
|
+
_end_date_list = trading_day[day_delta - 1::day_delta]
|
|
363
|
+
if len(_start_date_list) != len(_end_date_list):
|
|
364
|
+
_end_date_list.append(trading_day[-1])
|
|
365
|
+
|
|
366
|
+
for _idx in range(len(_start_date_list)):
|
|
367
|
+
_start_time = _start_date_list[_idx]
|
|
368
|
+
_end_time = _end_date_list[_idx]
|
|
369
|
+
if _idx == 0 and _start_time == start_time[: 8]:
|
|
370
|
+
_start_time = start_time
|
|
371
|
+
if _idx == len(trading_day) - 1 and _end_time == end_time[: 8]:
|
|
372
|
+
_end_time = end_time
|
|
373
|
+
if len(end_time) == 8:
|
|
374
|
+
end_time = '%s%s' % (end_time, day_end_time)
|
|
375
|
+
|
|
376
|
+
for _s in scr_num_list:
|
|
377
|
+
params = {
|
|
378
|
+
"scr_num": _s,
|
|
379
|
+
"strt_time": _start_time,
|
|
380
|
+
"end_time": _end_time,
|
|
381
|
+
"cols": columns,
|
|
382
|
+
}
|
|
383
|
+
params_list.append(params)
|
|
384
|
+
|
|
385
|
+
else: # if SPILIT_DAY > 0
|
|
386
|
+
_start_time = start_time
|
|
387
|
+
_end_time = end_time
|
|
388
|
+
for _s in scr_num_list:
|
|
389
|
+
params = {
|
|
390
|
+
"scr_num": _s,
|
|
391
|
+
"strt_time": _start_time,
|
|
392
|
+
"end_time": _end_time,
|
|
393
|
+
"cols": columns,
|
|
394
|
+
}
|
|
395
|
+
params_list.append(params)
|
|
396
|
+
|
|
397
|
+
for params in params_list:
|
|
398
|
+
_future = EXECUTOR.submit(func, **params)
|
|
399
|
+
_futures.append(_future)
|
|
400
|
+
|
|
401
|
+
dfs = collect_dfs_parallel(func, _futures)
|
|
402
|
+
|
|
403
|
+
global HF_SORT_COLS
|
|
404
|
+
result = sort_merge_df(dfs, HF_SORT_COLS[code_type])
|
|
405
|
+
return result
|
|
406
|
+
|
|
407
|
+
|
|
408
|
+
def regroup_scr_nums(scr_num_list, group_num):
|
|
409
|
+
scr_num_list.sort() # 否则合并时可能排序顺序不对
|
|
410
|
+
new_list = list([','.join(scr_num_list[i:i+group_num]) for i in range(0, len(scr_num_list), group_num)])
|
|
411
|
+
return new_list
|
|
412
|
+
|
|
413
|
+
|
|
414
|
+
def convert_result_data(df, rslt_type):
|
|
415
|
+
rslt = None
|
|
416
|
+
if df is not None:
|
|
417
|
+
if rslt_type == 0:
|
|
418
|
+
rslt = df
|
|
419
|
+
else:
|
|
420
|
+
rslt = df.values
|
|
421
|
+
return rslt
|
|
422
|
+
|
|
423
|
+
def collect_dfs_parallel(func, _futures):
|
|
424
|
+
dfs = []
|
|
425
|
+
if PARALLEL_MODE in {'Coroutine'}:
|
|
426
|
+
gevent.joinall(_futures)
|
|
427
|
+
for _f in _futures:
|
|
428
|
+
try:
|
|
429
|
+
if _f is None:
|
|
430
|
+
continue
|
|
431
|
+
elif _f.value is None:
|
|
432
|
+
continue
|
|
433
|
+
elif _f.value['data'] is None:
|
|
434
|
+
continue
|
|
435
|
+
|
|
436
|
+
if len(_f.value['data']) > 0:
|
|
437
|
+
dfs.append(_f.value['data'])
|
|
438
|
+
except Exception as ex:
|
|
439
|
+
warn_str = "并发处理异常,异常函数[%s]" % func
|
|
440
|
+
warnings.warn(warn_str)
|
|
441
|
+
# raise Exception("并发处理异常,异常函数[%s]" % func)
|
|
442
|
+
else:
|
|
443
|
+
for _f in as_completed(_futures):
|
|
444
|
+
try:
|
|
445
|
+
if _f is None:
|
|
446
|
+
continue
|
|
447
|
+
elif _f.result() is None:
|
|
448
|
+
continue
|
|
449
|
+
elif _f.result()['data'] is None:
|
|
450
|
+
continue
|
|
451
|
+
|
|
452
|
+
if len(_f.result()['data']) > 0:
|
|
453
|
+
dfs.append(_f.result()['data'])
|
|
454
|
+
except Exception as ex:
|
|
455
|
+
import traceback
|
|
456
|
+
warn_str = "并发处理异常,异常函数[%s],异常信息[%s]" % (func, traceback.format_exc())
|
|
457
|
+
warnings.warn(warn_str)
|
|
458
|
+
return dfs
|
|
459
|
+
|
|
460
|
+
#20240628 add 港股基本信息接口
|
|
461
|
+
def get_security_info(scr_num_list=None, scr_type_list=None, cols=None):
|
|
462
|
+
"""
|
|
463
|
+
获取港股的基本信息
|
|
464
|
+
|
|
465
|
+
"""
|
|
466
|
+
int_param = []
|
|
467
|
+
float_param = []
|
|
468
|
+
if cols:
|
|
469
|
+
int_param = list(set(int_param).intersection(set(convert_fields(cols))))
|
|
470
|
+
float_param = list(set(float_param).intersection(set(convert_fields(cols))))
|
|
471
|
+
else:
|
|
472
|
+
cols = [
|
|
473
|
+
'scr_code',
|
|
474
|
+
'scr_num',
|
|
475
|
+
'scr_abbr',
|
|
476
|
+
'scr_name',
|
|
477
|
+
'mkt_code',
|
|
478
|
+
'list_stat',
|
|
479
|
+
'list_date',
|
|
480
|
+
'delt_date',
|
|
481
|
+
'scr_type',
|
|
482
|
+
'scr_boar_type_code',
|
|
483
|
+
'ofer_crrc_code',
|
|
484
|
+
'trd_unit',
|
|
485
|
+
'isin_num'
|
|
486
|
+
]
|
|
487
|
+
|
|
488
|
+
params = {
|
|
489
|
+
"scr_num_list": scr_num_list,
|
|
490
|
+
"scr_type_list": scr_type_list,
|
|
491
|
+
"cols": cols,
|
|
492
|
+
"int_param": int_param,
|
|
493
|
+
"float_param": float_param
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
return get_data("get_hkscr_basc_info", **params)
|
|
497
|
+
|
|
498
|
+
#20240628 add 港股复权因子接口
|
|
499
|
+
def get_stk_rstr_fctr(scr_num_list=None, strt_date=None, end_date=None, cols=None):
|
|
500
|
+
"""
|
|
501
|
+
获取港股复权因子信息
|
|
502
|
+
|
|
503
|
+
"""
|
|
504
|
+
int_param = []
|
|
505
|
+
float_param = ['accu_rstr_cnst', 'aacu_rstr_fctr', 'aggr_accu_rstr_cnst', 'aggr_accu_rstr_fctr']
|
|
506
|
+
if cols:
|
|
507
|
+
int_param = list(set(int_param).intersection(set(convert_fields(cols))))
|
|
508
|
+
float_param = list(set(float_param).intersection(set(convert_fields(cols))))
|
|
509
|
+
else:
|
|
510
|
+
cols = [
|
|
511
|
+
'scr_num',
|
|
512
|
+
'scr_code',
|
|
513
|
+
'dr_day',
|
|
514
|
+
'accu_rstr_cnst',
|
|
515
|
+
'accu_rstr_fctr',
|
|
516
|
+
'aggr_accu_rstr_cnst',
|
|
517
|
+
'aggr_accu_rstr_fctr',
|
|
518
|
+
'aggr_rati_rstr_fctr',
|
|
519
|
+
'info_mine',
|
|
520
|
+
'exd_if_susp',
|
|
521
|
+
'next_resup_date',
|
|
522
|
+
]
|
|
523
|
+
|
|
524
|
+
params = {
|
|
525
|
+
"scr_num_list": scr_num_list,
|
|
526
|
+
"strt_date": strt_date,
|
|
527
|
+
"end_date": end_date,
|
|
528
|
+
"cols": cols,
|
|
529
|
+
"int_param": int_param,
|
|
530
|
+
"float_param": float_param
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
return get_data("get_hkstk_rstr_fctr", **params)
|
|
534
|
+
|
|
535
|
+
|
|
536
|
+
|
|
537
|
+
|
|
538
|
+
#20240606 新增港股查询api
|
|
539
|
+
@wait_until_bind()
|
|
540
|
+
def get_deal(scr_num_list, strt_time, end_time, cols=None, rslt_type=0):
|
|
541
|
+
"""
|
|
542
|
+
获取港股逐笔成交数据
|
|
543
|
+
"""
|
|
544
|
+
|
|
545
|
+
if scr_num_list is None or strt_time is None or end_time is None:
|
|
546
|
+
warnings.warn("函数[hk.get_deal]的参数(scr_num_list, strt_time, end_time)为必填项")
|
|
547
|
+
return None
|
|
548
|
+
|
|
549
|
+
if isinstance(scr_num_list, str):
|
|
550
|
+
scr_num_list = scr_num_list.split(',')
|
|
551
|
+
|
|
552
|
+
stk_list = []
|
|
553
|
+
|
|
554
|
+
global CODE_SECURITY_MAP
|
|
555
|
+
if len(CODE_SECURITY_MAP) == 0:
|
|
556
|
+
load_basic_info()
|
|
557
|
+
|
|
558
|
+
scr_code_list = \
|
|
559
|
+
[
|
|
560
|
+
_code for _code in scr_num_list if _code.split('.')[1] in ['XHKG']
|
|
561
|
+
]
|
|
562
|
+
|
|
563
|
+
|
|
564
|
+
noexist_code_list = set(scr_code_list) - set(list(CODE_SECURITY_MAP.keys()))
|
|
565
|
+
if len(noexist_code_list):
|
|
566
|
+
warnings.warn("函数[scr_num_list]中指定代码不存在[%s]" % ''.join(noexist_code_list))
|
|
567
|
+
return None
|
|
568
|
+
|
|
569
|
+
|
|
570
|
+
|
|
571
|
+
try:
|
|
572
|
+
|
|
573
|
+
stk_list = [_scr.replace('.XHKG', '.HK') for _scr in scr_num_list]
|
|
574
|
+
|
|
575
|
+
except IndexError:
|
|
576
|
+
raise Exception('scr_num_list输入格式异常[%s]' % scr_num_list)
|
|
577
|
+
|
|
578
|
+
stk_result = None
|
|
579
|
+
if len(stk_list) > 0:
|
|
580
|
+
stk_result = _async_get_hf_data(
|
|
581
|
+
get_hkstock_deal, stk_list, strt_time, end_time,
|
|
582
|
+
cols, 'hkstock'
|
|
583
|
+
)
|
|
584
|
+
|
|
585
|
+
final_result = None
|
|
586
|
+
concat_list = []
|
|
587
|
+
if stk_result is not None:
|
|
588
|
+
concat_list.append(stk_result)
|
|
589
|
+
|
|
590
|
+
if len(concat_list) > 1:
|
|
591
|
+
final_result = pd.concat(
|
|
592
|
+
concat_list,
|
|
593
|
+
axis=0, sort=False, ignore_index=True
|
|
594
|
+
)
|
|
595
|
+
elif len(concat_list) == 1:
|
|
596
|
+
final_result = concat_list[0]
|
|
597
|
+
|
|
598
|
+
final_result = convert_result_data(final_result, rslt_type)
|
|
599
|
+
|
|
600
|
+
return final_result
|
|
601
|
+
|
|
602
|
+
def get_hkstock_deal(scr_num, strt_time=None, end_time=None, cols=None, rslt_type=0):
|
|
603
|
+
"""
|
|
604
|
+
批量获取港股逐笔成交数据
|
|
605
|
+
|
|
606
|
+
"""
|
|
607
|
+
|
|
608
|
+
int_param = [
|
|
609
|
+
'total_num', 'page_num', 'total_pages',
|
|
610
|
+
't_id', 'qty'
|
|
611
|
+
]
|
|
612
|
+
float_param = [
|
|
613
|
+
'price'
|
|
614
|
+
]
|
|
615
|
+
if cols:
|
|
616
|
+
fix_cols = \
|
|
617
|
+
['scr_num', 'date_time']
|
|
618
|
+
if isinstance(cols, str):
|
|
619
|
+
cols = cols.split(',')
|
|
620
|
+
tmp_cols = fix_cols + cols
|
|
621
|
+
cols = list(set(tmp_cols))
|
|
622
|
+
cols.sort(key=tmp_cols.index)
|
|
623
|
+
|
|
624
|
+
int_param = list(set(int_param).intersection(set(cols)))
|
|
625
|
+
float_param = list(set(float_param).intersection(set(cols)))
|
|
626
|
+
|
|
627
|
+
if isinstance(cols, list):
|
|
628
|
+
cols = ','.join(cols)
|
|
629
|
+
|
|
630
|
+
if scr_num:
|
|
631
|
+
params = {
|
|
632
|
+
"scr_num": scr_num,
|
|
633
|
+
"strt_time": strt_time,
|
|
634
|
+
"end_time": end_time,
|
|
635
|
+
"cols": cols,
|
|
636
|
+
"page_num": 1,
|
|
637
|
+
"page_size": CONFIG_PAGE_SIZE,
|
|
638
|
+
"rslt_type": rslt_type,
|
|
639
|
+
"api_type": "quote",
|
|
640
|
+
"int_param": int_param,
|
|
641
|
+
"float_param": float_param
|
|
642
|
+
}
|
|
643
|
+
|
|
644
|
+
# 20220812 统一改为与期货快照一致
|
|
645
|
+
quote_data = quote_single_part(URL_GET_HKSTK_DEAL, params)
|
|
646
|
+
return quote_data
|
|
647
|
+
|
|
648
|
+
else:
|
|
649
|
+
warnings.warn("函数[get_hkstock_deal]的参数(scr_num)为必填项")
|
|
650
|
+
return None
|
|
651
|
+
|
|
652
|
+
|
|
653
|
+
@wait_until_bind()
|
|
654
|
+
def get_tick(scr_num_list, strt_time, end_time, cols=None, rslt_type=0):
|
|
655
|
+
"""
|
|
656
|
+
获取港股快照数据
|
|
657
|
+
"""
|
|
658
|
+
|
|
659
|
+
if scr_num_list is None or strt_time is None or end_time is None:
|
|
660
|
+
warnings.warn("函数[get_tick]的参数(scr_num_list, strt_time, end_time)为必填项")
|
|
661
|
+
return None
|
|
662
|
+
|
|
663
|
+
if isinstance(scr_num_list, str):
|
|
664
|
+
scr_num_list = scr_num_list.split(',')
|
|
665
|
+
|
|
666
|
+
stk_list = []
|
|
667
|
+
|
|
668
|
+
global CODE_SECURITY_MAP
|
|
669
|
+
if len(CODE_SECURITY_MAP) == 0:
|
|
670
|
+
load_basic_info()
|
|
671
|
+
|
|
672
|
+
scr_code_list = \
|
|
673
|
+
[
|
|
674
|
+
_code for _code in scr_num_list if _code.split('.')[1] in ['XHKG']
|
|
675
|
+
]
|
|
676
|
+
|
|
677
|
+
|
|
678
|
+
noexist_code_list = set(scr_code_list) - set(list(CODE_SECURITY_MAP.keys()))
|
|
679
|
+
if len(noexist_code_list):
|
|
680
|
+
warnings.warn("函数[scr_num_list]中指定代码不存在[%s]" % ''.join(noexist_code_list))
|
|
681
|
+
return None
|
|
682
|
+
|
|
683
|
+
try:
|
|
684
|
+
stk_list = [_scr.replace('.XHKG', '.HK') for _scr in scr_num_list]
|
|
685
|
+
except IndexError:
|
|
686
|
+
raise Exception('scr_num_list输入格式异常[%s]' % scr_num_list)
|
|
687
|
+
|
|
688
|
+
stk_result = None
|
|
689
|
+
if len(stk_list) > 0:
|
|
690
|
+
stk_result = _async_get_hf_data(
|
|
691
|
+
get_hkstock_tick, stk_list, strt_time, end_time,
|
|
692
|
+
cols, 'hkstock'
|
|
693
|
+
)
|
|
694
|
+
|
|
695
|
+
final_result = None
|
|
696
|
+
concat_list = []
|
|
697
|
+
if stk_result is not None:
|
|
698
|
+
concat_list.append(stk_result)
|
|
699
|
+
|
|
700
|
+
if len(concat_list) > 1:
|
|
701
|
+
final_result = pd.concat(
|
|
702
|
+
concat_list,
|
|
703
|
+
axis=0, sort=False, ignore_index=True
|
|
704
|
+
)
|
|
705
|
+
elif len(concat_list) == 1:
|
|
706
|
+
final_result = concat_list[0]
|
|
707
|
+
|
|
708
|
+
final_result = convert_result_data(final_result, rslt_type)
|
|
709
|
+
|
|
710
|
+
return final_result
|
|
711
|
+
|
|
712
|
+
def get_hkstock_tick(scr_num, strt_time=None, end_time=None, cols=None, rslt_type=0):
|
|
713
|
+
"""
|
|
714
|
+
批量获取股票代码快照数据
|
|
715
|
+
|
|
716
|
+
"""
|
|
717
|
+
|
|
718
|
+
int_param = [
|
|
719
|
+
'total_num', 'page_num', 'total_pages',
|
|
720
|
+
'volume', 'shortsell_volume', 'ie_volume', 'noliquidity_providers', 'lpb_no',
|
|
721
|
+
'bid_size1', 'bid_size2', 'bid_size3', 'bid_size4', 'bid_size5',
|
|
722
|
+
'bid_size6', 'bid_size7', 'bid_size8', 'bid_size9', 'bid_size10',
|
|
723
|
+
'bid_order1', 'bid_order2', 'bid_order3', 'bid_order4', 'bid_order5',
|
|
724
|
+
'bid_order6', 'bid_order7', 'bid_order8', 'bid_order9', 'bid_order10',
|
|
725
|
+
'offer_size1', 'offer_size2', 'offer_size3', 'offer_size4', 'offer_size5',
|
|
726
|
+
'offer_size6', 'offer_size7', 'offer_size8', 'offer_size9', 'offer_size10',
|
|
727
|
+
'offer_order1', 'offer_order2', 'offer_order3', 'offer_order4', 'offer_order5',
|
|
728
|
+
'offer_order6', 'offer_order7', 'offer_order8', 'offer_order9', 'offer_order10'
|
|
729
|
+
]
|
|
730
|
+
float_param = [
|
|
731
|
+
'turnover', 'high_px', 'low_px', 'last_px', 'shortsell_turnover', 'nominal_px', 'close_px',
|
|
732
|
+
'ie_price', 'refer_price', 'lower', 'upper', 'order_imbal_quantity', 'yield', 'open_px', 'preclose_px',
|
|
733
|
+
'bid_price1', 'bid_price2', 'bid_price3', 'bid_price4', 'bid_price5',
|
|
734
|
+
'bid_price6', 'bid_price7', 'bid_price8', 'bid_price9', 'bid_price10',
|
|
735
|
+
'offer_price1', 'offer_price2', 'offer_price3', 'offer_price4', 'offer_price5',
|
|
736
|
+
'offer_price6', 'offer_price7', 'offer_price8', 'offer_price9', 'offer_price10'
|
|
737
|
+
|
|
738
|
+
]
|
|
739
|
+
if cols:
|
|
740
|
+
fix_cols = \
|
|
741
|
+
['scr_num', 'date_time']
|
|
742
|
+
if isinstance(cols, str):
|
|
743
|
+
cols = cols.split(',')
|
|
744
|
+
tmp_cols = fix_cols + cols
|
|
745
|
+
cols = list(set(tmp_cols))
|
|
746
|
+
cols.sort(key=tmp_cols.index)
|
|
747
|
+
|
|
748
|
+
int_param = list(set(int_param).intersection(set(cols)))
|
|
749
|
+
float_param = list(set(float_param).intersection(set(cols)))
|
|
750
|
+
|
|
751
|
+
if isinstance(cols, list):
|
|
752
|
+
cols = ','.join(cols)
|
|
753
|
+
|
|
754
|
+
if scr_num:
|
|
755
|
+
params = {
|
|
756
|
+
"scr_num": scr_num,
|
|
757
|
+
"strt_time": strt_time,
|
|
758
|
+
"end_time": end_time,
|
|
759
|
+
"cols": cols,
|
|
760
|
+
"page_num": 1,
|
|
761
|
+
"page_size": CONFIG_PAGE_SIZE,
|
|
762
|
+
"rslt_type": rslt_type,
|
|
763
|
+
"api_type": "quote",
|
|
764
|
+
"int_param": int_param,
|
|
765
|
+
"float_param": float_param
|
|
766
|
+
}
|
|
767
|
+
|
|
768
|
+
# 20220812 统一改为与期货快照一致
|
|
769
|
+
quote_data = quote_single_part(URL_GET_HKSTK_TICK, params)
|
|
770
|
+
return quote_data
|
|
771
|
+
|
|
772
|
+
else:
|
|
773
|
+
warnings.warn("函数[get_hkstock_tick]的参数(scr_num)为必填项")
|
|
774
|
+
return None
|
|
775
|
+
|
|
776
|
+
@wait_until_bind()
|
|
777
|
+
def get_oddlot_order(scr_num_list, strt_time, end_time, cols=None, rslt_type=0):
|
|
778
|
+
"""
|
|
779
|
+
获取港股碎股数据
|
|
780
|
+
"""
|
|
781
|
+
|
|
782
|
+
if scr_num_list is None or strt_time is None or end_time is None:
|
|
783
|
+
warnings.warn("函数[get_odd]的参数(scr_num_list, strt_time, end_time)为必填项")
|
|
784
|
+
return None
|
|
785
|
+
|
|
786
|
+
if isinstance(scr_num_list, str):
|
|
787
|
+
scr_num_list = scr_num_list.split(',')
|
|
788
|
+
|
|
789
|
+
stk_list = []
|
|
790
|
+
|
|
791
|
+
global CODE_SECURITY_MAP
|
|
792
|
+
if len(CODE_SECURITY_MAP) == 0:
|
|
793
|
+
load_basic_info()
|
|
794
|
+
|
|
795
|
+
scr_code_list = \
|
|
796
|
+
[
|
|
797
|
+
_code for _code in scr_num_list if _code.split('.')[1] in ['XHKG']
|
|
798
|
+
]
|
|
799
|
+
|
|
800
|
+
noexist_code_list = set(scr_code_list) - set(list(CODE_SECURITY_MAP.keys()))
|
|
801
|
+
if len(noexist_code_list):
|
|
802
|
+
warnings.warn("函数[scr_num_list]中指定代码不存在[%s]" % ''.join(noexist_code_list))
|
|
803
|
+
return None
|
|
804
|
+
|
|
805
|
+
try:
|
|
806
|
+
stk_list = [_scr.replace('.XHKG', '.HK') for _scr in scr_num_list]
|
|
807
|
+
|
|
808
|
+
except IndexError:
|
|
809
|
+
raise Exception('scr_num_list输入格式异常[%s]' % scr_num_list)
|
|
810
|
+
|
|
811
|
+
stk_result = None
|
|
812
|
+
if len(stk_list) > 0:
|
|
813
|
+
stk_result = _async_get_hf_data(
|
|
814
|
+
get_hkstock_odd, stk_list, strt_time, end_time,
|
|
815
|
+
cols, 'hkstock'
|
|
816
|
+
)
|
|
817
|
+
|
|
818
|
+
final_result = None
|
|
819
|
+
concat_list = []
|
|
820
|
+
if stk_result is not None:
|
|
821
|
+
concat_list.append(stk_result)
|
|
822
|
+
|
|
823
|
+
if len(concat_list) > 1:
|
|
824
|
+
final_result = pd.concat(
|
|
825
|
+
concat_list,
|
|
826
|
+
axis=0, sort=False, ignore_index=True
|
|
827
|
+
)
|
|
828
|
+
elif len(concat_list) == 1:
|
|
829
|
+
final_result = concat_list[0]
|
|
830
|
+
|
|
831
|
+
final_result = convert_result_data(final_result, rslt_type)
|
|
832
|
+
|
|
833
|
+
return final_result
|
|
834
|
+
|
|
835
|
+
def get_hkstock_odd(scr_num, strt_time=None, end_time=None, cols=None, rslt_type=0):
|
|
836
|
+
"""
|
|
837
|
+
批量获取港股碎股数据
|
|
838
|
+
|
|
839
|
+
"""
|
|
840
|
+
|
|
841
|
+
int_param = [
|
|
842
|
+
'total_num', 'page_num', 'total_pages',
|
|
843
|
+
'order_id', 'qty', 'broker_id'
|
|
844
|
+
]
|
|
845
|
+
float_param = [
|
|
846
|
+
'price'
|
|
847
|
+
]
|
|
848
|
+
if cols:
|
|
849
|
+
fix_cols = \
|
|
850
|
+
['scr_num', 'date_time']
|
|
851
|
+
if isinstance(cols, str):
|
|
852
|
+
cols = cols.split(',')
|
|
853
|
+
tmp_cols = fix_cols + cols
|
|
854
|
+
cols = list(set(tmp_cols))
|
|
855
|
+
cols.sort(key=tmp_cols.index)
|
|
856
|
+
|
|
857
|
+
int_param = list(set(int_param).intersection(set(cols)))
|
|
858
|
+
float_param = list(set(float_param).intersection(set(cols)))
|
|
859
|
+
|
|
860
|
+
if isinstance(cols, list):
|
|
861
|
+
cols = ','.join(cols)
|
|
862
|
+
|
|
863
|
+
if scr_num:
|
|
864
|
+
params = {
|
|
865
|
+
"scr_num": scr_num,
|
|
866
|
+
"strt_time": strt_time,
|
|
867
|
+
"end_time": end_time,
|
|
868
|
+
"cols": cols,
|
|
869
|
+
"page_num": 1,
|
|
870
|
+
"page_size": CONFIG_PAGE_SIZE,
|
|
871
|
+
"rslt_type": rslt_type,
|
|
872
|
+
"api_type": "quote",
|
|
873
|
+
"int_param": int_param,
|
|
874
|
+
"float_param": float_param
|
|
875
|
+
}
|
|
876
|
+
|
|
877
|
+
# 20220812 统一改为与期货快照一致
|
|
878
|
+
quote_data = quote_single_part(URL_GET_HKSTK_ODD, params)
|
|
879
|
+
return quote_data
|
|
880
|
+
|
|
881
|
+
else:
|
|
882
|
+
warnings.warn("函数[get_hkstock_odd]的参数(scr_num)为必填项")
|
|
883
|
+
return None
|
|
884
|
+
|
|
885
|
+
@wait_until_bind()
|
|
886
|
+
def get_broker_queue(scr_num_list, strt_time, end_time, cols=None, rslt_type=0):
|
|
887
|
+
"""
|
|
888
|
+
获取港股经纪商队列数据
|
|
889
|
+
"""
|
|
890
|
+
|
|
891
|
+
if scr_num_list is None or strt_time is None or end_time is None:
|
|
892
|
+
warnings.warn("函数[get_broker]的参数(scr_num_list, strt_time, end_time)为必填项")
|
|
893
|
+
return None
|
|
894
|
+
|
|
895
|
+
if isinstance(scr_num_list, str):
|
|
896
|
+
scr_num_list = scr_num_list.split(',')
|
|
897
|
+
|
|
898
|
+
stk_list = []
|
|
899
|
+
|
|
900
|
+
global CODE_SECURITY_MAP
|
|
901
|
+
if len(CODE_SECURITY_MAP) == 0:
|
|
902
|
+
load_basic_info()
|
|
903
|
+
|
|
904
|
+
scr_code_list = \
|
|
905
|
+
[
|
|
906
|
+
_code for _code in scr_num_list if _code.split('.')[1] in ['XHKG']
|
|
907
|
+
]
|
|
908
|
+
|
|
909
|
+
|
|
910
|
+
noexist_code_list = set(scr_code_list) - set(list(CODE_SECURITY_MAP.keys()))
|
|
911
|
+
if len(noexist_code_list):
|
|
912
|
+
warnings.warn("函数[scr_num_list]中指定代码不存在[%s]" % ''.join(noexist_code_list))
|
|
913
|
+
return None
|
|
914
|
+
|
|
915
|
+
try:
|
|
916
|
+
|
|
917
|
+
stk_list = [_scr.replace('.XHKG', '.HK') for _scr in scr_num_list]
|
|
918
|
+
|
|
919
|
+
except IndexError:
|
|
920
|
+
raise Exception('scr_num_list输入格式异常[%s]' % scr_num_list)
|
|
921
|
+
|
|
922
|
+
stk_result = None
|
|
923
|
+
if len(stk_list) > 0:
|
|
924
|
+
stk_result = _async_get_hf_data(
|
|
925
|
+
get_hkstock_broker, stk_list, strt_time, end_time,
|
|
926
|
+
cols, 'hkstock'
|
|
927
|
+
)
|
|
928
|
+
|
|
929
|
+
final_result = None
|
|
930
|
+
concat_list = []
|
|
931
|
+
if stk_result is not None:
|
|
932
|
+
concat_list.append(stk_result)
|
|
933
|
+
|
|
934
|
+
if len(concat_list) > 1:
|
|
935
|
+
final_result = pd.concat(
|
|
936
|
+
concat_list,
|
|
937
|
+
axis=0, sort=False, ignore_index=True
|
|
938
|
+
)
|
|
939
|
+
elif len(concat_list) == 1:
|
|
940
|
+
final_result = concat_list[0]
|
|
941
|
+
|
|
942
|
+
final_result = convert_result_data(final_result, rslt_type)
|
|
943
|
+
|
|
944
|
+
return final_result
|
|
945
|
+
|
|
946
|
+
def get_hkstock_broker(scr_num, strt_time=None, end_time=None, cols=None, rslt_type=0):
|
|
947
|
+
"""
|
|
948
|
+
批量获取港股经纪商队列数据
|
|
949
|
+
|
|
950
|
+
"""
|
|
951
|
+
|
|
952
|
+
int_param = [
|
|
953
|
+
'total_num', 'page_num', 'total_pages',
|
|
954
|
+
'side', 'count'
|
|
955
|
+
]
|
|
956
|
+
float_param = []
|
|
957
|
+
if cols:
|
|
958
|
+
fix_cols = \
|
|
959
|
+
['scr_num', 'date_time']
|
|
960
|
+
if isinstance(cols, str):
|
|
961
|
+
cols = cols.split(',')
|
|
962
|
+
tmp_cols = fix_cols + cols
|
|
963
|
+
cols = list(set(tmp_cols))
|
|
964
|
+
cols.sort(key=tmp_cols.index)
|
|
965
|
+
|
|
966
|
+
int_param = list(set(int_param).intersection(set(cols)))
|
|
967
|
+
float_param = list(set(float_param).intersection(set(cols)))
|
|
968
|
+
|
|
969
|
+
if isinstance(cols, list):
|
|
970
|
+
cols = ','.join(cols)
|
|
971
|
+
|
|
972
|
+
if scr_num:
|
|
973
|
+
params = {
|
|
974
|
+
"scr_num": scr_num,
|
|
975
|
+
"strt_time": strt_time,
|
|
976
|
+
"end_time": end_time,
|
|
977
|
+
"cols": cols,
|
|
978
|
+
"page_num": 1,
|
|
979
|
+
"page_size": CONFIG_PAGE_SIZE,
|
|
980
|
+
"rslt_type": rslt_type,
|
|
981
|
+
"api_type": "quote",
|
|
982
|
+
"int_param": int_param,
|
|
983
|
+
"float_param": float_param
|
|
984
|
+
}
|
|
985
|
+
|
|
986
|
+
# 20220812 统一改为与期货快照一致
|
|
987
|
+
quote_data = quote_single_part(URL_GET_HKSTK_BROKER, params)
|
|
988
|
+
return quote_data
|
|
989
|
+
|
|
990
|
+
else:
|
|
991
|
+
warnings.warn("函数[get_hkstock_broker]的参数(scr_num)为必填项")
|
|
992
|
+
return None
|
|
993
|
+
|
|
994
|
+
@wait_until_bind()
|
|
995
|
+
def get_index_tick(scr_num_list, strt_time, end_time, cols=None, rslt_type=0):
|
|
996
|
+
"""
|
|
997
|
+
获取港股指数快照数据
|
|
998
|
+
"""
|
|
999
|
+
|
|
1000
|
+
if scr_num_list is None or strt_time is None or end_time is None:
|
|
1001
|
+
warnings.warn("函数[get_index_tick]的参数(scr_num_list, strt_time, end_time)为必填项")
|
|
1002
|
+
return None
|
|
1003
|
+
|
|
1004
|
+
if isinstance(scr_num_list, str):
|
|
1005
|
+
scr_num_list = scr_num_list.split(',')
|
|
1006
|
+
|
|
1007
|
+
stk_list = []
|
|
1008
|
+
|
|
1009
|
+
global CODE_SECURITY_MAP
|
|
1010
|
+
if len(CODE_SECURITY_MAP) == 0:
|
|
1011
|
+
load_basic_info()
|
|
1012
|
+
|
|
1013
|
+
scr_code_list = \
|
|
1014
|
+
[
|
|
1015
|
+
_code for _code in scr_num_list if _code.split('.')[1] in ['XHKG']
|
|
1016
|
+
]
|
|
1017
|
+
|
|
1018
|
+
# 等待港股代码服务完成后开放
|
|
1019
|
+
# noexist_code_list = set(scr_code_list) - set(list(CODE_SECURITY_MAP.keys()))
|
|
1020
|
+
# if len(noexist_code_list):
|
|
1021
|
+
# warnings.warn("函数[scr_num_list]中指定代码不存在[%s]" % ''.join(noexist_code_list))
|
|
1022
|
+
# return None
|
|
1023
|
+
|
|
1024
|
+
try:
|
|
1025
|
+
|
|
1026
|
+
stk_list = [_scr.replace('.XHKG', '.HK') for _scr in scr_num_list]
|
|
1027
|
+
|
|
1028
|
+
except IndexError:
|
|
1029
|
+
raise Exception('scr_num_list输入格式异常[%s]' % scr_num_list)
|
|
1030
|
+
|
|
1031
|
+
stk_result = None
|
|
1032
|
+
if len(stk_list) > 0:
|
|
1033
|
+
stk_result = _async_get_hf_data(
|
|
1034
|
+
get_hkstock_index, stk_list, strt_time, end_time,
|
|
1035
|
+
cols, 'hkstock'
|
|
1036
|
+
)
|
|
1037
|
+
|
|
1038
|
+
final_result = None
|
|
1039
|
+
concat_list = []
|
|
1040
|
+
if stk_result is not None:
|
|
1041
|
+
concat_list.append(stk_result)
|
|
1042
|
+
|
|
1043
|
+
if len(concat_list) > 1:
|
|
1044
|
+
final_result = pd.concat(
|
|
1045
|
+
concat_list,
|
|
1046
|
+
axis=0, sort=False, ignore_index=True
|
|
1047
|
+
)
|
|
1048
|
+
elif len(concat_list) == 1:
|
|
1049
|
+
final_result = concat_list[0]
|
|
1050
|
+
|
|
1051
|
+
#因index原始数据存在重复,对index_tick返回数据进行去重
|
|
1052
|
+
|
|
1053
|
+
if final_result is not None:
|
|
1054
|
+
final_result.drop_duplicates(subset=['scr_num', 'date_time'], keep='first', inplace=True)
|
|
1055
|
+
final_result = convert_result_data(final_result, rslt_type)
|
|
1056
|
+
|
|
1057
|
+
return final_result
|
|
1058
|
+
|
|
1059
|
+
def get_hkstock_index(scr_num, strt_time=None, end_time=None, cols=None, rslt_type=0):
|
|
1060
|
+
"""
|
|
1061
|
+
批量获取港股指数快照数据
|
|
1062
|
+
|
|
1063
|
+
"""
|
|
1064
|
+
|
|
1065
|
+
int_param = [
|
|
1066
|
+
'total_num', 'page_num', 'total_pages',
|
|
1067
|
+
'index_volume'
|
|
1068
|
+
]
|
|
1069
|
+
float_param = [
|
|
1070
|
+
'index_value', 'netchg_prevday', 'high', 'low', 'eas_value', 'index_turnover',
|
|
1071
|
+
'open', 'close', 'prevses_close', 'netchg_prevday_pct'
|
|
1072
|
+
]
|
|
1073
|
+
if cols:
|
|
1074
|
+
fix_cols = \
|
|
1075
|
+
['scr_num', 'date_time']
|
|
1076
|
+
if isinstance(cols, str):
|
|
1077
|
+
cols = cols.split(',')
|
|
1078
|
+
tmp_cols = fix_cols + cols
|
|
1079
|
+
cols = list(set(tmp_cols))
|
|
1080
|
+
cols.sort(key=tmp_cols.index)
|
|
1081
|
+
|
|
1082
|
+
int_param = list(set(int_param).intersection(set(cols)))
|
|
1083
|
+
float_param = list(set(float_param).intersection(set(cols)))
|
|
1084
|
+
|
|
1085
|
+
if isinstance(cols, list):
|
|
1086
|
+
cols = ','.join(cols)
|
|
1087
|
+
|
|
1088
|
+
if scr_num:
|
|
1089
|
+
params = {
|
|
1090
|
+
"scr_num": scr_num,
|
|
1091
|
+
"strt_time": strt_time,
|
|
1092
|
+
"end_time": end_time,
|
|
1093
|
+
"cols": cols,
|
|
1094
|
+
"page_num": 1,
|
|
1095
|
+
"page_size": CONFIG_PAGE_SIZE,
|
|
1096
|
+
"rslt_type": rslt_type,
|
|
1097
|
+
"api_type": "quote",
|
|
1098
|
+
"int_param": int_param,
|
|
1099
|
+
"float_param": float_param
|
|
1100
|
+
}
|
|
1101
|
+
|
|
1102
|
+
# 20220812 统一改为与期货快照一致
|
|
1103
|
+
quote_data = quote_single_part(URL_GET_HKSTK_INDEX, params)
|
|
1104
|
+
return quote_data
|
|
1105
|
+
|
|
1106
|
+
else:
|
|
1107
|
+
warnings.warn("函数[get_hkstock_index]的参数(scr_num)为必填项")
|
|
1108
|
+
return None
|
|
1109
|
+
|
|
1110
|
+
|