|
7 | 7 | import json |
8 | 8 | import logging |
9 | 9 | import sys |
10 | | -import os |
11 | 10 | from collections import defaultdict |
| 11 | +from itertools import accumulate, zip_longest |
12 | 12 |
|
13 | 13 | import stomp |
14 | 14 | from stomp.exception import ConnectFailedException |
|
17 | 17 | from tigeropen.common.consts import OrderStatus |
18 | 18 | from tigeropen.common.consts.params import P_SDK_VERSION, P_SDK_VERSION_PREFIX |
19 | 19 | from tigeropen.common.consts.push_destinations import QUOTE, QUOTE_DEPTH, QUOTE_FUTURE, QUOTE_OPTION, TRADE_ASSET, \ |
20 | | - TRADE_ORDER, TRADE_POSITION |
| 20 | + TRADE_ORDER, TRADE_POSITION, QUOTE_TICK |
21 | 21 | from tigeropen.common.consts.push_subscriptions import SUBSCRIPTION_QUOTE, SUBSCRIPTION_QUOTE_DEPTH, \ |
22 | 22 | SUBSCRIPTION_QUOTE_OPTION, SUBSCRIPTION_QUOTE_FUTURE, SUBSCRIPTION_TRADE_ASSET, SUBSCRIPTION_TRADE_POSITION, \ |
23 | | - SUBSCRIPTION_TRADE_ORDER |
| 23 | + SUBSCRIPTION_TRADE_ORDER, SUBSCRIPTION_QUOTE_TICK |
24 | 24 | from tigeropen.common.consts.push_types import RequestType, ResponseType |
25 | 25 | from tigeropen.common.consts.quote_keys import QuoteChangeKey, QuoteKeyType |
26 | 26 | from tigeropen.common.exceptions import ApiException |
27 | | -from tigeropen.common.util.string_utils import camel_to_underline |
28 | 27 | from tigeropen.common.util.common_utils import get_enum_value |
29 | 28 | from tigeropen.common.util.order_utils import get_order_status |
30 | 29 | from tigeropen.common.util.signature_utils import sign_with_rsa |
| 30 | +from tigeropen.common.util.string_utils import camel_to_underline, camel_to_underline_obj |
| 31 | +from tigeropen.common.util.tick_util import get_part_code, get_part_code_name, get_trade_condition_map, \ |
| 32 | + get_trade_condition |
31 | 33 | from tigeropen.push import _patch_ssl |
32 | 34 |
|
33 | 35 | HOUR_TRADING_QUOTE_KEYS_MAPPINGS = {'hourTradingLatestPrice': 'latest_price', 'hourTradingPreClose': 'pre_close', |
@@ -89,6 +91,7 @@ def __init__(self, host, port, use_ssl=True, connection_timeout=120, heartbeats= |
89 | 91 |
|
90 | 92 | self.subscribed_symbols = None |
91 | 93 | self.quote_changed = None |
| 94 | + self.tick_changed = None |
92 | 95 | self.asset_changed = None |
93 | 96 | self.position_changed = None |
94 | 97 | self.order_changed = None |
@@ -204,6 +207,11 @@ def on_message(self, frame): |
204 | 207 | items.append((camel_to_underline(key), value)) |
205 | 208 | if items: |
206 | 209 | self.quote_changed(symbol, items, hour_trading) |
| 210 | + elif response_type == str(ResponseType.GET_TRADING_TICK_END.value): |
| 211 | + if self.tick_changed: |
| 212 | + symbol, items = self._convert_tick(body) |
| 213 | + self.tick_changed(symbol, items) |
| 214 | + |
207 | 215 | elif response_type == str(ResponseType.SUBSCRIBE_ASSET.value): |
208 | 216 | if self.asset_changed: |
209 | 217 | data = json.loads(body) |
@@ -342,6 +350,15 @@ def subscribe_quote(self, symbols, quote_key_type=QuoteKeyType.TRADE, focus_keys |
342 | 350 | return self._handle_quote_subscribe(destination=QUOTE, subscription=SUBSCRIPTION_QUOTE, symbols=symbols, |
343 | 351 | extra_headers=extra_headers) |
344 | 352 |
|
| 353 | + def subscribe_tick(self, symbols): |
| 354 | + """ |
| 355 | + subscribe trade tick |
| 356 | + :param symbols: symbol列表 |
| 357 | + :return: |
| 358 | + """ |
| 359 | + return self._handle_quote_subscribe(destination=QUOTE_TICK, subscription=SUBSCRIPTION_QUOTE_TICK, |
| 360 | + symbols=symbols) |
| 361 | + |
345 | 362 | def subscribe_depth_quote(self, symbols): |
346 | 363 | """ |
347 | 364 | 订阅深度行情 |
@@ -383,6 +400,14 @@ def unsubscribe_quote(self, symbols=None, id=None): |
383 | 400 | """ |
384 | 401 | self._handle_quote_unsubscribe(destination=QUOTE, subscription=SUBSCRIPTION_QUOTE, sub_id=id, symbols=symbols) |
385 | 402 |
|
| 403 | + def unsubscribe_tick(self, symbols=None, id=None): |
| 404 | + """ |
| 405 | + 退订行情更新 |
| 406 | + :return: |
| 407 | + """ |
| 408 | + self._handle_quote_unsubscribe(destination=QUOTE_TICK, subscription=SUBSCRIPTION_QUOTE_TICK, sub_id=id, |
| 409 | + symbols=symbols) |
| 410 | + |
386 | 411 | def unsubscribe_depth_quote(self, symbols=None, id=None): |
387 | 412 | """ |
388 | 413 | 退订深度行情更新 |
@@ -440,3 +465,38 @@ def _generate_headers(self, extra_headers=None): |
440 | 465 | headers.update(extra_headers) |
441 | 466 | return headers |
442 | 467 |
|
| 468 | + @staticmethod |
| 469 | + def _convert_tick(tick): |
| 470 | + data = json.loads(tick) |
| 471 | + symbol = data.pop('symbol') |
| 472 | + data = camel_to_underline_obj(data) |
| 473 | + price_offset = 10 ** data.pop('price_offset') |
| 474 | + price_base = data.pop('price_base') |
| 475 | + # The latter time is equal to the sum of all previous values |
| 476 | + price_items = [('price', (item + price_base) / price_offset) for item in data.pop('prices')] |
| 477 | + time_items = [('time', item) for item in accumulate(data.pop('times'))] |
| 478 | + volumes = [('volume', item) for item in data.pop('volumes')] |
| 479 | + tick_type_items = [('tick_type', item) for item in data.pop('tick_type')] |
| 480 | + part_codes = data.pop('part_code') |
| 481 | + if part_codes: |
| 482 | + part_code_items = [('part_code', get_part_code(item)) for item in part_codes] |
| 483 | + part_code_name_items = [('part_code_name', get_part_code_name(item)) for item in part_codes] |
| 484 | + else: |
| 485 | + part_code_items = [('part_code', None) for _ in range(len(time_items))] |
| 486 | + part_code_name_items = [('part_code_name', None) for _ in range(len(time_items))] |
| 487 | + |
| 488 | + conds = data.pop('cond') |
| 489 | + cond_map = get_trade_condition_map(data.get('quote_level')) |
| 490 | + if conds: |
| 491 | + cond_items = [('cond', get_trade_condition(item, cond_map)) for item in conds] |
| 492 | + else: |
| 493 | + cond_items = [('cond', None) for _ in range(len(time_items))] |
| 494 | + tick_data = zip_longest(tick_type_items, price_items, volumes, part_code_items, |
| 495 | + part_code_name_items, cond_items, time_items) |
| 496 | + items = [] |
| 497 | + for item in tick_data: |
| 498 | + item_dict = dict(item) |
| 499 | + item_dict.update(data) |
| 500 | + items.append(item_dict) |
| 501 | + return symbol, items |
| 502 | + |
0 commit comments