Skip to content

Commit f8a5887

Browse files
shinny-packshinny-mayanqiong
authored andcommitted
Update Version 3.5.5
1 parent 160baa4 commit f8a5887

File tree

11 files changed

+91
-29
lines changed

11 files changed

+91
-29
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: 3.5.4
3+
Version: 3.5.5
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'3.5.4'
51+
version = u'3.5.5'
5252
# The full version, including alpha/beta/rc tags.
53-
release = u'3.5.4'
53+
release = u'3.5.5'
5454

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

doc/version.rst

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

33
版本变更
44
=============================
5+
3.5.5 (2024/03/27)
6+
7+
* 修复:TqSim 在调用 set_margin 之后,使用 is_changing 判断某个对象是否更新,可能返回的结果不正确
8+
* 优化:多账户下使用 :py:meth:`~tqsdk.algorithm.time_table_generater.vwap_table`,
9+
:py:meth:`~tqsdk.algorithm.time_table_generater.twap_table` 不需要用户多次指定账户
10+
11+
512
3.5.4 (2024/03/01)
613

714
* 修复:回测时,订阅多合约 K 线时,成交可能不符合预期的问题

setup.py

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

99
setuptools.setup(
1010
name='tqsdk',
11-
version="3.5.4",
11+
version="3.5.5",
1212
description='TianQin SDK',
1313
author='TianQin',
1414
author_email='[email protected]',

tqsdk/__version__.py

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

tqsdk/algorithm/time_table_generater.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
from tqsdk import utils
1414
from tqsdk.datetime import _get_trading_timestamp, _get_trade_timestamp, _get_trading_day_from_timestamp, \
1515
_datetime_to_timestamp_nano, _timestamp_nano_to_datetime
16+
from tqsdk.lib.time_table import TqTimeTable
1617
from tqsdk.rangeset import _rangeset_slice, _rangeset_head
1718
from tqsdk.tradeable import TqAccount, TqKq, TqSim
1819

@@ -124,7 +125,7 @@ def twap_table(api: TqApi, symbol: str, target_pos: int, duration: int, min_volu
124125
interval_list = _gen_random_list(sum_val=duration, min_val=min_interval, max_val=max_interval,
125126
length=len(volume_list))
126127

127-
time_table = DataFrame(columns=['interval', 'volume', 'price'])
128+
time_table = TqTimeTable(account=account)
128129
for index, volume in enumerate(volume_list):
129130
assert interval_list[index] >= 3
130131
active_interval = 2
@@ -253,7 +254,7 @@ def vwap_table(api: TqApi, symbol: str, target_pos: int, duration: float,
253254
predicted_percent = volume_percent.groupby(level=1).mean() # 将历史上相同时间单元的成交量占比使用算数平均计算出预测值
254255

255256
# 计算每个时间单元的成交量预测值
256-
time_table = DataFrame(columns=['interval', 'volume', 'price'])
257+
time_table = TqTimeTable(account=account)
257258
volume_left = target_volume # 剩余手数
258259
percent_left = 1 # 剩余百分比
259260
for index, value in predicted_percent.items():

tqsdk/api.py

Lines changed: 47 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -972,11 +972,12 @@ def _get_data_series(self, call_func: str, symbol_list: Union[str, List[str]], d
972972
if adj_type not in [None, "F", "B"]:
973973
raise Exception("adj_type 参数只支持 None (不复权) | 'F' (前复权) | 'B' (后复权) ")
974974
ds = DataSeries(self, symbol_list, dur_nano, start_dt_nano, end_dt_nano, adj_type)
975-
while not self._loop.is_running() and not ds.is_ready:
976-
deadline = time.time() + 30
977-
if not self.wait_update(deadline=deadline):
978-
raise TqTimeoutError(
979-
f"{call_func} 获取数据 ({symbol_list, duration_seconds, start_dt, end_dt}) 超时,请检查客户端及网络是否正常。")
975+
if not self._loop.is_running():
976+
while not ds._task.done():
977+
deadline = time.time() + 30
978+
if not self.wait_update(deadline=deadline, _task=ds._task):
979+
raise TqTimeoutError(
980+
f"{call_func} 获取数据 ({symbol_list, duration_seconds, start_dt, end_dt}) 超时,请检查客户端及网络是否正常。")
980981
return ds.df
981982

982983
# ----------------------------------------------------------------------
@@ -1811,13 +1812,12 @@ def set_risk_management_rule(self, exchange_id: str, enable: bool, count_limit:
18111812
rule = _get_obj(self._data, ["trade", self._account._get_account_key(account), "risk_management_rule", exchange_id], RiskManagementRule(self))
18121813
if not self._loop.is_running():
18131814
deadline = time.time() + 30
1814-
while not (rule_pack['enable'] == rule['enable']
1815-
and rule_pack['self_trade'].items() <= rule['self_trade'].items()
1816-
and rule_pack['frequent_cancellation'].items() <= rule['frequent_cancellation'].items()
1817-
and rule_pack['trade_position_ratio'].items() <= rule['trade_position_ratio'].items()):
1818-
# @todo: merge diffs
1819-
if not self.wait_update(deadline=deadline):
1820-
raise TqTimeoutError("设置风控规则超时请检查客户端及网络是否正常")
1815+
cond = lambda: (rule_pack['enable'] == rule['enable']
1816+
and rule_pack['self_trade'].items() <= rule['self_trade'].items()
1817+
and rule_pack['frequent_cancellation'].items() <= rule['frequent_cancellation'].items()
1818+
and rule_pack['trade_position_ratio'].items() <= rule['trade_position_ratio'].items())
1819+
if not self._wait_update_until(cond=cond, deadline=deadline):
1820+
raise TqTimeoutError("设置风控规则超时请检查客户端及网络是否正常")
18211821
return rule
18221822

18231823
# ----------------------------------------------------------------------
@@ -1933,6 +1933,38 @@ def wait_update(self, deadline: Optional[float] = None, _task: Union[asyncio.Tas
19331933
else: # 订阅多个合约
19341934
self._update_serial_multi(serial)
19351935

1936+
def _wait_update_until(self, cond: Callable[[], bool], deadline: Optional[float] = None) -> bool:
1937+
"""
1938+
TqApi 内部使用,用于等待某个条件满足。持续调用 wait_update(),直到 cond() 返回 True。
1939+
1940+
Args:
1941+
cond (Callable[[], bool]): 条件函数
1942+
deadline (float): [可选]指定截止时间,自unix epoch(1970-01-01 00:00:00 GMT)以来的秒数(time.time())。默认没有超时(无限等待)
1943+
1944+
Returns:
1945+
bool: 当 cond() 为 True 时返回 True, 如果到截止时间 cond() 依然为 False 则返回 False
1946+
1947+
注:用于 tqsdk 内部,某些地方会用到 api.wait_update(),等待数据更新后再返回给用户,
1948+
* 简单调用 wait_update() 导致 api._sync_diffs 丢失变更
1949+
* 为了避免这种情况,内部调用 wait_update() 应该传入 _task 参数,这样 api._sync_diffs 不会丢失变更
1950+
"""
1951+
if cond():
1952+
return True
1953+
1954+
async def _async_wait_task():
1955+
async with self.register_update_notify() as update_chan:
1956+
async for _ in update_chan:
1957+
if cond():
1958+
break
1959+
1960+
_task = self.create_task(_async_wait_task())
1961+
1962+
while not cond():
1963+
data_updated = self.wait_update(deadline=deadline, _task=_task)
1964+
if data_updated is False:
1965+
return False # TimeoutError
1966+
return True
1967+
19361968
# ----------------------------------------------------------------------
19371969
def is_changing(self, obj: Any, key: Union[str, List[str], None] = None) -> bool:
19381970
"""
@@ -2226,9 +2258,9 @@ def query_graphql(self, query: str, variables: dict, query_id: Optional[str] = N
22262258
})
22272259
deadline = time.time() + 60
22282260
if not self._loop.is_running():
2229-
while query_id not in symbols:
2230-
if not self.wait_update(deadline=deadline):
2231-
raise TqTimeoutError("查询合约服务 %s 超时,请检查客户端及网络是否正常 %s" % (query, query_id))
2261+
if not self._wait_update_until(cond=lambda: query_id in symbols, deadline=deadline):
2262+
# 使用 _task 参数,确保不会丢掉 _sync_diffs 里的变更
2263+
raise TqTimeoutError("查询合约服务 %s 超时,请检查客户端及网络是否正常 %s" % (query, query_id))
22322264
if isinstance(self._backtest, TqBacktest):
22332265
self._send_pack({
22342266
"aid": "ins_query",

tqsdk/data_series.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -68,9 +68,12 @@ def __init__(self, api, symbol_list, dur_nano, start_dt_nano, end_dt_nano, adj_t
6868
self._adj_type = adj_type
6969
self._dividend_cache = {} # 缓存合约对应的复权系数矩阵,每个合约只计算一次
7070
self.df = pd.DataFrame()
71-
self.is_ready = False
7271
DataSeries._ensure_cache_dir() # 确认缓存文件夹存在
73-
self._api.create_task(self._run())
72+
self._task = self._api.create_task(self._run())
73+
74+
@property
75+
def is_ready(self):
76+
return self._task.done()
7477

7578
async def _run(self):
7679
symbol = self._symbol_list[0] # todo: 目前只处理一个合约的情况
@@ -105,7 +108,6 @@ async def _run(self):
105108
target_rangeset_dt = _rangeset_intersection([(self._start_dt_nano, self._end_dt_nano)], rangeset_dt)
106109
assert len(target_rangeset_dt) <= 1 # 用户请求应该落在一个时间段内,或者用户请求的时间段内没有任何数据
107110
if len(target_rangeset_dt) == 0: # 用户请求的时间段内没有任何数据
108-
self.is_ready = True
109111
return
110112

111113
# 此时用户请求时间范围,转化为 target_rangeset_dt[0]
@@ -160,8 +162,6 @@ async def _run(self):
160162
adj_cols = DataSeries._get_adj_cols(symbol, self._dur_nano)
161163
ge = self.df["datetime"].ge(dt)
162164
self.df.loc[ge, adj_cols] = self.df.loc[ge, adj_cols] / factor
163-
# 结束状态
164-
self.is_ready = True
165165

166166
async def _download_data_series(self, rangeset):
167167
symbol = self._symbol_list[0]

tqsdk/lib/target_pos_scheduler.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
from tqsdk.channel import TqChan
1212
from tqsdk.datetime import _get_trade_timestamp
1313
from tqsdk.lib.target_pos_task import TargetPosTask
14+
from tqsdk.lib.time_table import TqTimeTable
1415
from tqsdk.lib.utils import _check_time_table, _get_deadline_from_interval
1516
from tqsdk.objs import Trade
1617

@@ -93,6 +94,8 @@ def __init__(self, api: TqApi, symbol: str, time_table: DataFrame, offset_priori
9394
api.close()
9495
"""
9596
self._api = api
97+
if isinstance(time_table, TqTimeTable):
98+
account = time_table.__dict__["_account"]
9699
self._account = api._account._check_valid(account)
97100

98101
# 这些参数直接传给 TargetPosTask,由 TargetPosTask 来检查其合法性

tqsdk/lib/time_table.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
#!/usr/bin/env python
2+
# -*- coding: utf-8 -*-
3+
__author__ = 'mayanqiong'
4+
5+
6+
from pandas import DataFrame
7+
8+
9+
class TqTimeTable(DataFrame):
10+
11+
def __init__(self, account=None):
12+
self.__dict__["_account"] = account
13+
self.__dict__["_columns"] = ['interval', 'volume', 'price']
14+
super(TqTimeTable, self).__init__(data=[], columns=self.__dict__["_columns"])

0 commit comments

Comments
 (0)