ZhuLinsen/daily_stock_analysis · warning · DataFetchError

EfinanceFetcher 不支持美股 {stock_code},请使用 AkshareFetcher 或 Yfin

Error message

EfinanceFetcher 不支持美股 {stock_code},请使用 AkshareFetcher 或 YfinanceFetcher

What it means

Intentional capability guard in EfinanceFetcher._fetch_raw_data: efinance's Eastmoney backend does not serve US equities, so US tickers (regex ^[A-Z]{1,5}(\.[A-Z])?$) are rejected immediately so DataFetcherManager can fail over to AkShare/YFinance without wasting a request.

Source

Thrown at data_provider/efinance_fetcher.py:381

    def _fetch_raw_data(self, stock_code: str, start_date: str, end_date: str) -> pd.DataFrame:
        """
        从 efinance 获取原始数据
        
        根据代码类型自动选择 API:
        - 美股:不支持,抛出异常让 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()
        

View on GitHub (pinned to 5159bd72e8)

Solutions

  1. Route US codes through DataFetcherManager.get_daily_data so the US source_order (Finnhub/AlphaVantage/YFinance/Longbridge) is used.
  2. If calling fetchers directly, gate on _is_us_code / market detection before invoking EfinanceFetcher.
  3. Treat this exception as a skip signal, not a hard failure — catch DataFetchError and move to the next source.

Example fix

# before
for f in manager.fetchers:
    df = f.get_daily_data('AAPL', ...)  # raises for efinance
# after
df = manager.get_daily_data('AAPL', ...)  # market-routed
Defensive patterns

Strategy: validation

Validate before calling

from data_provider.efinance_fetcher import _is_us_code
if _is_us_code(code):
    df = manager.get_daily_data(code, ...)  # US chain
else:
    df = efinance_fetcher.get_daily_data(code, ...)

Type guard

def is_us_ticker(code: str) -> bool:
    return _is_us_code(code)

Try / catch

try:
    df = fetcher.get_daily_data(code, ...)
except DataFetchError as e:
    if '不支持美股' in str(e):
        continue  # capability skip, not an error

Prevention

When it happens

Trigger: Calling EfinanceFetcher.get_daily_data directly (bypassing the manager's market filter) with a US symbol like 'AAPL' or 'BRK.B'. Through the manager this normally never surfaces because the fetcher is filtered out for market='us'.

Common situations: Custom code iterating over fetchers manually instead of using DataFetcherManager; unit tests exercising every registered fetcher with a mixed stock list.

Related errors


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