ZhuLinsen/daily_stock_analysis · warning · DataFetchError

EfinanceFetcher 不支持港股日线 {stock_code},请使用 AkshareFetcher 或其他港

Error message

EfinanceFetcher 不支持港股日线 {stock_code},请使用 AkshareFetcher 或其他港股数据源

What it means

Intentional capability guard in EfinanceFetcher._fetch_raw_data: efinance's history K-line endpoint can return wrong-market data for HK codes, so港股 codes are rejected upfront and delegated to AkShare/Tushare/YFinance/Longbridge. Deliberate correctness protection, not a bug.

Source

Thrown at data_provider/efinance_fetcher.py:386

        - 美股:不支持,抛出异常让 DataFetcherManager 切换到其他数据源
        - 普通股票:使用 ef.stock.get_quote_history()
        - ETF 基金:使用 ef.stock.get_quote_history()(ETF 是交易所证券,使用股票 K 线接口)
        
        流程:
        1. 判断代码类型(美股/股票/ETF)
        2. 设置随机 User-Agent
        3. 执行速率限制(随机休眠)
        4. 调用对应的 efinance API
        5. 处理返回数据
        """
        # 美股不支持,抛出异常让 DataFetcherManager 切换到 AkshareFetcher/YfinanceFetcher
        if _is_us_code(stock_code):
            raise DataFetchError(f"EfinanceFetcher 不支持美股 {stock_code},请使用 AkshareFetcher 或 YfinanceFetcher")

        # efinance 的历史 K 线接口在港股代码上可能返回非预期市场数据,
        # 明确跳过并交给 AkShare/Tushare/YFinance/Longbridge 等港股路径兜底。
        if _is_hk_market(stock_code):
            raise DataFetchError(f"EfinanceFetcher 不支持港股日线 {stock_code},请使用 AkshareFetcher 或其他港股数据源")
        
        # 根据代码类型选择不同的获取方法
        if _is_etf_code(stock_code):
            return self._fetch_etf_data(stock_code, start_date, end_date)
        else:
            return self._fetch_stock_data(stock_code, start_date, end_date)
    
    def _fetch_stock_data(self, stock_code: str, start_date: str, end_date: str) -> pd.DataFrame:
        """
        获取普通 A 股历史数据
        
        数据来源:ef.stock.get_quote_history()
        
        API 参数说明:
        - stock_codes: 股票代码
        - beg: 开始日期,格式 'YYYYMMDD'
        - end: 结束日期,格式 'YYYYMMDD'
        - klt: 周期,101=日线

View on GitHub (pinned to 5159bd72e8)

Solutions

  1. Use DataFetcherManager.get_daily_data for HK codes so the HK-capable chain handles them.
  2. When calling fetchers directly, skip EfinanceFetcher for _is_hk_market codes.
  3. Catch and treat as 'source skipped', continuing the failover chain — the message itself names the替代 sources.

Example fix

# before
fetcher = EfinanceFetcher()
df = fetcher.get_daily_data('hk00700', ...)  # raises
# after
from data_provider.base import get_fetcher_manager
df = get_fetcher_manager().get_daily_data('hk00700', ...)
Defensive patterns

Strategy: validation

Validate before calling

from data_provider.efinance_fetcher import _is_hk_market
if _is_hk_market(code):
    df = manager.get_daily_data(code, ...)  # HK-capable chain
else:
    df = efinance_fetcher.get_daily_data(code, ...)

Type guard

def is_hk_ticker(code: str) -> bool:
    return _is_hk_market(code)

Try / catch

try:
    df = fetcher.get_daily_data(code, ...)
except DataFetchError as e:
    if '不支持港股' in str(e):
        continue  # intentional skip for correctness

Prevention

When it happens

Trigger: Calling EfinanceFetcher directly with an HK code (e.g. 'hk00700' / '00700.HK' matched by _is_hk_market); via the manager this is pre-filtered by _filter_daily_fetchers_for_market(market='hk').

Common situations: Direct fetcher iteration over mixed A-share/HK watchlists; tests that probe every fetcher with every market's codes.

Related errors


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