pytdxdata 0.2.0__tar.gz → 0.2.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {pytdxdata-0.2.0 → pytdxdata-0.2.2}/PKG-INFO +4 -3
- {pytdxdata-0.2.0 → pytdxdata-0.2.2}/pyproject.toml +5 -3
- {pytdxdata-0.2.0 → pytdxdata-0.2.2}/src/pytdxdata/__init__.py +1 -1
- {pytdxdata-0.2.0 → pytdxdata-0.2.2}/src/pytdxdata/api.py +16 -11
- {pytdxdata-0.2.0 → pytdxdata-0.2.2}/src/pytdxdata/protocol/commands/__init__.py +2 -2
- {pytdxdata-0.2.0 → pytdxdata-0.2.2}/src/pytdxdata/protocol/commands/ex_proto.py +5 -2
- {pytdxdata-0.2.0 → pytdxdata-0.2.2}/src/pytdxdata/protocol/commands/minute.py +2 -17
- {pytdxdata-0.2.0 → pytdxdata-0.2.2}/LICENSE +0 -0
- {pytdxdata-0.2.0 → pytdxdata-0.2.2}/README.md +0 -0
- {pytdxdata-0.2.0 → pytdxdata-0.2.2}/src/pytdxdata/_binary.py +0 -0
- {pytdxdata-0.2.0 → pytdxdata-0.2.2}/src/pytdxdata/cache/__init__.py +0 -0
- {pytdxdata-0.2.0 → pytdxdata-0.2.2}/src/pytdxdata/cache/disk.py +0 -0
- {pytdxdata-0.2.0 → pytdxdata-0.2.2}/src/pytdxdata/cache/key.py +0 -0
- {pytdxdata-0.2.0 → pytdxdata-0.2.2}/src/pytdxdata/cache/manager.py +0 -0
- {pytdxdata-0.2.0 → pytdxdata-0.2.2}/src/pytdxdata/cache/memory.py +0 -0
- {pytdxdata-0.2.0 → pytdxdata-0.2.2}/src/pytdxdata/cache/ttl.py +0 -0
- {pytdxdata-0.2.0 → pytdxdata-0.2.2}/src/pytdxdata/cli.py +0 -0
- {pytdxdata-0.2.0 → pytdxdata-0.2.2}/src/pytdxdata/codec/__init__.py +0 -0
- {pytdxdata-0.2.0 → pytdxdata-0.2.2}/src/pytdxdata/codec/payload.py +0 -0
- {pytdxdata-0.2.0 → pytdxdata-0.2.2}/src/pytdxdata/config.py +0 -0
- {pytdxdata-0.2.0 → pytdxdata-0.2.2}/src/pytdxdata/indicator.py +0 -0
- {pytdxdata-0.2.0 → pytdxdata-0.2.2}/src/pytdxdata/models/__init__.py +0 -0
- {pytdxdata-0.2.0 → pytdxdata-0.2.2}/src/pytdxdata/pool/__init__.py +0 -0
- {pytdxdata-0.2.0 → pytdxdata-0.2.2}/src/pytdxdata/pool/connection.py +0 -0
- {pytdxdata-0.2.0 → pytdxdata-0.2.2}/src/pytdxdata/pool/ex_connection.py +0 -0
- {pytdxdata-0.2.0 → pytdxdata-0.2.2}/src/pytdxdata/pool/ex_pool.py +0 -0
- {pytdxdata-0.2.0 → pytdxdata-0.2.2}/src/pytdxdata/pool/health.py +0 -0
- {pytdxdata-0.2.0 → pytdxdata-0.2.2}/src/pytdxdata/pool/pool.py +0 -0
- {pytdxdata-0.2.0 → pytdxdata-0.2.2}/src/pytdxdata/protocol/__init__.py +0 -0
- {pytdxdata-0.2.0 → pytdxdata-0.2.2}/src/pytdxdata/protocol/commands/base.py +0 -0
- {pytdxdata-0.2.0 → pytdxdata-0.2.2}/src/pytdxdata/protocol/commands/ex_ext.py +0 -0
- {pytdxdata-0.2.0 → pytdxdata-0.2.2}/src/pytdxdata/protocol/commands/finance.py +0 -0
- {pytdxdata-0.2.0 → pytdxdata-0.2.2}/src/pytdxdata/protocol/commands/kline.py +0 -0
- {pytdxdata-0.2.0 → pytdxdata-0.2.2}/src/pytdxdata/protocol/commands/mac.py +0 -0
- {pytdxdata-0.2.0 → pytdxdata-0.2.2}/src/pytdxdata/protocol/commands/mac_ext.py +0 -0
- {pytdxdata-0.2.0 → pytdxdata-0.2.2}/src/pytdxdata/protocol/commands/quotes.py +0 -0
- {pytdxdata-0.2.0 → pytdxdata-0.2.2}/src/pytdxdata/protocol/commands/security_list.py +0 -0
- {pytdxdata-0.2.0 → pytdxdata-0.2.2}/src/pytdxdata/protocol/commands/setup.py +0 -0
- {pytdxdata-0.2.0 → pytdxdata-0.2.2}/src/pytdxdata/protocol/commands/std_ext.py +0 -0
- {pytdxdata-0.2.0 → pytdxdata-0.2.2}/src/pytdxdata/protocol/commands/transaction.py +0 -0
- {pytdxdata-0.2.0 → pytdxdata-0.2.2}/src/pytdxdata/protocol/commands/xdxr.py +0 -0
- {pytdxdata-0.2.0 → pytdxdata-0.2.2}/src/pytdxdata/protocol/datetime_.py +0 -0
- {pytdxdata-0.2.0 → pytdxdata-0.2.2}/src/pytdxdata/protocol/frame.py +0 -0
- {pytdxdata-0.2.0 → pytdxdata-0.2.2}/src/pytdxdata/protocol/mac_frame.py +0 -0
- {pytdxdata-0.2.0 → pytdxdata-0.2.2}/src/pytdxdata/protocol/price.py +0 -0
- {pytdxdata-0.2.0 → pytdxdata-0.2.2}/src/pytdxdata/protocol/volume.py +0 -0
- {pytdxdata-0.2.0 → pytdxdata-0.2.2}/src/pytdxdata/router.py +0 -0
- {pytdxdata-0.2.0 → pytdxdata-0.2.2}/src/pytdxdata/scheduler/__init__.py +0 -0
- {pytdxdata-0.2.0 → pytdxdata-0.2.2}/src/pytdxdata/scheduler/paginator.py +0 -0
- {pytdxdata-0.2.0 → pytdxdata-0.2.2}/src/pytdxdata/server_probe.py +0 -0
- {pytdxdata-0.2.0 → pytdxdata-0.2.2}/src/pytdxdata/servers.json +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pytdxdata
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.2
|
|
4
4
|
Summary: 通达信(TongDaXin)行情数据客户端:动态连接池 + 双层TTL缓存 + 3连接并发分页,纯asyncio零运行时依赖,支持A股/港股/美股/期货/期权
|
|
5
5
|
Keywords: tdx,trading,stock,kline,quote,通达信,A股,港股,美股,期货,asyncio,quant
|
|
6
6
|
Author: vex1023
|
|
@@ -11,8 +11,9 @@ Classifier: Development Status :: 4 - Beta
|
|
|
11
11
|
Classifier: Intended Audience :: Developers
|
|
12
12
|
Classifier: Intended Audience :: Financial and Insurance Industry
|
|
13
13
|
Classifier: Topic :: Office/Business :: Financial :: Investment
|
|
14
|
-
Classifier: Programming Language :: Python :: 3.
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
15
15
|
Classifier: Programming Language :: Python :: 3.12
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
16
17
|
Classifier: Operating System :: OS Independent
|
|
17
18
|
Classifier: Framework :: AsyncIO
|
|
18
19
|
Classifier: Typing :: Typed
|
|
@@ -20,7 +21,7 @@ Requires-Dist: pytest>=8.0 ; extra == 'dev'
|
|
|
20
21
|
Requires-Dist: pytest-asyncio>=0.24 ; extra == 'dev'
|
|
21
22
|
Requires-Dist: ruff>=0.6 ; extra == 'dev'
|
|
22
23
|
Requires-Dist: uvloop>=0.21 ; extra == 'uvloop'
|
|
23
|
-
Requires-Python: >=3.
|
|
24
|
+
Requires-Python: >=3.11
|
|
24
25
|
Project-URL: Homepage, https://github.com/vex1023/pytdxdata
|
|
25
26
|
Project-URL: Repository, https://github.com/vex1023/pytdxdata
|
|
26
27
|
Project-URL: Documentation, https://github.com/vex1023/pytdxdata#readme
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "pytdxdata"
|
|
3
|
-
version = "0.2.
|
|
3
|
+
version = "0.2.2"
|
|
4
4
|
description = "通达信(TongDaXin)行情数据客户端:动态连接池 + 双层TTL缓存 + 3连接并发分页,纯asyncio零运行时依赖,支持A股/港股/美股/期货/期权"
|
|
5
5
|
readme = "README.md"
|
|
6
|
-
requires-python = ">=3.
|
|
6
|
+
requires-python = ">=3.11"
|
|
7
7
|
license = "MIT"
|
|
8
8
|
license-files = ["LICENSE"]
|
|
9
9
|
keywords = ["tdx", "trading", "stock", "kline", "quote", "通达信", "A股", "港股", "美股", "期货", "asyncio", "quant"]
|
|
@@ -15,8 +15,9 @@ classifiers = [
|
|
|
15
15
|
"Intended Audience :: Developers",
|
|
16
16
|
"Intended Audience :: Financial and Insurance Industry",
|
|
17
17
|
"Topic :: Office/Business :: Financial :: Investment",
|
|
18
|
-
"Programming Language :: Python :: 3.
|
|
18
|
+
"Programming Language :: Python :: 3.11",
|
|
19
19
|
"Programming Language :: Python :: 3.12",
|
|
20
|
+
"Programming Language :: Python :: 3.13",
|
|
20
21
|
"Operating System :: OS Independent",
|
|
21
22
|
"Framework :: AsyncIO",
|
|
22
23
|
"Typing :: Typed",
|
|
@@ -45,6 +46,7 @@ target-version = "py313"
|
|
|
45
46
|
|
|
46
47
|
[tool.pytest.ini_options]
|
|
47
48
|
asyncio_mode = "auto"
|
|
49
|
+
testpaths = ["tests"]
|
|
48
50
|
|
|
49
51
|
[dependency-groups]
|
|
50
52
|
dev = [
|
|
@@ -3,6 +3,7 @@ from __future__ import annotations
|
|
|
3
3
|
|
|
4
4
|
import asyncio
|
|
5
5
|
import logging
|
|
6
|
+
from datetime import date as _date
|
|
6
7
|
from pathlib import Path
|
|
7
8
|
from typing import Sequence
|
|
8
9
|
|
|
@@ -32,7 +33,6 @@ from .protocol.commands import (
|
|
|
32
33
|
GetFinanceInfoCmd,
|
|
33
34
|
GetHistoryMinuteTimeDataCmd,
|
|
34
35
|
GetIndexBarsCmd,
|
|
35
|
-
GetMinuteTimeDataCmd,
|
|
36
36
|
GetSecurityBarsCmd,
|
|
37
37
|
GetSecurityCountCmd,
|
|
38
38
|
GetSecurityListCmd,
|
|
@@ -145,27 +145,30 @@ class TdxData:
|
|
|
145
145
|
adj = self.default_adjust if adjust is None else adjust
|
|
146
146
|
# EX扩展市场(港股/期货):market为ExMarket值,走ex池
|
|
147
147
|
if isinstance(market, ExMarket) or int(market) not in (0, 1, 2):
|
|
148
|
-
# EX通道统一用pytdx EX协议(0x23FF
|
|
148
|
+
# EX通道统一用pytdx EX协议(0x23FF): category=K线周期(与TDXParams一致, DAY=4)
|
|
149
149
|
from .protocol.commands.ex_proto import GetExInstrumentBarsCmd
|
|
150
|
+
cat = int(period)
|
|
150
151
|
fetch_count = max(700, start + count)
|
|
151
|
-
key = CacheKey("kline", int(market), code, period.name, start, fetch_count,
|
|
152
|
+
key = CacheKey("kline", int(market), code, period.name, start, fetch_count,
|
|
153
|
+
f"{adj.name}@{cat}")
|
|
152
154
|
async def fetch() -> bytes:
|
|
153
155
|
result = await self._fetch_paginated_ex(
|
|
154
|
-
lambda s2, c2: GetExInstrumentBarsCmd(int(market), code,
|
|
156
|
+
lambda s2, c2: GetExInstrumentBarsCmd(int(market), code, cat, s2, c2),
|
|
155
157
|
PageSpec(page_size=700, total=fetch_count, min_page=100))
|
|
156
158
|
bars = []
|
|
157
159
|
for d in result:
|
|
158
160
|
bars.append(SecurityBar(
|
|
159
161
|
market=int(market), code=code,
|
|
160
162
|
year=d["year"], month=d["month"], day=d["day"],
|
|
161
|
-
hour=0, minute=0,
|
|
163
|
+
hour=d.get("hour", 0), minute=d.get("minute", 0),
|
|
162
164
|
open=d["open"], high=d["high"], low=d["low"], close=d["close"],
|
|
163
165
|
vol=float(d.get("trade", 0) or 0), amount=0.0,
|
|
164
166
|
))
|
|
165
167
|
return pack_payload(bars)
|
|
166
168
|
bars = unpack_payload(await self._cache.get_or_fetch(key, fetch))
|
|
167
|
-
|
|
168
|
-
|
|
169
|
+
# EX 0x23FF 按时间升序返回(老→新):start=0 取最新 count 根
|
|
170
|
+
if count < len(bars):
|
|
171
|
+
return bars[-count:] if start == 0 else bars[start:start + count]
|
|
169
172
|
return bars
|
|
170
173
|
|
|
171
174
|
route = route_for("kline", adjust=adj)
|
|
@@ -295,10 +298,12 @@ class TdxData:
|
|
|
295
298
|
|
|
296
299
|
async def get_minute(self, market: Market, code: str, *,
|
|
297
300
|
date: int | None = None) -> list[MinuteBar]:
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
301
|
+
"""获取分时(date=None=今天;0x1b08当日分时在当前服务器格式已变,统一走历史命令0x0130)。"""
|
|
302
|
+
if date is None:
|
|
303
|
+
d = _date.today()
|
|
304
|
+
date = d.year * 10000 + d.month * 100 + d.day
|
|
305
|
+
key = CacheKey("minute", int(market), code, "", 0, 0, str(date))
|
|
306
|
+
cmd = GetHistoryMinuteTimeDataCmd(int(market), code, date)
|
|
302
307
|
payload = await self._cache.get_or_fetch(
|
|
303
308
|
key, lambda: self._fetch_minute(cmd)
|
|
304
309
|
)
|
|
@@ -5,7 +5,7 @@ from .base import BaseCommand, TdxDecodeError, build_standard_request
|
|
|
5
5
|
from .finance import GetFinanceInfoCmd
|
|
6
6
|
from .kline import GetIndexBarsCmd, GetSecurityBarsCmd, PAGE_SIZE as KLINE_PAGE
|
|
7
7
|
from .mac import MacKlineCmd, MAC_KLINE_PAGE
|
|
8
|
-
from .minute import GetHistoryMinuteTimeDataCmd
|
|
8
|
+
from .minute import GetHistoryMinuteTimeDataCmd
|
|
9
9
|
from .quotes import GetSecurityQuotesCmd, MAX_QUOTES
|
|
10
10
|
from .security_list import GetSecurityCountCmd, GetSecurityListCmd, PAGE_SIZE as LIST_PAGE
|
|
11
11
|
from .transaction import (
|
|
@@ -23,7 +23,7 @@ __all__ = [
|
|
|
23
23
|
"GetSecurityCountCmd", "GetSecurityListCmd", "LIST_PAGE",
|
|
24
24
|
"GetTransactionDataCmd", "GetHistoryTransactionDataCmd", "MacTransactionCmd",
|
|
25
25
|
"STD_PAGE_SIZE", "MAC_PAGE_SIZE",
|
|
26
|
-
"
|
|
26
|
+
"GetHistoryMinuteTimeDataCmd",
|
|
27
27
|
"GetXdxrInfoCmd", "GetFinanceInfoCmd",
|
|
28
28
|
"MacKlineCmd", "MAC_KLINE_PAGE",
|
|
29
29
|
]
|
|
@@ -4,6 +4,7 @@ from __future__ import annotations
|
|
|
4
4
|
import struct
|
|
5
5
|
|
|
6
6
|
from ..._binary import unpack_from
|
|
7
|
+
from ..datetime_ import get_datetime
|
|
7
8
|
from .base import BaseCommand
|
|
8
9
|
|
|
9
10
|
# pytdx EX setup 握手命令(完整84B: 12B帧头+72B body, 0x2454)—— 与MAC EX login同ID不同body
|
|
@@ -80,11 +81,13 @@ class GetExInstrumentBarsCmd(BaseCommand[list[dict]]):
|
|
|
80
81
|
for _ in range(ret_count):
|
|
81
82
|
if off + 32 > len(body):
|
|
82
83
|
break
|
|
83
|
-
|
|
84
|
+
# 时间4字节按category分格式:分钟级=2B zipday+2B tminutes;日线及以上=YYYYMMDD
|
|
85
|
+
year, month, day, hour, minute, _ = get_datetime(self.category, body, off)
|
|
84
86
|
open_, high, low, close, position, trade, _ = struct.unpack(
|
|
85
87
|
"<ffffIIf", body[off + 4: off + 32])
|
|
86
88
|
items.append({
|
|
87
|
-
"year":
|
|
89
|
+
"year": year, "month": month, "day": day,
|
|
90
|
+
"hour": hour, "minute": minute,
|
|
88
91
|
"open": open_, "high": high, "low": low, "close": close,
|
|
89
92
|
"position": position, "trade": trade,
|
|
90
93
|
})
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"""分时命令(标准通道
|
|
1
|
+
"""分时命令(标准通道 0x013000;0x1b08 当日分时在当前服务器格式已变,统一用历史命令传当天)"""
|
|
2
2
|
from __future__ import annotations
|
|
3
3
|
|
|
4
4
|
import struct
|
|
@@ -9,23 +9,8 @@ from ..price import get_price
|
|
|
9
9
|
from .base import BaseCommand
|
|
10
10
|
|
|
11
11
|
|
|
12
|
-
class GetMinuteTimeDataCmd(BaseCommand[list[MinuteBar]]):
|
|
13
|
-
"""今日分时(全天约240条)。"""
|
|
14
|
-
|
|
15
|
-
def __init__(self, market: int, code: str) -> None:
|
|
16
|
-
self.market = market
|
|
17
|
-
self.code = code.encode("utf-8")
|
|
18
|
-
|
|
19
|
-
def build_request(self) -> bytes:
|
|
20
|
-
header = bytes.fromhex("0c1b080001010e000e001d05".replace(" ", ""))
|
|
21
|
-
return header + struct.pack("<H6sI", self.market, self.code, 0)
|
|
22
|
-
|
|
23
|
-
def parse_response(self, body: bytes) -> list[MinuteBar]:
|
|
24
|
-
return _parse_minute_body(body, skip=4)
|
|
25
|
-
|
|
26
|
-
|
|
27
12
|
class GetHistoryMinuteTimeDataCmd(BaseCommand[list[MinuteBar]]):
|
|
28
|
-
"""
|
|
13
|
+
"""某日分时(date=YYYYMMDD;当日分时也用它,date 传当天)。"""
|
|
29
14
|
|
|
30
15
|
def __init__(self, market: int, code: str, date: int) -> None:
|
|
31
16
|
self.market = market
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|