Files
ferro-ta/crates/ferro_ta_core
Pratik BhadaneandGitHub 288b1546b2 feat: broaden CPU and platform coverage across PyPI, nodes, and crate… (#26)
* feat: broaden CPU and platform coverage across PyPI, nodes, and crates.io

Replace static SIMD with runtime CPU-feature dispatch and expand the release
wheel matrix so one set of artifacts runs on any target CPU and platform
without illegal-instruction crashes.

Rust core:
- Add multiversion runtime dispatch (crates/ferro_ta_core/src/simd.rs); drop
  compile-time `wide`. `simd` feature is now default-on and forwarded through
  the pyo3 crate, and stays compatible with #![forbid(unsafe_code)].

Packaging:
- abi3-py310: one cp310-abi3 wheel per platform (covers CPython 3.10+).
- CI matrix adds Linux aarch64 + musllinux (x86_64/aarch64) and Windows arm64.

Node/Docker + docs:
- api/Dockerfile: document baseline+dispatch (no target-cpu pin) and add a
  fail-fast import check; aarch64 containers now install cleanly.
- Rewrite docs/guides/simd.md; fix stale `wide` mention in ADR 0003.
- Add ADR 0006 (CPU coverage strategy).

Also bundles in-flight release prep already staged in the tree (DTW exception
types, SBOM/provenance security, supporting docs).

* fix(ci): clear cargo-deny and pip-audit failures; apply dependency bumps

cargo-deny (advisories):
- Ignore pyo3 RUSTSEC-2026-0176 / RUSTSEC-2026-0177 in deny.toml with a
  documented rationale: ferro-ta uses neither affected code path
  (PyList/PyTuple nth iterators; PyCFunction::new_closure). Upstream fix
  needs pyo3 >=0.29 (large API migration), tracked as a follow-up.

pip-audit:
- Bump dev lockfile idna 3.18, pytest 9.1.1, urllib3 2.7.0 to clear
  PYSEC-2026-215, CVE-2025-71176, PYSEC-2026-141/142.

Dependency bumps (supersede open dependabot PRs; they auto-close on merge):
- cargo: log 0.4.32, serde_json 1.0.150, rayon 1.12.0
- api/requirements.txt: uvicorn>=0.49.0, pydantic>=2.13.4, ferro-ta>=1.1.4
- CI actions: deploy-pages v5, upload-pages-artifact v5, action-gh-release v3

The open `wide` 1.5.0 bump (PR #24) is obsolete — the crate is removed in
this branch.

* chore: address CodeRabbit review; remove docs/adr section

CodeRabbit findings:
- CI sbom job: add `attestations: write` so attest-build-provenance can run
  (it had only contents:write + id-token:write).
- simd.rs: vectorize `wma_seed` with lane-local accumulators — it was scalar
  behind the multiversion wrapper, adding dispatch overhead for no SIMD gain.
- CHANGELOG: consolidate the duplicate `### Changed` heading.
- python/ferro_ta/__init__.py: also re-export the `FerroTaError` alias.
- docs/guides/dtw.md: soften "byte-for-byte" parity to within-tolerance.

Remove docs/adr/ at maintainer request and clean up the ADR links in the
SIMD and DTW guides. The ADR files remain in commit 9506a30 if ever needed.
2026-06-29 18:21:22 +05:30
..
2026-04-07 23:38:36 +05:30

ferro_ta_core

ferro_ta_core is the pure Rust indicator engine behind ferro-ta.

It provides allocation-friendly indicator functions over &[f64] slices without any PyO3, NumPy, or Python runtime dependency, which makes it a good fit for:

  • Rust-native technical analysis workloads
  • custom services and backtesting engines
  • non-Python bindings (WASM, FFI)

Installation

[dependencies]
ferro_ta_core = "1.1.4"

Design

  • Pure functions over Rust slices
  • No Python or NumPy dependency
  • Shared core for the Python package and WASM bindings
  • Output shape matches TA-Lib-style full-length series with NaN warm-up values where applicable

Modules

Module Functions Highlights
overlap 20 SMA, EMA, WMA, DEMA, TEMA, TRIMA, KAMA, T3, BBANDS, MACD, MACDFIX, MACDEXT, SAR, SAREXT, MAMA, MIDPOINT, MIDPRICE, MA, MAVP, Hull MA
momentum 26 RSI, MOM, STOCH, STOCHF, ADX, ADXR, DX, +DI, -DI, +DM, -DM, ROC, WILLR, AROON, CCI, BOP, STOCHRSI, APO, PPO, CMO, TRIX, ULTOSC
volatility 3 ATR, NATR, TRANGE
volume 4 OBV, MFI, AD, ADOSC
pattern 61 All TA-Lib candlestick patterns (CDL2CROWS through CDLXSIDEGAP3METHODS)
statistic 9 STDDEV, VAR, LINEARREG, LINEARREG_SLOPE/INTERCEPT/ANGLE, TSF, BETA, CORREL
math 24 Rolling SUM/MAX/MIN/MAXINDEX/MININDEX, element-wise ADD/SUB/MULT/DIV, 15 transforms (trig, exp, log, sqrt, ceil, floor)
price_transform 4 AVGPRICE, MEDPRICE, TYPPRICE, WCLPRICE
cycle 7 Hilbert Transform: TRENDLINE, DCPERIOD, DCPHASE, PHASOR, SINE, TRENDMODE
extended 10 VWAP, VWMA, Supertrend, Donchian, Keltner, Ichimoku, Pivot Points, Hull MA, Chandelier Exit, Choppiness Index
streaming 9 Stateful bar-by-bar: SMA, EMA, RSI, ATR, BBands, MACD, Stoch, VWAP, Supertrend
batch 8 Vectorized multi-column: batch_sma/ema/rsi/atr/stoch/adx, run_close/hlc_indicators
backtest 19 Signal generators, close-only and OHLCV engines, walk-forward, Monte Carlo, performance metrics
options 18 Black-Scholes/Black-76 pricing, Greeks, implied volatility, IV rank/percentile/zscore, smile metrics, chain analytics
futures 14 Basis, annualized basis, carry, roll (weighted/back-adjusted/ratio), curve analysis, synthetic forward/spot
portfolio 10 Beta, correlation matrix, drawdown, relative strength, spread, ratio, z-score, portfolio volatility
signals 4 Rank values, compose rank, top/bottom N indices
alerts 3 Threshold crossings, cross detection, alert bar collection
regime 4 ADX regime, combined regime, CUSUM breaks, variance breaks
aggregation 3 Tick bars, volume bars, time bars from trade data
resampling 2 Volume bars, OHLCV aggregation by label
chunked 4 Trim overlap, stitch chunks, make chunk ranges, forward fill NaN
crypto 3 Funding cumulative PnL, continuous bar labels, session boundaries

Example

use ferro_ta_core::overlap;

fn main() {
    let close = vec![1.0, 2.0, 3.0, 4.0, 5.0];
    let sma = overlap::sma(&close, 3);

    assert!(sma[0].is_nan());
    assert!(sma[1].is_nan());
    assert!((sma[2] - 2.0).abs() < 1e-10);
}

Relationship To ferro-ta

The published Python package (ferro-ta on PyPI) wraps this crate with PyO3 bindings and adds NumPy conversion, pandas/polars wrappers, and higher-level Python tooling. The WASM package (ferro-ta-wasm on npm) also wraps this crate with full feature parity.

If you only need Rust indicator functions, use ferro_ta_core directly.

Development

From the repository root:

cargo build -p ferro_ta_core
cargo test -p ferro_ta_core
cargo bench -p ferro_ta_core --no-run

License

MIT