ZhuLinsen/daily_stock_analysis · warning · DataFetchError

BaostockFetcher 不支持北交所 {stock_code},将自动切换其他数据源

Error message

BaostockFetcher 不支持北交所 {stock_code},将自动切换其他数据源

What it means

A guard DataFetchError raised in BaostockFetcher when is_bse_code(stock_code) is True — Beijing Stock Exchange codes (8xxxxx/4xxxxx style). Baostock does not cover BSE, so the fetcher raises with a message explicitly noting it will auto-switch sources ('将自动切换其他数据源'), matching the manager's fallback semantics.

Source

Thrown at data_provider/baostock_fetcher.py:213

        
        流程:
        1. 检查是否为美股(不支持)
        2. 使用上下文管理器管理连接
        3. 转换股票代码格式
        4. 调用 API 查询数据
        5. 将结果转换为 DataFrame
        """
        # 美股不支持,抛出异常让 DataFetcherManager 切换到其他数据源
        if _is_us_code(stock_code):
            raise DataFetchError(f"BaostockFetcher 不支持美股 {stock_code},请使用 AkshareFetcher 或 YfinanceFetcher")

        # 港股不支持,抛出异常让 DataFetcherManager 切换到其他数据源
        if _is_hk_market(stock_code):
            raise DataFetchError(f"BaostockFetcher 不支持港股 {stock_code},请使用 AkshareFetcher")

        # 北交所不支持,抛出异常让 DataFetcherManager 切换到其他数据源
        if is_bse_code(stock_code):
            raise DataFetchError(
                f"BaostockFetcher 不支持北交所 {stock_code},将自动切换其他数据源"
            )
        
        # 转换代码格式
        bs_code = self._convert_stock_code(stock_code)
        
        logger.debug(f"调用 Baostock query_history_k_data_plus({bs_code}, {start_date}, {end_date})")
        
        with self._baostock_session() as bs:
            try:
                # 查询日线数据
                # adjustflag: 1-后复权,2-前复权,3-不复权
                rs = bs.query_history_k_data_plus(
                    code=bs_code,
                    fields="date,open,high,low,close,volume,amount,pctChg",
                    start_date=start_date,
                    end_date=end_date,
                    frequency="d",  # 日线

View on GitHub (pinned to 5159bd72e8)

Solutions

  1. Route BSE codes to a BSE-capable source (e.g. Akshare's eastmoney interfaces).
  2. In a manager loop, catch and continue on this message — it is a skip, not a failure.
  3. Tag BSE codes in config so routing happens before the fetcher chain.

Example fix

# before
df = baostock_fetcher.fetch('832566', start, end)  # raises

# after
from src.utils.stock_utils import is_bse_code
if is_bse_code(code):
    df = akshare_fetcher.fetch(code, start, end)  # BSE-capable
else:
    df = baostock_fetcher.fetch(code, start, end)
Defensive patterns

Strategy: fallback

Validate before calling

from src.utils.stock_utils import is_bse_code
if is_bse_code(code):
    fetcher = akshare_fetcher  # BSE-capable source

Type guard

from src.utils.stock_utils import is_bse_code

def is_baostock_eligible(code: str) -> bool:
    """Baostock covers A-shares only; BSE (8xx/4xx) must go elsewhere."""
    return not is_bse_code(code)

Try / catch

try:
    df = baostock_fetcher.fetch(code, start, end)
except DataFetchError as e:
    if '北交所' in str(e):
        df = akshare_fetcher.fetch(code, start, end)
    else:
        raise

Prevention

When it happens

Trigger: Fetching BSE tickers such as '832566' or '430047' through BaostockFetcher. Deterministic guard before any baostock login/query, so the cost is just one exception in the fallback loop.

Common situations: Watchlists including BSE/NEEQ names after 2021 BSE launch; 8-prefixed codes colliding with Shenzhen prefixes in naive routing logic; users surprised Baostock lacks BSE coverage.

Related errors


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