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.
- {quantdb_sdk-0.3.5 → quantdb_sdk-0.4.1}/CHANGELOG.md +31 -0
- {quantdb_sdk-0.3.5/quantdb_sdk.egg-info → quantdb_sdk-0.4.1}/PKG-INFO +2 -2
- {quantdb_sdk-0.3.5 → quantdb_sdk-0.4.1}/pyproject.toml +69 -67
- {quantdb_sdk-0.3.5 → quantdb_sdk-0.4.1}/quantdb_sdk/__init__.py +6 -1
- {quantdb_sdk-0.3.5 → quantdb_sdk-0.4.1}/quantdb_sdk/__main__.py +32 -1
- {quantdb_sdk-0.3.5 → quantdb_sdk-0.4.1}/quantdb_sdk/async_client.py +17 -1
- {quantdb_sdk-0.3.5 → quantdb_sdk-0.4.1}/quantdb_sdk/client.py +18 -1
- quantdb_sdk-0.4.1/quantdb_sdk/examples/demo_07_data_hub.py +66 -0
- quantdb_sdk-0.4.1/quantdb_sdk/hub.py +1052 -0
- {quantdb_sdk-0.3.5 → quantdb_sdk-0.4.1/quantdb_sdk.egg-info}/PKG-INFO +2 -2
- {quantdb_sdk-0.3.5 → quantdb_sdk-0.4.1}/quantdb_sdk.egg-info/SOURCES.txt +3 -0
- {quantdb_sdk-0.3.5 → quantdb_sdk-0.4.1}/quantdb_sdk.egg-info/requires.txt +1 -1
- {quantdb_sdk-0.3.5 → quantdb_sdk-0.4.1}/tests/test_async_client.py +22 -3
- {quantdb_sdk-0.3.5 → quantdb_sdk-0.4.1}/tests/test_client.py +23 -8
- quantdb_sdk-0.4.1/tests/test_data_hub.py +343 -0
- {quantdb_sdk-0.3.5 → quantdb_sdk-0.4.1}/tests/test_update_pipeline.py +4 -2
- {quantdb_sdk-0.3.5 → quantdb_sdk-0.4.1}/LICENSE +0 -0
- {quantdb_sdk-0.3.5 → quantdb_sdk-0.4.1}/MANIFEST.in +0 -0
- {quantdb_sdk-0.3.5 → quantdb_sdk-0.4.1}/README.md +0 -0
- {quantdb_sdk-0.3.5 → quantdb_sdk-0.4.1}/quantdb_sdk/_utils.py +0 -0
- {quantdb_sdk-0.3.5 → quantdb_sdk-0.4.1}/quantdb_sdk/errors.py +0 -0
- {quantdb_sdk-0.3.5 → quantdb_sdk-0.4.1}/quantdb_sdk/examples/__init__.py +0 -0
- {quantdb_sdk-0.3.5 → quantdb_sdk-0.4.1}/quantdb_sdk/examples/demo_01_connect_basics.py +0 -0
- {quantdb_sdk-0.3.5 → quantdb_sdk-0.4.1}/quantdb_sdk/examples/demo_02_kline_v2_daily.py +0 -0
- {quantdb_sdk-0.3.5 → quantdb_sdk-0.4.1}/quantdb_sdk/examples/demo_03_sync_full_market.py +0 -0
- {quantdb_sdk-0.3.5 → quantdb_sdk-0.4.1}/quantdb_sdk/examples/demo_04_duckdb_warehouse.py +0 -0
- {quantdb_sdk-0.3.5 → quantdb_sdk-0.4.1}/quantdb_sdk/examples/demo_05_read_local_data.py +0 -0
- {quantdb_sdk-0.3.5 → quantdb_sdk-0.4.1}/quantdb_sdk/examples/demo_06_tick_and_factors.py +0 -0
- {quantdb_sdk-0.3.5 → quantdb_sdk-0.4.1}/quantdb_sdk/layout.py +0 -0
- {quantdb_sdk-0.3.5 → quantdb_sdk-0.4.1}/quantdb_sdk/py.typed +0 -0
- {quantdb_sdk-0.3.5 → quantdb_sdk-0.4.1}/quantdb_sdk.egg-info/dependency_links.txt +0 -0
- {quantdb_sdk-0.3.5 → quantdb_sdk-0.4.1}/quantdb_sdk.egg-info/entry_points.txt +0 -0
- {quantdb_sdk-0.3.5 → quantdb_sdk-0.4.1}/quantdb_sdk.egg-info/top_level.txt +0 -0
- {quantdb_sdk-0.3.5 → quantdb_sdk-0.4.1}/setup.cfg +0 -0
- {quantdb_sdk-0.3.5 → quantdb_sdk-0.4.1}/tests/test_hub_models.py +0 -0
- {quantdb_sdk-0.3.5 → quantdb_sdk-0.4.1}/tests/test_layout.py +0 -0
- {quantdb_sdk-0.3.5 → quantdb_sdk-0.4.1}/tests/test_technical_indicators.py +0 -0
- {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
|
+
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.
|
|
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.
|
|
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
|
-
|
|
34
|
-
# 0.
|
|
35
|
-
|
|
36
|
-
#
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
#
|
|
43
|
-
#
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
"
|
|
52
|
-
"
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
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.
|
|
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.
|
|
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.
|
|
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()
|