{"record":{"id":"2039c8f8df20e38c","repo":"ZhuLinsen/daily_stock_analysis","slug":"efinance-failure-message-2039c8","errorCode":null,"errorMessage":"efinance 获取数据失败: {failure_message}","messagePattern":"efinance 获取数据失败: (.+?)","errorType":"exception","errorClass":"DataFetchError","httpStatus":null,"severity":"error","filePath":"data_provider/efinance_fetcher.py","lineNumber":474,"sourceCode":"            \n            return df\n            \n        except Exception as e:\n            api_elapsed = time.time() - api_start\n            category, failure_message = self._build_history_failure_message(\n                stock_code=stock_code,\n                beg_date=beg_date,\n                end_date=end_date_fmt,\n                exc=e,\n                elapsed=api_elapsed,\n            )\n\n            if category == \"rate_limit_or_anti_bot\":\n                logger.warning(failure_message)\n                raise RateLimitError(f\"efinance 可能被限流: {failure_message}\") from e\n\n            logger.error(failure_message)\n            raise DataFetchError(f\"efinance 获取数据失败: {failure_message}\") from e\n    \n    def _fetch_etf_data(self, stock_code: str, start_date: str, end_date: str) -> pd.DataFrame:\n        \"\"\"\n        获取 ETF 基金历史数据\n\n        Exchange-traded ETFs have OHLCV data just like regular stocks, so we use\n        ef.stock.get_quote_history (the stock K-line API) which returns full\n        open/high/low/close/volume data.\n\n        Previously this method used ef.fund.get_quote_history which only returns\n        NAV data (单位净值/累计净值) without volume or OHLC, causing:\n        - Issue #541: 'got an unexpected keyword argument beg'\n        - Issue #527: ETF volume/turnover always showing 0\n\n        Args:\n            stock_code: ETF code, e.g. '512400', '159883', '515120'\n            start_date: Start date, format 'YYYY-MM-DD'\n            end_date: End date, format 'YYYY-MM-DD'","sourceCodeStart":456,"sourceCodeEnd":492,"githubUrl":"https://github.com/ZhuLinsen/daily_stock_analysis/blob/5159bd72e8373d215492dff122acc9d389e219c9/data_provider/efinance_fetcher.py#L456-L492","documentation":"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.","triggerScenarios":"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.","commonSituations":"efinance package upgraded and response schema drifted; Eastmoney changed field names; stock suspended long-term returning a degenerate payload.","solutions":["Read failure_message — it embeds the original exception and elapsed time, pinpointing parse vs network.","Pin or upgrade efinance to a version known to match the parsing code (check requirements.txt consistency).","If persistent, fail over via the manager to akshare/tushare and file/adjust the efinance normalizer."],"exampleFix":null,"handlingStrategy":"fallback","validationCode":"# smoke-test the parsing path before batch runs\nraw = efinance_fetcher._fetch_raw_data('600519', start, end)\nnormalized = efinance_fetcher._normalize_data(raw, '600519')\nassert not normalized.empty","typeGuard":null,"tryCatchPattern":"try:\n    df = efinance_fetcher.get_daily_data(code, ...)\nexcept DataFetchError as e:\n    logger.warning('efinance parse failed for %s: %s', code, e.__cause__)\n    df = manager.get_daily_data(code, ...)  # akshare/tushare fallback","preventionTips":["Pin the efinance version in requirements.txt and retest parsing on upgrades.","Add schema contract tests for Eastmoney response columns.","Include e.__cause__ in logs — the wrapper message hides the concrete exception type."],"tags":["efinance","schema-drift","parse-error","data-provider"],"backgroundTag":null,"analyzedSha":"5159bd72e8373d215492dff122acc9d389e219c9","analyzedAt":"2026-08-15T01:59:36.292Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}