ZhuLinsen/daily_stock_analysis · error · DataFetchError

无法确定 ETF {stock_code} 的 Eastmoney 市场前缀

Error message

无法确定 ETF {stock_code} 的 Eastmoney 市场前缀

What it means

Raised by _build_eastmoney_etf_secid when the code passes _is_etf_code but starts with neither _ETF_SH_PREFIXES nor _ETF_SZ_PREFIXES, so the Eastmoney market digit ('1.' for SH, '0.' for SZ) cannot be chosen. Means the ETF classifier and the prefix whitelist disagree.

Source

Thrown at data_provider/efinance_fetcher.py:178

    Args:
        stock_code: 股票/基金代码
        
    Returns:
        True 表示是 ETF 代码,False 表示是普通股票代码
    """
    return _is_a_share_etf_code(stock_code)


def _build_eastmoney_etf_secid(stock_code: str) -> str:
    """Build Eastmoney secid for A-share ETF historical K-line queries."""
    code = normalize_stock_code(stock_code)
    if not _is_etf_code(code):
        raise DataFetchError(f"无法识别 ETF 代码 {stock_code}")
    if code.startswith(_ETF_SH_PREFIXES):
        return f"1.{code}"
    if code.startswith(_ETF_SZ_PREFIXES):
        return f"0.{code}"
    raise DataFetchError(f"无法确定 ETF {stock_code} 的 Eastmoney 市场前缀")


def _is_us_code(stock_code: str) -> bool:
    """
    判断代码是否为美股
    
    美股代码规则:
    - 1-5个大写字母,如 'AAPL', 'TSLA'
    - 可能包含 '.',如 'BRK.B'
    """
    code = stock_code.strip().upper()
    return bool(re.match(r'^[A-Z]{1,5}(\.[A-Z])?$', code))


def _ef_call_with_timeout(func, *args, timeout=None, **kwargs):
    """Run an efinance library call in a thread with a timeout.

    efinance internally uses requests/urllib3 with no timeout, so when

View on GitHub (pinned to 5159bd72e8)

Solutions

  1. Confirm the code's actual exchange (SSE vs SZSE) from the fund's official page, then check it against _ETF_SH_PREFIXES/_ETF_SZ_PREFIXES in efinance_fetcher.py.
  2. Add the missing prefix to the correct tuple (with a regression test using the real code).
  3. If the code is not A-share, route it to the correct market fetcher instead of EfinanceFetcher's ETF path.

Example fix

# before
_ETF_SH_PREFIXES = ('51', '56', '58')
# after (new SSE ETF series)
_ETF_SH_PREFIXES = ('51', '56', '58', '60')
Defensive patterns

Strategy: validation

Validate before calling

from data_provider.efinance_fetcher import _ETF_SH_PREFIXES, _ETF_SZ_PREFIXES
code = normalize_stock_code(code)
if not (code.startswith(_ETF_SH_PREFIXES) or code.startswith(_ETF_SZ_PREFIXES)):
    raise ValueError(f'{code}: unknown ETF market prefix — extend prefix lists')

Type guard

def has_known_etf_prefix(code: str) -> bool:
    c = normalize_stock_code(code)
    return c.startswith(_ETF_SH_PREFIXES) or c.startswith(_ETF_SZ_PREFIXES)

Prevention

When it happens

Trigger: An A-share ETF code whose first digits fall outside the known SH/SZ ETF prefix ranges reaches the secid builder — new exchange prefix, LOF (16 is SZ so fine, but e.g. 50xxxx SH LOF variants), or an outdated prefix list.

Common situations: Exchange lists a new ETF series with an unseen prefix; the repo's prefix constants lag behind the market; user-supplied code from another market slipped through classification.

Related errors


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