quantdb-sdk 0.3.5__tar.gz → 0.4.1__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 (38) hide show
  1. {quantdb_sdk-0.3.5 → quantdb_sdk-0.4.1}/CHANGELOG.md +31 -0
  2. {quantdb_sdk-0.3.5/quantdb_sdk.egg-info → quantdb_sdk-0.4.1}/PKG-INFO +2 -2
  3. {quantdb_sdk-0.3.5 → quantdb_sdk-0.4.1}/pyproject.toml +69 -67
  4. {quantdb_sdk-0.3.5 → quantdb_sdk-0.4.1}/quantdb_sdk/__init__.py +6 -1
  5. {quantdb_sdk-0.3.5 → quantdb_sdk-0.4.1}/quantdb_sdk/__main__.py +32 -1
  6. {quantdb_sdk-0.3.5 → quantdb_sdk-0.4.1}/quantdb_sdk/async_client.py +17 -1
  7. {quantdb_sdk-0.3.5 → quantdb_sdk-0.4.1}/quantdb_sdk/client.py +18 -1
  8. quantdb_sdk-0.4.1/quantdb_sdk/examples/demo_07_data_hub.py +66 -0
  9. quantdb_sdk-0.4.1/quantdb_sdk/hub.py +1052 -0
  10. {quantdb_sdk-0.3.5 → quantdb_sdk-0.4.1/quantdb_sdk.egg-info}/PKG-INFO +2 -2
  11. {quantdb_sdk-0.3.5 → quantdb_sdk-0.4.1}/quantdb_sdk.egg-info/SOURCES.txt +3 -0
  12. {quantdb_sdk-0.3.5 → quantdb_sdk-0.4.1}/quantdb_sdk.egg-info/requires.txt +1 -1
  13. {quantdb_sdk-0.3.5 → quantdb_sdk-0.4.1}/tests/test_async_client.py +22 -3
  14. {quantdb_sdk-0.3.5 → quantdb_sdk-0.4.1}/tests/test_client.py +23 -8
  15. quantdb_sdk-0.4.1/tests/test_data_hub.py +343 -0
  16. {quantdb_sdk-0.3.5 → quantdb_sdk-0.4.1}/tests/test_update_pipeline.py +4 -2
  17. {quantdb_sdk-0.3.5 → quantdb_sdk-0.4.1}/LICENSE +0 -0
  18. {quantdb_sdk-0.3.5 → quantdb_sdk-0.4.1}/MANIFEST.in +0 -0
  19. {quantdb_sdk-0.3.5 → quantdb_sdk-0.4.1}/README.md +0 -0
  20. {quantdb_sdk-0.3.5 → quantdb_sdk-0.4.1}/quantdb_sdk/_utils.py +0 -0
  21. {quantdb_sdk-0.3.5 → quantdb_sdk-0.4.1}/quantdb_sdk/errors.py +0 -0
  22. {quantdb_sdk-0.3.5 → quantdb_sdk-0.4.1}/quantdb_sdk/examples/__init__.py +0 -0
  23. {quantdb_sdk-0.3.5 → quantdb_sdk-0.4.1}/quantdb_sdk/examples/demo_01_connect_basics.py +0 -0
  24. {quantdb_sdk-0.3.5 → quantdb_sdk-0.4.1}/quantdb_sdk/examples/demo_02_kline_v2_daily.py +0 -0
  25. {quantdb_sdk-0.3.5 → quantdb_sdk-0.4.1}/quantdb_sdk/examples/demo_03_sync_full_market.py +0 -0
  26. {quantdb_sdk-0.3.5 → quantdb_sdk-0.4.1}/quantdb_sdk/examples/demo_04_duckdb_warehouse.py +0 -0
  27. {quantdb_sdk-0.3.5 → quantdb_sdk-0.4.1}/quantdb_sdk/examples/demo_05_read_local_data.py +0 -0
  28. {quantdb_sdk-0.3.5 → quantdb_sdk-0.4.1}/quantdb_sdk/examples/demo_06_tick_and_factors.py +0 -0
  29. {quantdb_sdk-0.3.5 → quantdb_sdk-0.4.1}/quantdb_sdk/layout.py +0 -0
  30. {quantdb_sdk-0.3.5 → quantdb_sdk-0.4.1}/quantdb_sdk/py.typed +0 -0
  31. {quantdb_sdk-0.3.5 → quantdb_sdk-0.4.1}/quantdb_sdk.egg-info/dependency_links.txt +0 -0
  32. {quantdb_sdk-0.3.5 → quantdb_sdk-0.4.1}/quantdb_sdk.egg-info/entry_points.txt +0 -0
  33. {quantdb_sdk-0.3.5 → quantdb_sdk-0.4.1}/quantdb_sdk.egg-info/top_level.txt +0 -0
  34. {quantdb_sdk-0.3.5 → quantdb_sdk-0.4.1}/setup.cfg +0 -0
  35. {quantdb_sdk-0.3.5 → quantdb_sdk-0.4.1}/tests/test_hub_models.py +0 -0
  36. {quantdb_sdk-0.3.5 → quantdb_sdk-0.4.1}/tests/test_layout.py +0 -0
  37. {quantdb_sdk-0.3.5 → quantdb_sdk-0.4.1}/tests/test_technical_indicators.py +0 -0
  38. {quantdb_sdk-0.3.5 → quantdb_sdk-0.4.1}/tests/test_utils.py +0 -0
