quantdb-sdk 0.4.4__tar.gz → 0.4.6__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 (40) hide show
  1. {quantdb_sdk-0.4.4 → quantdb_sdk-0.4.6}/CHANGELOG.md +360 -337
  2. {quantdb_sdk-0.4.4/quantdb_sdk.egg-info → quantdb_sdk-0.4.6}/PKG-INFO +1 -1
  3. {quantdb_sdk-0.4.4 → quantdb_sdk-0.4.6}/pyproject.toml +69 -69
  4. {quantdb_sdk-0.4.4 → quantdb_sdk-0.4.6}/quantdb_sdk/__init__.py +1 -1
  5. {quantdb_sdk-0.4.4 → quantdb_sdk-0.4.6}/quantdb_sdk/__main__.py +190 -166
  6. {quantdb_sdk-0.4.4 → quantdb_sdk-0.4.6}/quantdb_sdk/_utils.py +289 -286
  7. {quantdb_sdk-0.4.4 → quantdb_sdk-0.4.6}/quantdb_sdk/async_client.py +1032 -1001
  8. {quantdb_sdk-0.4.4 → quantdb_sdk-0.4.6}/quantdb_sdk/client.py +60 -26
  9. {quantdb_sdk-0.4.4 → quantdb_sdk-0.4.6}/quantdb_sdk/examples/demo_07_data_hub.py +66 -66
  10. {quantdb_sdk-0.4.4 → quantdb_sdk-0.4.6}/quantdb_sdk/hub.py +1054 -1054
  11. quantdb_sdk-0.4.6/quantdb_sdk/mcp_download.py +111 -0
  12. {quantdb_sdk-0.4.4 → quantdb_sdk-0.4.6/quantdb_sdk.egg-info}/PKG-INFO +1 -1
  13. {quantdb_sdk-0.4.4 → quantdb_sdk-0.4.6}/quantdb_sdk.egg-info/SOURCES.txt +2 -0
  14. {quantdb_sdk-0.4.4 → quantdb_sdk-0.4.6}/tests/test_async_client.py +218 -216
  15. {quantdb_sdk-0.4.4 → quantdb_sdk-0.4.6}/tests/test_client.py +312 -310
  16. {quantdb_sdk-0.4.4 → quantdb_sdk-0.4.6}/tests/test_data_hub.py +351 -351
  17. quantdb_sdk-0.4.6/tests/test_mcp_download.py +134 -0
  18. {quantdb_sdk-0.4.4 → quantdb_sdk-0.4.6}/tests/test_technical_indicators.py +237 -237
  19. {quantdb_sdk-0.4.4 → quantdb_sdk-0.4.6}/tests/test_update_pipeline.py +44 -44
  20. {quantdb_sdk-0.4.4 → quantdb_sdk-0.4.6}/LICENSE +0 -0
  21. {quantdb_sdk-0.4.4 → quantdb_sdk-0.4.6}/MANIFEST.in +0 -0
  22. {quantdb_sdk-0.4.4 → quantdb_sdk-0.4.6}/README.md +0 -0
  23. {quantdb_sdk-0.4.4 → quantdb_sdk-0.4.6}/quantdb_sdk/errors.py +0 -0
  24. {quantdb_sdk-0.4.4 → quantdb_sdk-0.4.6}/quantdb_sdk/examples/__init__.py +0 -0
  25. {quantdb_sdk-0.4.4 → quantdb_sdk-0.4.6}/quantdb_sdk/examples/demo_01_connect_basics.py +0 -0
  26. {quantdb_sdk-0.4.4 → quantdb_sdk-0.4.6}/quantdb_sdk/examples/demo_02_kline_v2_daily.py +0 -0
  27. {quantdb_sdk-0.4.4 → quantdb_sdk-0.4.6}/quantdb_sdk/examples/demo_03_sync_full_market.py +0 -0
  28. {quantdb_sdk-0.4.4 → quantdb_sdk-0.4.6}/quantdb_sdk/examples/demo_04_duckdb_warehouse.py +0 -0
  29. {quantdb_sdk-0.4.4 → quantdb_sdk-0.4.6}/quantdb_sdk/examples/demo_05_read_local_data.py +0 -0
  30. {quantdb_sdk-0.4.4 → quantdb_sdk-0.4.6}/quantdb_sdk/examples/demo_06_tick_and_factors.py +0 -0
  31. {quantdb_sdk-0.4.4 → quantdb_sdk-0.4.6}/quantdb_sdk/layout.py +0 -0
  32. {quantdb_sdk-0.4.4 → quantdb_sdk-0.4.6}/quantdb_sdk/py.typed +0 -0
  33. {quantdb_sdk-0.4.4 → quantdb_sdk-0.4.6}/quantdb_sdk.egg-info/dependency_links.txt +0 -0
  34. {quantdb_sdk-0.4.4 → quantdb_sdk-0.4.6}/quantdb_sdk.egg-info/entry_points.txt +0 -0
  35. {quantdb_sdk-0.4.4 → quantdb_sdk-0.4.6}/quantdb_sdk.egg-info/requires.txt +0 -0
  36. {quantdb_sdk-0.4.4 → quantdb_sdk-0.4.6}/quantdb_sdk.egg-info/top_level.txt +0 -0
  37. {quantdb_sdk-0.4.4 → quantdb_sdk-0.4.6}/setup.cfg +0 -0
  38. {quantdb_sdk-0.4.4 → quantdb_sdk-0.4.6}/tests/test_hub_models.py +0 -0
  39. {quantdb_sdk-0.4.4 → quantdb_sdk-0.4.6}/tests/test_layout.py +0 -0
  40. {quantdb_sdk-0.4.4 → quantdb_sdk-0.4.6}/tests/test_utils.py +0 -0
