Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 8 additions & 3 deletions .github/workflows/tests-dev.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ["3.9", "3.10", "3.11", "3.12", "3.13", "3.14"]
python-version: ["3.11", "3.12", "3.13", "3.14", "3.14t", "3.15", "3.15t"]
env:
TA_INCLUDE_PATH: ${{ github.workspace }}/ta-lib-c/include
TA_LIBRARY_PATH: ${{ github.workspace }}/ta-lib-c/lib
Expand Down Expand Up @@ -56,15 +56,20 @@ jobs:
cmake --install ta-lib-c-build

- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v4
uses: actions/setup-python@v6
with:
python-version: ${{ matrix.python-version }}
allow-prereleases: true

- name: Install dependencies
run: |
pip install --upgrade pip wheel setuptools
pip install -r requirements_test.txt
if [[ "${{ matrix.python-version }}" == *t ]]; then
# Polars has no free-threaded wheels; exercise NumPy and pandas here.
pip install -r requirements.txt pytest pandas
else
pip install -r requirements_test.txt
fi
pip install flake8

- name: Build cython modules in-place
Expand Down
11 changes: 8 additions & 3 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ["3.9", "3.10", "3.11", "3.12", "3.13", "3.14"]
python-version: ["3.11", "3.12", "3.13", "3.14", "3.14t", "3.15", "3.15t"]
steps:
- uses: actions/checkout@v3

Expand All @@ -31,15 +31,20 @@ jobs:
version: ${{ steps.talib_c.outputs.version }}

- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v4
uses: actions/setup-python@v6
with:
python-version: ${{ matrix.python-version }}
allow-prereleases: true

- name: Install dependencies
run: |
pip install --upgrade pip wheel setuptools
pip install -r requirements_test.txt
if [[ "${{ matrix.python-version }}" == *t ]]; then
# Polars has no free-threaded wheels; exercise NumPy and pandas here.
pip install -r requirements.txt pytest pandas
else
pip install -r requirements_test.txt
fi
pip install flake8

- name: Build cython modules in-place
Expand Down
55 changes: 27 additions & 28 deletions .github/workflows/wheels.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,7 @@ env:
PIP_NO_VERIFY: 0
PIP_VERBOSE: 1
CIBW_BEFORE_BUILD: pip install -U setuptools Cython wheel meson-python ninja && pip install -U numpy
CIBW_TEST_REQUIRES: pytest pandas maturin polars
CIBW_SKIP: "pp* cp313t* cp314t*"
CIBW_SKIP: "pp* cp39-* cp310-* cp313t*"

