① 版本对吗
先 pip show 看分发名与版本,再看 ta.version。本站实测过「import 成功但装的是另一个分发」的情况,这一项能直接排掉。
下表按报错原文排列,共 11 条,全部来自本站实测或官方文档。先在浏览器里搜报错关键字,再按「原因 → 处置」执行。
| 报错原文 / 现象 | 触发原因 | 定位命令 | 处置 |
|---|---|---|---|
ERROR: No matching distribution found for pandas-ta | Python 版本低于 3.12,而 PyPI 上两个版本都要求 >=3.12 | python --version | 改用 pip install pandas-ta-classic |
AttributeError: 'Series' object has no attribute 'ta' | .ta 访问器只挂在 DataFrame 上 | print(type(obj)) | 改用 df.ta.rsi(...) 或模块级 ta.rsi(series, ...) |
AttributeError: 'NoneType' object has no attribute ... | 带 append=True 的调用返回 None,被当成结果继续用了 | print(type(result)) | 不要接返回值;或去掉 append |
| 一列都没加上(无异常) | 缺列(如没有 volume 却算 OBV)或行数不足 | print(df.columns, len(df)) | 补齐列或增加历史行数;文档见「数据契约」页 |
| 指标整列 NaN | 数据里有缺口(例如 resample 后插入周末空行),rolling 找不到连续窗口 | print(df.isna().sum()) | 在计算之前 df = df.dropna(),注意要赋值回去 |
TypeError: '_LazySubpackage' object is not callable | ta.volatility 是分类子包,遮蔽了同名的指标函数 | ta.utils.volatility(df['close']) | 改用 ta.utils.volatility(...)(实测返回 0.1609…) |
AttributeError: module 'pandas_ta_classic' has no attribute 'max' | max 只是内部别名(映射到 rolling_max),不是公开 API | print(hasattr(ta, 'max')) | 直接用 pandas 的 rolling(...).max() |
TypeError: sma() expected a pandas Series but got ndarray | 传了 numpy 数组(df['close'].values) | print(type(x)) | 传 Series;0.8.32 上该情况表现为返回 None + FutureWarning,更隐蔽 |
KeyError: 'BBU_20_2.0' | 列名里带参数;改了 length 或没传(默认 5)都会换名字 | print(df.columns) | 用 col_names 固定列名,或从返回值取列 |
AttributeError: 'AnalysisIndicators' object has no attribute 'cdl_2crows' | 访问器上不暴露单个形态方法 | df.ta.cdl_pattern(name='2crows') | 统一走 cdl_pattern(name=...) |
ta.version 读到 0.0.0 | 从源码安装且缺少 git 版本信息(该项目用 setuptools-scm 从 tag 生成版本号) | pip show pandas-ta-classic | 以 pip show 的版本为准;或改用 PyPI wheel 安装 |
这一节单独抽出来,因为「没有异常」最容易让人误判。以下三类问题本站都实测复现过。
| 类型 | 你怎么发现它 | 根因 | 修法 |
|---|---|---|---|
| 静默不加列 | 调用后 df.columns 没有变化 | 缺列或数据不足,库选择跳过而不是抛异常 | 在管道入口加列断言与长度断言(见「数据契约」页) |
| 静默回落 | 写了 talib=True 却不确定是否在用 C 实现 | 未安装 TA-Lib 时该参数被忽略,不报错 | 用 from pandas_ta_classic._meta import Imports; print(Imports['talib']) 确认真实状态 |
| 输出被污染 | 把 stdout 重定向成 JSON/CSV 时文件开头多了一段文字 | import 时会向 stdout 打印启动横幅(版本 + 255 项清单) | 把横幅写到 stderr 或丢弃;脚本里避免直接重定向 stdout |
contextlib.redirect_stdout 包住 import,或把 import 放在日志初始化之后,避免横幅混进结构化输出。ta.version、Imports、pandas.__version__、numpy.__version__。出现「我这能跑你那不行」时,这份日志是最快的定位材料。安装类问题的排查顺序很重要:先确认版本约束,再确认装到哪个分发,最后才怀疑网络。
| 现象 | 先查什么 | 再看什么 | 常见结论 |
|---|---|---|---|
| 找不到可用版本 | python --version | PyPI 上的 Requires-Python | 版本不匹配(本站实测 3.11 装不上原包) |
| 装上了但 import 失败 | pip show <包名> | 模块 __file__ 路径 | 装到了别的分发或别的解释器 |
| import 成功但不是想要的包 | pip list | findstr ta | 启动横幅里的版本号 | 本机实测 pandas-ta-openbb 也提供 pandas_ta 模块 |
| 疑似网络问题 | 换镜像重试 | 报错里是否有 SSL / timeout 字样 | 「No matching distribution」不是网络问题,换源无效 |
| 多环境混乱 | where python / python -m pip -V | 虚拟环境是否激活 | pip 与 python 指向不同环境 |
python -m venv venv)。把实验放进独立环境,能避免「把系统环境搞乱」和「查不清装了谁」两类麻烦。这一节处理「程序能跑,但结果不如预期」的问题。核心方法是先打印,再比对照,最后才改代码。
| 现象 | 该打印什么 | 第二步比什么 | 常见根因 |
|---|---|---|---|
| 数值看起来不合理 | df.head() 与 df.dtypes | 与简单指标(SMA)对账 | 复权口径不一致、字段单位不同(成交量单位),或索引不是时间 |
| 找不到列 | df.columns | 列名里的参数是否与调用一致 | 改了 length 或没传参数(默认值变了) |
| 列名重复 | df.columns[df.columns.duplicated()] | 是否把同一指标算了两次 | 重复 append;改用 prefix 区分 |
| 多列输出顺序记错 | 打印返回值本身 | 与你假设的顺序比 | BBands 的 5 列是 下轨/中轨/上轨/带宽/百分比,顺序容易记错 |
| 跨代码库结果不同 | 两边的包名与版本 | 两边参数与数据区间 | 一边在用另一个分发(如 pandas-ta-openbb) |
项目维护者最需要的信息是「能复现」。下面六个字段建议固化成模板,提 issue 或内部求助时一并贴上。
【pandas-ta 可复现报告模板】
1. 发行包与版本:pandas-ta-classic 0.8.32 (pip show 的输出)
2. 解释器与依赖:Python 3.11.9 / pandas 3.0.6 / numpy 2.4.6 / numba 未安装 / TA-Lib 未安装
3. 安装方式:pip install pandas-ta-classic(或 uv / 源码)
4. 数据概述:60 行日线,列名 open/high/low/close/volume(是否 MultiIndex、是否有缺口、是否复权)
5. 最小复现代码:10 行以内,能独立跑出问题
6. 实际输出 与 期望输出:贴原文,不要只说「结果不对」
| 字段 | 为什么维护者一定需要它 | 漏掉会怎样 |
|---|---|---|
| 包名与版本 | 同名分支多,先要确定是哪一条线 | 回答会基于错误的代码版本 |
| 解释器与依赖版本 | numpy/pandas 大版本会显著影响行为 | 无法判断是环境问题还是实现问题 |
| 安装方式 | 源码安装与 wheel 安装的行为可能不同 | 复现不出来 |
| 数据概述 | 列名、缺口、复权是最高频的三类根因 | 被当成实现 bug 排查很久 |
| 最小复现代码 | 把问题从业务代码里剥离出来 | 无法定位到具体调用 |
| 实际与期望输出 | 把「不对」变成可比对的字符串 | 变成一轮又一轮的来回询问 |
在贴出问题之前,先过一遍下面五项。它们覆盖了本站遇到过的绝大多数「不是 bug」的求助。
先 pip show 看分发名与版本,再看 ta.version。本站实测过「import 成功但装的是另一个分发」的情况,这一项能直接排掉。
打印 df.columns,确认 open/high/low/close/volume 都在。缺列时库不报错,只会什么都不做——这是最高频的原因。
打印 len(df) 与你要用的窗口长度。行数少于窗口时同样静默不输出。另外注意有缺口时起点会后移。
打印一下列名:SMA_10 说明你在用默认窗口 10;BBL_5_2.0 说明布林带默认 length=5。很多「结果不对」其实是默认参数与预期不同。
用 pandas 复算一次 SMA 或 BBands 中轨。若能对上,说明管道没问题;对不上就优先查数据(顺序、缺口、复权),而不是查库。
把上一节的模板贴全。这不只是礼貌问题——它决定了对方能不能复现,进而决定了这个问题能不能被解决。
下面的回答都指向可核验的官方文件或本站实测;与官方表述冲突时,以官方仓库与文档为准。
因为 .ta 只注册在 DataFrame 上,不在 Series 上。实测报 AttributeError: 'Series' object has no attribute 'ta'。只有 Series 时请用模块级函数:ta.rsi(series, length=14)。
这属于静默失败,两个原因:缺列、或行数不足。先打印 df.columns 与 len(df)。建议把这个检查固化成管道入口的断言,否则以后还会再踩。
因为 volatility 这个名字被分类子包占用了,实测报 TypeError: '_LazySubpackage' object is not callable。同名指标在 ta.utils.volatility,实测可用。
先确认 pip 与 python 指向同一个环境(python -m pip -V),再确认模块路径(ta.__file__)。多环境是这类问题的首要嫌疑。
该项目用 setuptools-scm 从 git tag 生成版本号;从源码安装且缺少版本信息时可能读到异常值。以 pip show 的输出为准,或改用 PyPI 上的 wheel 安装。
因为 import 时会向 stdout 打印启动横幅(版本与 255 项清单)。如果你把 stdout 重定向到文件,这段文字会一起写进去。用 redirect_stdout 隔离 import 即可。