Skip to content

Commit 9758f2c

Browse files
committed
Merge branch 'dev' into 'master'
Dev See merge request server/openapi/openapi-python-sdk!158
2 parents 10a2d2e + e8f6512 commit 9758f2c

File tree

6 files changed

+45
-18
lines changed

6 files changed

+45
-18
lines changed

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,10 @@
1+
## 2.3.1 (2023-02-23)
2+
### New
3+
- 支持2FA token自定义刷新间隔,可通过 client_config.token_refresh_duration = 0 关闭自动刷新
4+
### Fix
5+
- tick数据推送字段异常问题
6+
- 若开启token,刷新线程不随主线程退出的问题
7+
18
## 2.3.0 (2023-02-16)
29
### New
310
- 支持配置文件

tigeropen/common/util/tick_util.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ def get_part_code_name(code):
1616

1717

1818
def get_trade_condition_map(quote_level):
19-
if quote_level.lower().startswith(HK_QUOTE_LEVEL_PREFIX):
19+
if quote_level and quote_level.lower().startswith(HK_QUOTE_LEVEL_PREFIX):
2020
return HK_TRADE_COND_MAP
2121
return US_TRADE_COND_MAP
2222

tigeropen/push/push_client.py

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -508,10 +508,18 @@ def _generate_headers(self, extra_headers=None):
508508
return headers
509509

510510
def _convert_tick(self, tick):
511+
""""将原始数据转换为tick列表。
512+
513+
'{"symbol":"00700","type":"-+","sn":"17441","priceBase":"3552","priceOffset":1,"time":["1677119933174","97"],"price":["0","2"],"volume":["300","100"],"quoteLevel":"hkStockQuoteLv2","timestamp":"1677119933391","secType":"STK"}'
514+
515+
转换为tick的列表:
516+
[{'tick_type': '-', 'price': 355.2, 'volume': 300, 'part_code': None, 'part_code_name': None, 'cond': None, 'time': 1677119933174, 'sn': 17441, 'quote_level': 'hkStockQuoteLv2', 'timestamp': 1677119933391, 'sec_type': 'STK'},
517+
{'tick_type': '+', 'price': 355.4, 'volume': 100, 'part_code': None, 'part_code_name': None, 'cond': None, 'time': 1677119933271, 'sn': 17442, 'quote_level': 'hkStockQuoteLv2', 'timestamp': 1677119933391, 'sec_type': 'STK'}]
518+
"""
511519
data = json.loads(tick)
512520
symbol = data.pop('symbol')
513521
data = camel_to_underline_obj(data)
514-
price_offset = 10 ** data.pop('price_offset')
522+
price_offset = 10 ** data.pop('price_offset', 0)
515523
price_base = float(data.pop('price_base'))
516524
data['timestamp'] = int(data.get('timestamp'))
517525
prices = data.pop('prices') if 'prices' in data else data.pop('price')
@@ -521,7 +529,7 @@ def _convert_tick(self, tick):
521529
time_items = [('time', item) for item in accumulate(times)]
522530
volumes = data.pop('volumes') if 'volumes' in data else data.pop('volume')
523531
volume_items = [('volume', int(item)) for item in volumes]
524-
tick_types = data.pop('tick_type') if 'tick_type' in data else data.pop('type')
532+
tick_types = data.pop('tick_type') if 'tick_type' in data else data.pop('type', None)
525533
if tick_types:
526534
tick_type_items = [('tick_type', item) for item in tick_types]
527535
else:
@@ -534,8 +542,10 @@ def _convert_tick(self, tick):
534542
part_code_items = [('part_code', None) for _ in range(len(time_items))]
535543
part_code_name_items = [('part_code_name', None) for _ in range(len(time_items))]
536544
conds = data.pop('cond') if 'cond' in data else None
537-
cond_map = get_trade_condition_map(data.get('quote_level'))
545+
cond_map = get_trade_condition_map(data.get('quote_level', ''))
538546
if conds:
547+
if len(time_items) - len(conds) > 0:
548+
conds += ' ' * (len(time_items) - len(conds))
539549
cond_items = [('cond', get_trade_condition(item, cond_map)) for item in conds]
540550
else:
541551
cond_items = [('cond', None) for _ in range(len(time_items))]
@@ -553,11 +563,12 @@ def _convert_tick(self, tick):
553563
try:
554564
item_dict = dict(item)
555565
except:
556-
self.logger.error('convert tick error')
566+
self.logger.error(f'convert tick error, item:{item}')
557567
continue
558568
item_dict.update(data)
559569
if item_dict.get('merged_vols'):
560-
vols = item_dict.pop('merged_vols').get('vols')
570+
m_vols = item_dict.pop('merged_vols')
571+
vols = m_vols.get('vols') if 'vols' in m_vols else m_vols.get('vol')
561572
for i, vol in enumerate(vols):
562573
sub_item = dict(item_dict)
563574
sub_item['sn'] = sub_item['sn'] * 10 + i

