100% FreeNo Signup Required

pandas_ta Column Names

Which columns each indicator actually appends to your DataFrame. Captured by running the library against real price data, not copied from documentation.

Why BBM_20_2.0 raises a KeyError today

The 0.3.x release line is no longer installable from PyPI. A fresh `pip install pandas_ta` today gives 0.4.x, whose generated column names differ from every tutorial written against 0.3.x.

IndicatorName in 0.3.x tutorialsMeasured in 0.4.71b0
bbandsBBL_20_2.0 / BBM_20_2.0 / BBU_20_2.0BBL_5_2.0_2.0 / BBM_5_2.0_2.0 / BBU_5_2.0_2.0

default length changed 20 -> 5, and the suffix gained a fourth component. The 0.3.x names are recorded here as they appear in tutorials — they could not be re-measured, because that release is no longer installable (pip install pandas_ta==0.3.14b0 in a clean venv returned 'No matching distribution found ... (from versions: 0.4.67b0, 0.4.71b0)'). Only the 0.4.71b0 column is measured.

Every column, measured on 0.4.71b0

Defaults only — change a parameter and the suffix changes with it. Run df.ta.bbands(length=20) and the column becomes BBM_20_...; the suffix is the parameters.

CallColsColumns created
df.ta.bbands()5BBL_5_2.0_2.0, BBM_5_2.0_2.0, BBU_5_2.0_2.0, BBB_5_2.0_2.0, BBP_5_2.0_2.0
df.ta.macd()3MACD_12_26_9, MACDh_12_26_9, MACDs_12_26_9
df.ta.stoch()3STOCHk_14_3_3, STOCHd_14_3_3, STOCHh_14_3_3
df.ta.stochrsi()2STOCHRSIk_14_14_3_3, STOCHRSId_14_14_3_3
df.ta.adx()4ADX_14, ADXR_14_2, DMP_14, DMN_14
df.ta.atr()1ATRr_14
df.ta.rsi()1RSI_14
df.ta.ema()1EMA_10
df.ta.sma()1SMA_10
df.ta.wma()1WMA_10
df.ta.vwap()1VWAP_D
df.ta.obv()1OBV
df.ta.cci()1CCI_14_0.015
df.ta.mfi()1MFI_14
df.ta.willr()1WILLR_14
df.ta.psar()4PSARl_0.02_0.2, PSARs_0.02_0.2, PSARaf_0.02_0.2, PSARr_0.02_0.2
df.ta.supertrend()4SUPERT_7_3.0, SUPERTd_7_3.0, SUPERTl_7_3.0, SUPERTs_7_3.0
df.ta.kc()3KCLe_20_2, KCBe_20_2, KCUe_20_2
df.ta.donchian()3DCL_20_20, DCM_20_20, DCU_20_20
df.ta.aroon()3AROOND_14, AROONU_14, AROONOSC_14
df.ta.ao()1AO_5_34
df.ta.apo()1APO_12_26
df.ta.bop()1BOP
df.ta.cmf()1CMF_20
df.ta.coppock()1COPC_11_14_10
df.ta.dm()2DMP_14, DMN_14
df.ta.efi()1EFI_13
df.ta.eom()1EOM_14_100000000
df.ta.kdj()3K_9_3, D_9_3, J_9_3
df.ta.kst()2KST_10_15_20_30_10_10_10_15, KSTs_9
df.ta.massi()1MASSI_9_25
df.ta.mom()1MOM_10
df.ta.natr()1NATR_14
df.ta.ppo()3PPO_12_26_9, PPOh_12_26_9, PPOs_12_26_9
df.ta.pvo()3PVO_12_26_9, PVOh_12_26_9, PVOs_12_26_9
df.ta.qstick()1QS_10
df.ta.roc()1ROC_10
df.ta.rvi()1RVI_14
df.ta.slope()1SLOPE_1
df.ta.squeeze()4SQZ_20_2.0_20_1.5, SQZ_ON, SQZ_OFF, SQZ_NO
df.ta.trix()2TRIX_30_9, TRIXs_30_9
df.ta.tsi()2TSI_13_25_13, TSIs_13_25_13
df.ta.uo()1UO_7_14_28
df.ta.vortex()2VTXP_14, VTXM_14
df.ta.zscore()1ZS_30

How to read a suffix

pandas_ta names each output NAME_param1_param2...using the parameters the call actually ran with — which is why the name changes when you change a default, and why hardcoding a column string breaks silently on upgrade. The robust pattern is to take the returned frame's columns rather than typing the name: bb = df.ta.bbands(); mid = bb.iloc[:, 1], or bb.filter(like='BBM').

Measured on 400 real AAPL bars (2025-01-15 to 2026-08-19), pandas_ta 0.4.71b0, Python 3.12.10. Regenerate with python -m pipeline.pandas_ta_columns.