Skip to content

Commit 436f83b

Browse files
shinny-packshinny-mayanqiong
authored andcommitted
Update Version 2.9.4
1 parent 9129d7c commit 436f83b

File tree

13 files changed

+451
-373
lines changed

13 files changed

+451
-373
lines changed

PKG-INFO

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
Metadata-Version: 2.1
22
Name: tqsdk
3-
Version: 2.9.3
3+
Version: 2.9.4
44
Summary: TianQin SDK
55
Home-page: https://www.shinnytech.com/tqsdk
66
Author: TianQin

doc/conf.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,9 +48,9 @@
4848
# built documents.
4949
#
5050
# The short X.Y version.
51-
version = u'2.9.3'
51+
version = u'2.9.4'
5252
# The full version, including alpha/beta/rc tags.
53-
release = u'2.9.3'
53+
release = u'2.9.4'
5454

5555
# The language for content autogenerated by Sphinx. Refer to documentation
5656
# for a list of supported languages.

doc/version.rst

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,14 @@
22

33
版本变更
44
=============================
5+
2.9.4 (2021/11/04)
6+
7+
* 增加::py:meth:`~tqsdk.api.TqApi.query_symbol_info` 接口返回值中增加 ``upper_limit``, ``lower_limit`` 这两个字段
8+
* 优化: 多账户模式支持回测模块
9+
* 优化: query 系列函数,发送的查询请求中合约列表长度不能大于 8192
10+
* 优化: 网络连接优化断线重连机制
11+
12+
513
2.9.3 (2021/10/28)
614

715
* 增加::py:class:`~tqsdk.risk_rule.TqRuleOpenCountsLimit`、:py:class:`~tqsdk.risk_rule.TqRuleOpenVolumesLimit` 类,

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ def get_tag(self):
3636

