diff --git a/xiaobai-datahub/datahub/steward.py b/xiaobai-datahub/datahub/steward.py index 907c91a..4a03e8b 100644 --- a/xiaobai-datahub/datahub/steward.py +++ b/xiaobai-datahub/datahub/steward.py @@ -202,6 +202,11 @@ def _try_published(api, api_name: str, dataset: str, params: dict[str, Any], fie return None if dataset == "stocks": rows = _filter_stocks(rows, params) + # The published master is intentionally the active list. Historical + # delisted/paused lookups still belong in the hub, so use its live + # Tushare adapter when those filters cannot be answered by the snapshot. + if not rows and any(params.get(key) for key in ("ts_code", "list_status", "name")): + return None if dataset == "calendar": rows = _filter_calendar(rows, params) native = _to_tushare_native(dataset, rows) @@ -312,9 +317,12 @@ def _live_cache_key(api_name: str, params: dict[str, Any], fields: str) -> str: def _hub_query(params: dict[str, Any], **extra: Any) -> dict[str, str]: query = {key: str(value) for key, value in extra.items() if value not in (None, "")} - date = yyyymmdd(params.get("trade_date") or params.get("date") or "") - start = yyyymmdd(params.get("start_date") or params.get("from") or date) - end = yyyymmdd(params.get("end_date") or params.get("to") or date) + raw_date = params.get("trade_date") or params.get("date") or "" + date = yyyymmdd(raw_date) if raw_date else "" + raw_start = params.get("start_date") or params.get("from") or date + raw_end = params.get("end_date") or params.get("to") or date + start = yyyymmdd(raw_start) if raw_start else "" + end = yyyymmdd(raw_end) if raw_end else "" code = str(params.get("ts_code") or params.get("code") or "").strip() if code: query["code"] = code diff --git a/xiaobai-datahub/tests/test_steward.py b/xiaobai-datahub/tests/test_steward.py index 03056d3..6b5c2c1 100644 --- a/xiaobai-datahub/tests/test_steward.py +++ b/xiaobai-datahub/tests/test_steward.py @@ -54,6 +54,36 @@ class StewardQueryTests(unittest.TestCase): self.assertEqual(payload["meta"]["source"], "tushare") self.assertEqual(payload["data"][0]["ts_code"], "600000.SH") + def test_stock_filter_missing_from_active_snapshot_falls_back_inside_hub(self) -> None: + calls = [] + + def transport(api_name, params, fields): + calls.append((api_name, dict(params))) + if api_name == "stock_basic" and params.get("list_status") == "D": + return [ + { + "ts_code": "000627.SZ", + "symbol": "000627", + "name": "退市天茂", + "list_status": "D", + "list_date": "19961112", + } + ] + return fake_transport(api_name, params, fields) + + self.hub.pipeline.adapter._transport = transport + payload = self.hub.api.query_api( + { + "api_name": "stock_basic", + "params": {"list_status": "D"}, + "fields": "ts_code,name,list_status,list_date", + } + ) + + self.assertEqual(payload["meta"]["source"], "tushare") + self.assertEqual(payload["data"][0]["list_status"], "D") + self.assertIn(("stock_basic", {"list_status": "D"}), calls) + def test_rt_sw_k_is_blocked(self) -> None: from datahub.serving import ApiError