@@ -3,6 +3,37 @@
3
3
  所有 notable 变更都会记录在此文件。格式基于 [Keep a Changelog](https://keepachangelog.com/zh-CN/1.1.0/),
4
4
  版本号遵循 [Semantic Versioning](https://semver.org/lang/zh-CN/)。
5
5
 
6
+ ## \[0.4.1] - 2026-10-05
7
+
8
+ ### Changed
9
+
10
+ - **本地零流量读取提速**(`client.data.read_local` / `read`):改用 DuckDB 对**精确分区文件列表**做一次 `read_parquet`,把 `symbol` / 日期区间 / 列裁剪全部下推到 SQL,替代原先逐文件 `pd.read_parquet` 再 `concat`。实测(120 分区 × 1000 标的)单标的全历史 `0.62s → 0.22s`,带 `columns` 列裁剪 `→ 0.07s`。
11
+
12
+ - V2 按日分区与 tick 分片的 `trade_date` 由分区目录名 / 文件名推导,**不依赖** hive 注入的 `dt` 列(该列仅在较新 DuckDB 存在)。
13
+ - V1 逐股票表日期过滤用 `substr(replace(CAST(col AS VARCHAR),'-',''),1,8)` 归一化后下推,同时兼容整型报告期 `20251231` 与字符串 `2025-12-31` / 带时分秒。
14
+
15
+ - **依赖下界调整**:`duckdb` 由 `>=0.8.0` 改为 `>=1.0.0`。`read_local` 用到 `read_parquet(filename=true)` + `* EXCLUDE (filename)`;0.8.x 在部分环境(Windows / Python 3.10)导入即崩溃,1.0.0 ~ 1.5.5 已验证通过。
16
+
17
+ ### Fixed
18
+
19
+ - `read_local(..., columns=[...])` 在 V2 / tick 上未把 `symbol` 过滤下推:当 `columns` 不含 `symbol` 时,旧实现会在读取后被静默跳过过滤、返回全市场行。现 `symbol` 始终在 SQL 中下推。
20
+
21
+ ## \[0.4.0] - 2026-10-05
22
+
23
+ ### Added
24
+
25
+ - **统一数据入口** **`client.data`**(同步 `DataHub` / 异步 `AsyncDataHub`,模块 `quantdb_sdk.hub`):只凭 **dataset 名**即可跨 6 大分类目录取数,不必再手填 `category_id + sub_category`。SDK 侧解析分类后复用现有端点,**零后端改动**。
26
+
27
+ - **发现**:`datasets(category, access, keyword)` 列出 29 个数据集目录;`info(dataset)` 返回注册表字段并叠加云端元数据(覆盖区间 / 文件数 / 文件大小)。
28
+ - **本地零流量**:`local_files` / `local_path` / `read_local` / `read`(本地优先,缺失时显式回退在线)。数据根目录可配置(`root` 参数,缺省读 `QUANTDB_DATA_DIR`);多形态 glob 兼容 V2 `dt=` 分区、tick 平铺/子目录分片、V1 逐股票文件;V2/tick 无日期列时从路径注入 `trade_date`。
29
+ - **在线**:`preview` / `load` / `download` / `query` / `sync` / `mount`,逐项委托既有方法。`query` 按数据集自动路由:日线三兄弟走 `query_kline`、ETF 走 `query_etf_kline`、tick 走 `query_tick` 并按 symbol 后置过滤、其余 V2 走通用日分区分支、V1 逐股票走 `layout="v1"` + 日期列过滤。
30
+ - 异步方法统一 `a_` 前缀;异步端不含 `mount`(无 `a_mount_local_dataset`,DuckDB 仓库为同步)。
31
+ - 新增 `DATASET_REGISTRY` 注册表(29 项),`category_id` 复用 `SYNC_DATASET_CATEGORIES`,`category_dir` 复用 `CATEGORY_DIRS`,避免重复维护分类事实源。
32
+
33
+ - **命令行** **`quantdb datasets [name]`**:列出全部数据集目录或查看某个数据集详情(无需 API Key)。
34
+
35
+ - 新增演示脚本 `quantdb_sdk/examples/demo_07_data_hub.py`。
36
+
6
37
  ## \[0.3.5] - 2026-09-26
7
38
 
8
39
  ### Added
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: quantdb-sdk
3
- Version: 0.3.5
3
+ Version: 0.4.1
4
4
  Summary: QuantDB 量化数据平台官方 Python SDK
5
5
  Author: QuantDB Team
6
6
  License: MIT
@@ -26,7 +26,7 @@ License-File: LICENSE
26
26
  Requires-Dist: requests>=2.25.0
27
27
  Requires-Dist: pandas>=1.3.0
28
28
  Requires-Dist: httpx>=0.24.0
29
- Requires-Dist: duckdb>=0.8.0
29
+ Requires-Dist: duckdb>=1.0.0
30
30
  Requires-Dist: pyarrow>=10.0.0
31
31
  Provides-Extra: dev
32
32
  Requires-Dist: pytest>=7.0.0; extra == "dev"
@@ -1,67 +1,69 @@
1
- [build-system]
2
- requires = ["setuptools>=61.0", "wheel"]
3
- build-backend = "setuptools.build_meta"
4
-
5
- [project]
6
- name = "quantdb-sdk"
7
- version = "0.3.5"
8
- description = "QuantDB 量化数据平台官方 Python SDK"
9
- readme = "README.md"
10
- license = {text = "MIT"}
11
- requires-python = ">=3.8"
12
- authors = [
13
- {name = "QuantDB Team"},
14
- ]
15
- keywords = ["quant", "finance", "data", "a-share", "parquet"]
16
- classifiers = [
17
- "Development Status :: 3 - Alpha",
18
- "Intended Audience :: Developers",
19
- "Intended Audience :: Financial and Insurance Industry",
20
- "License :: OSI Approved :: MIT License",
21
- "Programming Language :: Python :: 3",
22
- "Programming Language :: Python :: 3.8",
23
- "Programming Language :: Python :: 3.9",
24
- "Programming Language :: Python :: 3.10",
25
- "Programming Language :: Python :: 3.11",
26
- "Programming Language :: Python :: 3.12",
27
- "Topic :: Office/Business :: Financial",
28
- ]
29
- dependencies = [
30
- "requests>=2.25.0",
31
- "pandas>=1.3.0",
32
- "httpx>=0.24.0",
33
- "duckdb>=0.8.0",
34
- # 0.1.1 修复:pyarrow 是 pd.read_parquet 的硬依赖(client.py:482, async_client.py:413),
35
- # 但 0.1.0 漏声明,导致 pip install 后首次 K线/Tick 查询会抛 ImportError。
36
- # 锁定到 >=10.0.0 以获得 Python 3.10+ 完整支持(pyarrow 14+ 更好)。
37
- "pyarrow>=10.0.0",
38
- ]
39
-
40
- # 0.1.2 新增:装包后提供 `quantdb` shell 命令,等价于 `python -m quantdb_sdk`。
41
- # 0.1.0/0.1.1 README 写的是 `python -m quantdb`(用了 PyPI 名带连字符),
42
- # 但 Python 模块名是下划线,安装后 `python -m quantdb` 会报 No module named quantdb。
43
- # 加这个 entry point 后两个名字都能用,README 不需要再改。
44
- [project.scripts]
45
- quantdb = "quantdb_sdk.__main__:main"
46
-
47
- [project.optional-dependencies]
48
- dev = [
49
- "pytest>=7.0.0",
50
- "pytest-asyncio>=0.21.0",
51
- "responses>=0.23.0",
52
- "respx>=0.20.0",
53
- ]
54
-
55
- [project.urls]
56
- Homepage = "https://quantdb.quantmind.cloud"
57
- Documentation = "https://quantdb.quantmind.cloud/docs/sdk.html"
58
- Repository = "https://github.com/quantdb/quantdb"
59
- Changelog = "https://github.com/quantdb/quantdb/blob/main/CHANGELOG.md"
60
-
61
- [tool.setuptools.packages.find]
62
- where = ["."]
63
- include = ["quantdb_sdk*"]
64
-
65
- # 0.1.2 新增:让 wheel 包含 LICENSE 和 CHANGELOG.md
66
- [tool.setuptools.package-data]
67
- quantdb_sdk = ["py.typed"]
1
+ [build-system]
2
+ requires = ["setuptools>=61.0", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "quantdb-sdk"
7
+ version = "0.4.1"
8
+ description = "QuantDB 量化数据平台官方 Python SDK"
9
+ readme = "README.md"
10
+ license = {text = "MIT"}
11
+ requires-python = ">=3.8"
12
+ authors = [
13
+ {name = "QuantDB Team"},
14
+ ]
15
+ keywords = ["quant", "finance", "data", "a-share", "parquet"]
16
+ classifiers = [
17
+ "Development Status :: 3 - Alpha",
18
+ "Intended Audience :: Developers",
19
+ "Intended Audience :: Financial and Insurance Industry",
20
+ "License :: OSI Approved :: MIT License",
21
+ "Programming Language :: Python :: 3",
22
+ "Programming Language :: Python :: 3.8",
23
+ "Programming Language :: Python :: 3.9",
24
+ "Programming Language :: Python :: 3.10",
25
+ "Programming Language :: Python :: 3.11",
26
+ "Programming Language :: Python :: 3.12",
27
+ "Topic :: Office/Business :: Financial",
28
+ ]
29
+ dependencies = [
30
+ "requests>=2.25.0",
31
+ "pandas>=1.3.0",
32
+ "httpx>=0.24.0",
33
+ # 0.4.1 起 client.data.read_local 用 read_parquet(filename=true) + `* EXCLUDE (filename)`
34
+ # 做精确分区读取;0.8.x 在部分环境(Windows/Python 3.10)导入即崩溃,1.0.0~1.5.5 已验证。
35
+ "duckdb>=1.0.0",
36
+ # 0.1.1 修复:pyarrow 是 pd.read_parquet 的硬依赖(client.py:482, async_client.py:413),
37
+ # 但 0.1.0 漏声明,导致 pip install 后首次 K线/Tick 查询会抛 ImportError。
38
+ # 锁定到 >=10.0.0 以获得 Python 3.10+ 完整支持(pyarrow 14+ 更好)。
39
+ "pyarrow>=10.0.0",
40
+ ]
41
+
42
+ # 0.1.2 新增:装包后提供 `quantdb` shell 命令,等价于 `python -m quantdb_sdk`。
43
+ # 0.1.0/0.1.1 README 写的是 `python -m quantdb`(用了 PyPI 名带连字符),
44
+ # 但 Python 模块名是下划线,安装后 `python -m quantdb` 会报 No module named quantdb。
45
+ # 加这个 entry point 后两个名字都能用,README 不需要再改。
46
+ [project.scripts]
47
+ quantdb = "quantdb_sdk.__main__:main"
48
+
49
+ [project.optional-dependencies]
50
+ dev = [
51
+ "pytest>=7.0.0",
52
+ "pytest-asyncio>=0.21.0",
53
+ "responses>=0.23.0",
54
+ "respx>=0.20.0",
55
+ ]
56
+
57
+ [project.urls]
58
+ Homepage = "https://quantdb.quantmind.cloud"
59
+ Documentation = "https://quantdb.quantmind.cloud/docs/sdk.html"
60
+ Repository = "https://github.com/quantdb/quantdb"
61
+ Changelog = "https://github.com/quantdb/quantdb/blob/main/CHANGELOG.md"
62
+
63
+ [tool.setuptools.packages.find]
64
+ where = ["."]
65
+ include = ["quantdb_sdk*"]
66
+
67
+ # 0.1.2 新增:让 wheel 包含 LICENSE 和 CHANGELOG.md
68
+ [tool.setuptools.package-data]
69
+ quantdb_sdk = ["py.typed"]
@@ -5,12 +5,13 @@ try:
5
5
  # 注意:此处用 PyPI 包名(连字符)查找版本号,不是模块名(下划线)
6
6
  __version__ = version("quantdb-sdk")
7
7
  except ImportError:
8
- __version__ = "0.3.4"
8
+ __version__ = "0.4.1"
9
9
 
10
10
  from . import layout
11
11
  from ._utils import scan_local_directory
12
12
  from .async_client import AsyncQuantDBClient
13
13
  from .client import DuckDBWarehouse, QuantDBClient
14
+ from .hub import DATASET_REGISTRY, AsyncDataHub, DataHub
14
15
  from .errors import (
15
16
  AuthError,
16
17
  InsufficientTrafficError,
@@ -33,6 +34,10 @@ __all__ = [
33
34
  "QuantDBClient",
34
35
  "AsyncQuantDBClient",
35
36
  "DuckDBWarehouse",
37
+ # 统一数据入口(quantdb_sdk.hub)
38
+ "DataHub",
39
+ "AsyncDataHub",
40
+ "DATASET_REGISTRY",
36
41
  "QuantDBError",
37
42
  "AuthError",
38
43
  "InsufficientTrafficError",
@@ -4,6 +4,8 @@
4
4
  python -m quantdb --version
5
5
  python -m quantdb --help
6
6
  python -m quantdb layout # 查看本地数据目录规范
7
+ python -m quantdb datasets # 列出全部数据集目录(无需 API Key)
8
+ python -m quantdb datasets l1_factors # 查看某个数据集详情
7
9
  QUANTDB_API_KEY=qdb_xxx quantdb check # 验证 API Key 是否有效
8
10
 
9
11
  演示脚本见 quantdb_sdk.examples(demo_01 ~ demo_06),
@@ -13,6 +15,7 @@
13
15
  import argparse
14
16
  import os
15
17
  import sys
18
+ from typing import Optional
16
19
 
17
20
  from . import __version__, layout
18
21
  from .client import QuantDBClient
@@ -38,6 +41,27 @@ def cmd_layout() -> int:
38
41
  return 0
39
42
 
40
43
 
44
+ def cmd_datasets(name: Optional[str] = None) -> int:
45
+ """列出全部数据集目录,或查看某个数据集详情(无需 API Key)。"""
46
+ from .hub import DATASET_REGISTRY
47
+
48
+ if name:
49
+ info = DATASET_REGISTRY.get(name)
50
+ if info is None:
51
+ print(f"[ERROR] 未知数据集: {name}", file=sys.stderr)
52
+ return 1
53
+ print(f"{info.dataset} {info.name} ({info.category_id} {info.category_dir})")
54
+ print(f" 描述: {info.description}")
55
+ print(f" 访问: {info.access} 布局: {info.layout} 选择器: {', '.join(info.selectors) or '-'}")
56
+ print(f" 关键词: {', '.join(info.keywords)}")
57
+ return 0
58
+
59
+ print(f"共 {len(DATASET_REGISTRY)} 个数据集:")
60
+ for info in DATASET_REGISTRY.values():
61
+ print(f" [{info.category_id}] {info.dataset:<20s} {info.name:<16s} {info.access:<12s} {info.layout}")
62
+ return 0
63
+
64
+
41
65
  def main() -> int:
42
66
  parser = argparse.ArgumentParser(
43
67
  prog="quantdb",
@@ -71,6 +95,11 @@ def main() -> int:
71
95
  # layout 命令:打印目录规范
72
96
  layout_parser = subparsers.add_parser("layout", help="查看本地数据目录规范(无需 API Key)")
73
97
 
98
+ # datasets 命令:列出数据集目录(无需 API Key)
99
+ datasets_parser = subparsers.add_parser("datasets", help="列出全部数据集目录(无需 API Key)")
100
+ datasets_parser.add_argument("name", nargs="?", default=None,
101
+ help="可选:查看某个数据集详情,如 l1_factors")
102
+
74
103
  sync_parser = subparsers.add_parser("sync", help="以 release/Manifest 增量同步一个数据集")
75
104
  sync_parser.add_argument("dataset", help="数据集,如 daily_forward、balance、etf_pcf")
76
105
  sync_parser.add_argument("--save-dir", default=None,
@@ -83,9 +112,11 @@ def main() -> int:
83
112
  parser.print_help()
84
113
  return 0
85
114
 
86
- # layout 命令无需 API Key,直接打印目录规范
115
+ # layout / datasets 命令无需 API Key
87
116
  if args.command == "layout":
88
117
  return cmd_layout()
118
+ if args.command == "datasets":
119
+ return cmd_datasets(args.name)
89
120
 
90
121
  api_key = os.getenv(args.api_key_env)
91
122
  if not api_key:
@@ -28,7 +28,7 @@ from .errors import (
28
28
  )
29
29
 
30
30
  # 维护提示:每次发版必须与 pyproject.toml 版本号同步
31
- _USER_AGENT = "QuantDB-Python-SDK/0.3.5"
31
+ _USER_AGENT = "QuantDB-Python-SDK/0.4.1"
32
32
 
33
33
 
34
34
  def _etag_hex(value: Optional[str]) -> Optional[str]:
@@ -83,6 +83,9 @@ class AsyncQuantDBClient:
83
83
  # 进程内 parquet ETag 缓存:同对象(ETag 未变)不重复下载,避免重复计费。
84
84
  self._cache: Dict[str, Dict[str, Any]] = {}
85
85
 
86
+ # 统一数据入口(quantdb_sdk.hub.AsyncDataHub)惰性实例,见 data property。
87
+ self._data_hub: Optional[Any] = None
88
+
86
89
  async def close(self) -> None:
87
90
  """关闭底层 httpx 客户端。"""
88
91
  await self.client.aclose()
@@ -92,6 +95,19 @@ class AsyncQuantDBClient:
92
95
  """清空进程内 Parquet 缓存(强制下次重新下载最新数据)。"""
93
96
  self._cache.clear()
94
97
 
98
+ @property
99
+ def data(self) -> "AsyncDataHub":
100
+ """统一数据入口(异步):只凭 dataset 名跨 6 大分类目录取数。
101
+
102
+ 返回 :class:`quantdb_sdk.hub.AsyncDataHub`,惰性创建,方法名统一 ``a_`` 前缀。
103
+ 不含挂载方法(异步端无 ``a_mount_local_dataset``);如需 DuckDB 挂载视图,
104
+ 请改用同步客户端 ``client.data.mount(...)``。
105
+ """
106
+ if self._data_hub is None:
107
+ from .hub import AsyncDataHub # 函数内 import,避免与 hub 循环依赖
108
+ self._data_hub = AsyncDataHub(self)
109
+ return self._data_hub
110
+
95
111
  @asynccontextmanager
96
112
  async def _download_stream(self, params: Dict[str, Any], headers: Optional[Dict[str, str]] = None):
97
113
  """下载专用流式请求:手动处理服务端 302 CDN 直连跳转。
@@ -32,7 +32,7 @@ from .errors import (
32
32
  )
33
33
 
34
34
  # 维护提示:每次发版必须与 pyproject.toml 版本号同步
35
- _USER_AGENT = "QuantDB-Python-SDK/0.3.5"
35
+ _USER_AGENT = "QuantDB-Python-SDK/0.4.1"
36
36
 
37
37
 
38
38
  def _etag_hex(value: Optional[str]) -> Optional[str]:
@@ -92,6 +92,9 @@ class QuantDBClient:
92
92
  # 只需下载一次。进程退出即失效(无跨进程副作用)。
93
93
  self._cache: Dict[str, Dict[str, Any]] = {}
94
94
 
95
+ # 统一数据入口(quantdb_sdk.hub.DataHub)惰性实例,见 data property。
96
+ self._data_hub: Optional[Any] = None
97
+
95
98
  retries = Retry(
96
99
  total=max_retries,
97
100
  backoff_factor=0.5,
@@ -263,6 +266,20 @@ class QuantDBClient:
263
266
  """
264
267
  self._cache.clear()
265
268
 
269
+ @property
270
+ def data(self) -> "DataHub":
271
+ """统一数据入口:只凭 dataset 名跨 6 大分类目录取数。
272
+
273
+ 返回 :class:`quantdb_sdk.hub.DataHub`,惰性创建。支持发现(``datasets`` /
274
+ ``info``)、本地零流量读取(``local_files`` / ``local_path`` / ``read_local`` /
275
+ ``read``)、在线查询(``preview`` / ``load`` / ``download`` / ``query``)与
276
+ 同步挂载(``sync`` / ``mount``)。
277
+ """
278
+ if self._data_hub is None:
279
+ from .hub import DataHub # 函数内 import,避免与 hub 循环依赖
280
+ self._data_hub = DataHub(self)
281
+ return self._data_hub
282
+
266
283
  @staticmethod
267
284
  def _validate_layout(layout: str) -> Literal["auto", "v1", "v2"]:
268
285
  if layout not in {"auto", "v1", "v2"}:
@@ -0,0 +1,66 @@
1
+ """demo_07 统一数据入口 client.data(DataHub)。
2
+
3
+ 只凭 dataset 名跨 6 大分类目录取数,不必手填 category_id + sub_category:
4
+ 1. datasets() — 列出 29 个数据集目录(零流量)
5
+ 2. info() — 覆盖区间 + 文件大小
6
+ 3. read_local() — 本地零流量读取(root 可配,缺省读 QUANTDB_DATA_DIR)
7
+ 4. preview() — 在线预览(不消耗下载流量)
8
+ 5. query() — 在线查询(消耗下载流量)
9
+
10
+ 运行::
11
+
12
+ QUANTDB_API_KEY=qdb_xxx python -m quantdb_sdk.examples.demo_07_data_hub
13
+ QUANTDB_API_KEY=qdb_xxx python -m quantdb_sdk.examples.demo_07_data_hub --dataset l1_factors
14
+ """
15
+
16
+ import argparse
17
+ import os
18
+
19
+ from quantdb_sdk import QuantDBClient
20
+ from quantdb_sdk.errors import NotFoundError, QuantDBError
21
+
22
+
23
+ def main() -> None:
24
+ p = argparse.ArgumentParser(description=__doc__)
25
+ p.add_argument("--api-host", default="https://www.quantdb.cn")
26
+ p.add_argument("--api-key", default=None, help="默认读环境变量 QUANTDB_API_KEY")
27
+ p.add_argument("--root", default=None, help="本地数据根目录(默认读 QUANTDB_DATA_DIR / 回退默认下载目录)")
28
+ p.add_argument("--symbol", default="600519.SH")
29
+ p.add_argument("--dataset", default="daily_forward")
30
+ args = p.parse_args()
31
+
32
+ api_key = args.api_key or os.getenv("QUANTDB_API_KEY")
33
+ if not api_key:
34
+ raise SystemExit("请设置 QUANTDB_API_KEY 或传 --api-key")
35
+
36
+ client = QuantDBClient(api_host=args.api_host, api_key=api_key)
37
+ hub = client.data
38
+
39
+ # 1. 数据集目录(零流量)
40
+ print("== 数据集目录(前 8 个)==")
41
+ print(hub.datasets().head(8).to_string(index=False))
42
+
43
+ # 2. 元数据(覆盖区间 + 文件大小)
44
+ info = hub.info(args.dataset)
45
+ print(f"\n== {args.dataset} 元数据 ==")
46
+ print(f" {info['name']} 分类={info['category_dir']} 区间={info['min_date']}~{info['max_date']}")
47
+ print(f" 文件数={info['file_count']} 大小={info['file_size_gb']} GB")
48
+
49
+ # 3. 本地零流量读取(root 可配)
50
+ print(f"\n== 本地读取 {args.dataset} ==")
51
+ try:
52
+ local = hub.read_local(args.dataset, symbol=args.symbol, root=args.root, latest=True)
53
+ print(local.head(3).to_string(index=False))
54
+ except NotFoundError:
55
+ print(f" 本地未找到 {args.dataset};可先 client.data.sync('{args.dataset}') 同步")
56
+
57
+ # 4. 在线预览(不消耗下载流量)
58
+ try:
59
+ print(f"\n== 在线预览 {args.dataset} ==")
60
+ print(hub.preview(args.dataset, symbol=args.symbol, limit=3).to_string(index=False))
61
+ except QuantDBError as e:
62
+ print(f" 预览失败: {e}")
63
+
64
+
65
+ if __name__ == "__main__":
66
+ main()