Skip to content

Commit 1734bd5

Browse files
shinny-packshinny-mayanqiong
authored andcommitted
Update Version 3.5.9
1 parent ded2cec commit 1734bd5

File tree

9 files changed

+72
-102
lines changed

9 files changed

+72
-102
lines changed

PKG-INFO

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
Metadata-Version: 2.1
22
Name: tqsdk
3-
Version: 3.5.8
3+
Version: 3.5.9
44
Summary: TianQin SDK
55
Home-page: https://www.shinnytech.com/tqsdk
66
Author: TianQin

doc/conf.py

+2-2
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.8'
51+
version = u'3.5.9'
5252
# The full version, including alpha/beta/rc tags.
53-
release = u'3.5.8'
53+
release = u'3.5.9'
5454

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

doc/version.rst

+6
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,12 @@
22

33
版本变更
44
=============================
5+
3.5.9 (2024/05/09)
6+
7+
* 增加::py:meth:`~tqsdk.TqApi.query_all_level_finance_options` 增加中金所股指期权标的
8+
* 优化::py:meth:`~tqsdk.TqApi.get_kline_data_series`、:py:meth:`~tqsdk.TqApi.get_tick_data_series` 接口在请求没有任何成交数据的合约时能够及时退出,避免等待超时
9+
10+
511
3.5.8 (2024/04/29)
612

713
* 增加::py:class:`~tqsdk.tools.DataDownloader` 增加 write_mode 参数,作为写入模式参数,并且在模式为 'a' 时,不写入标题行

