ZhuLinsen/daily_stock_analysis · error · DataFetchError

Yahoo Finance 获取数据失败: {e}

Error message

Yahoo Finance 获取数据失败: {e}

What it means

Catch-all wrapper in YfinanceFetcher.fetch_stock_data: any non-DataFetchError exception from the yfinance call path is re-raised as DataFetchError with the original message. yfinance is a screen-scraping client of Yahoo endpoints, so breakages cluster around network errors, HTTP 429 rate limiting, and upstream HTML/API changes that newer yfinance versions patch.

Source

Thrown at data_provider/yfinance_fetcher.py:234

                multi_level_index=True
            )

            # 筛选出 yf_code 的列, 避免多只股票数据混淆
            if isinstance(df.columns, pd.MultiIndex) and len(df.columns) > 1:
                ticker_level = df.columns.get_level_values(1)
                mask = ticker_level == yf_code
                if mask.any():
                    df = df.loc[:, mask].copy()

            if df.empty:
                raise DataFetchError(f"Yahoo Finance 未查询到 {stock_code} 的数据")

            return df

        except Exception as e:
            if isinstance(e, DataFetchError):
                raise
            raise DataFetchError(f"Yahoo Finance 获取数据失败: {e}") from e

    def _normalize_data(self, df: pd.DataFrame, stock_code: str) -> pd.DataFrame:
        """
        标准化 Yahoo Finance 数据

        yfinance 返回的列名:
        Open, High, Low, Close, Volume(索引是日期)

        注意:新版 yfinance 返回 MultiIndex 列名,如 ('Close', 'AMD')
        需要先扁平化列名再进行处理

        需要映射到标准列名:
        date, open, high, low, close, volume, amount, pct_chg
        """
        df = df.copy()

        # 处理 MultiIndex 列名(新版 yfinance 返回格式)
        # 例如: ('Close', 'AMD') -> 'Close'

View on GitHub (pinned to 5159bd72e8)

Solutions

  1. Read the inner exception message {e}: '429' → slow down/cache; 'JSONDecodeError'/None-format errors → pip install -U yfinance and retry.
  2. Retry with backoff for transient network failures, or fall through to Tushare/Akshare via the data_provider chain.
  3. Pin a known-good yfinance version in requirements.txt once verified, and keep it updated when this error recurs repo-wide.
  4. For batches, add per-request delay or use yf.download with multiple tickers in one call to reduce request count.
Defensive patterns

Strategy: retry

Validate before calling

import yfinance, requests

requests.head("https://query1.finance.yahoo.com", timeout=5).raise_for_status()
assert yfinance.__version__ >= "0.2.40", "yfinance too old for current Yahoo API"

Try / catch

for attempt, delay in enumerate((0, 2, 8), 1):
    try:
        df = yfinance_fetcher.fetch_stock_data(code)
        break
    except DataFetchError as e:
        if attempt == 3 or "未查询到" in str(e):
            df = akshare_fetcher.fetch_stock_data(code)
            break
        time.sleep(delay)  # transient 429/network -> backoff

Prevention

When it happens

Trigger: yf.download raising for network timeouts, Yahoo rate limiting (429 'Too Many Requests'), JSONDecodeError after a Yahoo response-format change, or an outdated yfinance failing on the current endpoint contract. The empty-df case (184) is re-raised unchanged, not wrapped.

Common situations: yfinance pinned to an old version while Yahoo changed its API (very common; fixed only by upgrading yfinance); running large batch downloads that trip Yahoo rate limits; corporate proxy/egress rules blocking query1.finance.yahoo.com.

Related errors


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