55 lines
1.5 KiB
Python
55 lines
1.5 KiB
Python
"""股票代码规范化工具。"""
|
|
|
|
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
|