{"record":{"id":"225382fc9db3e0bc","repo":"ZhuLinsen/daily_stock_analysis","slug":"pytdx-e","errorCode":null,"errorMessage":"Pytdx 获取数据失败: {e}","messagePattern":"Pytdx 获取数据失败: (.+?)","errorType":"exception","errorClass":"DataFetchError","httpStatus":null,"severity":"error","filePath":"data_provider/pytdx_fetcher.py","lineNumber":374,"sourceCode":"                    count=count\n                )\n                \n                if data is None or len(data) == 0:\n                    raise DataFetchError(f\"Pytdx 未查询到 {stock_code} 的数据\")\n                \n                # 转换为 DataFrame\n                df = api.to_df(data)\n                \n                # 过滤日期范围\n                df['datetime'] = pd.to_datetime(df['datetime'])\n                df = df[(df['datetime'] >= start_date) & (df['datetime'] <= end_date)]\n                \n                return df\n                \n            except Exception as e:\n                if isinstance(e, DataFetchError):\n                    raise\n                raise DataFetchError(f\"Pytdx 获取数据失败: {e}\") from e\n    \n    def _normalize_data(self, df: pd.DataFrame, stock_code: str) -> pd.DataFrame:\n        \"\"\"\n        标准化 Pytdx 数据\n        \n        Pytdx 返回的列名：\n        datetime, open, high, low, close, vol, amount\n        \n        需要映射到标准列名：\n        date, open, high, low, close, volume, amount, pct_chg\n        \"\"\"\n        df = df.copy()\n        \n        # 列名映射\n        column_mapping = {\n            'datetime': 'date',\n            'vol': 'volume',\n        }","sourceCodeStart":356,"sourceCodeEnd":392,"githubUrl":"https://github.com/ZhuLinsen/daily_stock_analysis/blob/5159bd72e8373d215492dff122acc9d389e219c9/data_provider/pytdx_fetcher.py#L356-L392","documentation":"Catch-all DataFetchError wrapping any non-DataFetchError exception raised inside the pytdx fetch loop (to_df conversion, pandas datetime parsing, date filtering, or TDX API errors). The 'from e' chain preserves the original exception for diagnosis.","triggerScenarios":"api.to_df(data) failing on malformed payloads; pandas errors while parsing 'datetime' strings; KeyError from unexpected DataFrame columns; low-level TDX protocol errors surfacing mid-request.","commonSituations":"pytdx version changes altering returned columns; partially received network payloads; float precision / NaN issues in vol/amount columns breaking to_df; concurrent use of a non-thread-safe api session.","solutions":["Inspect the chained cause (raise ... from e — log e.__cause__) to identify whether it is a parsing, protocol, or data-shape failure.","Pin/upgrade pytdx to a version whose to_df output matches the normalization code.","Wrap at the manager level with provider fallback so a single pytdx parse failure does not kill the analysis run."],"exampleFix":"# before\ntry:\n    df = pytdx_fetcher.get_stock_data(code, start, end)\nexcept DataFetchError as e:\n    raise  # cause hidden, run aborts\n\n# after\ntry:\n    df = pytdx_fetcher.get_stock_data(code, start, end)\nexcept DataFetchError as e:\n    logger.warning(f\"pytdx fetch failed: {e}; cause={e.__cause__}\")\n    df = akshare_fetcher.get_stock_data(code, start, end)","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try:\n    df = pytdx_fetcher.get_stock_data(code, start, end)\nexcept DataFetchError as e:\n    logger.warning(f\"pytdx failure, cause: {e.__cause__!r}\")\n    df = akshare_fetcher.get_stock_data(code, start, end)  # or re-raise for non-fetch contexts","preventionTips":["Always log the chained cause (__cause__) for wrapper errors before deciding on a fix.","Pin the pytdx version so to_df output columns stay stable.","Do not share one TDX session across threads; open a session per request via _pytdx_session()."],"tags":["pytdx","wrapper-exception","parsing","fallback"],"backgroundTag":null,"analyzedSha":"5159bd72e8373d215492dff122acc9d389e219c9","analyzedAt":"2026-08-15T01:59:36.292Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}