pandas-ta · 数据契约

pandas-ta 的列名与数据要求:为什么算不出值,也不报错

「算了半天一列都没加上」是本站遇到过最多的问题。原因不是指标算法,而是库在缺列与数据不足时的行为是静默的。本节把契约、静默失败、缺口、预热期与 pandas 对账一次讲清。

核验日期 2026-10-10classic 0.8.32 实测pandas 3.0.6 复算
列名匹配(大小写不敏感)
缺列 → 静默不加列
长度不足 → 静默不加列
缺口 → 大片 NaN
依据本机运行期实测与官方 quickstart 的 NaN 章节绘制的数据门槛示意;非官方故障图。
pandas-ta · 列名契约

指标函数要求什么样的数据?

pandas-ta 不取数据,它假设你的 DataFrame 里已经有正确的列。下表列出各类指标需要的列,以及缺列时实测会发生什么——这一列比「需要什么」更重要。

指标类别需要的列缺列时的实测行为你该怎么防
单序列类(sma / ema / rsi / bbands)close 或显式传入的序列拿不到 close 时该次计算失败或被跳过先断言 close 存在;更稳的是显式传序列
带高低价的(atr / stoch / adx / psar)high、low、close缺 high 或 low 时同样被跳过做一次集合断言 {'high','low','close'} ⊆ columns
成交量类(obv / mfi / vwap)外加 volume实测:静默返回原 DataFrame,一列都不加,也不报错成交量类指标单独做列断言
K 线形态(cdl_pattern)open、high、low、close缺列时跳过形态依赖 open 列,容易被忽略
列名大小写Close 与 close 都可用实测大写列名一样能算出 SMA_20但大小写混用的表(Close 与 volume 并存)容易埋坑,建议统一小写
注意点MultiIndex 列(yfinance 常见)需要先展平展平前指标函数找不到列见下方「列结构」一节
这一页最重要的一条:缺列与数据不足时,库不会抛异常,而是静默地什么都不做。append=True 之后 df.columns 没有任何变化——如果你没断言列数,会以为「指标算完了」,实际上一个都没算。
pandas-ta · 两个静默失败

为什么不报错,却一列都没加上?

下面的复现步骤都是本站实测的真实行为。把它们加进你的数据检查函数,能提前拦掉大部分「算了但没算」的问题。

失败类型复现方式(实测)观察到的结果加什么断言
① 缺列把 DataFrame 的 volume 列删掉,再执行 d.ta.obv(append=True)形状仍为 60×4,没有新增任何列,无异常assert {"high","low","close"} <= set(df.columns)
② 数据不足取 10 行数据执行 d.ta.sma(length=20) 与 d.ta.rsi(length=14)形状仍为 10×5,没有新增任何列,无异常assert len(df) >= 需要的窗口长度
③ 缺口(这一种会静默出 NaN)对仅含交易日的日线执行 resample('D') 后会插入周末空行官方文档记载:300 行日线中含周末缺口时,224 个指标里 80 多个整列 NaN先 df = df.dropna() 再算(必须赋值回去)
  1. 把列断言写成函数 在管道入口加一个 check_ohlcv(df):断言必需列存在、索引为日期且递增、high >= max(open, close) >= min(open, close) >= low、无重复日期。返回一份检查结论,而不是抛异常。
  2. 把长度断言写进指标封装 包一层 safe_ta(df, fn, **kw):调用前记录 len(df) 与 set(df.columns),调用后比对是否真的新增了列;没新增就记一条日志。这样「静默失败」会变成可查记录。
  3. 把缺口处理前置 取数或重采样之后、算指标之前做一次 dropna();若业务上不能丢行(例如需要保留交易日对齐),就改成只在指标输入序列上做 dropna() 再对齐回原索引。
  4. 把这三条写进项目 README 让后来的协作者知道:这里不报错不等于算对了。本站的建议是把它写成「数据契约」一节,与指标默认参数放在一起。
pandas-ta · 列结构

yfinance 取来的 MultiIndex 列怎么处理?

pandas-ta 只认单层列名。直接从 yf.download() 拿到的表在批量下载时列是多层的,必须先展平。下表给出可复制的处理顺序。

步骤做什么命令示例为什么必须做
① 看列结构先打印列的层级数print(df.columns.nlevels)多层列下 df["close"] 取不到单列
② 展平多层列批量下载时通常只保留价格层df.columns = df.columns.get_level_values(0)取下价格层(Open/High/Low/Close/Volume)
③ 统一小写把列名规范成小写df.columns = [c.lower() for c in df.columns]虽然大写也能用,但混用容易埋坑
④ 只留需要的列丢掉 adj close 等多余列或明确保留策略df = df[["open","high","low","close","volume"]]避免后续误用复权列
⑤ 排序并去重索引保证日期递增且不重复df = df[~df.index.duplicated(keep="last")].sort_index()指标按顺序滚动,乱序会全错
⑥ 处理缺口决定 dropna 还是保留df = df.dropna()缺口会让依赖 rolling 的指标整列 NaN
注意点复权语义要与回测口径一致—用复权价算指标、用未复权价估收益是常见错误
本站不代取数据:pandas-ta 本身不提供行情接口,官方 quickstart 推荐配 yfinance 使用,仓库里也给了取数示例脚本。数据来源的选择、复权口径与合规要求都由你自己决定。
pandas-ta · 起始有效值

指标要跑多少行才有可用的数值?

指标不是从最开头就有值的。下面是本站实测的起始非空位置,用来估算你至少需要多少历史数据。