3737
setuptools.setup(
3838
name='tqsdk',
39-
version="2.9.3",
39+
version="2.9.4",
4040
description='TianQin SDK',
4141
author='TianQin',
4242
author_email='tianqincn@gmail.com',

tqsdk/__version__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
__version__ = '2.9.3'
1+
__version__ = '2.9.4'

tqsdk/api.py

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -265,7 +265,7 @@ def __init__(self, account: Union[TqMultiAccount, TqAccount, TqSim, None] = None
265265
self._pending_diffs = [] # 从网络上收到的待处理的 diffs, 只在 wait_update 函数执行过程中才可能为非空
266266
self._pending_peek = False # 是否有发出的 peek_message 还没收到数据回复
267267
self._prototype = self._gen_prototype() # 各业务数据的原型, 用于决定默认值及将收到的数据转为特定的类型
268-
self._security_prototype = self._gen_security_prototype() # 股票业务数据原型
268+
self._security_prototype = self._gen_security_prototype() # 股票业务数据原型
269269
self._dividend_cache = {} # 缓存合约对应的复权系数矩阵,每个合约只计算一次
270270
self._send_chan, self._recv_chan = TqChan(self), TqChan(self) # 消息收发队列
271271
self._ws_md_recv_chan = None # 记录 ws_md_recv_chan 引用
@@ -1858,7 +1858,7 @@ def wait_update(self, deadline: Optional[float] = None, _task: Union[asyncio.Tas
18581858
self._process_serial_extra_array(serial)
18591859
self._run_until_idle(async_run=False) # 这里 self._run_until_idle() 主要为了把上一步计算出得需要绘制的数据发送到 TqWebHelper
18601860
if _task is not None:
1861-
# 如果 _task 已经 done,则提前返回 True, False 代表超时会抛错
1861+
# 如果 _task 已经 done,则提前返回 True, False 代表超时会抛错
18621862
_tasks = _task if isinstance(_task, list) else [_task]
18631863
if all([t.done() for t in _tasks]):
18641864
return True
@@ -2377,7 +2377,8 @@ def query_quotes(self, ins_class: str = None, exchange_id: str = None, product_i
23772377
if isinstance(self._backtest, TqBacktest):
23782378
variables["timestamp"] = int(self._get_current_datetime().timestamp() * 1e9)
23792379
args_definitions, args = _get_query_args(variables)
2380-
query = f"query({args_definitions}){{multi_symbol_info({args}){{ ... on basic {{instrument_id }} }}}}"
2380+
query = f"query{f'({args_definitions})' if args_definitions else ''}{{multi_symbol_info{f'({args})' if args else ''}{{ ... on basic {{instrument_id }} }}}}"
2381+
23812382
def filter(query_result):
23822383
result = []
23832384
for quote in query_result.get("result", {}).get("multi_symbol_info", []):
@@ -2387,6 +2388,7 @@ def filter(query_result):
23872388
else:
23882389
result.append(quote["instrument_id"])
23892390
return result
2391+
23902392
return self._get_symbol_list(query=query, variables=variables, filter=filter)
23912393

23922394
def _get_symbol_list(self, query: str, variables: dict, filter: Callable[[dict], list]):
@@ -2465,6 +2467,7 @@ def query_cont_quotes(self, exchange_id: str = None, product_id: str = None, has
24652467
query = f"query( {args_definitions} ){{multi_symbol_info( {args} ){{...basic ...cont}}}}"
24662468
fragments = "fragment basic on basic {instrument_id}" \
24672469
"fragment cont on derivative{underlying{edges{node{...on basic{instrument_id exchange_id}...on future {product_id}}}}}"
2470+
24682471
def filter(query_result):
24692472
result = []
24702473
for quote in query_result.get("result", {}).get("multi_symbol_info", []):
@@ -2476,8 +2479,8 @@ def filter(query_result):
24762479
continue
24772480
result.append(underlying_quote["instrument_id"])
24782481
return result
2479-
return self._get_symbol_list(query=query + fragments, variables=variables, filter=filter)
24802482

2483+
return self._get_symbol_list(query=query + fragments, variables=variables, filter=filter)
24812484

24822485
def query_options(self, underlying_symbol: str, option_class: str = None, exercise_year: int = None,
24832486
exercise_month: int = None, strike_price: float = None, expired: bool = None, has_A: bool = None,
@@ -2534,6 +2537,7 @@ def query_options(self, underlying_symbol: str, option_class: str = None, exerci
25342537
if self._stock is False:
25352538
raise Exception("期货行情系统(_stock = False)不支持当前接口调用")
25362539
query, variables = self._query_options_by_underlying(underlying_symbol)
2540+
25372541
def filter(query_result):
25382542
options = []
25392543
exe_year = exercise_year if exercise_year else kwargs.get("delivery_year")
@@ -2554,6 +2558,7 @@ def filter(query_result):
25542558
continue
25552559
options.append(option["instrument_id"])
25562560
return options
2561+
25572562
return self._get_symbol_list(query=query, variables=variables, filter=filter)
25582563

25592564
def query_atm_options(self, underlying_symbol, underlying_price, price_level, option_class, exercise_year: int = None,
@@ -2644,6 +2649,7 @@ def query_atm_options(self, underlying_symbol, underlying_price, price_level, op
26442649
if exercise_year and exercise_month and not (isinstance(exercise_year, int) and isinstance(exercise_month, int)):
26452650
raise Exception("exercise_year / exercise_month 类型错误")
26462651
query, variables = self._query_options_by_underlying(underlying_symbol)
2652+
26472653
def filter(query_result):
26482654
options = self._convert_query_result_to_list(query_result)
26492655
if options:
@@ -2659,6 +2665,7 @@ def filter(query_result):
26592665
return rst_options
26602666
else:
26612667
return []
2668+
26622669
return self._get_symbol_list(query=query, variables=variables, filter=filter)
26632670

26642671
def query_symbol_info(self, symbol: Union[str, List[str]]):
@@ -2699,12 +2706,19 @@ def query_symbol_info(self, symbol: Union[str, List[str]]):
26992706
* exercise_year: 期权最后行权日年份,只对期权品种有效。
27002707
* exercise_month: 期权最后行权日月份,只对期权品种有效。
27012708
* option_class: 期权方向
2709+
* upper_limit: 涨停价
2710+
* lower_limit: 跌停价
27022711
* pre_settlement: 昨结算
27032712
* pre_open_interest: 昨持仓
27042713
* pre_close: 昨收盘
27052714
* trading_time_day: 白盘交易时间段,list 类型
27062715
* trading_time_night: 夜盘交易时间段,list 类型
27072716
2717+
注意:
2718+
2719+
1. 回测时,以下字段值为 nan: "upper_limit", "lower_limit", "pre_settlement", "pre_open_interest", "pre_close"
2720+
2. 中金所合约未提供涨停价、跌停价
2721+
27082722
Example1::
27092723
27102724
from tqsdk import TqApi, TqAuth
@@ -2800,6 +2814,7 @@ def query_all_level_options(self, underlying_symbol, underlying_price, option_cl
28002814
if exercise_year and exercise_month and not (isinstance(exercise_year, int) and isinstance(exercise_month, int)):
28012815
raise Exception("exercise_year / exercise_month 类型错误")
28022816
query, variables = self._query_options_by_underlying(underlying_symbol)
2817+
28032818
def filter(query_result):
28042819
options = self._convert_query_result_to_list(query_result)
28052820
if options:
@@ -2814,6 +2829,7 @@ def filter(query_result):
28142829
return in_money_options, at_money_options, out_of_money_options
28152830
else:
28162831
return [], [], []
2832+
28172833
return self._get_symbol_level_list(query=query, variables=variables, filter=filter)
28182834

28192835
def _get_symbol_level_list(self, query: str, variables: dict, filter: Callable[[dict], Tuple[list, list, list]]):
@@ -2907,6 +2923,7 @@ def query_all_level_finance_options(self, underlying_symbol, underlying_price, o
29072923
if any([i not in [0, 1, 2, 3] for i in nearbys]):
29082924
raise Exception(f"ETF 期权标的为:{underlying_symbol},exercise_date 参数应该是在 [0, 1, 2, 3] 之间。")
29092925
query, variables = self._query_options_by_underlying(underlying_symbol)
2926+
29102927
def filter(query_result):
29112928
options = self._convert_query_result_to_list(query_result)
29122929
if options:
@@ -2918,6 +2935,7 @@ def filter(query_result):
29182935
return in_money_options, at_money_options, out_of_money_options
29192936
else:
29202937
return [], [], []
2938+
29212939
return self._get_symbol_level_list(query=query, variables=variables, filter=filter)
29222940

29232941
def _query_options_by_underlying(self, underlying_symbol):

tqsdk/connect.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,7 @@ async def _run(self, api, url, send_chan, recv_chan):
179179
# 希望做到的效果是遇到网络问题可以断线重连, 但是可能抛出的例外太多了(TimeoutError,socket.gaierror等), 又没有文档或工具可以理出 try 代码中所有可能遇到的例外
180180
# 而这里的 except 又需要处理所有子函数及子函数的子函数等等可能抛出的例外, 因此这里只能遇到问题之后再补, 并且无法避免 false positive 和 false negative
181181
except (websockets.exceptions.ConnectionClosed, websockets.exceptions.InvalidStatusCode,
182-
websockets.exceptions.InvalidState, websockets.exceptions.ProtocolError, OSError,
182+
websockets.exceptions.InvalidState, websockets.exceptions.ProtocolError, OSError, EOFError,
183183
TqBacktestPermissionError) as e:
184184
in_ops_time = datetime.now().hour == 19 and 0 <= datetime.now().minute <= 30
185185
# 发送网络连接断开的通知,code = 2019112911

tqsdk/multiaccount.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,13 @@
44
__author__ = 'Hong Yan'
55

66
from typing import List, Union
7+
8+
from shinny_structlog import ShinnyLoggerAdapter
9+
710
from tqsdk.account import TqAccount, TqKq
8-
from tqsdk.sim import TqSim
11+
from tqsdk.connect import TqConnect, TdReconnectHandler
912
from tqsdk.channel import TqChan
10-
from shinny_structlog import ShinnyLoggerAdapter, JSONFormatter
11-
from tqsdk.connect import TqConnect, MdReconnectHandler, TdReconnectHandler
13+
from tqsdk.sim import TqSim
1214

1315

1416
class TqMultiAccount(object):
@@ -21,10 +23,8 @@ class TqMultiAccount(object):
2123
2224
**注意**
2325
24-
- 多账户模式暂未支持回测模块
2526
- 多账户模式暂未支持 `webgui`
2627
- 多账户模式下, 对于 get_position,account,insert_order,set_target_volume 等函数必须指定 account 参数
27-
- 多账户必须指定信易账户信息, 如 ``api = TqApi(TqMultiAccount(...), auth=TqAuth("信易账户", "账户密码"))``
2828
- 多账户模式下, 实盘账户的数量受限于信易账户支持实盘账户数, 详见:`更多的实盘交易账户数 <https://doc.shinnytech.com/tqsdk/latest/profession.html#id2>`_
2929
3030
"""

tqsdk/objs_not_entity.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -232,13 +232,13 @@ def __init__(self, api, symbol_list, backtest_timestamp, *args, **kwargs):
232232
"exercise_year",
233233
"exercise_month",
234234
"option_class",
235+
"upper_limit",
236+
"lower_limit",
235237
"pre_settlement",
236238
"pre_open_interest",
237239
"pre_close",
238240
"trading_time_day",
239241
"trading_time_night"
240-
# todo upper_limit 涨停价
241-
# todo lower_limit 跌停价
242242
]
243243
default_quote = Quote(None)
244244
data = [{k: (s if k == "instrument_id" else default_quote.get(k, None)) for k in self.__dict__["_columns"]} for s in symbol_list]
@@ -271,6 +271,8 @@ async def async_update(self):
271271
quotes = self.__dict__["_api"]._symbols_to_quotes(query_result, keys=all_keys)
272272
self._quotes_to_dataframe(quotes)
273273
if self.__dict__["_backtest_timestamp"]:
274+
# 回测时这些字段应该为 nan
275+
self.loc[:, ["upper_limit", "lower_limit", "pre_settlement", "pre_open_interest", "pre_close"]] = float('nan')
274276
# 回测时清空请求,不缓存请求内容
275277
self.__dict__["_api"]._send_pack({
276278
"aid": "ins_query",
@@ -292,9 +294,9 @@ def _quotes_to_dataframe(self, quotes):
292294
self.loc[:, col] = [_get_expire_rest_days(quotes[s]['expire_datetime'], current_dt) for s in self.__dict__["_symbol_list"]]
293295
elif col == "trading_time_day" or col == "trading_time_night":
294296
k = 'day' if col == "trading_time_day" else 'night'
295-
self.loc[:, col] = [self._get_trading_time(quotes, s, k) for s in self.__dict__["_symbol_list"]]
297+
self.loc[:, col] = Series([self._get_trading_time(quotes, s, k) for s in self.__dict__["_symbol_list"]])
296298
else:
297-
self.loc[:, col] = [quotes[s].get(col, default_quote[col]) for s in self.__dict__["_symbol_list"]]
299+
self.loc[:, col] = Series([quotes[s].get(col, default_quote[col]) for s in self.__dict__["_symbol_list"]])
298300

299301
def __await__(self):
300302
return self.__dict__["_task"].__await__()

0 commit comments

Comments
 (0)