"""股票代码规范化工具。""" from __future__ import annotations import re SUPPORTED_MARKETS = {"SH", "SZ", "BJ"} def normalize_ts_code(value: str | None) -> str: """把常见 A 股代码输入规范成 Tushare 格式。 支持: - 603779 -> 603779.SH - 300750 -> 300750.SZ - 430047 -> 430047.BJ - sh600519 / sz000001 / bj430047 - 600519.sh -> 600519.SH """ text = str(value or "").strip().upper() if not text: return "" compact_match = re.fullmatch(r"(SH|SZ|BJ)(\d{6})", text) if compact_match: market, code = compact_match.groups() return f"{code}.{market}" dotted_match = re.fullmatch(r"(\d{6})\.(SH|SZ|BJ)", text) if dotted_match: code, market = dotted_match.groups() return f"{code}.{market}" if re.fullmatch(r"\d{6}", text): if text.startswith(("6", "9")): return f"{text}.SH" if text.startswith(("0", "2", "3")): return f"{text}.SZ" if text.startswith(("4", "8")): return f"{text}.BJ" return text def split_ts_code(value: str | None) -> tuple[str, str]: """返回 (code, market),无法识别时抛出带上下文的 ValueError。""" normalized = normalize_ts_code(value) if "." not in normalized: raise ValueError(f"无效股票代码格式: {value!r}") code, market = normalized.split(".", 1) if not re.fullmatch(r"\d{6}", code) or market not in SUPPORTED_MARKETS: raise ValueError(f"无效股票代码格式: {value!r}") return code, market