指标参数起始非空位置(实测)留数据时怎么算
smalength=200 基索引 19(第 20 行)至少留 length 行
atrlength=140 基索引 14RMA 平滑,先消耗 14 行
rsilength=1460 行数据里出现 46 个非空值约需 length + 1 行
macd12/26/9需要先跑满慢线窗口再加信号窗口保守留 26 + 9 行以上
bbands20 / 2.0与 sma 相同(中轨即均线)至少留 length 行
ichimoku9/26/26以最长窗口为准,另有前瞻位移留 26 × 2 行以上更稳
注意点以上是「无缺口」情况下的读数—有缺口时起点会后移,因为 rolling 需要连续非 NaN
做回测时要给预热期(warm-up)单独留出这段时间,否则最早那一批信号是在指标还没算出值的区间里产生的。本站的「未来函数审计」页给出了一种把预热期也纳入判定流程的做法。
pandas-ta · 与 pandas 对账

自己用 pandas 复算,能对上吗?

很多人会想「我用 pandas 自己写公式不就行了」。可以,但必须知道哪些能对上、哪些对不上。下表是本站用 pandas 3.0.6 逐项复算的最大绝对差。

指标复算公式最大绝对差结论与用法
sma(20)close.rolling(20).mean()0.0完全一致,可以互换
bbands(20, 2) 中轨close.rolling(20).mean()0.0一致
bbands(20, 2) 上轨mid + 2 × std(ddof=0)1e-12吻合 → 库用 ddof=0(与签名一致)
bbands(20, 2) 上轨(另一种口径)mid + 2 × std(ddof=1)0.1677不吻合,排除 ddof=1。自己复算时用错这个会整体偏移
ema(20)close.ewm(span=20, adjust=False).mean()0.0593不完全一致:种子与递推口径不同,别假定相等
rsi(14)朴素 Wilder(ewm(alpha=1/14))18.81差异很大:原因在平滑与种子细节,必须直接用库的输出
macd(12,26,9)ewm(span=12) − ewm(span=26)0.3821同样受 EMA 口径影响
atr(14)TR.rolling(14).mean() / TR.ewm(alpha=1/14)0.0889 / 0.0545两种都不完全一致;列名 ATRr_14 里的 r 表示 RMA 平滑
结论:简单移动平均与布林带可以自己复算;EMA、RSI、MACD、ATR 建议直接使用库输出,除非你把它的实现读透并逐值对齐。这也解释了为什么「我按公式写的 RSI 和库不一样」不是 bug。
pandas-ta · 数据检查单

接指标之前要检查哪些项?

把下面的检查项做成一个函数,在每次算指标前调用。它拦掉的是不会报错但结果错的问题。

检查项判据不通过的后果处置
必需列存在{'open','high','low','close','volume'} ⊆ columns静默不加列补列或改传显式序列
索引是日期且递增isinstance(index, DatetimeIndex) 且 index.is_monotonic_increasing滚动窗口按错顺序计算排序并转日期索引
索引无重复index.has_duplicates == False重采样与对齐出错去重
行数大于最大窗口len(df) > max_window指标整列 NaN 或静默无输出补历史数据或缩短窗口
OHLC 自洽high ≥ max(open, close)、low ≤ min(open, close)ATR / PSAR 等高低价指标失真修正数据或标注为异常
缺口比例可接受df.isna().mean() < 阈值依赖 rolling 的指标大面积 NaN先 dropna() 再算
数值列可运算用 df.dtypes 确认 OHLCV 五列都是数值型对象型列会让计算报错或静默跳过用 pd.to_numeric(errors="coerce") 转换并记录被强转的行数
成交量单位一致确认单位(股 / 手 / 千股)在整条管道里统一成交量类指标数值量级错乱但不会报错在取数层统一单位,并写进数据字典
FAQ

pandas-ta 数据问题常见问答:为什么没加列、为什么全是 NaN

下面的回答都指向可核验的官方文件或本站实测;与官方表述冲突时,以官方仓库与文档为准。

为什么我算完指标,DataFrame 一列都没多?

两种最可能:①列名不对或缺列(例如没有 volume 却算 OBV);②行数少于指标窗口。本站实测这两种情况都不抛异常,只是什么都不加。先打印 df.columns 与 len(df)。

列名一定要小写吗?

不一定。实测 Close 这样的大写列名同样能算出 SMA_20。但大小写混用(Close 与 volume 并存)容易埋坑,建议统一成小写。

从 yfinance 拿的数据为什么直接用不了?

批量下载时列是 MultiIndex(多层),而指标函数只认单层列名。需要先取价格层、转小写、排序去重、处理缺口,顺序见本页「列结构」一节。

全是 NaN 是算错了吗?

通常是三类原因:数据长度不够、数据里有缺口、或者你取错了列。官方 quickstart 明确记载:含周末缺口的日线上,224 个指标里有 80 多个会整列 NaN,而 ema/rma/atr 仍出值。官方给的解法是在计算之前 dropna(),并且必须赋值回去。

dropna() 放在计算前还是计算后?

放在计算之前。放在后面只能删掉 NaN,不能改变「滚动窗口看不到足够连续数据」这个事实。另外 daily.dropna() 会返回副本,写成单独一行等于没做。

自己用 pandas 写公式靠谱吗?

取决于指标。本站实测:SMA 与 BBands 中轨完全一致;BBands 上轨用 ddof=0 才吻合;但 EMA 差 0.06、RSI 差 18.8、MACD 差 0.38、ATR 差 0.05–0.09。所以简单均线可以自己写,振荡类建议直接用库输出。

下一步:确认你要用的指标在不在,默认参数是什么

数据摆对之后,下一个问题是「我要的指标有没有、默认参数是多少」。下一节把分类目录与数量口径讲清。