Skip to content

Commit 7f3c3b0

Browse files
committed
multi license conf
1 parent b5e830d commit 7f3c3b0

File tree

12 files changed

+263
-20
lines changed

12 files changed

+263
-20
lines changed

CHANGELOG.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,12 @@
1+
## 2.1.9 (2022-10-12)
2+
### New
3+
- 支持多牌照配置, 分牌照请求不同域名. 可通过 client_config.license 指定牌照
4+
### Modify
5+
- `Contract` 新增属性 `short_initial_margin`, `short_maintenance_margin`, 新增方法 `to_str()` 可打印全部属性
6+
- `QuoteClient.get_financial_report` 增加参数 `begin_date`, `end_date`
7+
- `QuoteClient.get_trade_ticks` 兼容 1.0 版本接口
8+
9+
110
## 2.1.8 (2022-08-26)
211
### Modify
312
- `TradeClient.get_orders` 新增参数 `seg_type`, 可指定交易品种(证券SEC/期货FUT/全部ALL)

setup.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,5 +34,6 @@
3434
'Programming Language :: Python :: 3.7',
3535
'Programming Language :: Python :: 3.8',
3636
'Programming Language :: Python :: 3.9',
37+
'Programming Language :: Python :: 3.10',
3738
],
3839
)

tests/test_client_config.py

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
# -*- coding: utf-8 -*-
2+
#
3+
# @Date : 2022/10/8
4+
# @Author : sukai
5+
import unittest
6+
from unittest.mock import MagicMock
7+
8+
from tigeropen.common.consts import License
9+
from tigeropen.tiger_open_config import TigerOpenClientConfig, GATEWAY_SUFFIX
10+
11+
12+
class TestClientConfig(unittest.TestCase):
13+
14+
def test_refresh_server_info(self):
15+
domain_map = {
16+
'socket_port': 9883,
17+
'port': 9887,
18+
'TBSG-QUOTE': 'https://openapi.tigerfintech.com/sgp-quote',
19+
'TBNZ-QUOTE': 'https://openapi.tigerfintech.com/hkg-quote',
20+
'TBSG-PAPER': 'https://openapi-sandbox.tigerfintech.com/sgp',
21+
'TBNZ-PAPER': 'https://openapi-sandbox.tigerfintech.com/hkg',
22+
'TBSG': 'https://openapi.tigerfintech.com/sgp',
23+
'TBNZ': 'https://openapi.tigerfintech.com/hkg',
24+
'COMMON': 'https://openapi.tigerfintech.com',
25+
}
26+
config = TigerOpenClientConfig()
27+
config.query_domains = MagicMock(name='query_domains', return_value=domain_map)
28+
config.domain_conf = config.query_domains()
29+
30+
self.assertEqual('https://openapi.tigerfintech.com' + GATEWAY_SUFFIX, config.server_url)
31+
self.assertEqual(('ssl', 'openapi.tigerfintech.com', 9883), config.socket_host_port)
32+
33+
config.license = License.TBNZ
34+
config.refresh_server_info()
35+
self.assertEqual('https://openapi.tigerfintech.com/hkg' + GATEWAY_SUFFIX, config.server_url)
36+
self.assertEqual('https://openapi.tigerfintech.com/hkg-quote' + GATEWAY_SUFFIX, config.quote_server_url)
37+
38+
config.license = 'TBSG'
39+
config.refresh_server_info()
40+
self.assertEqual('https://openapi.tigerfintech.com/sgp' + GATEWAY_SUFFIX, config.server_url)
41+
self.assertEqual('https://openapi.tigerfintech.com/sgp-quote' + GATEWAY_SUFFIX, config.quote_server_url)
42+
43+
config.is_paper = True
44+
config.license = 'TBNZ'
45+
config.refresh_server_info()
46+
self.assertEqual('https://openapi-sandbox.tigerfintech.com/hkg' + GATEWAY_SUFFIX, config.server_url)
47+
self.assertEqual('https://openapi.tigerfintech.com/hkg-quote' + GATEWAY_SUFFIX, config.quote_server_url)
48+
49+
config = TigerOpenClientConfig(enable_dynamic_domain=False)
50+
config.query_domains = MagicMock(name='query_domains', return_value=domain_map)
51+
config.domain_conf = config.query_domains()
52+
config.license = 'TBNZ'
53+
config.refresh_server_info()
54+
self.assertEqual('https://openapi.tigerfintech.com' + GATEWAY_SUFFIX, config.server_url)
55+
self.assertEqual(('ssl', 'openapi.tigerfintech.com', 9883), config.socket_host_port)

tigeropen/common/consts/__init__.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,3 +169,17 @@ class OrderType(Enum):
169169
STP = 'STP' # 止损单
170170
STP_LMT = 'STP_LMT' # 止损限价单
171171
TRAIL = 'TRAIL' # 跟踪止损单
172+
173+
174+
@unique
175+
class License(Enum):
176+
TBNZ = 'TBNZ'
177+
TBSG = 'TBSG'
178+
179+
180+
@unique
181+
class ServiceType(Enum):
182+
COMMON = 'COMMON'
183+
TRADE = 'TRADE'
184+
QUOTE = 'QUOTE'
185+

tigeropen/common/consts/service_types.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@
2525
ORDER_TRANSACTIONS = "order_transactions" # 订单成交记录
2626
ANALYTICS_ASSET = "analytics_asset"
2727

