quantdb-sdk 0.2.2__tar.gz → 0.2.4__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 (23) hide show
  1. {quantdb_sdk-0.2.2 → quantdb_sdk-0.2.4}/CHANGELOG.md +10 -0
  2. {quantdb_sdk-0.2.2/quantdb_sdk.egg-info → quantdb_sdk-0.2.4}/PKG-INFO +1 -1
  3. {quantdb_sdk-0.2.2 → quantdb_sdk-0.2.4}/pyproject.toml +1 -1
  4. {quantdb_sdk-0.2.2 → quantdb_sdk-0.2.4}/quantdb_sdk/__init__.py +1 -1
  5. {quantdb_sdk-0.2.2 → quantdb_sdk-0.2.4}/quantdb_sdk/__main__.py +2 -2
  6. {quantdb_sdk-0.2.2 → quantdb_sdk-0.2.4}/quantdb_sdk/async_client.py +1 -1
  7. {quantdb_sdk-0.2.2 → quantdb_sdk-0.2.4}/quantdb_sdk/client.py +18 -4
  8. {quantdb_sdk-0.2.2 → quantdb_sdk-0.2.4/quantdb_sdk.egg-info}/PKG-INFO +1 -1
  9. {quantdb_sdk-0.2.2 → quantdb_sdk-0.2.4}/tests/test_client.py +11 -0
  10. {quantdb_sdk-0.2.2 → quantdb_sdk-0.2.4}/LICENSE +0 -0
  11. {quantdb_sdk-0.2.2 → quantdb_sdk-0.2.4}/MANIFEST.in +0 -0
  12. {quantdb_sdk-0.2.2 → quantdb_sdk-0.2.4}/README.md +0 -0
  13. {quantdb_sdk-0.2.2 → quantdb_sdk-0.2.4}/quantdb_sdk/_utils.py +0 -0
  14. {quantdb_sdk-0.2.2 → quantdb_sdk-0.2.4}/quantdb_sdk/errors.py +0 -0
  15. {quantdb_sdk-0.2.2 → quantdb_sdk-0.2.4}/quantdb_sdk/py.typed +0 -0
  16. {quantdb_sdk-0.2.2 → quantdb_sdk-0.2.4}/quantdb_sdk.egg-info/SOURCES.txt +0 -0
  17. {quantdb_sdk-0.2.2 → quantdb_sdk-0.2.4}/quantdb_sdk.egg-info/dependency_links.txt +0 -0
  18. {quantdb_sdk-0.2.2 → quantdb_sdk-0.2.4}/quantdb_sdk.egg-info/entry_points.txt +0 -0
  19. {quantdb_sdk-0.2.2 → quantdb_sdk-0.2.4}/quantdb_sdk.egg-info/requires.txt +0 -0
  20. {quantdb_sdk-0.2.2 → quantdb_sdk-0.2.4}/quantdb_sdk.egg-info/top_level.txt +0 -0
  21. {quantdb_sdk-0.2.2 → quantdb_sdk-0.2.4}/setup.cfg +0 -0
  22. {quantdb_sdk-0.2.2 → quantdb_sdk-0.2.4}/tests/test_async_client.py +0 -0
  23. {quantdb_sdk-0.2.2 → quantdb_sdk-0.2.4}/tests/test_technical_indicators.py +0 -0
@@ -3,6 +3,16 @@
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.2.4] - 2026-07-26
7
+
8
+ ### Fixed
9
+ - **Windows CLI 编码**:移除 `✓/✗` 字符,GBK 控制台可正常执行 `quantdb check`。
10
+
11
+ ## [0.2.3] - 2026-07-26
12
+
13
+ ### Added
14
+ - **财务本地仓库**:`mount_local_dataset()` 支持财务 V1、ETF/可转债与更多日频子类;财务数据以 `Symbol + m_timetag/endDate/time` 业务主键去重。
15
+
6
16
  ## [0.2.2] - 2026-07-26
7
17
 
