ZhuLinsen/daily_stock_analysis · error · DataFetchError

无法识别 ETF 代码 {stock_code}

Error message

无法识别 ETF 代码 {stock_code}

What it means

Raised by _build_eastmoney_etf_secid in EfinanceFetcher: after normalize_stock_code, the code does not satisfy _is_a_share_etf_code, so no Eastmoney ETF secid can be built. It is a routing/classification error — a non-A-share-ETF code reached the A-share ETF K-line path.

Source

Thrown at data_provider/efinance_fetcher.py:173

    
    ETF 代码规则:
    - 上交所 ETF: 51xxxx, 52xxxx, 56xxxx, 58xxxx
    - 深交所 ETF: 15xxxx, 16xxxx, 18xxxx
    
    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))

View on GitHub (pinned to 5159bd72e8)

Solutions

  1. Verify the code is a genuine A-share ETF (SH 51/56/58/60 prefixes, SZ 15/16/18 prefixes per _ETF_SH_PREFIXES/_ETF_SZ_PREFIXES).
  2. Check what normalize_stock_code does to the input — ensure you pass the bare 6-digit code without exchange suffix.
  3. If you support new ETF prefixes, extend _ETF_SH_PREFIXES/_ETF_SZ_PREFIXES rather than bypassing the check.

Example fix

# before
fetcher.get_daily_data('510300.SH', ...)  # suffix may break classification
# after
fetcher.get_daily_data('510300', ...)
Defensive patterns

Strategy: validation

Validate before calling

from data_provider.efinance_fetcher import _is_etf_code
code = normalize_stock_code(user_input)
if not _is_etf_code(code):
    raise ValueError(f'{user_input} is not an A-share ETF; route to stock path')

Type guard

def is_a_share_etf(code: str) -> bool:
    c = normalize_stock_code(code)
    return _is_etf_code(c)

Try / catch

try:
    df = fetcher.get_daily_data(code, ...)
except DataFetchError as e:
    if '无法识别 ETF' in str(e):
        df = fetcher._fetch_stock_data(code, ...)  # or route via manager

Prevention

When it happens

Trigger: Calling EfinanceFetcher._fetch_etf_data (or get_daily_data routed to the ETF branch because _is_etf_code matched) with a code that normalize_stock_code mangles or that matches the outer ETF heuristic but not _is_a_share_etf_code — e.g. LOF/funds with unexpected prefixes, codes with typos, or non-CN fund identifiers.

Common situations: User passes a mutual-fund or bond code (e.g. 5-digit odd prefix) that the generic ETF heuristic accepts but the A-share ETF prefix list rejects; code normalization strips or keeps a suffix inconsistently.

Related errors


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