@@ -1,340 +1,363 @@
1
- # Changelog
2
-
3
- 所有 notable 变更都会记录在此文件。格式基于 [Keep a Changelog](https://keepachangelog.com/zh-CN/1.1.0/),
4
- 版本号遵循 [Semantic Versioning](https://semver.org/lang/zh-CN/)。
5
-
6
- ## \[0.4.4] - 2026-10-11
7
-
8
- ### Fixed
9
-
10
- - **`get_usage()` / `a_get_usage()` 漏算流量包额度**:旧实现用 `remaining = traffic_limit + credit_limit + purchased_traffic - used_traffic`,**完全没算流量包**,导致持有流量包的用户剩余流量被低估(少报的量正好等于流量包余额),`is_active` 也会在仍有流量包可用时被误判为 `False`。
11
-
12
- 修正后的口径与后端下载预扣一致:可用总额度 = 套餐额度(`traffic_limit + credit_limit + purchased_traffic`)+ 流量包总额;可用剩余 = (套餐额度 − 已用) + 流量包剩余。因用量接口返回的 `package_traffic` 是流量包**剩余量**,总额从 `GET /api/v1/subscription/traffic-packages` 台账累加;台账接口不可用时退化为「总额 = 剩余」,保证 `get_usage()` 在旧版服务端上依然可用。
13
-
14
- ### Added
15
-
16
- - **`get_usage()` / `a_get_usage()` 新增额度明细字段**(原有字段全部保留,取值已修正):
17
- - 合计:`total_gb` / `used_gb` / `remaining_gb`
18
- - 套餐额度:`plan_total_gb` / `plan_used_gb` / `plan_remaining_gb`
19
- - 流量包额度:`package_total_gb` / `package_used_gb` / `package_remaining_gb`
20
- - **`quantdb usage` CLI** 改为分行展示套餐 / 流量包 / 合计的已用、总额与剩余,不再只显示一个总额。
21
-
22
- ## \[0.4.3] - 2026-10-05
23
-
24
- ### Changed
25
-
26
- - **`per_share` 数据集更名**:中文名由「每股指标(补充)」改为「**财务指标(TTM)**」,描述与关键词同步更新(`每股/eps` → `财务/ttm`)。
27
-
28
- 该表实际为 **TTM 口径财务指标补充表**(营收 / 归母净利 / 扣非净利 / 经营现金流等),原名既与 `pershare_index`「每股指标」混淆,也不符合数据口径。与后端 MCP catalog、桌面端分类表保持一致;`per_share` 标识符不变,`client.data` 用法不受影响。
29
-
30
- ## \[0.4.2] - 2026-10-05
31
-
32
- ### Added
33
-
34
- - **新增数据集 `per_share`(每股指标补充表,分类 3)**:补登记为第 30 个数据集。
35
-
36
- - `SYNC_DATASET_CATEGORIES` 与 `DATASET_REGISTRY` 由 29 项增至 30 项;`client.data.datasets()` / `info()` / `local_files()` / `read_local()` / `sync_dataset()` / `mount()` 均可直接按 `per_share` 使用。
37
- - 物理形态为 V1 逐股票文件 `3_financial_data/per_share/{Symbol}.parquet`(由 `03_financial.py` 采集,部分股票为空);`layout=v1_symbol`,读取/查询需提供 `symbol`。
38
- - 与 MCP catalog、后端 `subCategoryMapping`、前端分类表同步对齐(均为 30 项)。
39
-
40
- ## \[0.4.1] - 2026-10-05
41
-
42
- ### Changed
43
-
44
- - **本地零流量读取提速**(`client.data.read_local` / `read`):改用 DuckDB 对**精确分区文件列表**做一次 `read_parquet`,把 `symbol` / 日期区间 / 列裁剪全部下推到 SQL,替代原先逐文件 `pd.read_parquet` 再 `concat`。实测(120 分区 × 1000 标的)单标的全历史 `0.62s → 0.22s`,带 `columns` 列裁剪 `→ 0.07s`。
45
-
46
- - V2 按日分区与 tick 分片的 `trade_date` 由分区目录名 / 文件名推导,**不依赖** hive 注入的 `dt` 列(该列仅在较新 DuckDB 存在)。
47
- - V1 逐股票表日期过滤用 `substr(replace(CAST(col AS VARCHAR),'-',''),1,8)` 归一化后下推,同时兼容整型报告期 `20251231` 与字符串 `2025-12-31` / 带时分秒。
48
-
49
- - **依赖下界调整**:`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 已验证通过。
50
-
51
- ### Fixed
52
-
53
- - `read_local(..., columns=[...])` 在 V2 / tick 上未把 `symbol` 过滤下推:当 `columns` 不含 `symbol` 时,旧实现会在读取后被静默跳过过滤、返回全市场行。现 `symbol` 始终在 SQL 中下推。
54
-
55
- ## \[0.4.0] - 2026-10-05
56
-
57
- ### Added
58
-
59
- - **统一数据入口** **`client.data`**(同步 `DataHub` / 异步 `AsyncDataHub`,模块 `quantdb_sdk.hub`):只凭 **dataset 名**即可跨 6 大分类目录取数,不必再手填 `category_id + sub_category`。SDK 侧解析分类后复用现有端点,**零后端改动**。
60
-
61
- - **发现**:`datasets(category, access, keyword)` 列出 29 个数据集目录;`info(dataset)` 返回注册表字段并叠加云端元数据(覆盖区间 / 文件数 / 文件大小)。
62
- - **本地零流量**:`local_files` / `local_path` / `read_local` / `read`(本地优先,缺失时显式回退在线)。数据根目录可配置(`root` 参数,缺省读 `QUANTDB_DATA_DIR`);多形态 glob 兼容 V2 `dt=` 分区、tick 平铺/子目录分片、V1 逐股票文件;V2/tick 无日期列时从路径注入 `trade_date`。
63
- - **在线**:`preview` / `load` / `download` / `query` / `sync` / `mount`,逐项委托既有方法。`query` 按数据集自动路由:日线三兄弟走 `query_kline`、ETF 走 `query_etf_kline`、tick 走 `query_tick` 并按 symbol 后置过滤、其余 V2 走通用日分区分支、V1 逐股票走 `layout="v1"` + 日期列过滤。
64
- - 异步方法统一 `a_` 前缀;异步端不含 `mount`(无 `a_mount_local_dataset`,DuckDB 仓库为同步)。
65
- - 新增 `DATASET_REGISTRY` 注册表(29 项),`category_id` 复用 `SYNC_DATASET_CATEGORIES`,`category_dir` 复用 `CATEGORY_DIRS`,避免重复维护分类事实源。
66
-
67
- - **命令行** **`quantdb datasets [name]`**:列出全部数据集目录或查看某个数据集详情(无需 API Key)。
68
-
69
- - 新增演示脚本 `quantdb_sdk/examples/demo_07_data_hub.py`。
70
-
71
- ## \[0.3.5] - 2026-09-26
72
-
73
- ### Added
74
-
75
- - **分区大小查询** **`query_partition_size`** **/** **`a_query_partition_size`**:查询各子分类的分区总大小(`file_count` 分区数 + `file_size` 总字节 + 换算列 `file_size_gb`),用于估算下载流量与数据占用。缺省返回全部子分类,可传 `sub_category`(如 `daily_forward`)单查。
76
-
77
- - **`query_meta`** **/** **`a_query_meta`** 新增 `sub_category` 过滤参数:后端 `data_meta` 现含 `file_size`(分区总字节,由发布管线从 COS 元数据重建),可按子分类精准取各数据集日期范围/行数/文件数/文件大小。
78
-
79
- ## \[0.3.4] - 2026-09-04
80
-
81
- ### Added
82
-
83
- - **ETF 日 K 线查询** **`query_etf_kline`** **/** **`a_query_etf_kline`**:新增便捷方法查询分类 4 的 `etf_kline`(V2 全市场按日分区,symbol 形如 510300.SH),`auto` 优先 V2、日期范围覆盖不完整时回退 V1。
84
-
85
- - **`sync_dataset("etf_kline")`** **支持**:`SYNC_DATASET_CATEGORIES` 注册 `etf_kline` → 分类 4,此前会报「不支持同步的数据集」。
86
-
87
- ## \[0.3.3] - 2026-08-29
88
-
89
- ### Added
90
-
91
- - **本地完整性扫描** **`scan_local_directory`**,并作为 `QuantDBClient.scan_local()` / `AsyncQuantDBClient.a_scan_local()` 方法公开:扫描本地数据目录,流式计算每个文件的 MD5 与 COS 形态 ETag。只做本地 IO、不发起网络请求、不消耗流量,用于对落地数据做独立的完整性指纹扫描(发布前/对账/排障前置核对)。
92
-
93
- - 支持递归/非递归、按后缀过滤(默认 `.parquet`)、可选进度回调。
94
-
95
- - 返回含汇总 `file_count` / `total_bytes` 与逐文件 `{relative_path, path, size, md5, etag}` 的清单;读取失败的文件登记到 `errors` 不中断扫描。
96
-
97
- ## \[0.3.2] - 2026-08-27
98
-
99
- ### Changed
100
-
101
- - **同步/异步客户端** **`sync_dataset`** **服务端 304 权威对账**:当本地文件已在磁盘(含 sqlite 记录缺失或指纹对不上场景)时,先发 `If-None-Match=<本地文件 MD5>` 给 `/download`,命中 304(网关在预扣/COS 直连前短路,免流量)则只登记跳过,避免"本地明明有文件但记录/指纹对不上"时的整块重下。修复此前 V2 release 对象缺 `etag` 字段导致 `local_file_matches` 恒 `False`、本地清空 sqlite 后全量重下的问题。
102
-
103
- - **判重主键从 etag 改为** **`sha256`**:V2 release 对象无 etag 字段,原判重实际退化为仅靠弱指纹;现统一以内容 sha256 判重,正常增量仍按 sha 命中跳过。
104
-
105
- - 下载成功后落库记录**真实 COS ETag**,供后续对账/304 复用。
106
-
107
- ## \[0.3.1] - 2026-08-15
108
-
109
- ### Added
110
-
111
- - **CLI 目录规范命令**:`quantdb layout` 打印本地数据目录规范(顶层分类目录、各数据集 V1/V2/tick 布局、路径示例),无需 API Key。
112
-
113
- - **CLI 帮助增强**:`quantdb --help` 补充演示脚本提示;`quantdb sync` 帮助说明数据根目录来源(`QUANTDB_DATA_DIR` → 默认下载目录),并打印 `matched`(本地对账跳过数)。
114
-
115
- ## \[0.3.0] - 2026-08-15
116
-
117
- ### Added
118
-
119
- - **目录规范模块** **`quantdb_sdk.layout`**:新增本地数据目录规范,与采集根目录 `D:\quant_data` 保持一致。
120
-
121
- - `CATEGORY_DIRS`:6 个顶层分类目录(1\_kline\_data / 2\_base\_sector / 3\_financial\_data / 4\_bond\_etf / 5\_technical\_derived / 6\_ml\_datasets)。
122
-
123
- - `dataset_dir(dataset)` / `category_id(dataset)` / `dataset_layout(dataset)`:数据集 → 相对目录 / 分类 ID / 物理布局(`v2_daily_partition | v1_symbol | tick_shard`)。
124
-
125
- - `local_relative_path(dataset, symbol=None, trade_date=None, layout=None)`:生成 V1(`{Symbol}.parquet`)、V2(`dt=YYYYMMDD/data.parquet`)、tick(`{SYM}_{YYYYMMDD}.parquet`)的相对路径。
126
-
127
- - `data_root()`:新增 `QUANTDB_DATA_DIR` 环境变量指定本地数据根目录,未设置时回退 SDK 默认下载目录。
128
-
129
- - **演示脚本包** **`quantdb_sdk.examples`**(随 wheel 发布,6 个):
130
-
131
- - `demo_01_connect_basics` 连接 / 用量 / 订阅 / 股票列表 / 日历(零流量接口)
132
-
133
- - `demo_02_kline_v2_daily` 按 V2 日分区查询 K 线(单日全市场切片 + 单股日期范围)
134
-
135
- - `demo_03_sync_full_market` 全市场增量同步,落地到规范目录
136
-
137
- - `demo_04_duckdb_warehouse` DuckDB 本地 SQL JOIN(V2 日分区)
138
-
139
- - `demo_05_read_local_data` 按目录规范定位并读取本地已同步数据
140
-
141
- - `demo_06_tick_and_factors` Tick 按日下载 + L1 因子 V2 分区装载
142
-
143
- - 公开导出:`quantdb_sdk.layout` 模块及 `CATEGORY_DIRS` / `V2_DAILY_PARTITION` / `data_root` / `dataset_dir` / `dataset_layout` / `local_relative_path`。
144
-
145
- ### Changed
146
-
147
- - `DuckDBWarehouse.mount_local_dataset` 的目录映射字典重构为复用 `layout.dataset_dir`,消除与目录规范的重复定义,行为不变。
148
-
149
- - **同步对账(reconciliation)**:`sync_dataset()` / `a_sync_dataset()` 新增本地磁盘对账——目标文件已存在、大小一致且本地 MD5 == COS ETag 时,直接登记进状态并跳过下载(V2 与 V1 Manifest 两条路径均生效)。数据根目录可任意调整(`QUANTDB_DATA_DIR` / `--root` / `save_dir`),指向已含相同数据的目录时无需全量重下,与 Electron 本地对账语义一致。返回结果新增 `matched` 字段(已对账跳过对象数)。
150
-
151
- - 目录规范模块说明不再包含任何绝对路径,`D:\quant_data` 仅作为组织方式参考;本地根目录始终可配置。
152
-
153
- ## \[0.2.10] - 2026-08-03
154
-
155
- ### Fixed
156
-
157
- - **对象 SHA-256 校验在旧 manifest 过期时卡死整个 release**:追加式发布链中同一 `dt=` 分区可被多份历史 manifest 引用,重写分区后旧清单 sha256 过期。同步/异步客户端此前对过期条目硬校验失败即中止整份 release 且不提交 cursor,导致每次重下、永远卡死(`对象 SHA-256 校验失败`)。现在 sync 时以 cursor 序列中**最新一份** manifest 的指纹作为权威校验值,旧清单过期只重下该分区,不再阻塞。管线侧已配套加 manifest 回填 + 全量审计(`pipeline/sync_to_cos.py`、`pipeline/verify_cos_manifests.py`)。
158
-
159
- - **User-Agent 版本号与 pyproject 不同步**:0.2.9 发版时漏改,同步/异步客户端 `_USER_AGENT` 仍为 0.2.8,已对齐为 0.2.10。
160
-
161
- ## \[0.2.9] - 2026-07-30
162
-
163
- ### Fixed
164
-
165
- - **CDN 直连重试路径缺失导入**:0.2.8 引入的重试逻辑(指数退避)在同步/异步客户端分别使用 `time.sleep` / `asyncio.sleep`,但模块缺失 `import time` / `import asyncio`,触发重试时抛 `NameError` 导致下载中断,已补齐导入。
166
-
167
- ## \[0.2.8] - 2026-07-30
168
-
169
- ### Fixed
170
-
171
- - **CDN 直连下载 302 相对 URL 拼接**:服务端 CDN 直连模式(`QUANTDB_DOWNLOAD_REDIRECT`)的 Stage 1 302 返回相对 URL(`/api/v1/data/cdn-bridge?token=xxx`),同步/异步客户端此前直接将此相对路径作为请求 URL,导致 `requests`/`httpx` 无法解析(`MissingSchema`/`UnsupportedProtocol`),CDN 直连下载完全不可用。现在当 `Location` 以 `/` 开头时自动拼接 `api_host` 构造完整 URL。
172
-
173
- - **CDN 直连请求无重试**:cdn-bridge 和 CDN 签名 URL 请求此前使用裸 `requests.get()`/`httpx.stream()` 调用,无重试、无超时容错。一次 connect timeout 或网络抖动即导致整个 `sync_dataset` 中断(且预扣流量不退)。现在两跳均带 2 次重试(指数退避 1s/2s),捕获 `ConnectionError`/`Timeout`/`ReadError` 自动重试。
174
-
175
- - **302 重定向链路手动跟随**:此前只跟随第一跳 302,服务端两跳链路(`/download` → `/cdn-bridge?token=xxx` → CDN 签名 URL)的第二跳被忽略。现在统一用 `_follow_redirect_with_retry` 循环跟随最多 3 跳,ETag 逐跳透传。
176
-
177
- ## \[0.2.7] - 2026-07-29
1
+ # Changelog
2
+
3
+ 所有 notable 变更都会记录在此文件。格式基于 [Keep a Changelog](https://keepachangelog.com/zh-CN/1.1.0/),
4
+ 版本号遵循 [Semantic Versioning](https://semver.org/lang/zh-CN/)。
5
+
6
+ ## \[0.4.6] - 2026-10-27
178
7
 
179
8
  ### Fixed
180
9
 
181
- - **V1 回退对纯 V2 数据集失效**:`query_kline` / `a_query_kline` 无日期范围时不再默认走 V1。`margin_trading`、`features_daily`、`l1_factors`、`l2_factors` 等 11 个纯 V2 数据集在 COS 上已无 V1 逐股票文件,V1 回退会 404。现在无范围时也走 V2 manifest 路径(manifest 列出的所有分区全量下载),仅在有日期范围时才做日历完整性校验。显式 `layout="v1"` 仍可直接走逐股票文件。
182
-
183
- - **异步客户端时区处理不一致**:`AsyncQuantDBClient._normalise_kline` 缺少 `tz_convert` 逻辑,与同步客户端行为不一致(相同输入可能产生不同的 `trade_date` 字符串),已对齐。
184
-
185
- ## \[0.2.6] - 2026-07-27
186
-
187
- ### Fixed
188
-
189
- - **适配服务端 CDN 直连下载(302 跳转)**:异步客户端(httpx 默认不跟随重定向)此前在服务端开启 302 直连后所有下载/同步接口失效,现已修复。
190
-
191
- - **凭证保护**:同步客户端此前跟随 302 时会把 `X-API-Key` 透传给 CDN 域;现两个客户端统一改为「手动处理 302 + 无鉴权头裸请求直连 CDN」,凭证只发给 QuantDB 网关。
192
-
193
- - 302 响应中的 COS ETag 回填至 CDN 响应,保证进程内 ETag 缓存与 If-None-Match 304 逻辑不受影响。
194
-
195
- ### Security (后端)
196
-
197
- - **一次性下载令牌**:302 直连模式改为两跳(`/download` → `/cdn-bridge?token=xxx` → CDN),令牌一次性消费,防止签名 URL 被重复使用或分享给他人免费下载。
198
-
199
- - **移除** **`?direct=1`** **请求级覆盖**:用户无法再通过请求参数强制走 302 模式,仅全局开关 `QUANTDB_DOWNLOAD_REDIRECT` 可控制。
200
-
201
- - 令牌有效期 90s,远小于 CDN 签名有效期 300s,窗口极小。
202
-
203
- ### Data Architecture (COS)
204
-
205
- - **V2 数据集全面清理 V1 残留**:COS 上 11 个 V2 数据集已删除全部 V1 逐股票文件(\~1.8 万对象),实现纯 V2 存储。ListObjects 分页效率提升 3-5 倍。
206
-
207
- - **L1 日频因子 V2 全量上线**:`l1_factors` 2565 个交易日分区(2016-01-04 \~ 至今),支持按日范围高效查询。
208
-
209
- - **L2 高频因子 V2 上线**:`l2_factors` 34 个交易日分区(2026-01-05 \~ 2026-02-27)。
210
-
211
- - **融资融券纯 V2**:`margin_trading` 已从 V1 迁移至纯 V2 按日分区(2563 个分区)。
212
-
213
- ## \[0.2.5] - 2026-07-26
214
-
215
- ### Security
216
-
217
- - 下载响应文件名与 release/Manifest 相对路径均限制在指定下载目录内,防止路径穿越。
218
-
219
- - 公网 API Host 强制 HTTPS;CLI 改从环境变量读取 API Key,避免密钥出现在命令历史和进程参数中。
220
-
221
- - 下载增加单文件大小上限(默认 2 GiB,可通过 `QUANTDB_MAX_DOWNLOAD_BYTES` 配置)。
222
-
223
- - `query_local()` / `a_query_local()` 只接受 WHERE 条件,拒绝完整 SQL、JOIN 和外部表函数。
224
-
225
- ### Documentation
226
-
227
- - 更新官网 SDK 文档:并发下载建议、V1/V2 选择、安全配置与异常处理。
228
-
229
- ## \[0.2.4] - 2026-07-26
230
-
231
- ### Fixed
232
-
233
- - **Windows CLI 编码**:移除 `✓/✗` 字符,GBK 控制台可正常执行 `quantdb check`。
234
-
235
- ## \[0.2.3] - 2026-07-26
236
-
237
- ### Added
238
-
239
- - **财务本地仓库**:`mount_local_dataset()` 支持财务 V1、ETF/可转债与更多日频子类;财务数据以 `Symbol + m_timetag/endDate/time` 业务主键去重。
240
-
241
- ## \[0.2.2] - 2026-07-26
242
-
243
- ### Added
244
-
245
- - **全数据集增量同步**:`sync_dataset()` / `a_sync_dataset()` 覆盖基础、财务、ETF/可转债、行情、技术与 ML 子类;没有 V2 release 的数据集自动走 V1 Manifest。
246
-
247
- - **CLI 同步**:新增 `quantdb sync <api_key> <dataset> --save-dir <目录>`。
248
-
249
- ### Fixed
250
-
251
- - **V1 强校验**:V1 Manifest 同步以 ETag + size 判断变更,并在原子落盘前验证实际字节数。
252
-
253
- - **同步/异步一致性**:异步 release 同步采用 `relative_path`,SQLite 同时记录对象大小,与同步客户端保持同构目录和恢复语义。
254
-
255
- ## \[0.2.1] - 2026-07-26
256
-
257
- ### Fixed
258
-
259
- - **历史发布清单兼容**:同步客户端自动归一化旧 release manifest 遗留的 `v2/` 前缀,并可下载 release patch 对象。
260
-
261
- - **布局回退**:服务端以 COS Manifest 为可用性权威,V2 元数据缺失时可正确回退 V1,而非将数据误判为不可下载。
262
-
263
- ## \[0.2.0] - 2026-07-26
264
-
265
- ### Added
266
-
267
- - **V1/V2 布局兼容**:同步与异步客户端的下载、Manifest、DataFrame、K 线和 Tick 接口均支持 `layout="auto" | "v1" | "v2"`。
268
-
269
- - **V2 release 增量同步**:`sync_dataset()` / `a_sync_dataset()` 使用发布 cursor,同步 daily 与 patch 对象;文件 SHA-256 校验和原子落盘成功后才推进 cursor。
270
-
271
- ### Changed
272
-
273
- - `query_kline()` 在给出日期范围时优先 V2 日切片;V2 覆盖缺日时自动模式整体回退 V1,显式 V2 则返回覆盖错误。未给日期范围时保持 V1 全历史行为。
274
-
275
- - 下载接口支持 ETag 条件请求;服务端命中 `304 Not Modified` 时不传输对象正文、不扣下载流量。
276
-
277
- ## \[0.1.4] - 2026-07-25
278
-
279
- ### Fixed
280
-
281
- - **用户名密码登录**:先初始化 HTTP 会话再登录,修复 `QuantDBClient(username=..., password=...)` 初始化时访问未创建会话的错误。
282
-
283
- - **API Key 删除**:`delete_api_key()` / `a_delete_api_key()` 改为调用服务端实际的 `DELETE /api/v1/auth/api-keys/{id}` 接口,并明确接受 API Key ID。
284
-
285
- - **流量用量**:`get_usage()` / `a_get_usage()` 将余额购买的额外流量纳入剩余流量和活跃状态计算,并新增 `purchased_gb` 返回字段。
286
-
287
- ## \[0.1.3] - 2026-07-25
288
-
289
- ### Changed
290
-
291
- - **User-Agent 统一规范**:同步同步客户端 (`client.py`) 与异步客户端 (`async_client.py`) 的 `User-Agent` 标头为 `QuantDB-Python-SDK/0.1.3`,提升服务端请求追踪与日志分流精度。
292
-
293
- - **服务端 Redis 集中式缓存兼容**:完全兼容服务端网关新上线的 Redis 集中缓存层(自动接收 `X-Cache-Hit` 响应标头)。
294
-
295
- ## \[0.1.2] - 2026-07-25
296
-
297
- ### Added
298
-
299
- - **CLI 入口**:`[project.scripts]` 注册 `quantdb` 命令,装包后可直接 `quantdb --help` / `quantdb check <key>`,等价于 `python -m quantdb_sdk`。修复了 0.1.0/0.1.1 README 中 `python -m quantdb`(用连字符)会报 `No module named quantdb` 的问题。
300
-
301
- - `CHANGELOG.md` 与 `LICENSE`(MIT)文本随仓库发布。
302
-
303
- - `pyproject.toml` 新增 `Changelog` 项目 URL。
304
-
305
- ### Notes
306
-
307
- - 0.1.2 严格向后兼容 0.1.1,仅元数据层面的修补,不改任何运行时行为。
308
-
309
- - 若 0.1.1 已经在生产环境运行,可选升级;不升级也不受影响。
310
-
311
- ## \[0.1.1] - 2026-07-25
312
-
313
- ### Fixed
314
-
315
- - **关键 packaging bug**:`pyarrow` 未声明在 `pyproject.toml` 的运行时依赖,但 `client.py:482` 与 `async_client.py:413` 调用了 `pd.read_parquet(io.BytesIO(...))`。
316
-
317
- - **影响**:任何 `pip install quantdb-sdk==0.1.0` 的用户,在首次调用 `query_kline` / `query_tick` / `query_financial` 等下载类接口时会抛 `ImportError: Missing optional dependency 'pyarrow'`。只有 `get_usage` / `query_stock_list` 等非 parquet 接口 OOTB 可用。
318
-
319
- - **修复**:在 `dependencies` 加入 `pyarrow>=10.0.0`。
320
-
321
- - **服务端 User-Agent** 同步从 `0.1.0` 升级到 `0.1.1`,便于服务端按版本做调用归因与问题分流。
322
-
323
- ## \[0.1.0] - 2026-07-22
324
-
325
- ### Added
326
-
327
- - 初版发布。
328
-
329
- - `QuantDBClient` 同步客户端(基于 `requests`)。
330
-
331
- - `AsyncQuantDBClient` 异步客户端(基于 `httpx`)。
332
-
333
- - `DuckDBWarehouse` 本地仓库管理:自动下载 Parquet → 注册 DuckDB 视图 → 跨表 SQL 查询。
334
-
335
- - 异常体系:`QuantDBError` / `AuthError` / `RateLimitError` / `InsufficientTrafficError` / `NotFoundError` / `ServerError` / `ValidationError`。
336
-
337
- - 覆盖接口:流量查询、用户信息、API Key 管理、订阅与订单、股票列表、交易日历、K 线、Tick、财务、按日分片分钟线。
338
-
339
- - `py.typed` 标记(PEP 561),第三方库可获得完整类型信息。
340
-
10
+ - **增量同步的「检查更新」不再重复计费**:`sync_dataset` 此前对本地已存在的文件先发一次带 `If-None-Match` 的 GET 探测版本。ETag 命中时服务端在预扣前返回 304(免流量),但**ETag 不匹配时(对象已更新,正是需要下载的常见情况)该请求会继续走到流量预扣 + CDN 直连,把整个文件传完**,客户端却丢弃响应体再重下一次。CDN 直连模式签发即计费、不退款,于是「检查更新」被白白计费一次。
11
+
12
+ 实测近 2 天生产数据:下载请求 309,973 次但只涉及 71,675 个不同文件(**放大到 4.3 倍**),其中 **93.6% 是同 ETag 的纯重复下载**,纯浪费带宽与用户流量。
13
+
14
+ 修复:探测改用服务端新增的 `HEAD /api/v1/data/download`——只回 ETag 与长度,在流量预扣之前返回,**零流量、零令牌、零 PG 事务**。ETag 命中时同样返回 304。同步与异步客户端的 V2 release 与 V1 manifest 两条探测路径均已改用 HEAD。
15
+
16
+ 客户端侧行为不变:探测结果与本地记录一致即免流量跳过,不一致才真正下载。
17
+
18
+ 兼容性:服务端不支持 HEAD 时(老版本返回 405)自动退回原 GET 流程,不影响可用性。
19
+
20
+ ## \[0.4.5] - 2026-10-18
21
+
22
+ ### Added
23
+
24
+ - 本地 MCP 可调用 `quantdb-sdk` 执行单文件/全市场日分区下载与数据集增量同步,并查询、取消后台任务。远程 MCP 提供用户电脑可执行的 SDK 下载方案。
25
+ - `quantdb download <dataset> --trade-date YYYYMMDD --save-dir <root> --json`:下载 Parquet 并输出保存路径、大小;V1 逐股票文件使用 `--symbol`。V2 下载包含全市场,不做单股票裁切。
26
+ - `quantdb sync <dataset> --json`:复用 SDK release cursor/Manifest 同步并返回精简摘要。
27
+ - `python -m quantdb_sdk.mcp_download`:供本地 MCP 子进程使用的 JSON stdin/stdout 执行入口,凭据不进入进程参数或返回值。
28
+
29
+ ## \[0.4.4] - 2026-10-11
30
+
31
+ ### Fixed
32
+
33
+ - **`get_usage()` / `a_get_usage()` 漏算流量包额度**:旧实现用 `remaining = traffic_limit + credit_limit + purchased_traffic - used_traffic`,**完全没算流量包**,导致持有流量包的用户剩余流量被低估(少报的量正好等于流量包余额),`is_active` 也会在仍有流量包可用时被误判为 `False`。
34
+
35
+ 修正后的口径与后端下载预扣一致:可用总额度 = 套餐额度(`traffic_limit + credit_limit + purchased_traffic`)+ 流量包总额;可用剩余 = (套餐额度 − 已用) + 流量包剩余。因用量接口返回的 `package_traffic` 是流量包**剩余量**,总额从 `GET /api/v1/subscription/traffic-packages` 台账累加;台账接口不可用时退化为「总额 = 剩余」,保证 `get_usage()` 在旧版服务端上依然可用。
36
+
37
+ ### Added
38
+
39
+ - **`get_usage()` / `a_get_usage()` 新增额度明细字段**(原有字段全部保留,取值已修正):
40
+ - 合计:`total_gb` / `used_gb` / `remaining_gb`
41
+ - 套餐额度:`plan_total_gb` / `plan_used_gb` / `plan_remaining_gb`
42
+ - 流量包额度:`package_total_gb` / `package_used_gb` / `package_remaining_gb`
43
+ - **`quantdb usage` CLI** 改为分行展示套餐 / 流量包 / 合计的已用、总额与剩余,不再只显示一个总额。
44
+
45
+ ## \[0.4.3] - 2026-10-05
46
+
47
+ ### Changed
48
+
49
+ - **`per_share` 数据集更名**:中文名由「每股指标(补充)」改为「**财务指标(TTM)**」,描述与关键词同步更新(`每股/eps` → `财务/ttm`)。
50
+
51
+ 该表实际为 **TTM 口径财务指标补充表**(营收 / 归母净利 / 扣非净利 / 经营现金流等),原名既与 `pershare_index`「每股指标」混淆,也不符合数据口径。与后端 MCP catalog、桌面端分类表保持一致;`per_share` 标识符不变,`client.data` 用法不受影响。
52
+
53
+ ## \[0.4.2] - 2026-10-05
54
+
55
+ ### Added
56
+
57
+ - **新增数据集 `per_share`(每股指标补充表,分类 3)**:补登记为第 30 个数据集。
58
+
59
+ - `SYNC_DATASET_CATEGORIES` 与 `DATASET_REGISTRY` 由 29 项增至 30 项;`client.data.datasets()` / `info()` / `local_files()` / `read_local()` / `sync_dataset()` / `mount()` 均可直接按 `per_share` 使用。
60
+ - 物理形态为 V1 逐股票文件 `3_financial_data/per_share/{Symbol}.parquet`(由 `03_financial.py` 采集,部分股票为空);`layout=v1_symbol`,读取/查询需提供 `symbol`。
61
+ - 与 MCP catalog、后端 `subCategoryMapping`、前端分类表同步对齐(均为 30 项)。
62
+
63
+ ## \[0.4.1] - 2026-10-05
64
+
65
+ ### Changed
66
+
67
+ - **本地零流量读取提速**(`client.data.read_local` / `read`):改用 DuckDB 对**精确分区文件列表**做一次 `read_parquet`,把 `symbol` / 日期区间 / 列裁剪全部下推到 SQL,替代原先逐文件 `pd.read_parquet` 再 `concat`。实测(120 分区 × 1000 标的)单标的全历史 `0.62s → 0.22s`,带 `columns` 列裁剪 `→ 0.07s`。
68
+
69
+ - V2 按日分区与 tick 分片的 `trade_date` 由分区目录名 / 文件名推导,**不依赖** hive 注入的 `dt` 列(该列仅在较新 DuckDB 存在)。
70
+ - V1 逐股票表日期过滤用 `substr(replace(CAST(col AS VARCHAR),'-',''),1,8)` 归一化后下推,同时兼容整型报告期 `20251231` 与字符串 `2025-12-31` / 带时分秒。
71
+
72
+ - **依赖下界调整**:`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 已验证通过。
73
+
74
+ ### Fixed
75
+
76
+ - `read_local(..., columns=[...])` 在 V2 / tick 上未把 `symbol` 过滤下推:当 `columns` 不含 `symbol` 时,旧实现会在读取后被静默跳过过滤、返回全市场行。现 `symbol` 始终在 SQL 中下推。
77
+
78
+ ## \[0.4.0] - 2026-10-05
79
+
80
+ ### Added
81
+
82
+ - **统一数据入口** **`client.data`**(同步 `DataHub` / 异步 `AsyncDataHub`,模块 `quantdb_sdk.hub`):只凭 **dataset 名**即可跨 6 大分类目录取数,不必再手填 `category_id + sub_category`。SDK 侧解析分类后复用现有端点,**零后端改动**。
83
+
84
+ - **发现**:`datasets(category, access, keyword)` 列出 29 个数据集目录;`info(dataset)` 返回注册表字段并叠加云端元数据(覆盖区间 / 文件数 / 文件大小)。
85
+ - **本地零流量**:`local_files` / `local_path` / `read_local` / `read`(本地优先,缺失时显式回退在线)。数据根目录可配置(`root` 参数,缺省读 `QUANTDB_DATA_DIR`);多形态 glob 兼容 V2 `dt=` 分区、tick 平铺/子目录分片、V1 逐股票文件;V2/tick 无日期列时从路径注入 `trade_date`。
86
+ - **在线**:`preview` / `load` / `download` / `query` / `sync` / `mount`,逐项委托既有方法。`query` 按数据集自动路由:日线三兄弟走 `query_kline`、ETF 走 `query_etf_kline`、tick 走 `query_tick` 并按 symbol 后置过滤、其余 V2 走通用日分区分支、V1 逐股票走 `layout="v1"` + 日期列过滤。
87
+ - 异步方法统一 `a_` 前缀;异步端不含 `mount`(无 `a_mount_local_dataset`,DuckDB 仓库为同步)。
88
+ - 新增 `DATASET_REGISTRY` 注册表(29 项),`category_id` 复用 `SYNC_DATASET_CATEGORIES`,`category_dir` 复用 `CATEGORY_DIRS`,避免重复维护分类事实源。
89
+
90
+ - **命令行** **`quantdb datasets [name]`**:列出全部数据集目录或查看某个数据集详情(无需 API Key)。
91
+
92
+ - 新增演示脚本 `quantdb_sdk/examples/demo_07_data_hub.py`。
93
+
94
+ ## \[0.3.5] - 2026-09-26
95
+
96
+ ### Added
97
+
98
+ - **分区大小查询** **`query_partition_size`** **/** **`a_query_partition_size`**:查询各子分类的分区总大小(`file_count` 分区数 + `file_size` 总字节 + 换算列 `file_size_gb`),用于估算下载流量与数据占用。缺省返回全部子分类,可传 `sub_category`(如 `daily_forward`)单查。
99
+
100
+ - **`query_meta`** **/** **`a_query_meta`** 新增 `sub_category` 过滤参数:后端 `data_meta` 现含 `file_size`(分区总字节,由发布管线从 COS 元数据重建),可按子分类精准取各数据集日期范围/行数/文件数/文件大小。
101
+
102
+ ## \[0.3.4] - 2026-09-04
103
+
104
+ ### Added
105
+
106
+ - **ETF 日 K 线查询** **`query_etf_kline`** **/** **`a_query_etf_kline`**:新增便捷方法查询分类 4 的 `etf_kline`(V2 全市场按日分区,symbol 形如 510300.SH),`auto` 优先 V2、日期范围覆盖不完整时回退 V1。
107
+
108
+ - **`sync_dataset("etf_kline")`** **支持**:`SYNC_DATASET_CATEGORIES` 注册 `etf_kline` → 分类 4,此前会报「不支持同步的数据集」。
109
+
110
+ ## \[0.3.3] - 2026-08-29
111
+
112
+ ### Added
113
+
114
+ - **本地完整性扫描** **`scan_local_directory`**,并作为 `QuantDBClient.scan_local()` / `AsyncQuantDBClient.a_scan_local()` 方法公开:扫描本地数据目录,流式计算每个文件的 MD5 与 COS 形态 ETag。只做本地 IO、不发起网络请求、不消耗流量,用于对落地数据做独立的完整性指纹扫描(发布前/对账/排障前置核对)。
115
+
116
+ - 支持递归/非递归、按后缀过滤(默认 `.parquet`)、可选进度回调。
117
+
118
+ - 返回含汇总 `file_count` / `total_bytes` 与逐文件 `{relative_path, path, size, md5, etag}` 的清单;读取失败的文件登记到 `errors` 不中断扫描。
119
+
120
+ ## \[0.3.2] - 2026-08-27
121
+
122
+ ### Changed
123
+
124
+ - **同步/异步客户端** **`sync_dataset`** **服务端 304 权威对账**:当本地文件已在磁盘(含 sqlite 记录缺失或指纹对不上场景)时,先发 `If-None-Match=<本地文件 MD5>` 给 `/download`,命中 304(网关在预扣/COS 直连前短路,免流量)则只登记跳过,避免"本地明明有文件但记录/指纹对不上"时的整块重下。修复此前 V2 release 对象缺 `etag` 字段导致 `local_file_matches` 恒 `False`、本地清空 sqlite 后全量重下的问题。
125
+
126
+ - **判重主键从 etag 改为** **`sha256`**:V2 release 对象无 etag 字段,原判重实际退化为仅靠弱指纹;现统一以内容 sha256 判重,正常增量仍按 sha 命中跳过。
127
+
128
+ - 下载成功后落库记录**真实 COS ETag**,供后续对账/304 复用。
129
+
130
+ ## \[0.3.1] - 2026-08-15
131
+
132
+ ### Added
133
+
134
+ - **CLI 目录规范命令**:`quantdb layout` 打印本地数据目录规范(顶层分类目录、各数据集 V1/V2/tick 布局、路径示例),无需 API Key。
135
+
136
+ - **CLI 帮助增强**:`quantdb --help` 补充演示脚本提示;`quantdb sync` 帮助说明数据根目录来源(`QUANTDB_DATA_DIR` → 默认下载目录),并打印 `matched`(本地对账跳过数)。
137
+
138
+ ## \[0.3.0] - 2026-08-15
139
+
140
+ ### Added
141
+
142
+ - **目录规范模块** **`quantdb_sdk.layout`**:新增本地数据目录规范,与采集根目录 `D:\quant_data` 保持一致。
143
+
144
+ - `CATEGORY_DIRS`:6 个顶层分类目录(1\_kline\_data / 2\_base\_sector / 3\_financial\_data / 4\_bond\_etf / 5\_technical\_derived / 6\_ml\_datasets)。
145
+
146
+ - `dataset_dir(dataset)` / `category_id(dataset)` / `dataset_layout(dataset)`:数据集 → 相对目录 / 分类 ID / 物理布局(`v2_daily_partition | v1_symbol | tick_shard`)。
147
+
148
+ - `local_relative_path(dataset, symbol=None, trade_date=None, layout=None)`:生成 V1(`{Symbol}.parquet`)、V2(`dt=YYYYMMDD/data.parquet`)、tick(`{SYM}_{YYYYMMDD}.parquet`)的相对路径。
149
+
150
+ - `data_root()`:新增 `QUANTDB_DATA_DIR` 环境变量指定本地数据根目录,未设置时回退 SDK 默认下载目录。
151
+
152
+ - **演示脚本包** **`quantdb_sdk.examples`**(随 wheel 发布,6 个):
153
+
154
+ - `demo_01_connect_basics` 连接 / 用量 / 订阅 / 股票列表 / 日历(零流量接口)
155
+
156
+ - `demo_02_kline_v2_daily` 按 V2 日分区查询 K 线(单日全市场切片 + 单股日期范围)
157
+
158
+ - `demo_03_sync_full_market` 全市场增量同步,落地到规范目录
159
+
160
+ - `demo_04_duckdb_warehouse` DuckDB 本地 SQL JOIN(V2 日分区)
161
+
162
+ - `demo_05_read_local_data` 按目录规范定位并读取本地已同步数据
163
+
164
+ - `demo_06_tick_and_factors` Tick 按日下载 + L1 因子 V2 分区装载
165
+
166
+ - 公开导出:`quantdb_sdk.layout` 模块及 `CATEGORY_DIRS` / `V2_DAILY_PARTITION` / `data_root` / `dataset_dir` / `dataset_layout` / `local_relative_path`。
167
+
168
+ ### Changed
169
+
170
+ - `DuckDBWarehouse.mount_local_dataset` 的目录映射字典重构为复用 `layout.dataset_dir`,消除与目录规范的重复定义,行为不变。
171
+
172
+ - **同步对账(reconciliation)**:`sync_dataset()` / `a_sync_dataset()` 新增本地磁盘对账——目标文件已存在、大小一致且本地 MD5 == COS ETag 时,直接登记进状态并跳过下载(V2 与 V1 Manifest 两条路径均生效)。数据根目录可任意调整(`QUANTDB_DATA_DIR` / `--root` / `save_dir`),指向已含相同数据的目录时无需全量重下,与 Electron 本地对账语义一致。返回结果新增 `matched` 字段(已对账跳过对象数)。
173
+
174
+ - 目录规范模块说明不再包含任何绝对路径,`D:\quant_data` 仅作为组织方式参考;本地根目录始终可配置。
175
+
176
+ ## \[0.2.10] - 2026-08-03
177
+
178
+ ### Fixed
179
+
180
+ - **对象 SHA-256 校验在旧 manifest 过期时卡死整个 release**:追加式发布链中同一 `dt=` 分区可被多份历史 manifest 引用,重写分区后旧清单 sha256 过期。同步/异步客户端此前对过期条目硬校验失败即中止整份 release 且不提交 cursor,导致每次重下、永远卡死(`对象 SHA-256 校验失败`)。现在 sync 时以 cursor 序列中**最新一份** manifest 的指纹作为权威校验值,旧清单过期只重下该分区,不再阻塞。管线侧已配套加 manifest 回填 + 全量审计(`pipeline/sync_to_cos.py`、`pipeline/verify_cos_manifests.py`)。
181
+
182
+ - **User-Agent 版本号与 pyproject 不同步**:0.2.9 发版时漏改,同步/异步客户端 `_USER_AGENT` 仍为 0.2.8,已对齐为 0.2.10。
183
+
184
+ ## \[0.2.9] - 2026-07-30
185
+
186
+ ### Fixed
187
+
188
+ - **CDN 直连重试路径缺失导入**:0.2.8 引入的重试逻辑(指数退避)在同步/异步客户端分别使用 `time.sleep` / `asyncio.sleep`,但模块缺失 `import time` / `import asyncio`,触发重试时抛 `NameError` 导致下载中断,已补齐导入。
189
+
190
+ ## \[0.2.8] - 2026-07-30
191
+
192
+ ### Fixed
193
+
194
+ - **CDN 直连下载 302 相对 URL 拼接**:服务端 CDN 直连模式(`QUANTDB_DOWNLOAD_REDIRECT`)的 Stage 1 302 返回相对 URL(`/api/v1/data/cdn-bridge?token=xxx`),同步/异步客户端此前直接将此相对路径作为请求 URL,导致 `requests`/`httpx` 无法解析(`MissingSchema`/`UnsupportedProtocol`),CDN 直连下载完全不可用。现在当 `Location` 以 `/` 开头时自动拼接 `api_host` 构造完整 URL。
195
+
196
+ - **CDN 直连请求无重试**:cdn-bridge 和 CDN 签名 URL 请求此前使用裸 `requests.get()`/`httpx.stream()` 调用,无重试、无超时容错。一次 connect timeout 或网络抖动即导致整个 `sync_dataset` 中断(且预扣流量不退)。现在两跳均带 2 次重试(指数退避 1s/2s),捕获 `ConnectionError`/`Timeout`/`ReadError` 自动重试。
197
+
198
+ - **302 重定向链路手动跟随**:此前只跟随第一跳 302,服务端两跳链路(`/download` → `/cdn-bridge?token=xxx` → CDN 签名 URL)的第二跳被忽略。现在统一用 `_follow_redirect_with_retry` 循环跟随最多 3 跳,ETag 逐跳透传。
199
+
200
+ ## \[0.2.7] - 2026-07-29
201
+
202
+ ### Fixed
203
+
204
+ - **V1 回退对纯 V2 数据集失效**:`query_kline` / `a_query_kline` 无日期范围时不再默认走 V1。`margin_trading`、`features_daily`、`l1_factors`、`l2_factors` 等 11 个纯 V2 数据集在 COS 上已无 V1 逐股票文件,V1 回退会 404。现在无范围时也走 V2 manifest 路径(manifest 列出的所有分区全量下载),仅在有日期范围时才做日历完整性校验。显式 `layout="v1"` 仍可直接走逐股票文件。
205
+
206
+ - **异步客户端时区处理不一致**:`AsyncQuantDBClient._normalise_kline` 缺少 `tz_convert` 逻辑,与同步客户端行为不一致(相同输入可能产生不同的 `trade_date` 字符串),已对齐。
207
+
208
+ ## \[0.2.6] - 2026-07-27
209
+
210
+ ### Fixed
211
+
212
+ - **适配服务端 CDN 直连下载(302 跳转)**:异步客户端(httpx 默认不跟随重定向)此前在服务端开启 302 直连后所有下载/同步接口失效,现已修复。
213
+
214
+ - **凭证保护**:同步客户端此前跟随 302 时会把 `X-API-Key` 透传给 CDN 域;现两个客户端统一改为「手动处理 302 + 无鉴权头裸请求直连 CDN」,凭证只发给 QuantDB 网关。
215
+
216
+ - 302 响应中的 COS ETag 回填至 CDN 响应,保证进程内 ETag 缓存与 If-None-Match 304 逻辑不受影响。
217
+
218
+ ### Security (后端)
219
+
220
+ - **一次性下载令牌**:302 直连模式改为两跳(`/download` → `/cdn-bridge?token=xxx` → CDN),令牌一次性消费,防止签名 URL 被重复使用或分享给他人免费下载。
221
+
222
+ - **移除** **`?direct=1`** **请求级覆盖**:用户无法再通过请求参数强制走 302 模式,仅全局开关 `QUANTDB_DOWNLOAD_REDIRECT` 可控制。
223
+
224
+ - 令牌有效期 90s,远小于 CDN 签名有效期 300s,窗口极小。
225
+
226
+ ### Data Architecture (COS)
227
+
228
+ - **V2 数据集全面清理 V1 残留**:COS 上 11 个 V2 数据集已删除全部 V1 逐股票文件(\~1.8 万对象),实现纯 V2 存储。ListObjects 分页效率提升 3-5 倍。
229
+
230
+ - **L1 日频因子 V2 全量上线**:`l1_factors` 2565 个交易日分区(2016-01-04 \~ 至今),支持按日范围高效查询。
231
+
232
+ - **L2 高频因子 V2 上线**:`l2_factors` 34 个交易日分区(2026-01-05 \~ 2026-02-27)。
233
+
234
+ - **融资融券纯 V2**:`margin_trading` 已从 V1 迁移至纯 V2 按日分区(2563 个分区)。
235
+
236
+ ## \[0.2.5] - 2026-07-26
237
+
238
+ ### Security
239
+
240
+ - 下载响应文件名与 release/Manifest 相对路径均限制在指定下载目录内,防止路径穿越。
241
+
242
+ - 公网 API Host 强制 HTTPS;CLI 改从环境变量读取 API Key,避免密钥出现在命令历史和进程参数中。
243
+
244
+ - 下载增加单文件大小上限(默认 2 GiB,可通过 `QUANTDB_MAX_DOWNLOAD_BYTES` 配置)。
245
+
246
+ - `query_local()` / `a_query_local()` 只接受 WHERE 条件,拒绝完整 SQL、JOIN 和外部表函数。
247
+
248
+ ### Documentation
249
+
250
+ - 更新官网 SDK 文档:并发下载建议、V1/V2 选择、安全配置与异常处理。
251
+
252
+ ## \[0.2.4] - 2026-07-26
253
+
254
+ ### Fixed
255
+
256
+ - **Windows CLI 编码**:移除 `✓/✗` 字符,GBK 控制台可正常执行 `quantdb check`。
257
+
258
+ ## \[0.2.3] - 2026-07-26
259
+
260
+ ### Added
261
+
262
+ - **财务本地仓库**:`mount_local_dataset()` 支持财务 V1、ETF/可转债与更多日频子类;财务数据以 `Symbol + m_timetag/endDate/time` 业务主键去重。
263
+
264
+ ## \[0.2.2] - 2026-07-26
265
+
266
+ ### Added
267
+
268
+ - **全数据集增量同步**:`sync_dataset()` / `a_sync_dataset()` 覆盖基础、财务、ETF/可转债、行情、技术与 ML 子类;没有 V2 release 的数据集自动走 V1 Manifest。
269
+
270
+ - **CLI 同步**:新增 `quantdb sync <api_key> <dataset> --save-dir <目录>`。
271
+
272
+ ### Fixed
273
+
274
+ - **V1 强校验**:V1 Manifest 同步以 ETag + size 判断变更,并在原子落盘前验证实际字节数。
275
+
276
+ - **同步/异步一致性**:异步 release 同步采用 `relative_path`,SQLite 同时记录对象大小,与同步客户端保持同构目录和恢复语义。
277
+
278
+ ## \[0.2.1] - 2026-07-26
279
+
280
+ ### Fixed
281
+
282
+ - **历史发布清单兼容**:同步客户端自动归一化旧 release manifest 遗留的 `v2/` 前缀,并可下载 release patch 对象。
283
+
284
+ - **布局回退**:服务端以 COS Manifest 为可用性权威,V2 元数据缺失时可正确回退 V1,而非将数据误判为不可下载。
285
+
286
+ ## \[0.2.0] - 2026-07-26
287
+
288
+ ### Added
289
+
290
+ - **V1/V2 布局兼容**:同步与异步客户端的下载、Manifest、DataFrame、K 线和 Tick 接口均支持 `layout="auto" | "v1" | "v2"`。
291
+
292
+ - **V2 release 增量同步**:`sync_dataset()` / `a_sync_dataset()` 使用发布 cursor,同步 daily 与 patch 对象;文件 SHA-256 校验和原子落盘成功后才推进 cursor。
293
+
294
+ ### Changed
295
+
296
+ - `query_kline()` 在给出日期范围时优先 V2 日切片;V2 覆盖缺日时自动模式整体回退 V1,显式 V2 则返回覆盖错误。未给日期范围时保持 V1 全历史行为。
297
+
298
+ - 下载接口支持 ETag 条件请求;服务端命中 `304 Not Modified` 时不传输对象正文、不扣下载流量。
299
+
300
+ ## \[0.1.4] - 2026-07-25
301
+
302
+ ### Fixed
303
+
304
+ - **用户名密码登录**:先初始化 HTTP 会话再登录,修复 `QuantDBClient(username=..., password=...)` 初始化时访问未创建会话的错误。
305
+
306
+ - **API Key 删除**:`delete_api_key()` / `a_delete_api_key()` 改为调用服务端实际的 `DELETE /api/v1/auth/api-keys/{id}` 接口,并明确接受 API Key ID。
307
+
308
+ - **流量用量**:`get_usage()` / `a_get_usage()` 将余额购买的额外流量纳入剩余流量和活跃状态计算,并新增 `purchased_gb` 返回字段。
309
+
310
+ ## \[0.1.3] - 2026-07-25
311
+
312
+ ### Changed
313
+
314
+ - **User-Agent 统一规范**:同步同步客户端 (`client.py`) 与异步客户端 (`async_client.py`) 的 `User-Agent` 标头为 `QuantDB-Python-SDK/0.1.3`,提升服务端请求追踪与日志分流精度。
315
+
316
+ - **服务端 Redis 集中式缓存兼容**:完全兼容服务端网关新上线的 Redis 集中缓存层(自动接收 `X-Cache-Hit` 响应标头)。
317
+
318
+ ## \[0.1.2] - 2026-07-25
319
+
320
+ ### Added
321
+
322
+ - **CLI 入口**:`[project.scripts]` 注册 `quantdb` 命令,装包后可直接 `quantdb --help` / `quantdb check <key>`,等价于 `python -m quantdb_sdk`。修复了 0.1.0/0.1.1 README 中 `python -m quantdb`(用连字符)会报 `No module named quantdb` 的问题。
323
+
324
+ - `CHANGELOG.md` 与 `LICENSE`(MIT)文本随仓库发布。
325
+
326
+ - `pyproject.toml` 新增 `Changelog` 项目 URL。
327
+
328
+ ### Notes
329
+
330
+ - 0.1.2 严格向后兼容 0.1.1,仅元数据层面的修补,不改任何运行时行为。
331
+
332
+ - 若 0.1.1 已经在生产环境运行,可选升级;不升级也不受影响。
333
+
334
+ ## \[0.1.1] - 2026-07-25
335
+
336
+ ### Fixed
337
+
338
+ - **关键 packaging bug**:`pyarrow` 未声明在 `pyproject.toml` 的运行时依赖,但 `client.py:482` 与 `async_client.py:413` 调用了 `pd.read_parquet(io.BytesIO(...))`。
339
+
340
+ - **影响**:任何 `pip install quantdb-sdk==0.1.0` 的用户,在首次调用 `query_kline` / `query_tick` / `query_financial` 等下载类接口时会抛 `ImportError: Missing optional dependency 'pyarrow'`。只有 `get_usage` / `query_stock_list` 等非 parquet 接口 OOTB 可用。
341
+
342
+ - **修复**:在 `dependencies` 加入 `pyarrow>=10.0.0`。
343
+
344
+ - **服务端 User-Agent** 同步从 `0.1.0` 升级到 `0.1.1`,便于服务端按版本做调用归因与问题分流。
345
+
346
+ ## \[0.1.0] - 2026-07-22
347
+
348
+ ### Added
349
+
350
+ - 初版发布。
351
+
352
+ - `QuantDBClient` 同步客户端(基于 `requests`)。
353
+
354
+ - `AsyncQuantDBClient` 异步客户端(基于 `httpx`)。
355
+
356
+ - `DuckDBWarehouse` 本地仓库管理:自动下载 Parquet → 注册 DuckDB 视图 → 跨表 SQL 查询。
357
+
358
+ - 异常体系:`QuantDBError` / `AuthError` / `RateLimitError` / `InsufficientTrafficError` / `NotFoundError` / `ServerError` / `ValidationError`。
359
+
360
+ - 覆盖接口:流量查询、用户信息、API Key 管理、订阅与订单、股票列表、交易日历、K 线、Tick、财务、按日分片分钟线。
361
+
362
+ - `py.typed` 标记(PEP 561),第三方库可获得完整类型信息。
363
+