# bukosabino/ta: forty-three technical indicators in a single pandas-native package

> A MIT licensed Python library that turns OHLCV financial series into indicator columns, with every indicator exposed twice, once as a class and once as a plain function.

**bukosabino/ta** — Technical Analysis Library using Pandas and Numpy

- Repository: https://github.com/bukosabino/ta
- Website: https://technical-analysis-library-in-python.readthedocs.io/en/latest/
- Stars: 5,238 · Forks: 1,163
- Language: Jupyter Notebook
- License: MIT
- Published: 2026-10-06 · Updated: 2026-10-06 · Language: en
- Canonical page: https://hysenlabs.com/projects/bukosabino-ta

## Forty-three indicators, each exposed twice

The README makes one headline claim, that the library has implemented 43 indicators, and then backs it with a table that has an ID column, a Name column, a Class column and a defs column. That structure is the most useful thing on the page, because it tells you the library is not one API but two parallel ones.

Look at the first nine rows, all under Volume. Money Flow Index maps to `MFIIndicator` and to `money_flow_index`. Accumulation/Distribution Index maps to `AccDistIndexIndicator` and `acc_dist_index`. On-Balance Volume maps to `OnBalanceVolumeIndicator` and `on_balance_volume`. The same pattern runs through the Volatility block: Average True Range is both `AverageTrueRange` and `average_true_range`, Bollinger Bands is `BollingerBands` with seven listed functions, Keltner Channel is `KeltnerChannel` with seven, Donchian Channel is `DonchianChannel`.

So a reader has a choice to make on day one. The class form takes an input series in the constructor and returns a value you can hold. The function form takes a series as an argument and returns one, which composes better inside a pandas `apply` or a pipeline cell. Having both means you can switch styles per indicator without rewriting the surrounding code.

The category list in the repository topics fills in what the visible tables start: volume, volatility, momentum, trend, oscillator, plus fundamental-analysis and financial as broader labels. The table also shows the naming convention is exact rather than approximate. Ease of Movement is listed as EoM, EMV and `EaseOfMovementIndicator`, and it carries two functions, `ease_of_movement` and `sma_ease_of_movement`, because a moving average of the indicator is treated as a separate function rather than something the caller composes.

## Input is one row set, output is another

The README's opening sentence defines the contract in one line: it is a technical analysis library for feature engineering from financial time series datasets, with Open, Close, High, Low and Volume as the inputs, built on Pandas and Numpy. That is the whole interface. There is no data loader, no ticker abstraction, no backtester and no broker connection anywhere in the repository tree.

That restraint is the design. `ta/` is the package, `test/` is the test suite, and everything else in the tree is tooling rather than features: `docs/`, `examples_to_use/`, `static/` for the Bollinger Bands image the README embeds, plus `MANIFEST`, `RELEASE.md` and `setup.cfg`. The absence of a data layer is what lets the library sit inside a notebook, a script or a training pipeline without arguing about where the numbers came from.

The dependency list is equally short and lives in `setup.py`.

```python
from distutils.core import setup

setup(
    name="ta",
    packages=["ta"],
    version="0.11.0",
    install_requires=[
        "numpy",
        "pandas",
    ],
)
```

Two runtime dependencies, numpy and pandas, and the package list is a single entry, `packages=["ta"]`. Nothing is optional at install time, so there is no extras mechanism to learn.

## setup.py still calls distutils, which matters on new Python

The first line of `setup.py` is worth pausing on. It imports `setup` from `distutils.core`, not from `setuptools`. distutils was deprecated in Python 3.10 and removed from the standard library in Python 3.12, so an install on a current interpreter depends on whichever installed copy of setuptools happens to be supplying the shim.

The rest of the file gives you the packaging metadata in full. The name is `ta`, the version is `0.11.0`, and the keywords are `technical analysis`, `python3` and `pandas`. The author and maintainer fields name Dario Lopez Padial. License metadata says The MIT License, and the classifier list includes `License :: OSI Approved :: MIT License` along with Python 3.6 and Python 3.7.

Those two classifiers are the second thing worth pausing on. They tell you the packaging metadata was written when 3.7 was current, which is consistent with the distutils import and with the `download_url` pointing at the 0.11.0 tarball. Nothing in the metadata claims support for a modern interpreter, and nothing claims incompatibility either, so the file simply predates the shift.

There is a matching detail in the `Makefile`, where the formatter runs `black --target-version py36`. The whole toolchain is pinned to a Python 3.6 syntax target, which tells you the code is conservative in style as well as in packaging.

The long description in `setup.py` also states the positioning more directly than the README does: a technical analysis library for financial time series datasets, usable to do feature engineering, built on the Python Pandas library.

## The Makefile is the actual developer workflow

Most Python repositories bury their contributor instructions in a CONTRIBUTING file. This one puts them in a Makefile, and the targets are worth reading because they tell you what the maintainer considers done.

```bash
init:
	pip install -r requirements.txt

test: lint
	coverage run -m unittest discover
	coverage report -m
```