setup.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
setuptools.setup(
1010
name='tqsdk',
11-
version="3.5.8",
11+
version="3.5.9",
1212
description='TianQin SDK',
1313
author='TianQin',
1414
author_email='tianqincn@gmail.com',

tqsdk/__version__.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
__version__ = '3.5.8'
1+
__version__ = '3.5.9'

tqsdk/api.py

+5-2
Original file line numberDiff line numberDiff line change
@@ -2928,7 +2928,9 @@ def query_all_level_finance_options(self, underlying_symbol, underlying_price, o
29282928
29292929
Args:
29302930
underlying_symbol (str): [必填] 标的合约 (针对 ETF 期权和股指期权,只支持以下几个合约)
2931-
* "SSE.000300" 为中金所股指期权标的
2931+
* "SSE.000300" 为中金所沪深 300 股指期权(IO)标的
2932+
* "SSE.000852" 为中金所中证 1000 股指期权(MO)标的
2933+
* "SSE.000016" 为中金所上证 50 股指期权(HO)标的
29322934
* "SSE.510050" 为上交所华夏上证 50 ETF 期权标的
29332935
* "SSE.510300" 为上交所华泰柏瑞沪深 300 ETF 期权标的
29342936
* "SZSE.159919" 为深交所嘉实沪深 300 ETF 期权标的
@@ -2991,7 +2993,8 @@ def query_all_level_finance_options(self, underlying_symbol, underlying_price, o
29912993
"""
29922994
if self._stock is False:
29932995
raise Exception("期货行情系统(_stock = False)不支持当前接口调用")
2994-
if underlying_symbol not in ["SSE.000300", "SSE.510050", "SSE.510300", "SZSE.159919", "SZSE.159915", "SZSE.159922", "SSE.510500"]:
2996+
if underlying_symbol not in ["SSE.000300", "SSE.510050", "SSE.510300", "SZSE.159919", "SZSE.159915", "SZSE.159922", "SSE.510500",
2997+
"SSE.000016", "SSE.000852"]:
29952998
raise Exception("不支持的标的合约")
29962999
if option_class not in ['CALL', 'PUT']:
29973000
raise Exception("option_class 参数错误,option_class 必须是 'CALL' 或者 'PUT'")

tqsdk/data_series.py

+7-53
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,7 @@
1313
from tqsdk.channel import TqChan
1414
from tqsdk.diff import _get_obj
1515
from tqsdk.rangeset import _rangeset_difference, _rangeset_intersection
16-
from tqsdk.tafunc import get_dividend_df
17-
from tqsdk.utils import _generate_uuid
16+
from tqsdk.utils import _generate_uuid, _get_dividend_factor
1817

1918
CACHE_DIR = os.path.join(os.path.expanduser('~'), ".tqsdk/data_series_1")
2019

@@ -144,7 +143,8 @@ async def _run(self):
144143
# 复权, 如果存在 STOCK / FUND 并且 adj_type is not None, 这里需要提前准备下载时间段内的复权因子
145144
quote = self._api.get_quote(symbol)
146145
if self._adj_type and quote.ins_class in ["STOCK", "FUND"]:
147-
factor_df = await self._update_dividend_factor(symbol) # 复权需要根据日线计算除权因子,todo: 如果本地下载过日线,不需要再从服务器获取日线数据
146+
factor_df = await _get_dividend_factor(self._api, quote, self._start_dt_nano, self._end_dt_nano,
147+
chart_id_prefix="PYSDK_data_factor") # 复权需要根据日线计算除权因子,todo: 如果本地下载过日线,不需要再从服务器获取日线数据
148148
if self._adj_type == "F":
149149
# 倒序循环 factor_df, 对于小于当前 factor_df[datetime] 的行 乘以 factor_df[factor]
150150
for i in range(factor_df.shape[0] - 1, -1, -1):
@@ -212,13 +212,12 @@ async def _download_data(self, start_dt, end_dt, data_chan):
212212
async for _ in update_chan:
213213
if not (chart_info.items() <= _get_obj(chart, ["state"]).items()):
214214
continue # 当前请求还没收齐回应, 不应继续处理
215+
if chart.get("ready", False) is False:
216+
continue # 数据还没全部收到
217+
if serial.get("last_id", -1) == -1:
218+
return # 合约没有任何数据
215219
left_id = chart.get("left_id", -1)
216220
right_id = chart.get("right_id", -1)
217-
if (left_id == -1 and right_id == -1) or self._api._data.get("mdhis_more_data", True):
218-
continue # 定位信息还没收到, 或数据序列还没收到
219-
# 检查合约的数据是否收到
220-
if serial.get("last_id", -1) == -1:
221-
continue
222221
if current_id is None:
223222
current_id = max(left_id, 0)
224223
while current_id <= right_id:
@@ -245,51 +244,6 @@ async def _download_data(self, start_dt, end_dt, data_chan):
245244
"view_width": 2000,
246245
})
247246

248-
async def _update_dividend_factor(self, symbol):
249-
quote = self._api.get_quote(symbol)
250-
df = get_dividend_df(quote.stock_dividend_ratio, quote.cash_dividend_ratio)
251-
between = df["datetime"].between(self._start_dt_nano, self._end_dt_nano) # 只需要开始时间~结束时间之间的复权因子
252-
df["pre_close"] = float('nan')
253-
for i in df[between].index:
254-
chart_info = {
255-
"aid": "set_chart",
256-
"chart_id": _generate_uuid("PYSDK_data_factor"),
257-
"ins_list": symbol,
258-
"duration": 86400 * 1000000000,
259-
"view_width": 2,
260-
"focus_datetime": int(df.iloc[i].datetime),
261-
"focus_position": 1
262-
}
263-
await self._api._send_chan.send(chart_info)
264-
chart = _get_obj(self._api._data, ["charts", chart_info["chart_id"]])
265-
serial = _get_obj(self._api._data, ["klines", symbol, str(86400000000000)])
266-
try:
267-
async with self._api.register_update_notify() as update_chan:
268-
async for _ in update_chan:
269-
if not (chart_info.items() <= _get_obj(chart, ["state"]).items()):
270-
continue # 当前请求还没收齐回应, 不应继续处理
271-
left_id = chart.get("left_id", -1)
272-
right_id = chart.get("right_id", -1)
273-
if (left_id == -1 and right_id == -1) or self._api._data.get("mdhis_more_data",
274-
True) or serial.get("last_id",
275-
-1) == -1:
276-
continue # 定位信息还没收到, 或数据序列还没收到, 合约的数据是否收到
277-
last_item = serial["data"].get(str(left_id), {})
278-
# 复权时间点的昨收盘
279-
df.loc[i, 'pre_close'] = last_item['close'] if last_item.get('close') else float('nan')
280-
break
281-
finally:
282-
await self._api._send_chan.send({
283-
"aid": "set_chart",
284-
"chart_id": chart_info["chart_id"],
285-
"ins_list": "",
286-
"duration": 86400000000000,
287-
"view_width": 2
288-
})
289-
df["factor"] = (df["pre_close"] - df["cash_dividend"]) / df["pre_close"] / (1 + df["stock_dividend"])
290-
df["factor"].fillna(1, inplace=True)
291-
return df
292-
293247
def _merge_rangeset(self):
294248
symbol = self._symbol_list[0]
295249
rangeset = DataSeries._get_rangeset_id(symbol, self._dur_nano)

tqsdk/tools/downloader.py

+2-42
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,7 @@
1515
from tqsdk.api import TqApi
1616
from tqsdk.datetime import _cst_tz, _convert_user_input_to_nano
1717
from tqsdk.diff import _get_obj
18-
from tqsdk.tafunc import get_dividend_df
19-
from tqsdk.utils import _generate_uuid
18+
from tqsdk.utils import _generate_uuid, _get_dividend_factor
2019

2120
try:
2221
file_path = os.path.split(os.path.abspath(__file__))[0]
@@ -188,46 +187,7 @@ def _get_data_series(self) -> Optional[pandas.DataFrame]:
188187

189188
async def _ensure_dividend_factor(self, quote, timestamp):
190189
if quote.instrument_id not in self._dividend_cache:
191-
# 对每个除权除息矩阵增加 factor 序列,为当日的复权因子
192-
df = get_dividend_df(quote.stock_dividend_ratio, quote.cash_dividend_ratio)
193-
df = df[df["datetime"].between(timestamp, self._end_dt_nano, inclusive="right")] # 只需要第一笔行情时间~结束时间之间的复权因子, 左开右闭
194-
df["pre_close"] = float('nan') # 初始化 pre_close 为 nan
195-
for i in range(len(df)):
196-
chart_info = {
197-
"aid": "set_chart",
198-
"chart_id": _generate_uuid("PYSDK_downloader"),
199-
"ins_list": quote.instrument_id,
200-
"duration": 86400 * 1000000000,
201-
"view_width": 2,
202-
"focus_datetime": int(df["datetime"].iloc[i]),
203-
"focus_position": 1
204-
}
205-
await self._api._send_chan.send(chart_info)
206-
chart = _get_obj(self._api._data, ["charts", chart_info["chart_id"]])
207-
serial = _get_obj(self._api._data, ["klines", quote.instrument_id, str(86400000000000)])
208-
try:
209-
async with self._api.register_update_notify() as update_chan:
210-
async for _ in update_chan:
211-
if not (chart_info.items() <= _get_obj(chart, ["state"]).items()):
212-
continue # 当前请求还没收齐回应, 不应继续处理
213-
if chart.get("ready", False) is False:
214-
continue # 合约的数据是否收到
215-
left_id = chart.get("left_id", -1)
216-
assert left_id != -1 # 需要下载除权除息日的前一天行情,即这一天一定是有行情的,left_id 一定不是 -1
217-
last_item = serial["data"].get(str(left_id), {})
218-
# 复权时间点的昨收盘
219-
df.loc[i, 'pre_close'] = last_item['close'] if last_item.get('close') else float('nan')
220-
break
221-
finally:
222-
await self._api._send_chan.send({
223-
"aid": "set_chart",
224-
"chart_id": chart_info["chart_id"],
225-
"ins_list": "",
226-
"duration": 86400000000000,
227-
"view_width": 2
228-
})
229-
df["factor"] = (df["pre_close"] - df["cash_dividend"]) / df["pre_close"] / (1 + df["stock_dividend"])
230-
df["factor"].fillna(1.0, inplace=True)
190+
df = await _get_dividend_factor(self._api, quote, timestamp, self._end_dt_nano, chart_id_prefix="PYSDK_downloader")
231191
# 插入结束时间这条记录, 因为可能存在行情时间等于 _end_dt_nano 的行情,因此这里 +1
232192
df = df.append({"datetime": self._end_dt_nano+1, "factor": 1.0}, ignore_index=True)
233193
if self._adj_type == "F":

tqsdk/utils.py

+47
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,9 @@
1010
from sgqlc.operation import Operation
1111
from pandas.core.internals import BlockManager
1212

13+
from tqsdk.diff import _get_obj
1314
from tqsdk.ins_schema import ins_schema, _add_all_frags
15+
from tqsdk.tafunc import get_dividend_df
1416

1517
RD = random.Random(secrets.randbits(128)) # 初始化随机数引擎,使用随机数作为seed,防止用户同时拉起多个策略,产生同样的 seed
1618

@@ -150,3 +152,48 @@ def __init__(self, *args, **kwargs):
150152
self._known_consolidated = False
151153

152154
def _consolidate_inplace(self): pass
155+
156+
157+
async def _get_dividend_factor(api, quote, start_dt_nano, end_dt_nano, chart_id_prefix="PYSDK_dividend_factor"):
158+
# 对每个除权除息矩阵增加 factor 序列,为当日的复权因子
159+
df = get_dividend_df(quote.stock_dividend_ratio, quote.cash_dividend_ratio)
160+
df = df[df["datetime"].between(start_dt_nano, end_dt_nano, inclusive="right")] # 只需要一段时间之间的复权因子, 左开右闭
161+
df["pre_close"] = float('nan') # 初始化 pre_close 为 nan
162+
for i in range(len(df)):
163+
chart_info = {
164+
"aid": "set_chart",
165+
"chart_id": _generate_uuid(chart_id_prefix),
166+
"ins_list": quote.instrument_id,
167+
"duration": 86400 * 1000000000,
168+
"view_width": 2,
169+
"focus_datetime": int(df["datetime"].iloc[i]),
170+
"focus_position": 1
171+
}
172+
await api._send_chan.send(chart_info)
173+
chart = _get_obj(api._data, ["charts", chart_info["chart_id"]])
174+
serial = _get_obj(api._data, ["klines", quote.instrument_id, str(86400000000000)])
175+
try:
176+
async with api.register_update_notify() as update_chan:
177+
async for _ in update_chan:
178+
if not (chart_info.items() <= _get_obj(chart, ["state"]).items()):
179+
continue # 当前请求还没收齐回应, 不应继续处理
180+
if chart.get("ready", False) is False:
181+
continue # 合约的数据是否收到
182+
left_id = chart.get("left_id", -1)
183+
assert left_id != -1 # 需要下载除权除息日的前一天行情,即这一天一定是有行情的,left_id 一定不是 -1
184+
last_item = serial["data"].get(str(left_id), {})
185+
# 复权时间点的昨收盘
186+
df.loc[i, 'pre_close'] = last_item['close'] if last_item.get('close') else float('nan')
187+
break
188+
finally:
189+
await api._send_chan.send({
190+
"aid": "set_chart",
191+
"chart_id": chart_info["chart_id"],
192+
"ins_list": "",
193+
"duration": 86400000000000,
194+
"view_width": 2
195+
})
196+
df["factor"] = (df["pre_close"] - df["cash_dividend"]) / df["pre_close"] / (1 + df["stock_dividend"])
197+
df["factor"].fillna(1.0, inplace=True)
198+
return df
199+

0 commit comments

Comments
 (0)