diff --git a/xiaobai-datahub/datahub/adapters/eastmoney.py b/xiaobai-datahub/datahub/adapters/eastmoney.py index bb1bffc..81c731d 100644 --- a/xiaobai-datahub/datahub/adapters/eastmoney.py +++ b/xiaobai-datahub/datahub/adapters/eastmoney.py @@ -128,13 +128,19 @@ class EastmoneyAdapter(MarketAdapter): def fetch_quotes(self, codes: list[str]) -> list[dict[str, Any]]: # Eastmoney ulist.np accepts ~60 secids per request; page remaining codes. secids = [] + suffixes: dict[str, str] = {} for code in codes: ts = str(code or "").upper() symbol = ts.split(".")[0] - if ts.endswith(".SH") or symbol.startswith(("5", "6", "9")): + if ts.endswith(".BJ") or symbol.startswith(("4", "8", "92")): + secids.append(f"0.{symbol}") + suffixes[symbol] = "BJ" + elif ts.endswith(".SH") or symbol.startswith(("5", "6", "9")): secids.append(f"1.{symbol}") + suffixes[symbol] = "SH" else: secids.append(f"0.{symbol}") + suffixes[symbol] = "SZ" if not secids: return [] result: list[dict[str, Any]] = [] @@ -154,7 +160,7 @@ class EastmoneyAdapter(MarketAdapter): symbol = str(row.get("f12") or "") if not symbol: continue - ts_code = f"{symbol}.SH" if symbol.startswith(("5", "6", "9")) else f"{symbol}.SZ" + ts_code = f"{symbol}.{suffixes.get(symbol, 'SZ')}" epoch = int(finite_number(row.get("f124")) or 0) close = round4(finite_number(row.get("f2"))) previous = round4(finite_number(row.get("f18"))) @@ -462,10 +468,10 @@ def _normalize_market_quote(row: dict[str, Any]) -> dict[str, Any] | None: if close <= 0 or previous_close <= 0: return None market = int(finite_number(row.get("f13")) or 0) - if market == 1 or symbol.startswith(("5", "6", "9")): - ts_code = f"{symbol}.SH" - elif symbol.startswith(("4", "8")): + if market == 0 and symbol.startswith(("4", "8", "92")): ts_code = f"{symbol}.BJ" + elif market == 1 or symbol.startswith(("5", "6", "9")): + ts_code = f"{symbol}.SH" else: ts_code = f"{symbol}.SZ" epoch = int(finite_number(row.get("f124")) or 0) diff --git a/xiaobai-datahub/datahub/adapters/tencent.py b/xiaobai-datahub/datahub/adapters/tencent.py index 4981090..04374dc 100644 --- a/xiaobai-datahub/datahub/adapters/tencent.py +++ b/xiaobai-datahub/datahub/adapters/tencent.py @@ -158,10 +158,10 @@ def _tencent_symbol(code: str) -> str: symbol = raw.split(".")[0] if not symbol.isdigit() or len(symbol) != 6: return "" + if raw.endswith(".BJ") or symbol.startswith(("4", "8", "92")): + return f"bj{symbol}" if raw.endswith(".SH") or symbol.startswith(("5", "6", "9")): return f"sh{symbol}" - if raw.endswith(".BJ") or symbol.startswith(("4", "8")): - return f"bj{symbol}" return f"sz{symbol}" diff --git a/xiaobai-datahub/datahub/realtime_serve.py b/xiaobai-datahub/datahub/realtime_serve.py index b3cfb71..16b6235 100644 --- a/xiaobai-datahub/datahub/realtime_serve.py +++ b/xiaobai-datahub/datahub/realtime_serve.py @@ -616,6 +616,8 @@ def _guess_ts_code(code: str) -> str | None: if "." in raw: return raw if len(raw) == 6 and raw.isdigit(): + if raw.startswith(("4", "8", "92")): + return f"{raw}.BJ" if raw.startswith(("5", "6", "9")): return f"{raw}.SH" return f"{raw}.SZ" diff --git a/xiaobai-datahub/datahub/serving.py b/xiaobai-datahub/datahub/serving.py index 9114a91..db8f215 100644 --- a/xiaobai-datahub/datahub/serving.py +++ b/xiaobai-datahub/datahub/serving.py @@ -192,7 +192,7 @@ class V1API: limit, offset = self._page(q) today = yyyymmdd(now_shanghai()) batch_id, snapshot = self.pipeline.published_stock_snapshot(today) - if batch_id: + if batch_id and snapshot: # Formal view: the latest published stock snapshot, with batch # metadata. Filters are applied in-memory on the snapshot. pub = self.pipeline.latest_stocks_publication(today) or {} diff --git a/xiaobai-datahub/tests/test_realtime_intraday.py b/xiaobai-datahub/tests/test_realtime_intraday.py index a7b27cf..3364fb2 100644 --- a/xiaobai-datahub/tests/test_realtime_intraday.py +++ b/xiaobai-datahub/tests/test_realtime_intraday.py @@ -6,7 +6,8 @@ from pathlib import Path from unittest.mock import patch from datahub.adapters.base import AdapterError -from datahub.adapters.eastmoney import HIS_TRENDS_URL, TRENDS_URL, EastmoneyAdapter +from datahub.adapters.eastmoney import HIS_TRENDS_URL, TRENDS_URL, EastmoneyAdapter, _normalize_market_quote +from datahub.adapters.tencent import _tencent_symbol from datahub.db import HubDB from datahub.realtime_serve import fetch_intraday from datahub.serving import ApiError, V1API @@ -47,6 +48,15 @@ class EastmoneyIntradayLookbackTests(unittest.TestCase): self.assertEqual([point["time"] for point in payload["points"]], ["09:30", "15:00"]) self.assertEqual(payload["points"][0]["close"], 55.9) + def test_beijing_exchange_920_codes_keep_their_market(self): + self.assertEqual(_tencent_symbol("920703.BJ"), "bj920703") + self.assertEqual(_tencent_symbol("920703"), "bj920703") + quote = _normalize_market_quote({ + "f12": "920703", "f13": 0, "f2": 18.2, "f18": 18.0, + "f3": 1.1, "f5": 0, "f6": 0, + }) + self.assertEqual(quote["ts_code"], "920703.BJ") + def test_preferred_date_keeps_that_session(self): adapter = FakeEastmoney() payload = adapter.fetch_intraday("601318.SH", "20260907")