`test` does not depend on `test` running tests directly. It depends on `lint`, which means lint failures block the test run. `lint` in turn depends on `isort`, which is `isort --check-only --recursive ta test`, so import ordering is enforced before anything else. After that, `prospector` runs twice, once over `test/` and once over `ta/`, using `--no-autodetect`.

The coverage side uses the standard library runner, `coverage run -m unittest discover`, followed by `coverage report -m`. That matches the `.coveragerc` and `.coveralls.yml` files in the tree, and the README carries a Coveralls badge for coverage status and a CircleCI badge for the build.

Formatting has the same shape. `format` depends on `isort` rather than on `isort-fix`, so running `make format` on a dirty tree checks ordering first and then runs `black` over `ta` and `test`. A separate `isort-fix` target exists for when you do want it to rewrite. There is also a `.prospector.yaml` and a `pylintrc`, so the linter configuration is committed rather than implicit.

What this tells you about the project is that it is defended by a fairly conventional Python gate: import order, a static linter, black formatting, unit tests, and a coverage number.

## Four requirements files instead of one

The tree carries five requirements files, which is more than a library this small strictly needs, and the naming scheme explains why. There is `requirements-core.txt`, then `requirements-test.txt`, `requirements-coverage.txt`, `requirements-doc.txt` and `requirements-play.txt`.

The top-level `requirements.txt` is not a list of packages at all. It is three inclusions and nothing else.

```bash
-r requirements-test.txt
-r requirements-coverage.txt
-r requirements-doc.txt
```

So `make init`, which runs `pip install -r requirements.txt`, installs the test, coverage and documentation stacks but not the core requirements, since numpy and pandas come from `install_requires` in `setup.py` instead. `requirements-play.txt` is the interesting one: it is present in the tree but excluded from the default file, which suggests a separate set of dependencies for trying the examples, most likely the Jupyter stack.

That also explains why the repository's primary language shows up as Jupyter Notebook rather than Python. The notebooks are not the library, they are the `examples_to_use/` directory, and `requirements-play.txt` exists to serve them separately from the library itself.

## A popular repository with an unusually large issue count

The repository has 5,226 stars, 1,158 forks and 158 open issues, on the `master` branch, under the MIT license, with the last push on 2026-03-18. It is not archived. There are no published releases, so the version to install is whatever PyPI currently serves, and the README carries both a PyPI version badge and a monthly downloads badge.

The fork count relative to the star count is the number that stands out, a little over a fifth of stars, which is what you see when people fork a library to add one indicator rather than to contribute it back. The issue count is the other one. A project with this many users accumulates issues faster than a single maintainer closes them, and 158 open with one maintainer listed in the metadata is consistent with that.

Set against those numbers, the shape of the project is clear. This is a widely used, thinly staffed, feature-complete-enough library. Forty-three indicators covering the standard volume, volatility, momentum, trend and oscillator families is well past the point where the hard part is coverage and well before the point where anyone would call it institutional. The absence of releases and the old distutils call are the cost of that shape, and both are things you can see before you install anything.

## Conclusion

ta earns its place in a feature engineering pipeline rather than in a trading application, which is exactly what its README says it is for. Its value is breadth without ceremony: forty-three indicators, two entry points each, numpy and pandas as the only runtime dependencies, and no configuration layer at all. The counterweights are equally plain, a setup.py still calling distutils.core, classifiers pinned to Python 3.6 and 3.7, and no tagged releases to install against. For a reader deciding whether to depend on it, the fastest check is to install it, run `ta.macd` and `ta.rsi` on your own frame, and read the source of the indicators you plan to trust, since the README documents which functions exist but not how each one handles the edges of your data.

## FAQ

### How do I install bukosabino/ta and what does it depend on?

Install it from PyPI as `ta`. The `setup.py` declares exactly two runtime dependencies, numpy and pandas, under `install_requires`, and installs a single package, `ta`, at version 0.11.0. Note that the packaging file imports from `distutils.core`, so on Python 3.12 or newer the install relies on setuptools supplying that module.

### What is the difference between the class and the function form of an indicator?

Every indicator is exposed twice, as a class such as `AverageTrueRange` and as a plain function such as `average_true_range`. The class form takes the input series at construction time, and the function form takes it as an argument, which is the one that composes inside pandas pipelines. Bollinger Bands, for example, lists seven functions against its single class.

### Does ta fetch stock data or run backtests?

No. The library's job is feature engineering on financial time series you already hold, taking Open, Close, High, Low and Volume as input. There is no data loader, ticker abstraction, backtester or broker connection in the repository, which is what lets it sit inside an existing notebook or training pipeline.

## Sources

- [bukosabino/ta on GitHub](https://github.com/bukosabino/ta)
- [Issues](https://github.com/bukosabino/ta/issues)
- [License: MIT](https://github.com/bukosabino/ta/blob/master/LICENSE)
- [Project website](https://technical-analysis-library-in-python.readthedocs.io/en/latest/)
- [README](https://github.com/bukosabino/ta/blob/master/README.md)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/bukosabino-ta