8
18
  ### Added
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: quantdb-sdk
3
- Version: 0.2.2
3
+ Version: 0.2.4
4
4
  Summary: QuantDB 量化数据平台官方 Python SDK
5
5
  Author: QuantDB Team
6
6
  License: MIT
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "quantdb-sdk"
7
- version = "0.2.2"
7
+ version = "0.2.4"
8
8
  description = "QuantDB 量化数据平台官方 Python SDK"
9
9
  readme = "README.md"
10
10
  license = {text = "MIT"}
@@ -5,7 +5,7 @@ try:
5
5
  # 注意:此处用 PyPI 包名(连字符)查找版本号,不是模块名(下划线)
6
6
  __version__ = version("quantdb-sdk")
7
7
  except ImportError:
8
- __version__ = "0.2.2"
8
+ __version__ = "0.2.4"
9
9
 
10
10
  from .async_client import AsyncQuantDBClient
11
11
  from .client import DuckDBWarehouse, QuantDBClient
@@ -56,7 +56,7 @@ def main() -> int:
56
56
 
57
57
  if args.command == "check":
58
58
  me = client.get_me()
59
- print(f" API Key 有效")
59
+ print("[OK] API Key 有效")
60
60
  print(f" 用户: {me.get('username', 'N/A')}")
61
61
  print(f" ID: {me.get('id', 'N/A')}")
62
62
  return 0
@@ -81,7 +81,7 @@ def main() -> int:
81
81
  return 0
82
82
 
83
83
  except Exception as e:
84
- print(f" 错误: {e}", file=sys.stderr)
84
+ print(f"[ERROR] {e}", file=sys.stderr)
85
85
  return 1
86
86
 
87
87
  return 0
@@ -37,7 +37,7 @@ class AsyncQuantDBClient:
37
37
  ):
38
38
  self.api_host = api_host.rstrip("/")
39
39
  self.timeout = timeout
40
- headers = {"User-Agent": "QuantDB-Python-SDK/0.2.2"}
40
+ headers = {"User-Agent": "QuantDB-Python-SDK/0.2.4"}
41
41
  if api_key:
42
42
  headers["X-API-Key"] = api_key
43
43
  elif token:
@@ -48,7 +48,7 @@ class QuantDBClient:
48
48
  self.session = requests.Session()
49
49
  # User-Agent 中的版本与 pyproject.toml 同步,用于服务端日志归因
50
50
  # 维护提示:每次版本号变化必须同步改这里(init 里的 __version__ 走 metadata 自动同步)
51
- self.session.headers.update({"User-Agent": "QuantDB-Python-SDK/0.2.2"})
51
+ self.session.headers.update({"User-Agent": "QuantDB-Python-SDK/0.2.4"})
52
52
 
53
53
  if api_key:
54
54
  self.headers = {"X-API-Key": api_key}
@@ -713,7 +713,17 @@ class QuantDBClient:
713
713
  """挂载本地 V1/V2 同构数据集;V2 patch 与 daily 文件均参与去重。"""
714
714
  warehouse = self.get_local_warehouse(save_dir)
715
715
  root = os.path.abspath(save_dir or default_download_dir()).replace("\\", "/")
716
- views = {"daily_forward":"1_kline_data/daily_forward", "valuation":"5_technical_derived/valuation", "technical_indicators":"5_technical_derived/technical_indicators", "market_sentiment":"5_technical_derived/market_sentiment", "features_daily":"6_ml_datasets/features_daily"}
716
+ views = {
717
+ "daily_unadjusted": "1_kline_data/daily_unadjusted", "daily_forward": "1_kline_data/daily_forward",
718
+ "daily_backward": "1_kline_data/daily_backward", "index_daily": "1_kline_data/index_daily",
719
+ "margin_trading": "2_base_sector/margin_trading", "valuation": "5_technical_derived/valuation",
720
+ "technical_indicators": "5_technical_derived/technical_indicators", "market_sentiment": "5_technical_derived/market_sentiment",
721
+ "features_daily": "6_ml_datasets/features_daily", "balance": "3_financial_data/balance",
722
+ "income": "3_financial_data/income", "cashflow": "3_financial_data/cashflow",
723
+ "capital": "3_financial_data/capital", "holder_num": "3_financial_data/holder_num",
724
+ "pershare_index": "3_financial_data/pershare_index", "dividend_factors": "3_financial_data/dividend_factors",
725
+ "etf_pcf": "4_bond_etf/etf_pcf", "convertible_bond": "4_bond_etf/convertible_bond",
726
+ }
717
727
  if dataset not in views: raise ValidationError(f"不支持的 V2 数据集: {dataset}")
