ZhuLinsen/daily_stock_analysis · error · DataFetchError

efinance 获取数据失败: {failure_message}

Error message

efinance 获取数据失败: {failure_message}

What it means

Generic terminal failure of EfinanceFetcher._fetch_stock_data: _build_history_failure_message classified the exception as something other than rate-limit/anti-bot (parse error, schema change, KeyError, network fault), and it is re-raised as DataFetchError with the categorized failure message attached.

Source

Thrown at data_provider/efinance_fetcher.py:474

            
            return df
            
        except Exception as e:
            api_elapsed = time.time() - api_start
            category, failure_message = self._build_history_failure_message(
                stock_code=stock_code,
                beg_date=beg_date,
                end_date=end_date_fmt,
                exc=e,
                elapsed=api_elapsed,
            )

            if category == "rate_limit_or_anti_bot":
                logger.warning(failure_message)
                raise RateLimitError(f"efinance 可能被限流: {failure_message}") from e

            logger.error(failure_message)
            raise DataFetchError(f"efinance 获取数据失败: {failure_message}") from e
    
    def _fetch_etf_data(self, stock_code: str, start_date: str, end_date: str) -> pd.DataFrame:
        """
        获取 ETF 基金历史数据

        Exchange-traded ETFs have OHLCV data just like regular stocks, so we use
        ef.stock.get_quote_history (the stock K-line API) which returns full
        open/high/low/close/volume data.

        Previously this method used ef.fund.get_quote_history which only returns
        NAV data (单位净值/累计净值) without volume or OHLC, causing:
        - Issue #541: 'got an unexpected keyword argument beg'
        - Issue #527: ETF volume/turnover always showing 0

        Args:
            stock_code: ETF code, e.g. '512400', '159883', '515120'
            start_date: Start date, format 'YYYY-MM-DD'
            end_date: End date, format 'YYYY-MM-DD'

View on GitHub (pinned to 5159bd72e8)

Solutions

  1. Read failure_message — it embeds the original exception and elapsed time, pinpointing parse vs network.
  2. Pin or upgrade efinance to a version known to match the parsing code (check requirements.txt consistency).
  3. If persistent, fail over via the manager to akshare/tushare and file/adjust the efinance normalizer.
Defensive patterns

Strategy: fallback

Validate before calling

# smoke-test the parsing path before batch runs
raw = efinance_fetcher._fetch_raw_data('600519', start, end)
normalized = efinance_fetcher._normalize_data(raw, '600519')
assert not normalized.empty

Try / catch

try:
    df = efinance_fetcher.get_daily_data(code, ...)
except DataFetchError as e:
    logger.warning('efinance parse failed for %s: %s', code, e.__cause__)
    df = manager.get_daily_data(code, ...)  # akshare/tushare fallback

Prevention

When it happens

Trigger: ef.stock.get_quote_history succeeding HTTP-wise but returning an unexpected shape; efraction/efinance library version changes renaming columns; KeyError/AttributeError inside response processing; non-throttle network errors.

Common situations: efinance package upgraded and response schema drifted; Eastmoney changed field names; stock suspended long-term returning a degenerate payload.

Related errors


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