jobs:
build_linux_x86_64:
Expand All @@ -23,9 +22,9 @@ jobs:
runs-on: ${{ matrix.os }}
steps:
- name: Checkout repository
uses: actions/checkout@v4
uses: actions/checkout@v7
- name: Build wheels
uses: pypa/cibuildwheel@v3.2.1
uses: pypa/cibuildwheel@v4.2.1
env:
CIBW_BEFORE_ALL: |
bash ./tools/build_talib_linux.sh
Expand All @@ -47,7 +46,7 @@ jobs:
export LD_LIBRARY_PATH="/project/ta-lib-install/lib:$LD_LIBRARY_PATH"
auditwheel repair -w {dest_dir} {wheel}
- name: Upload wheels
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v7
with:
path: ./wheelhouse/*.whl
name: "ta_lib-${{ github.ref_name }}-linux_x86_64"
Expand All @@ -59,9 +58,9 @@ jobs:
runs-on: ${{ matrix.os }}
steps:
- name: Checkout repository
uses: actions/checkout@v4
uses: actions/checkout@v7
- name: Build wheels
uses: pypa/cibuildwheel@v3.2.1
uses: pypa/cibuildwheel@v4.2.1
env:
CIBW_BEFORE_ALL: |
bash ./tools/build_talib_linux.sh
Expand All @@ -83,19 +82,19 @@ jobs:
export LD_LIBRARY_PATH="/project/ta-lib-install/lib:$LD_LIBRARY_PATH"
auditwheel repair -w {dest_dir} {wheel}
- name: Upload wheels
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v7
with:
path: ./wheelhouse/*.whl
name: "ta_lib-${{ github.ref_name }}-linux_arm64"
build_windows_amd64:
name: Build Windows amd64 wheels
strategy:
matrix:
os: ["windows-2022"]
os: ["windows-2025-vs2026"]
runs-on: ${{ matrix.os }}
steps:
- name: Checkout the repository
uses: actions/checkout@v4
uses: actions/checkout@v7
- name: Set up MSVC for x64
uses: ilammy/msvc-dev-cmd@v1
with:
Expand All @@ -104,7 +103,7 @@ jobs:
run: tools/build_talib_windows.cmd
shell: cmd
- name: Build wheels
uses: pypa/cibuildwheel@v3.2.1
uses: pypa/cibuildwheel@v4.2.1
env:
CIBW_TEST_SKIP: "cp*"
CIBW_TEST_COMMAND: >
Expand All @@ -117,19 +116,19 @@ jobs:
TA_INCLUDE_PATH="ta-lib-$TALIB_C_VER\\include;$INCLUDE"
PIP_NO_BUILD_ISOLATION=false
- name: Upload wheel
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v7
with:
path: ./wheelhouse/*.whl
name: "ta_lib-${{ github.ref_name }}-win_amd64"
build_windows_x86:
name: Build Windows x86 wheels
strategy:
matrix:
os: ["windows-2022"]
os: ["windows-2025-vs2026"]
runs-on: ${{ matrix.os }}
steps:
- name: Checkout the repository
uses: actions/checkout@v4
uses: actions/checkout@v7
- name: Set up MSVC for x86
uses: ilammy/msvc-dev-cmd@v1
with:
Expand All @@ -138,7 +137,7 @@ jobs:
run: tools/build_talib_windows.cmd
shell: cmd
- name: Build wheels
uses: pypa/cibuildwheel@v3.2.1
uses: pypa/cibuildwheel@v4.2.1
env:
CIBW_TEST_SKIP: "cp*"
CIBW_TEST_COMMAND: >
Expand All @@ -151,19 +150,19 @@ jobs:
TA_INCLUDE_PATH="ta-lib-$TALIB_C_VER\\include;$INCLUDE"
PIP_NO_BUILD_ISOLATION=false
- name: Upload wheel
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v7
with:
path: ./wheelhouse/*.whl
name: "ta_lib-${{ github.ref_name }}-win32"
build_windows_arm64:
name: Build Windows arm64 wheels
strategy:
matrix:
os: ["windows-11-arm"]
os: ["windows-11-vs2026-arm"]
runs-on: ${{ matrix.os }}
steps:
- name: Checkout the repository
uses: actions/checkout@v4
uses: actions/checkout@v7
- name: Set up MSVC for arm
uses: ilammy/msvc-dev-cmd@v1
with:
Expand All @@ -172,7 +171,7 @@ jobs:
run: tools/build_talib_windows.cmd
shell: cmd
- name: Build wheels
uses: pypa/cibuildwheel@v3.2.1
uses: pypa/cibuildwheel@v4.2.1
env:
CIBW_TEST_SKIP: "cp*"
CIBW_TEST_COMMAND: >
Expand All @@ -185,21 +184,21 @@ jobs:
TA_INCLUDE_PATH="ta-lib-$TALIB_C_VER\\include;$INCLUDE"
PIP_NO_BUILD_ISOLATION=false
- name: Upload wheel
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v7
with:
path: ./wheelhouse/*.whl
name: "ta_lib-${{ github.ref_name }}-win_arm64"
build_macos_x86_64:
name: Build MacOS x86_64 wheels
strategy:
matrix:
os: [macos-15-intel]
os: [macos-26-intel]
runs-on: ${{ matrix.os }}
steps:
- name: Checkout repository
uses: actions/checkout@v4
uses: actions/checkout@v7
- name: Build wheels
uses: pypa/cibuildwheel@v3.2.1
uses: pypa/cibuildwheel@v4.2.1
env:
CIBW_BEFORE_ALL: |
bash ./tools/build_talib_macos.sh
Expand All @@ -216,21 +215,21 @@ jobs:
export DYLD_LIBRARY_PATH="/Users/runner/work/${{ github.event.repository.name }}/${{ github.event.repository.name }}/ta-lib-install/lib:$DYLD_LIBRARY_PATH"
delocate-wheel --require-archs {delocate_archs} -w {dest_dir} -v {wheel}
- name: Upload wheels
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v7
with:
path: ./wheelhouse/*.whl
name: "ta_lib-${{ github.ref_name }}-macos_x86_64"
build_macos_arm64:
name: Build MacOS arm64 wheels
strategy:
matrix:
os: [macos-15]
os: [macos-26]
runs-on: ${{ matrix.os }}
steps:
- name: Checkout repository
uses: actions/checkout@v4
uses: actions/checkout@v7
- name: Build wheels
uses: pypa/cibuildwheel@v3.2.1
uses: pypa/cibuildwheel@v4.2.1
env:
CIBW_BEFORE_ALL: |
bash ./tools/build_talib_macos.sh
Expand All @@ -247,7 +246,7 @@ jobs:
export DYLD_LIBRARY_PATH="/Users/runner/work/${{ github.event.repository.name }}/${{ github.event.repository.name }}/ta-lib-install/lib:$DYLD_LIBRARY_PATH"
delocate-wheel --require-archs {delocate_archs} -w {dest_dir} -v {wheel}
- name: Upload wheels
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v7
with:
path: ./wheelhouse/*.whl
name: "ta_lib-${{ github.ref_name }}-macos_arm64"
21 changes: 21 additions & 0 deletions CHANGELOG
Original file line number Diff line number Diff line change
@@ -1,6 +1,27 @@
0.8.2
=====

- [NEW]: Support free-threaded CPython without enabling the GIL on import.

0.8.1
=====

- [CHANGE]: Native indicator calculations and stream operations release the
GIL on regular CPython too. Independent calls can run concurrently;
operations on a shared stream handle are protected by a per-handle mutex.
Python argument conversion, array allocation and result construction still
require Python thread state. Input arrays must not be modified or resized
during a call. Short calls can incur additional GIL handoff overhead.

- [CHANGE]: Changing process-wide unstable periods, compatibility or candle
settings while a call is active or any stream is alive now raises
``RuntimeError``. Settings cannot change between lookback calculation and
computation. Explicit shutdown also rejects active calls or streams.

- [FIX]: ``tools/threads_talib.py`` now benchmarks a fixed number of calls,
propagates worker failures and reports median throughput across thread
counts, replacing its racy shared counter.

- [CHANGE]: ``talib.stream`` is now the real streaming API of TA-Lib C 0.8.1:
``stream.SMA(close)`` returns a handle, not a value. ``handle.value`` is the
value at the last history bar, ``handle.update(bar)`` costs O(1) and returns
Expand Down
25 changes: 25 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -611,6 +611,31 @@ s.advance() # count a skipped bar: the range moves, the va
A handle points into the TA-Lib C library, so it cannot be pickled or shared
with another process. Keep the history and re-open instead.

## Threads

TA-Lib supports both regular and free-threaded CPython. Native calculations,
including stream opening, updates, reads and cloning, release the GIL on
regular CPython. Python argument conversion, array allocation and result
construction still require Python thread state. Independent calculations run
concurrently; operations on the same stream handle use a per-handle mutex.

Inputs must remain unchanged during a call: do not write to or resize an input
array from another thread. Calls allocate their own output arrays.

Settings are process-wide. Set unstable periods, compatibility and candle
settings before starting calculations or opening streams. Changing settings
while a calculation is active or any stream is alive raises `RuntimeError`.
After calls finish and all streams (including copies) are released, settings
can be changed again. The settings gate protects lookback calculation, output
allocation and computation together, while allowing simultaneous readers.

The synchronization covers calls through this Python extension; other code
calling the same C library directly must observe TA-Lib's settings and lifecycle
contract too. Separate subinterpreters are not supported.

Free-threaded Python requires a matching free-threaded extension build and
compatible dependencies. Importing TA-Lib does not enable the GIL in that build.

## Supported Indicators and Functions 📋

We can show all the TA functions supported by TA-Lib, either as a `list` or
Expand Down
11 changes: 5 additions & 6 deletions docs/func_groups/cycle_indicators.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,34 +2,33 @@
### HT_DCPERIOD - Hilbert Transform - Dominant Cycle Period
NOTE: The ``HT_DCPERIOD`` function has an unstable period.
```python
real = HT_DCPERIOD(real)
real = HT_DCPERIOD(close)
```

### HT_DCPHASE - Hilbert Transform - Dominant Cycle Phase
NOTE: The ``HT_DCPHASE`` function has an unstable period.
```python
real = HT_DCPHASE(real)
real = HT_DCPHASE(close)
```

### HT_PHASOR - Hilbert Transform - Phasor Components
NOTE: The ``HT_PHASOR`` function has an unstable period.
```python
inphase, quadrature = HT_PHASOR(real)
inphase, quadrature = HT_PHASOR(close)
```

### HT_SINE - Hilbert Transform - SineWave
NOTE: The ``HT_SINE`` function has an unstable period.
```python
sine, leadsine = HT_SINE(real)
sine, leadsine = HT_SINE(close)
```

### HT_TRENDMODE - Hilbert Transform - Trend vs Cycle Mode
NOTE: The ``HT_TRENDMODE`` function has an unstable period.
```python
integer = HT_TRENDMODE(real)
integer = HT_TRENDMODE(close)
```


[Documentation Index](../doc_index.md)

[FLOAT_RIGHTAll Function Groups](../funcs.md)
Loading
Loading