718
728
  name = view_name or re.sub(r"[^a-zA-Z0-9_]", "_", dataset)
719
729
  state_path = os.path.join(root.replace("/", os.sep), "quantdb_sync.sqlite")
@@ -732,9 +742,13 @@ class QuantDBClient:
732
742
  quoted = ", ".join("'" + p.replace("'", "''") + "'" for p in files)
733
743
  relation = f"read_parquet([{quoted}], union_by_name=true)"
734
744
  columns = {row[0] for row in warehouse.conn.execute(f"DESCRIBE SELECT * FROM {relation}").fetchall()}
735
- if {"symbol", "time"}.issubset(columns):
745
+ symbol_column = "symbol" if "symbol" in columns else ("Symbol" if "Symbol" in columns else None)
746
+ date_column = next((column for column in ("time", "m_timetag", "endDate", "date") if column in columns), None)
747
+ if symbol_column and date_column:
736
748
  order = "coalesce(release_id, '') DESC" if "release_id" in columns else "0"
737
- warehouse.conn.execute(f"CREATE OR REPLACE VIEW {name} AS SELECT * EXCLUDE (rn) FROM (SELECT *, row_number() OVER (PARTITION BY symbol, time ORDER BY {order}) rn FROM {relation}) WHERE rn=1")
749
+ symbol_sql = '"' + symbol_column.replace('"', '""') + '"'
750
+ date_sql = '"' + date_column.replace('"', '""') + '"'
751
+ warehouse.conn.execute(f"CREATE OR REPLACE VIEW {name} AS SELECT * EXCLUDE (rn) FROM (SELECT *, row_number() OVER (PARTITION BY {symbol_sql}, {date_sql} ORDER BY {order}) rn FROM {relation}) WHERE rn=1")
738
752
  else:
739
753
  warehouse.conn.execute(f"CREATE OR REPLACE VIEW {name} AS SELECT * FROM {relation}")
740
754
  warehouse._views[name] = f"{dataset}"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: quantdb-sdk
3
- Version: 0.2.2
3
+ Version: 0.2.4
4
4
  Summary: QuantDB 量化数据平台官方 Python SDK
5
5
  Author: QuantDB Team
6
6
  License: MIT
@@ -230,3 +230,14 @@ def test_duckdb_warehouse(tmp_path):
230
230
  df = wh.query("SELECT * FROM stock_val WHERE val > 15")
231
231
  assert len(df) == 1
232
232
  assert df.iloc[0]["code"] == "600519.SH"
233
+
234
+
235
+ def test_mount_local_financial_dataset_deduplicates_business_key(tmp_path):
236
+ pytest.importorskip("duckdb")
237
+ directory = tmp_path / "3_financial_data" / "balance"
238
+ directory.mkdir(parents=True)
239
+ pd.DataFrame({"Symbol": ["600000.SH"], "m_timetag": [20260331], "value": [1]}).to_parquet(directory / "a.parquet")
240
+ pd.DataFrame({"Symbol": ["600000.SH"], "m_timetag": [20260331], "value": [2]}).to_parquet(directory / "b.parquet")
241
+ client = QuantDBClient(api_host=API_HOST, api_key="test-key")
242
+ warehouse = client.mount_local_dataset("balance", str(tmp_path))
243
+ assert len(warehouse.query("SELECT * FROM balance")) == 1
File without changes
File without changes
File without changes
File without changes