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.
Files changed (51) hide show
  1. {pytdxdata-0.2.0 → pytdxdata-0.2.2}/PKG-INFO +4 -3
  2. {pytdxdata-0.2.0 → pytdxdata-0.2.2}/pyproject.toml +5 -3
  3. {pytdxdata-0.2.0 → pytdxdata-0.2.2}/src/pytdxdata/__init__.py +1 -1
  4. {pytdxdata-0.2.0 → pytdxdata-0.2.2}/src/pytdxdata/api.py +16 -11
  5. {pytdxdata-0.2.0 → pytdxdata-0.2.2}/src/pytdxdata/protocol/commands/__init__.py +2 -2
  6. {pytdxdata-0.2.0 → pytdxdata-0.2.2}/src/pytdxdata/protocol/commands/ex_proto.py +5 -2
  7. {pytdxdata-0.2.0 → pytdxdata-0.2.2}/src/pytdxdata/protocol/commands/minute.py +2 -17
  8. {pytdxdata-0.2.0 → pytdxdata-0.2.2}/LICENSE +0 -0
  9. {pytdxdata-0.2.0 → pytdxdata-0.2.2}/README.md +0 -0
  10. {pytdxdata-0.2.0 → pytdxdata-0.2.2}/src/pytdxdata/_binary.py +0 -0
  11. {pytdxdata-0.2.0 → pytdxdata-0.2.2}/src/pytdxdata/cache/__init__.py +0 -0
  12. {pytdxdata-0.2.0 → pytdxdata-0.2.2}/src/pytdxdata/cache/disk.py +0 -0
  13. {pytdxdata-0.2.0 → pytdxdata-0.2.2}/src/pytdxdata/cache/key.py +0 -0
  14. {pytdxdata-0.2.0 → pytdxdata-0.2.2}/src/pytdxdata/cache/manager.py +0 -0
  15. {pytdxdata-0.2.0 → pytdxdata-0.2.2}/src/pytdxdata/cache/memory.py +0 -0
  16. {pytdxdata-0.2.0 → pytdxdata-0.2.2}/src/pytdxdata/cache/ttl.py +0 -0
  17. {pytdxdata-0.2.0 → pytdxdata-0.2.2}/src/pytdxdata/cli.py +0 -0
  18. {pytdxdata-0.2.0 → pytdxdata-0.2.2}/src/pytdxdata/codec/__init__.py +0 -0
  19. {pytdxdata-0.2.0 → pytdxdata-0.2.2}/src/pytdxdata/codec/payload.py +0 -0
  20. {pytdxdata-0.2.0 → pytdxdata-0.2.2}/src/pytdxdata/config.py +0 -0
  21. {pytdxdata-0.2.0 → pytdxdata-0.2.2}/src/pytdxdata/indicator.py +0 -0
  22. {pytdxdata-0.2.0 → pytdxdata-0.2.2}/src/pytdxdata/models/__init__.py +0 -0
  23. {pytdxdata-0.2.0 → pytdxdata-0.2.2}/src/pytdxdata/pool/__init__.py +0 -0
  24. {pytdxdata-0.2.0 → pytdxdata-0.2.2}/src/pytdxdata/pool/connection.py +0 -0
  25. {pytdxdata-0.2.0 → pytdxdata-0.2.2}/src/pytdxdata/pool/ex_connection.py +0 -0
  26. {pytdxdata-0.2.0 → pytdxdata-0.2.2}/src/pytdxdata/pool/ex_pool.py +0 -0
  27. {pytdxdata-0.2.0 → pytdxdata-0.2.2}/src/pytdxdata/pool/health.py +0 -0
  28. {pytdxdata-0.2.0 → pytdxdata-0.2.2}/src/pytdxdata/pool/pool.py +0 -0
  29. {pytdxdata-0.2.0 → pytdxdata-0.2.2}/src/pytdxdata/protocol/__init__.py +0 -0
  30. {pytdxdata-0.2.0 → pytdxdata-0.2.2}/src/pytdxdata/protocol/commands/base.py +0 -0
  31. {pytdxdata-0.2.0 → pytdxdata-0.2.2}/src/pytdxdata/protocol/commands/ex_ext.py +0 -0
  32. {pytdxdata-0.2.0 → pytdxdata-0.2.2}/src/pytdxdata/protocol/commands/finance.py +0 -0
  33. {pytdxdata-0.2.0 → pytdxdata-0.2.2}/src/pytdxdata/protocol/commands/kline.py +0 -0
  34. {pytdxdata-0.2.0 → pytdxdata-0.2.2}/src/pytdxdata/protocol/commands/mac.py +0 -0
  35. {pytdxdata-0.2.0 → pytdxdata-0.2.2}/src/pytdxdata/protocol/commands/mac_ext.py +0 -0
  36. {pytdxdata-0.2.0 → pytdxdata-0.2.2}/src/pytdxdata/protocol/commands/quotes.py +0 -0
  37. {pytdxdata-0.2.0 → pytdxdata-0.2.2}/src/pytdxdata/protocol/commands/security_list.py +0 -0
  38. {pytdxdata-0.2.0 → pytdxdata-0.2.2}/src/pytdxdata/protocol/commands/setup.py +0 -0
  39. {pytdxdata-0.2.0 → pytdxdata-0.2.2}/src/pytdxdata/protocol/commands/std_ext.py +0 -0
  40. {pytdxdata-0.2.0 → pytdxdata-0.2.2}/src/pytdxdata/protocol/commands/transaction.py +0 -0
  41. {pytdxdata-0.2.0 → pytdxdata-0.2.2}/src/pytdxdata/protocol/commands/xdxr.py +0 -0
  42. {pytdxdata-0.2.0 → pytdxdata-0.2.2}/src/pytdxdata/protocol/datetime_.py +0 -0
  43. {pytdxdata-0.2.0 → pytdxdata-0.2.2}/src/pytdxdata/protocol/frame.py +0 -0
  44. {pytdxdata-0.2.0 → pytdxdata-0.2.2}/src/pytdxdata/protocol/mac_frame.py +0 -0
  45. {pytdxdata-0.2.0 → pytdxdata-0.2.2}/src/pytdxdata/protocol/price.py +0 -0
  46. {pytdxdata-0.2.0 → pytdxdata-0.2.2}/src/pytdxdata/protocol/volume.py +0 -0
  47. {pytdxdata-0.2.0 → pytdxdata-0.2.2}/src/pytdxdata/router.py +0 -0
  48. {pytdxdata-0.2.0 → pytdxdata-0.2.2}/src/pytdxdata/scheduler/__init__.py +0 -0
  49. {pytdxdata-0.2.0 → pytdxdata-0.2.2}/src/pytdxdata/scheduler/paginator.py +0 -0
  50. {pytdxdata-0.2.0 → pytdxdata-0.2.2}/src/pytdxdata/server_probe.py +0 -0
  51. {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.0
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.13
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.13
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.0"
3
+ version = "0.2.2"
4
4
  description = "通达信(TongDaXin)行情数据客户端:动态连接池 + 双层TTL缓存 + 3连接并发分页,纯asyncio零运行时依赖,支持A股/港股/美股/期货/期权"
5
5
  readme = "README.md"
6
- requires-python = ">=3.13"
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.13",
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 = [
@@ -16,7 +16,7 @@ from .models import (
16
16
  XdxrRecord,
17
17
  )
18
18
 
19
- __version__ = "0.2.0"
19
+ __version__ = "0.2.2"
20
20
  __all__ = [
21
21
  "TdxData",
22
22
  "Market",
@@ -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, 3台服务器均支持): category=0日线
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, adj.name)
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, 0, s2, c2),
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
- if start == 0 and count < fetch_count:
168
- return bars[:count]
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
- key = CacheKey("minute", int(market), code, "", 0, 0,
299
- "" if date is None else str(date))
300
- cmd = (GetHistoryMinuteTimeDataCmd(int(market), code, date)
301
- if date is not None else GetMinuteTimeDataCmd(int(market), code))
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, GetMinuteTimeDataCmd
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
- "GetMinuteTimeDataCmd", "GetHistoryMinuteTimeDataCmd",
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
- (ymd,) = unpack_from("<I", body, off, "ex bar date")
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": ymd // 10000, "month": (ymd % 10000) // 100, "day": ymd % 100,
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
- """分时命令(标准通道 今日0x1B0800 / 历史0x013000)"""
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
- """历史某日分时(date=YYYYMMDD)。"""
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