polars_ta_lib exposes every TA-Lib 0.8.3 indicator as a Polars expression
plugin. The backend is TA-Lib's official pure-Rust crate: no C toolchain, no
global initialization, and no per-row Python callbacks.
| Indicators | 237, across all 10 TA-Lib groups |
| Backend | ta-lib 0.8.3, pure Rust |
| API | Top-level functions: pta.sma(...), pta.atr(...), pta.macd() |
| Inputs | Dense, finite numeric columns; conventional column defaults |
| Outputs | Float64, Int32, or a Struct of outputs |
| Warm-up rows | Polars null, never NaN/0 sentinels |
| Docs | MkDocs Material, generated from TA-Lib metadata |
Install
The targeted PyPI name is
polars_ta_lib_extension(canonical:polars-ta-lib-extension); it is currently unoccupied. Publication is pending, so build from source for now.
# from PyPI, once published
pip install polars_ta_lib_extension
# from source
uv venv
uv pip install maturin "polars>=2.1,<3"
uv run maturin develop --uv
Requirements: Python 3.11+, Polars 2.1+, Rust 1.95+.
PyPI distribution is polars_ta_lib_extension; the Python import remains
polars_ta_lib.
Compatibility
| Polars | Python | Status |
|---|---|---|
| 2.1.0 | 3.11 | tested |
| 2.1.0 | 3.12 | tested |
Quick start
import polars as pl
import polars_ta_lib as pta
df = pl.DataFrame(
{
"open": [1.0, 2.0, 3.0, 4.0, 5.0],
"high": [2.0, 3.0, 4.0, 5.0, 6.0],
"low": [0.5, 1.5, 2.5, 3.5, 4.5],
"close": [1.0, 2.0, 3.0, 4.0, 5.0],
"volume": [10.0, 20.0, 30.0, 40.0, 50.0],
}
)
out = df.with_columns(
pta.sma(time_period=3).alias("sma3"),
pta.atr(time_period=3).alias("atr3"),
pta.macd().struct.field("macd_signal").alias("macd_signal"),
pta.cdlengulfing().alias("engulfing"),
)
shape: (5, 9)
┌──────┬──────┬─────┬───────┬───┬──────┬──────┬─────────────┬───────────┐
│ open ┆ high ┆ low ┆ close ┆ … ┆ sma3 ┆ atr3 ┆ macd_signal ┆ engulfing │
│ f64 ┆ f64 ┆ f64 ┆ f64 ┆ ┆ f64 ┆ f64 ┆ f64 ┆ i32 │
╞══════╪══════╪═════╪═══════╪═══╪══════╪══════╪═════════════╪═══════════╡
│ 1.0 ┆ 2.0 ┆ 0.5 ┆ 1.0 ┆ … ┆ null ┆ null ┆ null ┆ null │
│ 2.0 ┆ 3.0 ┆ 1.5 ┆ 2.0 ┆ … ┆ null ┆ null ┆ null ┆ null │
│ 3.0 ┆ 4.0 ┆ 2.5 ┆ 3.0 ┆ … ┆ 2.0 ┆ null ┆ null ┆ 0 │
│ 4.0 ┆ 5.0 ┆ 3.5 ┆ 4.0 ┆ … ┆ 3.0 ┆ 2.0 ┆ null ┆ 0 │
│ 5.0 ┆ 6.0 ┆ 4.5 ┆ 5.0 ┆ … ┆ 4.0 ┆ 2.0 ┆ null ┆ 0 │
└──────┴──────┴─────┴───────┴───┴──────┴──────┴─────────────┴───────────┘
API
Input defaults
Single-series indicators default to close; price components default to the
column of the same name. Multiple real inputs are required.
pta.sma(time_period=20) # pl.col("close")
pta.atr(time_period=14) # high, low, close
pta.cdlengulfing() # open, high, low, close
pta.beta(pl.col("a"), pl.col("b")) # required
| Input | Default |
|---|---|
real |
pl.col("close") |
real0 / real1 |
required |
periods |
pl.col("periods") |
| price components | pl.col("high"), pl.col("low"), … |
Multi-output
Multi-output indicators return a Struct; access a field with
.struct.field(...) or unnest the column.
pta.macd() # macd, macd_signal, macd_hist
pta.bbands() # upper_band, middle_band, lower_band
pta.stoch() # slow_k, slow_d
pta.minmaxindex() # min_idx, max_idx
Parameters
Names are snake_case. TA-Lib's original names stay available in the metadata. List parameters accept the numeric value or its display name.
pta.ma(time_period=20, ma_type="sma")
pta.ma(time_period=20, ma_type=0)
Inspect everything at runtime:
pta.FUNCS["atr"] # metadata: inputs, params, defaults, outputs
pta.functions() # all 237 entries
Grouping
Use .over("symbol"). Each group starts its own warm-up window.
df.with_columns(
pta.sma(time_period=20).over("symbol").alias("sma20")
)
Sort by time within each symbol before computing history-dependent indicators.
Semantics
Input contract
Inputs must be numeric, dense, and finite. Null, NaN, or ±Inf raises a
ComputeError naming the column and position:
input `close` contains 1 null(s), first at index 1;
drop, fill or forward-fill them before using TA-Lib
Clean explicitly:
df.filter(pl.col("close").is_not_null())
# or
df.with_columns(pl.col("close").forward_fill())
Output contract
- Rows before an indicator's lookback are Polars null, including
Int32outputs.0is never a missing sentinel. - Output length always equals input length.
- Empty or too-short inputs return a correctly typed, all-null column.
- TA-Lib may produce NaN or ±Inf for math transforms (for example
acosoutside[-1, 1]); those values pass through unchanged.
Performance
Local smoke test, dev build, 1M rows, 16 threads. Not a benchmark.
| Indicator | Time |
|---|---|
| SMA(20) | 28.7 ms |
| EMA(20) | 19.9 ms |
| RSI(14) | 21.6 ms |
| ATR(14) | 54.8 ms |
| MACD(12, 26, 9) | 27.3 ms |
The hot path borrows a dense single-chunk Float64 column without copying,
allocates each output once, and lets TA-Lib write directly into the final
buffer.
How it works
flowchart LR
A["polars_ta_lib.sma(...)"] --> B["register_plugin_function"]
B --> C["one #[polars_expr] call"]
C --> D["ta-lib abstract API\nParamHolder / lookback / call"]
D --> E["Float64 / Int32 / Struct\nwith null warm-up"]
- Python functions are generated at import time from
_internal.functions_json(), so a new TA-Lib release needs no hand-written wrappers. - The Rust engine binds inputs and parameters through TA-Lib's abstract API and returns full-length buffers; the plugin boundary adds the null validity bitmap.
- One generic plugin expression covers all 237 indicators.
Testing
uv run pytest -q
The suite covers:
- all 237 functions, compared against
polars-talib-fast==2.0.0; - parameter parity (
SMA,BBANDS,MACD,STOCH); - grouped
.over(), empty/short inputs, multi-chunk inputs; Int32/Float32casts, null/NaN/Inf errors, invalid parameters.
Current status: 24 tests passed.
Documentation
The API reference is generated from pta.FUNCS with MkDocs Material:
uv pip install "mkdocs>=1.6,<2" mkdocs-material
python tools/generate_docs.py
mkdocs build --strict # output in site/
# or: mkdocs serve
Status
Core v1 is complete:
- 237 top-level functions
- Pythonic parameter and Struct field names
- Polars-native null output
- Generated signatures, docstrings, and type stubs
- 237-function parity tests
- MkDocs API reference
- abi3 wheel build
Not yet included:
.taexpression namespaceunstable_period/ candle-settings configuration- streaming / incremental API
- Series-level API
License
MIT. TA-Lib is BSD-3-Clause; see NOTICE and LICENSES/TA-Lib.txt.
Metadata
Release files for polars-ta-lib-extension 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| polars_ta_lib_extension-0.1.0.tar.gz | 61.5 kB | With provenance | Details for polars_ta_lib_extension-0.1.0.tar.gz |
Built distributions (wheels)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| polars_ta_lib_extension-0.1.0-cp311-abi3-win_amd64.whl | CPython 3.11 | abi3 | Windows x86-64 | Details for polars_ta_lib_extension-0.1.0-cp311-abi3-win_amd64.whl |
| polars_ta_lib_extension-0.1.0-cp311-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl | CPython 3.11 | abi3 | Linux glibc 2.17+ x86-64 | Details for polars_ta_lib_extension-0.1.0-cp311-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl |
| polars_ta_lib_extension-0.1.0-cp311-abi3-macosx_10_12_universal2.macosx_10_12_x86_64.macosx_11_0_arm64.whl | CPython 3.11 | abi3 | macOS 10.12+ universal2 (ARM64, x86-64), macOS 10.12+ x86-64, macOS 11.0+ ARM64 | Details for polars_ta_lib_extension-0.1.0-cp311-abi3-macosx_10_12_universal2.macosx_10_12_x86_64.macosx_11_0_arm64.whl |
Total release size: 18.8 MB
Release files / polars_ta_lib_extension-0.1.0.tar.gz
| Download URL | polars_ta_lib_extension-0.1.0.tar.gz |
|---|---|
| Size | 61.5 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
0d037dbc08ce5fea1c049e17a9e1a232bc99b96c43820eda716e0d13fafb1771
|
|
BLAKE2b-256 checksum How to use checksums |
c16bd43d7d9134246146e14a813f404cb5c73df404a654b2a90d3eaec075440e
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Nov 7, 2026.
Transparency logRelease files / polars_ta_lib_extension-0.1.0-cp311-abi3-win_amd64.whl
| Download URL | polars_ta_lib_extension-0.1.0-cp311-abi3-win_amd64.whl |
|---|---|
| Size | 5.2 MB |
| Tags | CPython 3.11 Windows x86-64 abi3 |
|
SHA-256 checksum How to use checksums |
a0bd03820a1633831ad572dd4714ccad7e6092399d195eb5809d18a5ccddd656
|
|
BLAKE2b-256 checksum How to use checksums |
bc1cc8bc11481845b7aee0102fa7a62e7fde6622c85156bc37e1e9aad9b43fcd
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Nov 7, 2026.
Transparency logRelease files / polars_ta_lib_extension-0.1.0-cp311-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl
| Download URL | polars_ta_lib_extension-0.1.0-cp311-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl |
|---|---|
| Size | 4.8 MB |
| Tags | CPython 3.11 Linux glibc 2.17+ x86-64 abi3 |
|
SHA-256 checksum How to use checksums |
65ded892421a30cdb8f4889caa4435dbfb6eb993d327361e013d6ae35330d770
|
|
BLAKE2b-256 checksum How to use checksums |
21cf57d4336c6b313e5a76d564461320d2b4bf89c6bd76863d95a8f003d1de65
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Nov 7, 2026.
Transparency logRelease files / polars_ta_lib_extension-0.1.0-cp311-abi3-macosx_10_12_universal2.macosx_10_12_x86_64.macosx_11_0_arm64.whl
| Download URL | polars_ta_lib_extension-0.1.0-cp311-abi3-macosx_10_12_universal2.macosx_10_12_x86_64.macosx_11_0_arm64.whl |
|---|---|
| Size | 8.7 MB |
| Tags | CPython 3.11 abi3 macOS 10.12+ universal2 (ARM64, x86-64) macOS 10.12+ x86-64 macOS 11.0+ ARM64 |
|
SHA-256 checksum How to use checksums |
a2a2606431d152fa0a290921436aa9d878d6701397865b62c47563354b6beee0
|
|
BLAKE2b-256 checksum How to use checksums |
77a7c64c86c94c03de1f69b6def6d6c548e505f53686a68bc26a181f2beb1eb9
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Nov 7, 2026.
Transparency logSecurity for polars-ta-lib-extension 0.1.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
All 4 files in this release have been uploaded with provenance metadata.
Attestation for polars_ta_lib_extension-0.1.0.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Nov 7, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.