28+
USER_LICENSE = "user_license"
29+
2830
"""
2931
合约
3032
"""
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import re
2+
3+
PAPER_ACCOUNT_DIGIT_LEN = 17
4+
5+
6+
class AccountUtil:
7+
8+
@staticmethod
9+
def is_paper_account(account):
10+
try:
11+
if account:
12+
account = str(account)
13+
return account.isdigit() and len(account) >= PAPER_ACCOUNT_DIGIT_LEN
14+
except:
15+
pass
16+
return False
17+

tigeropen/quote/quote_client.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,9 @@ def __init__(self, client_config, logger=None, is_grab_permission=True):
7676
super(QuoteClient, self).__init__(client_config, logger=self.logger)
7777
self._lang = LANGUAGE
7878
self._timezone = eastern
79+
self._url = None
7980
if client_config:
81+
self._url = client_config.quote_server_url
8082
self._lang = client_config.language
8183
if client_config.timezone:
8284
self._timezone = client_config.timezone
@@ -87,7 +89,7 @@ def __init__(self, client_config, logger=None, is_grab_permission=True):
8789

8890
def __fetch_data(self, request):
8991
try:
90-
response = super(QuoteClient, self).execute(request)
92+
response = super(QuoteClient, self).execute(request, url=self._url)
9193
return response
9294
except Exception as e:
9395
if hasattr(THREAD_LOCAL, 'logger') and THREAD_LOCAL.logger:

tigeropen/tiger_open_client.py

Lines changed: 35 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,10 @@
1212
from tigeropen.common.consts import OPEN_API_SERVICE_VERSION, THREAD_LOCAL
1313
from tigeropen.common.consts.params import P_TIMESTAMP, P_TIGER_ID, P_METHOD, P_CHARSET, P_VERSION, P_SIGN_TYPE, \
1414
P_DEVICE_ID, P_NOTIFY_URL, COMMON_PARAM_KEYS, P_SIGN
15+
from tigeropen.common.consts.service_types import USER_LICENSE
1516
from tigeropen.common.exceptions import ResponseException, RequestException
17+
from tigeropen.common.request import OpenApiRequest
18+
from tigeropen.common.response import TigerResponse
1619
from tigeropen.common.util.common_utils import has_value
1720
from tigeropen.common.util.signature_utils import get_sign_content, sign_with_rsa, verify_with_rsa
1821
from tigeropen.common.util.web_utils import do_post
@@ -40,6 +43,16 @@ def __init__(self, client_config, logger=None):
4043
"User-Agent": 'openapi-python-sdk-' + __VERSION__
4144
}
4245
self.__device_id = self.__get_device_id()
46+
self.__init_license()
47+
self.__refresh_server_info()
48+
49+
def __init_license(self):
50+
if self.__config.license is None and self.__config.enable_dynamic_domain:
51+
self.__config.license = self.query_license()
52+
53+
def __refresh_server_info(self):
54+
self.__config.refresh_server_info()
55+
4356

4457
"""
4558
内部方法,从params中抽取公共参数
@@ -82,7 +95,7 @@ def __remove_common_params(self, params):
8295
"""
8396
内部方法,通过请求request对象构造请求查询字符串和业务参数
8497
"""
85-
def __prepare_request(self, request):
98+
def __prepare_request(self, request, url=None):
8699
THREAD_LOCAL.logger = self.__logger
87100
params = request.get_params()
88101
params[P_TIMESTAMP] = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
@@ -97,7 +110,7 @@ def __prepare_request(self, request):
97110
raise RequestException('[' + THREAD_LOCAL.uuid + ']request sign failed. ' + str(e))
98111
all_params[P_SIGN] = sign
99112

100-
log_url = self.__config.server_url + '?' + sign_content + "&sign=" + sign
113+
log_url = url + '?' + sign_content + "&sign=" + sign
101114
if THREAD_LOCAL.logger:
102115
THREAD_LOCAL.logger.debug('[' + THREAD_LOCAL.uuid + ']request:' + log_url)
103116

@@ -134,12 +147,29 @@ def __parse_response(self, response_str, timestamp=None):
134147
执行接口请求
135148
"""
136149

137-
def execute(self, request):
150+
def execute(self, request, url=None):
151+
if url is None:
152+
url = self.__config.server_url
138153
THREAD_LOCAL.uuid = str(uuid.uuid1())
139154
query_string = None
140-
params = self.__prepare_request(request)
155+
params = self.__prepare_request(request, url)
141156

142-
response = do_post(self.__config.server_url, query_string, self.__headers, params, self.__config.timeout,
157+
response = do_post(url, query_string, self.__headers, params, self.__config.timeout,
143158
self.__config.charset)
144159

145160
return self.__parse_response(response, params.get('timestamp'))
161+
162+
def query_license(self):
163+
request = OpenApiRequest(method=USER_LICENSE)
164+
165+
response_content = None
166+
try:
167+
response_content = self.execute(request)
168+
except Exception as e:
169+
self.__logger.error(e, exc_info=True)
170+
if response_content:
171+
response = TigerResponse()
172+
response.parse_response_content(response_content)
173+
if response.is_success():
174+
return json.loads(response.data).get('license')
175+
self.__logger.error(f"failed to query license, response: {response_content}")

0 commit comments

Comments
 (0)