{"record":{"id":"0ad2fd616668833a","repo":"ZhuLinsen/daily_stock_analysis","slug":"efinancefetcher-stock-code-aksharefe","errorCode":null,"errorMessage":"EfinanceFetcher 不支持港股日线 {stock_code}，请使用 AkshareFetcher 或其他港股数据源","messagePattern":"EfinanceFetcher 不支持港股日线 (.+?)，请使用 AkshareFetcher 或其他港股数据源","errorType":"exception","errorClass":"DataFetchError","httpStatus":null,"severity":"warning","filePath":"data_provider/efinance_fetcher.py","lineNumber":386,"sourceCode":"        - 美股：不支持，抛出异常让 DataFetcherManager 切换到其他数据源\n        - 普通股票：使用 ef.stock.get_quote_history()\n        - ETF 基金：使用 ef.stock.get_quote_history()（ETF 是交易所证券，使用股票 K 线接口）\n        \n        流程：\n        1. 判断代码类型（美股/股票/ETF）\n        2. 设置随机 User-Agent\n        3. 执行速率限制（随机休眠）\n        4. 调用对应的 efinance API\n        5. 处理返回数据\n        \"\"\"\n        # 美股不支持，抛出异常让 DataFetcherManager 切换到 AkshareFetcher/YfinanceFetcher\n        if _is_us_code(stock_code):\n            raise DataFetchError(f\"EfinanceFetcher 不支持美股 {stock_code}，请使用 AkshareFetcher 或 YfinanceFetcher\")\n\n        # efinance 的历史 K 线接口在港股代码上可能返回非预期市场数据，\n        # 明确跳过并交给 AkShare/Tushare/YFinance/Longbridge 等港股路径兜底。\n        if _is_hk_market(stock_code):\n            raise DataFetchError(f\"EfinanceFetcher 不支持港股日线 {stock_code}，请使用 AkshareFetcher 或其他港股数据源\")\n        \n        # 根据代码类型选择不同的获取方法\n        if _is_etf_code(stock_code):\n            return self._fetch_etf_data(stock_code, start_date, end_date)\n        else:\n            return self._fetch_stock_data(stock_code, start_date, end_date)\n    \n    def _fetch_stock_data(self, stock_code: str, start_date: str, end_date: str) -> pd.DataFrame:\n        \"\"\"\n        获取普通 A 股历史数据\n        \n        数据来源：ef.stock.get_quote_history()\n        \n        API 参数说明：\n        - stock_codes: 股票代码\n        - beg: 开始日期，格式 'YYYYMMDD'\n        - end: 结束日期，格式 'YYYYMMDD'\n        - klt: 周期，101=日线","sourceCodeStart":368,"sourceCodeEnd":404,"githubUrl":"https://github.com/ZhuLinsen/daily_stock_analysis/blob/5159bd72e8373d215492dff122acc9d389e219c9/data_provider/efinance_fetcher.py#L368-L404","documentation":"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.","triggerScenarios":"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').","commonSituations":"Direct fetcher iteration over mixed A-share/HK watchlists; tests that probe every fetcher with every market's codes.","solutions":["Use DataFetcherManager.get_daily_data for HK codes so the HK-capable chain handles them.","When calling fetchers directly, skip EfinanceFetcher for _is_hk_market codes.","Catch and treat as 'source skipped', continuing the failover chain — the message itself names the替代 sources."],"exampleFix":"# before\nfetcher = EfinanceFetcher()\ndf = fetcher.get_daily_data('hk00700', ...)  # raises\n# after\nfrom data_provider.base import get_fetcher_manager\ndf = get_fetcher_manager().get_daily_data('hk00700', ...)","handlingStrategy":"validation","validationCode":"from data_provider.efinance_fetcher import _is_hk_market\nif _is_hk_market(code):\n    df = manager.get_daily_data(code, ...)  # HK-capable chain\nelse:\n    df = efinance_fetcher.get_daily_data(code, ...)","typeGuard":"def is_hk_ticker(code: str) -> bool:\n    return _is_hk_market(code)","tryCatchPattern":"try:\n    df = fetcher.get_daily_data(code, ...)\nexcept DataFetchError as e:\n    if '不支持港股' in str(e):\n        continue  # intentional skip for correctness","preventionTips":["Never send HK codes to efinance's K-line endpoint — it can silently return wrong-market data.","Centralize market detection and reuse the same predicates the fetchers use.","Alert if HK codes appear in the EfinanceFetcher call path; that's a routing bug."],"tags":["efinance","hk-stocks","capability-guard","failover"],"backgroundTag":null,"analyzedSha":"5159bd72e8373d215492dff122acc9d389e219c9","analyzedAt":"2026-08-15T01:59:36.292Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}