Compare commits

...

1 Commits

Author SHA1 Message Date
Pratik Bhadane 682bf063ca release: cut v1.0.1
Prepare the first patch release after v1.0.0 by finalizing the outstanding release, packaging, and workflow fixes.

This release keeps PyPI and crates.io publishing anchored to CI.yml, splits the large CI workflow into focused rust/python/wasm/docs suites, fixes the ci-complete gate, and updates the release SBOM action pin.

It also switches the npm publish workflow to GitHub OIDC, installs the wasm32 target required for packaging, ensures the WASM npm tarball includes pkg/ artifacts during prepack, and adds a dedicated README plus docs.rs metadata for ferro_ta_core.

Finally, bump all published package versions to 1.0.1 and record the patch release notes in CHANGELOG.md.
2026-03-24 00:38:50 +05:30
13 changed files with 482 additions and 338 deletions
+38 -325
View File
@@ -10,43 +10,8 @@ on:
permissions:
contents: read
pages: write
jobs:
# -------------------------------------------------------------------------
# Dependency audits — cargo audit (Rust) and pip-audit (Python)
# -------------------------------------------------------------------------
audit:
name: Dependency audit (cargo + pip)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- name: Install cargo-audit and run cargo audit
run: |
cargo install cargo-audit
cargo audit
- name: Install cargo-deny and run cargo deny check
run: |
cargo install cargo-deny --locked
cargo deny check
- name: Set up Python 3.12
uses: actions/setup-python@v6
with:
python-version: "3.12"
- name: Install uv
run: pip install uv
- name: Install pip-audit via uv and run pip-audit
run: |
uv run --with pip-audit pip-audit
- name: Verify uv.lock is up-to-date
run: uv lock --check
# -------------------------------------------------------------------------
# Version consistency — Cargo.toml and pyproject.toml must have same version
# -------------------------------------------------------------------------
@@ -76,285 +41,28 @@ jobs:
fi
echo "OK: versions match ($CARGO_VERSION)"
rust:
name: Rust (fmt + clippy)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: dtolnay/rust-toolchain@v1
with:
toolchain: stable
components: rustfmt, clippy
- run: cargo fmt --all -- --check
- run: cargo clippy --release -- -D warnings
- name: Verify benchmarks compile (ferro_ta_core)
run: cargo bench -p ferro_ta_core --no-run
# -------------------------------------------------------------------------
# Rust coverage — optional, runs in a separate non-blocking job
# Modularized CI suites.
# Keep release publishing jobs in this file so trusted-publisher bindings
# remain anchored to CI.yml for PyPI and crates.io.
# -------------------------------------------------------------------------
rust-coverage:
name: Rust coverage (tarpaulin, optional)
runs-on: ubuntu-latest
continue-on-error: true
steps:
- uses: actions/checkout@v6
- uses: dtolnay/rust-toolchain@v1
with:
toolchain: stable
- name: Install cargo-tarpaulin
run: cargo install cargo-tarpaulin --locked
- name: Collect Rust coverage (ferro_ta_core)
run: cargo tarpaulin -p ferro_ta_core --out Xml --output-dir coverage/
- name: Upload Rust coverage artifact
uses: actions/upload-artifact@v7
with:
name: rust-coverage
path: coverage/
if-no-files-found: ignore
rust-suite:
name: Rust and audit
uses: ./.github/workflows/ci-rust.yml
lint:
name: Lint (ruff)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
python-suite:
name: Python quality and tests
uses: ./.github/workflows/ci-python.yml
- name: Set up Python 3.12
uses: actions/setup-python@v6
with:
python-version: "3.12"
- name: Install uv
run: pip install uv
- name: Run ruff check via uv
run: uv run --with ruff ruff check python/ tests/
- name: Run ruff format check via uv
run: uv run --with ruff ruff format --check python/ tests/
typecheck:
name: Type checking (mypy + pyright)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- name: Set up Python 3.12
uses: actions/setup-python@v6
with:
python-version: "3.12"
- name: Install uv
run: pip install uv
- name: Run mypy on ferro_ta via uv
run: uv run --with mypy --with numpy mypy python/ferro_ta --ignore-missing-imports --no-error-summary
- name: Run pyright on ferro_ta via uv
run: uv run --with pyright pyright python/ferro_ta
test:
name: Test (ubuntu-latest / Python ${{ matrix.python-version }})
runs-on: ubuntu-latest
strategy:
# Python 3.103.13 supported (requires-python in pyproject.toml)
fail-fast: false
matrix:
python-version: ["3.10", "3.11", "3.12", "3.13"]
steps:
- uses: actions/checkout@v6
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v6
with:
python-version: ${{ matrix.python-version }}
- name: Install maturin and test dependencies
run: |
pip install maturin numpy pytest pytest-cov pandas polars hypothesis pyyaml
- name: Build and install ferro_ta (dev mode)
run: |
maturin build --release --out dist
pip install dist/*.whl
- name: Run unit tests with coverage
run: pytest tests/unit/ tests/integration/ -v --cov=ferro_ta --cov-report=xml --cov-report=term-missing --cov-fail-under=65
- name: Upload coverage report
uses: actions/upload-artifact@v7
if: matrix.python-version == '3.12'
with:
name: coverage-python-${{ matrix.python-version }}
path: coverage.xml
# -------------------------------------------------------------------------
# WASM binding — build and test with wasm-pack
# -------------------------------------------------------------------------
wasm:
name: WASM binding (wasm-pack test --node)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
name: WASM binding
uses: ./.github/workflows/ci-wasm.yml
- name: Install Rust (stable)
uses: dtolnay/rust-toolchain@v1
with:
toolchain: stable
targets: wasm32-unknown-unknown
- name: Install wasm-pack
run: curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh
- name: Build and test WASM binding
working-directory: wasm
run: wasm-pack test --node
- name: Build WASM package (nodejs target)
working-directory: wasm
run: wasm-pack build --target nodejs --out-dir pkg
- name: Upload WASM package artifact
uses: actions/upload-artifact@v7
with:
name: wasm-pkg
path: wasm/pkg/
# -------------------------------------------------------------------------
# ferro_ta vs TA-Lib speed comparison — required for PRs.
# Performance regressions block merging.
# -------------------------------------------------------------------------
benchmark-vs-talib:
name: Benchmark vs TA-Lib
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- name: Set up Python 3.12
uses: actions/setup-python@v6
with:
python-version: "3.12"
- name: Install TA-Lib C library (Ubuntu)
run: |
sudo apt-get update
sudo apt-get install -y build-essential curl
curl -sL https://sourceforge.net/projects/ta-lib/files/ta-lib/0.4.0/ta-lib-0.4.0-src.tar.gz/download -o ta-lib-0.4.0-src.tar.gz
tar -xzf ta-lib-0.4.0-src.tar.gz
cd ta-lib
./configure --prefix=/usr
make
sudo make install
sudo ldconfig
- name: Install maturin and ta-lib Python package
run: |
pip install maturin numpy
pip install ta-lib
- name: Build and install ferro_ta
run: |
maturin build --release --out dist
pip install dist/*.whl
- name: Run benchmark comparison
run: |
python benchmarks/bench_vs_talib.py --sizes 10000 100000 --json benchmark_vs_talib.json
- name: Enforce benchmark regression policy
run: |
python3 benchmarks/check_vs_talib_regression.py --input benchmark_vs_talib.json
- name: Upload benchmark results
uses: actions/upload-artifact@v7
with:
name: benchmark-vs-talib
path: benchmark_vs_talib.json
# -------------------------------------------------------------------------
# Pure Rust core library — build and test without PyO3 / numpy
# -------------------------------------------------------------------------
rust-core:
name: Rust core library (ferro_ta_core)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: dtolnay/rust-toolchain@v1
with:
toolchain: stable
- name: Build core crate
run: cargo build -p ferro_ta_core
- name: Test core crate
run: cargo test -p ferro_ta_core
# -------------------------------------------------------------------------
# Fuzzing (short run in CI to catch panics) — optional, non-blocking
# This job is explicitly marked continue-on-error because cargo-fuzz
# requires nightly Rust and may not be available in all environments.
# Failures here are visible in the job log but do not block the PR.
# -------------------------------------------------------------------------
fuzz:
name: Fuzz targets (short CI run, optional)
runs-on: ubuntu-latest
continue-on-error: true
steps:
- uses: actions/checkout@v6
- uses: dtolnay/rust-toolchain@v1
with:
toolchain: nightly
- name: Install cargo-fuzz
run: cargo install cargo-fuzz --locked
- name: Run fuzz_sma (10000 iterations)
working-directory: fuzz
run: cargo fuzz run fuzz_sma -- -runs=10000 -max_len=512
- name: Run fuzz_rsi (10000 iterations)
working-directory: fuzz
run: cargo fuzz run fuzz_rsi -- -runs=10000 -max_len=512
- name: Upload fuzz artifacts on crash
uses: actions/upload-artifact@v7
if: always()
with:
name: fuzz-artifacts
path: fuzz/artifacts/
if-no-files-found: ignore
# -------------------------------------------------------------------------
# Sphinx documentation build
# -------------------------------------------------------------------------
docs:
name: Documentation (Sphinx build)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- name: Set up Python 3.12
uses: actions/setup-python@v6
with:
python-version: "3.12"
- name: Install maturin and docs dependencies
run: |
pip install maturin numpy
pip install sphinx sphinx-rtd-theme
- name: Build and install ferro_ta wheel
run: |
maturin build --release --out dist
pip install dist/*.whl
- name: Build Sphinx documentation
run: sphinx-build -b html docs docs/_build -W --keep-going
- name: Upload docs artifact
uses: actions/upload-artifact@v7
with:
name: sphinx-docs
path: docs/_build/
- name: Upload GitHub Pages artifact
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
uses: actions/upload-pages-artifact@v4
with:
path: docs/_build/
name: Documentation
uses: ./.github/workflows/ci-docs.yml
with:
upload-pages-artifact: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }}
# -------------------------------------------------------------------------
# Deploy docs to GitHub Pages (on push to main only)
@@ -384,16 +92,11 @@ jobs:
name: CI complete (required gate)
runs-on: ubuntu-latest
needs:
- audit
- changelog-check
- version-check
- rust
- rust-core
- lint
- typecheck
- test
- rust-suite
- python-suite
- wasm
- benchmark-vs-talib
- docs
if: always()
steps:
@@ -401,21 +104,31 @@ jobs:
run: |
results='${{ toJSON(needs) }}'
echo "Job results: $results"
failed=$(echo "$results" | python3 -c "
import json, sys
needs = json.load(sys.stdin)
failed = [name for name, data in needs.items() if data['result'] not in ('success', 'skipped')]
failed="$(
RESULTS_JSON="$results" python3 - <<'PY'
import json
import os
needs = json.loads(os.environ["RESULTS_JSON"])
failed = [
name
for name, data in needs.items()
if data["result"] not in ("success", "skipped")
]
if failed:
print(' '.join(failed))
")
if [ -n \"\$failed\" ]; then
echo \"FAILED jobs: \$failed\"
print(" ".join(failed))
PY
)"
if [ -n "$failed" ]; then
echo "FAILED jobs: $failed"
exit 1
fi
echo \"All required CI jobs passed.\"
echo "All required CI jobs passed."
# -------------------------------------------------------------------------
# Build wheels for all platforms and publish to PyPI on release
# Keep release jobs here because trusted-publisher configuration points to
# CI.yml specifically.
# -------------------------------------------------------------------------
build-wheels:
name: Build wheels (${{ matrix.os }})
@@ -503,7 +216,7 @@ jobs:
- uses: actions/checkout@v6
- name: Set up Python 3.12
uses: actions/setup-python@v5
uses: actions/setup-python@v6
with:
python-version: "3.12"
@@ -516,7 +229,7 @@ jobs:
pip install dist/*.whl
- name: Generate Python SBOM (CycloneDX via anchore/sbom-action)
uses: anchore/sbom-action@v0.17
uses: anchore/sbom-action@v0.24.0
with:
artifact-name: ferro-ta-python-sbom.spdx.json
output-file: ferro-ta-python-sbom.spdx.json
+49
View File
@@ -0,0 +1,49 @@
name: CI Docs
on:
workflow_call:
inputs:
upload-pages-artifact:
required: false
type: boolean
default: false
permissions:
contents: read
jobs:
docs:
name: Documentation (Sphinx build)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- name: Set up Python 3.12
uses: actions/setup-python@v6
with:
python-version: "3.12"
- name: Install maturin and docs dependencies
run: |
pip install maturin numpy
pip install sphinx sphinx-rtd-theme
- name: Build and install ferro_ta wheel
run: |
maturin build --release --out dist
pip install dist/*.whl
- name: Build Sphinx documentation
run: sphinx-build -b html docs docs/_build -W --keep-going
- name: Upload docs artifact
uses: actions/upload-artifact@v7
with:
name: sphinx-docs
path: docs/_build/
- name: Upload GitHub Pages artifact
if: ${{ inputs.upload-pages-artifact }}
uses: actions/upload-pages-artifact@v4
with:
path: docs/_build/
+127
View File
@@ -0,0 +1,127 @@
name: CI Python
on:
workflow_call:
permissions:
contents: read
jobs:
lint:
name: Lint (ruff)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- name: Set up Python 3.12
uses: actions/setup-python@v6
with:
python-version: "3.12"
- name: Install uv
run: pip install uv
- name: Run ruff check via uv
run: uv run --with ruff ruff check python/ tests/
- name: Run ruff format check via uv
run: uv run --with ruff ruff format --check python/ tests/
typecheck:
name: Type checking (mypy + pyright)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- name: Set up Python 3.12
uses: actions/setup-python@v6
with:
python-version: "3.12"
- name: Install uv
run: pip install uv
- name: Run mypy on ferro_ta via uv
run: uv run --with mypy --with numpy mypy python/ferro_ta --ignore-missing-imports --no-error-summary
- name: Run pyright on ferro_ta via uv
run: uv run --with pyright pyright python/ferro_ta
test:
name: Test (ubuntu-latest / Python ${{ matrix.python-version }})
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
python-version: ["3.10", "3.11", "3.12", "3.13"]
steps:
- uses: actions/checkout@v6
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v6
with:
python-version: ${{ matrix.python-version }}
- name: Install maturin and test dependencies
run: |
pip install maturin numpy pytest pytest-cov pandas polars hypothesis pyyaml
- name: Build and install ferro_ta (dev mode)
run: |
maturin build --release --out dist
pip install dist/*.whl
- name: Run unit tests with coverage
run: pytest tests/unit/ tests/integration/ -v --cov=ferro_ta --cov-report=xml --cov-report=term-missing --cov-fail-under=65
- name: Upload coverage report
uses: actions/upload-artifact@v7
if: matrix.python-version == '3.12'
with:
name: coverage-python-${{ matrix.python-version }}
path: coverage.xml
benchmark-vs-talib:
name: Benchmark vs TA-Lib
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- name: Set up Python 3.12
uses: actions/setup-python@v6
with:
python-version: "3.12"
- name: Install TA-Lib C library (Ubuntu)
run: |
sudo apt-get update
sudo apt-get install -y build-essential curl
curl -sL https://sourceforge.net/projects/ta-lib/files/ta-lib/0.4.0/ta-lib-0.4.0-src.tar.gz/download -o ta-lib-0.4.0-src.tar.gz
tar -xzf ta-lib-0.4.0-src.tar.gz
cd ta-lib
./configure --prefix=/usr
make
sudo make install
sudo ldconfig
- name: Install maturin and ta-lib Python package
run: |
pip install maturin numpy
pip install ta-lib
- name: Build and install ferro_ta
run: |
maturin build --release --out dist
pip install dist/*.whl
- name: Run benchmark comparison
run: |
python benchmarks/bench_vs_talib.py --sizes 10000 100000 --json benchmark_vs_talib.json
- name: Enforce benchmark regression policy
run: python3 benchmarks/check_vs_talib_regression.py --input benchmark_vs_talib.json
- name: Upload benchmark results
uses: actions/upload-artifact@v7
with:
name: benchmark-vs-talib
path: benchmark_vs_talib.json
+110
View File
@@ -0,0 +1,110 @@
name: CI Rust
on:
workflow_call:
permissions:
contents: read
jobs:
audit:
name: Dependency audit (cargo + pip)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- name: Install cargo-audit and run cargo audit
run: |
cargo install cargo-audit
cargo audit
- name: Install cargo-deny and run cargo deny check
run: |
cargo install cargo-deny --locked
cargo deny check
- name: Set up Python 3.12
uses: actions/setup-python@v6
with:
python-version: "3.12"
- name: Install uv
run: pip install uv
- name: Install pip-audit via uv and run pip-audit
run: uv run --with pip-audit pip-audit
- name: Verify uv.lock is up-to-date
run: uv lock --check
rust:
name: Rust (fmt + clippy)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: dtolnay/rust-toolchain@v1
with:
toolchain: stable
components: rustfmt, clippy
- run: cargo fmt --all -- --check
- run: cargo clippy --release -- -D warnings
- name: Verify benchmarks compile (ferro_ta_core)
run: cargo bench -p ferro_ta_core --no-run
rust-core:
name: Rust core library (ferro_ta_core)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: dtolnay/rust-toolchain@v1
with:
toolchain: stable
- name: Build core crate
run: cargo build -p ferro_ta_core
- name: Test core crate
run: cargo test -p ferro_ta_core
rust-coverage:
name: Rust coverage (tarpaulin, optional)
runs-on: ubuntu-latest
continue-on-error: true
steps:
- uses: actions/checkout@v6
- uses: dtolnay/rust-toolchain@v1
with:
toolchain: stable
- name: Install cargo-tarpaulin
run: cargo install cargo-tarpaulin --locked
- name: Collect Rust coverage (ferro_ta_core)
run: cargo tarpaulin -p ferro_ta_core --out Xml --output-dir coverage/
- name: Upload Rust coverage artifact
uses: actions/upload-artifact@v7
with:
name: rust-coverage
path: coverage/
if-no-files-found: ignore
fuzz:
name: Fuzz targets (short CI run, optional)
runs-on: ubuntu-latest
continue-on-error: true
steps:
- uses: actions/checkout@v6
- uses: dtolnay/rust-toolchain@v1
with:
toolchain: nightly
- name: Install cargo-fuzz
run: cargo install cargo-fuzz --locked
- name: Run fuzz_sma (10000 iterations)
working-directory: fuzz
run: cargo fuzz run fuzz_sma -- -runs=10000 -max_len=512
- name: Run fuzz_rsi (10000 iterations)
working-directory: fuzz
run: cargo fuzz run fuzz_rsi -- -runs=10000 -max_len=512
- name: Upload fuzz artifacts on crash
uses: actions/upload-artifact@v7
if: always()
with:
name: fuzz-artifacts
path: fuzz/artifacts/
if-no-files-found: ignore
+37
View File
@@ -0,0 +1,37 @@
name: CI WASM
on:
workflow_call:
permissions:
contents: read
jobs:
wasm:
name: WASM binding (wasm-pack test --node)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- name: Install Rust (stable)
uses: dtolnay/rust-toolchain@v1
with:
toolchain: stable
targets: wasm32-unknown-unknown
- name: Install wasm-pack
run: curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh
- name: Build and test WASM binding
working-directory: wasm
run: wasm-pack test --node
- name: Build WASM package (nodejs target)
working-directory: wasm
run: wasm-pack build --target nodejs --out-dir pkg
- name: Upload WASM package artifact
uses: actions/upload-artifact@v7
with:
name: wasm-pkg
path: wasm/pkg/
+8 -4
View File
@@ -4,6 +4,10 @@ on:
release:
types: [published]
permissions:
contents: read
id-token: write
jobs:
publish:
name: Build and publish to npm
@@ -12,13 +16,15 @@ jobs:
- uses: actions/checkout@v6
- name: Setup Node.js
uses: actions/setup-node@v4
uses: actions/setup-node@v6
with:
node-version: "20"
node-version: "24"
registry-url: "https://registry.npmjs.org"
- name: Install Rust and wasm-pack
uses: dtolnay/rust-toolchain@stable
with:
targets: wasm32-unknown-unknown
- run: cargo install wasm-pack
- name: Build WASM package
@@ -29,5 +35,3 @@ jobs:
- name: Publish to npm
working-directory: wasm
run: npm publish --access public
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
+24 -1
View File
@@ -9,6 +9,28 @@ and the project uses [Semantic Versioning](https://semver.org/).
## [Unreleased]
## [1.0.1] — 2026-03-24
### Added
- `crates/ferro_ta_core/README.md` is now shipped with the published Rust crate, and
`ferro_ta_core` metadata now points documentation to docs.rs.
### Fixed
- CI has been modularized into focused workflow files (`ci-rust.yml`,
`ci-python.yml`, `ci-wasm.yml`, `ci-docs.yml`) while keeping the release
publishing jobs in `CI.yml` for PyPI and crates.io trusted-publisher
compatibility.
- The `ci-complete` gate no longer fails successful runs because of an escaped
shell variable, and the release SBOM job now uses a valid `anchore/sbom-action`
version.
- The npm publish workflow now uses GitHub OIDC trusted publishing, installs
the `wasm32-unknown-unknown` target, and no longer depends on an `NPM_TOKEN`
secret.
- The WASM npm package now removes the generated `pkg/.gitignore` during
`prepack`, so the published tarball includes the built `pkg/` artifacts.
## [1.0.0] — 2026-03-23 *(initial stable release)*
### Performance
@@ -252,5 +274,6 @@ and the project uses [Semantic Versioning](https://semver.org/).
---
[Unreleased]: https://github.com/pratikbhadane24/ferro-ta/compare/v1.0.0...HEAD
[Unreleased]: https://github.com/pratikbhadane24/ferro-ta/compare/v1.0.1...HEAD
[1.0.1]: https://github.com/pratikbhadane24/ferro-ta/compare/v1.0.0...v1.0.1
[1.0.0]: https://github.com/pratikbhadane24/ferro-ta/releases/tag/v1.0.0
Generated
+2 -2
View File
@@ -207,7 +207,7 @@ checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719"
[[package]]
name = "ferro_ta"
version = "1.0.0"
version = "1.0.1"
dependencies = [
"criterion",
"ferro_ta_core",
@@ -222,7 +222,7 @@ dependencies = [
[[package]]
name = "ferro_ta_core"
version = "1.0.0"
version = "1.0.1"
dependencies = [
"criterion",
"wide",
+2 -2
View File
@@ -5,7 +5,7 @@ resolver = "2"
[package]
name = "ferro_ta"
version = "1.0.0"
version = "1.0.1"
edition = "2021"
license = "MIT"
publish = false
@@ -23,7 +23,7 @@ ndarray = "0.16"
rayon = "1.10"
log = "0.4"
pyo3-log = "0.12"
ferro_ta_core = { path = "crates/ferro_ta_core", version = "1.0.0" }
ferro_ta_core = { path = "crates/ferro_ta_core", version = "1.0.1" }
[dev-dependencies]
criterion = { version = "0.8", features = ["html_reports"] }
+3 -2
View File
@@ -1,12 +1,13 @@
[package]
name = "ferro_ta_core"
version = "1.0.0"
version = "1.0.1"
edition = "2021"
description = "Pure Rust core indicator library — no PyO3, no numpy dependency"
license = "MIT"
readme = "README.md"
repository = "https://github.com/pratikbhadane24/ferro-ta"
homepage = "https://github.com/pratikbhadane24/ferro-ta#readme"
documentation = "https://github.com/pratikbhadane24/ferro-ta#readme"
documentation = "https://docs.rs/ferro_ta_core"
keywords = ["technical-analysis", "trading", "indicators", "finance", "ta-lib"]
categories = ["finance", "mathematics"]
+79
View File
@@ -0,0 +1,79 @@
# ferro_ta_core
`ferro_ta_core` is the pure Rust indicator engine behind [`ferro-ta`](https://github.com/pratikbhadane24/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
- future non-Python bindings such as WASM and other FFI layers
## Installation
```toml
[dependencies]
ferro_ta_core = "1.0.1"
```
## 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
- `overlap` - moving averages, MACD, Bollinger Bands
- `momentum` - RSI, MOM
- `volatility` - ATR, TRANGE
- `volume` - OBV
- `statistic` - STDDEV
- `math` - rolling SUM/MAX/MIN helpers
## Example
```rust
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:
- crate: `ferro_ta`
- PyPI package: `ferro-ta`
wraps this crate with PyO3 bindings and adds:
- NumPy conversion
- pandas/polars wrappers
- streaming classes
- batch helpers
- higher-level Python tooling
If you only need Rust indicator functions, use `ferro_ta_core` directly.
## Development
From the repository root:
```bash
cargo build -p ferro_ta_core
cargo test -p ferro_ta_core
cargo bench -p ferro_ta_core --no-run
```
## License
MIT
+1 -1
View File
@@ -4,7 +4,7 @@ build-backend = "maturin"
[project]
name = "ferro-ta"
version = "1.0.0"
version = "1.0.1"
description = "A fast Technical Analysis library — TA-Lib alternative powered by Rust and PyO3"
readme = "README.md"
license = { text = "MIT" }
+2 -1
View File
@@ -1,12 +1,13 @@
{
"name": "ferro-ta-wasm",
"version": "1.0.0",
"version": "1.0.1",
"description": "WebAssembly bindings for ferro-ta technical analysis indicators",
"main": "pkg/ferro_ta_wasm.js",
"types": "pkg/ferro_ta_wasm.d.ts",
"files": ["pkg"],
"scripts": {
"build": "wasm-pack build --target nodejs --out-dir pkg",
"prepack": "npm run build && node -e \"require('fs').rmSync('pkg/.gitignore', { force: true })\"",
"test": "wasm-pack test --node"
},
"license": "MIT",