tigeropen/quote/response/quote_bar_response.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
from tigeropen.common.response import TigerResponse
1010

11-
COLUMNS = ['symbol', 'time', 'open', 'high', 'low', 'close', 'volume', 'next_page_token']
11+
COLUMNS = ['symbol', 'time', 'open', 'high', 'low', 'close', 'volume', 'amount', 'next_page_token']
1212
BAR_FIELD_MAPPINGS = {'avgPrice': 'avg_price'}
1313

1414

tigeropen/tiger_open_client.py

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,9 @@ def _get_retry_deco(self, service):
176176
(RequestException, ResponseException),
177177
max_time=self.__config.retry_max_time,
178178
max_tries=self.__config.retry_max_tries,
179+
logger=self.__logger,
180+
on_giveup=lambda x: self.__logger.error(f'give up after '
181+
f'{self.__config.retry_max_tries} retries'),
179182
jitter=None)
180183
return None
181184

@@ -215,7 +218,7 @@ def query_license(self):
215218
return json.loads(response.data).get('license')
216219
self.__logger.error(f"failed to query license, response: {response_content}")
217220

218-
def refresh_token(self):
221+
def query_token(self):
219222
request = OpenApiRequest(method=USER_TOKEN_REFRESH)
220223

221224
response_content = None
@@ -231,21 +234,25 @@ def refresh_token(self):
231234
self.__logger.error(f"failed to refresh token, response: {response_content}")
232235
return None
233236

234-
def token_refresh_task(self):
237+
def refresh_token(self):
238+
new_token = self.query_token()
239+
if new_token:
240+
self.__logger.info(f"refresh token, old:{self.__config.token}, new:{new_token}")
241+
self.__config.load_or_store_token(new_token)
242+
243+
def __token_refresh_task(self):
235244
try:
236245
if self.__config.should_token_refresh():
237-
new_token = self.refresh_token()
238-
if new_token:
239-
self.__logger.info(f"refresh token, old:{self.__config.token}, new:{new_token}")
240-
self.__config.load_or_store_token(new_token)
246+
self.refresh_token()
241247
except Exception as e:
242248
self.__logger.error(e, exc_info=True)
243249

244250
def __schedule_thread(self):
245-
if not _SCHEDULE_STATE['is_running']:
251+
if not _SCHEDULE_STATE['is_running'] and self.__config.token_refresh_duration != 0:
246252
_SCHEDULE_STATE['is_running'] = True
247253
self.__logger.info('Starting schedule thread...')
248-
daemon = RepeatTimer(TOKEN_CHECK_INTERVAL, self.token_refresh_task)
254+
daemon = RepeatTimer(TOKEN_CHECK_INTERVAL, self.__token_refresh_task)
255+
daemon.daemon = True
249256
daemon.start()
250257

251258

tigeropen/tiger_open_config.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,8 @@ def __init__(self, sandbox_debug=None, enable_dynamic_domain=True, props_path='.
9595
self.retry_max_tries = 5
9696
self.props_path = props_path
9797
self.token = None
98+
# token 刷新间隔周期, 单位秒
99+
self.token_refresh_duration = TOKEN_REFRESH_DURATION
98100
self._load_props()
99101
self.load_or_store_token()
100102

@@ -289,11 +291,11 @@ def load_or_store_token(self, token=None):
289291
except Exception as e:
290292
logging.error(e, exc_info=True)
291293

292-
def should_token_refresh(self, duration=TOKEN_REFRESH_DURATION):
293-
if self.token:
294+
def should_token_refresh(self):
295+
if self.token and self.token_refresh_duration != 0:
294296
tokeninfo = base64.b64decode(self.token)
295297
gen_ts, expire_ts = tokeninfo[:27].decode('utf-8').split(',')
296-
if (int(time.time()) - int(gen_ts) // 1000) > duration:
298+
if (int(time.time()) - int(gen_ts) // 1000) > self.token_refresh_duration:
297299
return True
298300
return False
299301

0 commit comments

Comments
 (0)