ZhuLinsen/daily_stock_analysis · error · DataFetchError

无法识别港股代码 {raw_code}

Error message

无法识别港股代码 {raw_code}

What it means

DataFetchError raised in the HK branch of TushareFetcher code normalization when an HK-market code contains no digits after stripping non-digit characters (re.sub(r'\D', '', raw_code) is empty). The fetcher needs a numeric HK code to build the 5-digit .HK ts_code, so codes like 'hk', '.HK', or 'hk.XY' are rejected.

Source

Thrown at data_provider/tushare_fetcher.py:459

    def _convert_hk_stock_code_for_tushare(self, stock_code: str) -> str:
        """
        将用户输入转为 Tushare Pro 接口所需的 ts_code(含港股 nnnnn.HK)。

        - 非港股:委托 _convert_stock_code(A 股 / ETF / 北交所等)。
        - 港股:从 HK00700、00700、00700.HK 等形式归一为 5 位数字 + .HK。
        """
        raw_code = stock_code.strip()
        if _is_hk_market(raw_code):
            if "." in raw_code:
                ts_code = raw_code.upper()
                if ts_code.endswith(".SS"):
                    return f"{ts_code[:-3]}.SH"
                if ts_code.endswith(".HK"):
                    return ts_code
            digits = re.sub(r"\D", "", raw_code)
            if not digits:
                raise DataFetchError(f"无法识别港股代码 {raw_code}")
            code = digits[-5:].rjust(5, "0")
            return f"{code}.HK"
        return self._convert_stock_code(stock_code)

    @retry(
        stop=stop_after_attempt(3),
        wait=wait_exponential(multiplier=1, min=2, max=30),
        retry=retry_if_exception_type((ConnectionError, TimeoutError)),
        before_sleep=before_sleep_log(logger, logging.WARNING),
    )
    def _fetch_raw_data(self, stock_code: str, start_date: str, end_date: str) -> pd.DataFrame:
        """
        从 Tushare 获取原始数据
        
        根据代码类型选择不同接口:
        - 普通股票:daily()
        - ETF 基金:fund_daily()
        

View on GitHub (pinned to 5159bd72e8)

Solutions

  1. Fix the upstream code construction so HK codes always carry the numeric part (e.g. '00700', 'hk00700', '00700.HK').
  2. Validate user/watchlist input with a regex like ^\D*(\d{1,5})\D*$ before it reaches the fetcher.
  3. Reject or quarantine malformed codes at ingestion instead of letting them hit the provider layer.

Example fix

# before
raw = "hk."                       # matched as HK market, no digits -> DataFetchError
code = tushare_fetcher._convert_stock_code(raw)

# after
import re
m = re.search(r"(\d{1,6})", raw)
if m:
    code = m.group(1)[-5:].rjust(5, "0") + ".HK"   # safe to pass on
else:
    raise ValueError(f"invalid HK code: {raw!r}")  # fail at ingestion with clear input error
Defensive patterns

Strategy: validation

Validate before calling

import re

def valid_hk_code(raw: str) -> bool:
    """HK codes must contain at least one digit to be normalizable."""
    return bool(re.search(r"\d", raw))

if _is_hk_market(raw) and not valid_hk_code(raw):
    raise ValueError(f"malformed HK code: {raw!r}")  # reject at ingestion

Type guard

import re

def has_hk_digits(code: str) -> bool:
    """True when an HK-market code carries a numeric part."""
    return bool(re.search(r"\d", code))

Try / catch

try:
    ts_code = tushare_fetcher._convert_stock_code(raw)
except DataFetchError as e:
    if "无法识别港股代码" in str(e):
        raise ValueError(f"bad HK code from upstream: {raw!r}") from e  # surface as input error
    raise

Prevention

When it happens

Trigger: Passing a code matched by _is_hk_market that has no digits at all, e.g. 'hk', 'HK.', '.hk', or codes whose only content is a market prefix/suffix.

Common situations: Upstream parsing splitting 'hk00700' into prefix and empty body; watchlist typos; programmatic construction of codes producing prefix-only strings; malformed user input in bot commands.

Related errors


AI-assisted analysis of ZhuLinsen/daily_stock_analysis@5159bd72e8 (2026-08-15). Data as JSON: /api/errors/c852b61566b30e1d. Report an issue: GitHub.