{"record":{"id":"e8d96623878ccaf5","repo":"ZhuLinsen/daily_stock_analysis","slug":"aksharefetcher-stock-code-yfinancefetc","errorCode":null,"errorMessage":"AkshareFetcher 不支持美股 {stock_code}，请使用 YfinanceFetcher 获取正确的复权价格","messagePattern":"AkshareFetcher 不支持美股 (.+?)，请使用 YfinanceFetcher 获取正确的复权价格","errorType":"exception","errorClass":"DataFetchError","httpStatus":null,"severity":"warning","filePath":"data_provider/akshare_fetcher.py","lineNumber":486,"sourceCode":"        \n        根据代码类型自动选择 API：\n        - 美股：不支持，抛出异常由 YfinanceFetcher 处理（Issue #311）\n        - 港股：使用 ak.stock_hk_hist()\n        - ETF 基金：使用 ak.fund_etf_hist_em()\n        - 普通 A 股：使用 ak.stock_zh_a_hist()\n        \n        流程：\n        1. 判断代码类型（美股/港股/ETF/A股）\n        2. 设置随机 User-Agent\n        3. 执行速率限制（随机休眠）\n        4. 调用对应的 akshare API\n        5. 处理返回数据\n        \"\"\"\n        # 根据代码类型选择不同的获取方法\n        if _is_us_code(stock_code):\n            # 美股：akshare 的 stock_us_daily 接口复权存在已知问题（参见 Issue #311）\n            # 交由 YfinanceFetcher 处理，确保复权价格一致\n            raise DataFetchError(\n                f\"AkshareFetcher 不支持美股 {stock_code}，请使用 YfinanceFetcher 获取正确的复权价格\"\n            )\n        elif _is_hk_code(stock_code):\n            return self._fetch_hk_data(stock_code, start_date, end_date)\n        elif _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        策略：\n        1. 优先尝试东方财富接口 (ak.stock_zh_a_hist)\n        2. 失败后尝试新浪财经接口 (ak.stock_zh_a_daily)\n        3. 最后尝试腾讯财经接口 (ak.stock_zh_a_hist_tx)\n        \"\"\"","sourceCodeStart":468,"sourceCodeEnd":504,"githubUrl":"https://github.com/ZhuLinsen/daily_stock_analysis/blob/5159bd72e8373d215492dff122acc9d389e219c9/data_provider/akshare_fetcher.py#L468-L504","documentation":"DataFetchError raised deliberately by AkshareFetcher when asked for a US stock: akshare's stock_us_daily has a known adjusted-price defect (akshare Issue #311), so the fetcher refuses US codes and instructs the caller to use YfinanceFetcher instead. This is a routing guard, not an incidental failure.","triggerScenarios":"Calling AkshareFetcher.fetch_stock_data (directly or via a data provider that doesn't route by market) with a US code such as 'AAPL', 'AMD', 'TSLA' — detected by _is_us_code(stock_code).","commonSituations":"Custom scripts or provider configurations that hardcode AkshareFetcher as the single source for all markets; new multi-market support added without per-market fetcher routing; accidentally passing a US ticker to an A-share pipeline.","solutions":["Use YfinanceFetcher for US stocks — it returns correctly adjusted prices.","If you use the repo's data provider facade, ensure codes are routed by market (A/HK/ETF -> akshare, US -> yfinance).","Catch DataFetchError with this message as a signal to reroute rather than retry.","Do not attempt to bypass by stripping the US check — the underlying akshare data is known-bad for this case."],"exampleFix":"# before\nfetcher = AkshareFetcher()\ndf = fetcher.fetch_stock_data('AAPL', '2024-01-01', '2024-12-31')  # raises\n\n# after\nfrom data_provider.yfinance_fetcher import YfinanceFetcher\ndf = YfinanceFetcher().fetch_stock_data('AAPL', '2024-01-01', '2024-12-31')","handlingStrategy":"validation","validationCode":"def pick_fetcher(stock_code: str):\n    import re\n    if re.fullmatch(r'[A-Z]{1,5}', stock_code.strip().upper()):\n        return YfinanceFetcher()   # US codes -> yfinance\n    return AkshareFetcher()        # A-share/HK/ETF -> akshare\n\nfetcher = pick_fetcher('AAPL')","typeGuard":"from data_provider.exceptions import DataFetchError\n\ndef is_us_unsupported_by_akshare(exc: Exception) -> bool:\n    return isinstance(exc, DataFetchError) and '请使用 YfinanceFetcher' in str(exc)","tryCatchPattern":"try:\n    df = akshare_fetcher.fetch_stock_data(code, start, end)\nexcept DataFetchError as e:\n    if '请使用 YfinanceFetcher' in str(e):\n        df = yfinance_fetcher.fetch_stock_data(code, start, end)  # reroute, don't retry akshare\n    else:\n        raise","preventionTips":["Route fetchers by market classification before calling (US -> yfinance).","Never bypass the US-code guard — akshare US adjusted prices are known-bad (akshare #311).","Centralize market detection (_is_us_code/_is_hk_code/_is_etf_code) so all call sites share one routing rule."],"tags":["akshare","us-stocks","data-provider","routing"],"backgroundTag":null,"analyzedSha":"5159bd72e8373d215492dff122acc9d389e219c9","analyzedAt":"2026-08-15T01:59:36.292Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}