Files
ferro-ta/docs/compatibility/finta.md
2026-03-23 23:34:28 +05:30

146 lines
5.1 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# ferro-ta ↔ finta Compatibility
[finta](https://github.com/peerchemist/finta) implements over 80 financial
technical indicators as class methods on a single `TA` class, operating
entirely on Pandas DataFrames.
---
## Key architectural differences
| Aspect | ferro-ta | finta |
|--------|---------|-------|
| **Backend** | Rust/C + SIMD | Pure Pandas |
| **Input type** | NumPy array or list | OHLCV Pandas DataFrame (required) |
| **DatetimeIndex** | Not required | **Required** |
| **Column names** | Separate arrays | `open/high/low/close/volume` |
| **Output type** | NumPy array | Pandas Series or DataFrame |
| **NaN handling** | Pads warmup with NaN | Pads warmup with NaN |
| **Streaming** | Yes (StreamingXxx classes) | No |
| **Speed** | ~700× faster on ATR | Baseline (pure Pandas) |
---
## Required DataFrame format
finta requires a **Pandas DataFrame with a DatetimeIndex** and lowercase
column names:
```python
import pandas as pd
import numpy as np
df = pd.DataFrame({
"open": open_prices,
"high": high_prices,
"low": low_prices,
"close": close_prices,
"volume": volume_data, # required for volume indicators
}, index=pd.date_range("2020-01-01", periods=len(close_prices), freq="D"))
```
ferro-ta accepts raw NumPy arrays or Python lists — no DataFrame needed.
---
## Function signature mapping
finta uses a class-method API: `TA.INDICATOR(ohlcv_df, period, ...)`.
| Indicator | ferro-ta | finta |
|-----------|---------|-------|
| SMA | `SMA(close, timeperiod=20)` | `TA.SMA(df, 20)` |
| EMA | `EMA(close, timeperiod=20)` | `TA.EMA(df, 20)` |
| WMA | `WMA(close, timeperiod=14)` | `TA.WMA(df, 14)` |
| DEMA | `DEMA(close, timeperiod=30)` | `TA.DEMA(df, 30)` |
| TEMA | `TEMA(close, timeperiod=30)` | `TA.TEMA(df, 30)` |
| HMA | Not supported | `TA.HMA(df, 16)` |
| RSI | `RSI(close, timeperiod=14)` | `TA.RSI(df, 14)` |
| MACD | `MACD(close, 12, 26, 9)` → (macd, signal, hist) | `TA.MACD(df, 12, 26, 9)` → DataFrame with `MACD`/`SIGNAL` columns |
| BBANDS | `BBANDS(close, 20, 2.0, 2.0)` → (upper, mid, lower) | `TA.BBANDS(df, 20)` → DataFrame with `BB_UPPER`/`BB_MIDDLE`/`BB_LOWER` |
| ATR | `ATR(high, low, close, timeperiod=14)` | `TA.ATR(df, 14)` |
| TRUE RANGE | `TRANGE(high, low, close)` | `TA.TR(df)` |
| OBV | `OBV(close, volume)` | `TA.OBV(df)` |
| MFI | `MFI(high, low, close, volume, timeperiod=14)` | `TA.MFI(df, 14)` |
| CCI | `CCI(high, low, close, timeperiod=14)` | `TA.CCI(df, 14)` |
| STOCH | `STOCH(high, low, close, 5, 3, 3)` | `TA.STOCH(df, 14)` |
| WILLR | `WILLR(high, low, close, timeperiod=14)` | `TA.WILLIAMS(df, 14)` |
| ADX | `ADX(high, low, close, timeperiod=14)` | `TA.ADX(df, 14)` |
| AROON | `AROON(high, low, timeperiod=14)` → (up, down) | `TA.AROON(df, 14)` → DataFrame |
---
## Numerical accuracy
finta uses sample standard deviation (ddof=1) for Bollinger Bands while
ferro-ta follows the TA-Lib convention (population std, ddof=0). For a
window of 20 bars this creates a ~0.5% difference in band width.
For EMA-based indicators, finta seeds with the first data point while ferro-ta
follows TA-Lib (SMA of first `timeperiod` bars). Values converge after
~3× the period.
Cross-library correlation between ferro-ta and finta is ≥ 0.95 for all
indicators after discarding the warm-up period.
---
## Speed comparison
On 10,000 bars (median µs, Apple M-series):
| Indicator | ferro-ta | finta | ferro-ta speedup |
|-----------|--------:|-------:|----------------:|
| SMA | 16.7 | 178.1 | **10.7×** |
| MACD | 70.4 | 383.9 | **5.5×** |
| ATR | 51.4 | 1,247 | **24×** |
On 100,000 bars:
| Indicator | ferro-ta | finta | ferro-ta speedup |
|-----------|--------:|--------:|----------------:|
| SMA | 126.2 | 699.7 | **5.6×** |
| MACD | 465.9 | 1,470.8 | **3.2×** |
| ATR | 478.5 | 6,782 | **14×** |
finta's ATR scales especially poorly because it relies on Pandas `.apply()`
with a lambda, which cannot be vectorised.
---
## Migration guide
```python
# FROM finta
import pandas as pd
from finta import TA
ohlcv = pd.DataFrame(...) # must have DatetimeIndex + open/high/low/close/volume
sma = TA.SMA(ohlcv, 20) # returns Pandas Series
macd_df = TA.MACD(ohlcv, 12, 26, 9) # returns DataFrame with MACD/SIGNAL cols
bb_df = TA.BBANDS(ohlcv, 20) # returns DataFrame with BB_UPPER/MIDDLE/LOWER
# TO ferro-ta (NumPy arrays — no DataFrame required)
import ferro_ta
import numpy as np
close = ohlcv["close"].values
sma = ferro_ta.SMA(close, timeperiod=20)
macd, signal, hist = ferro_ta.MACD(close, fastperiod=12, slowperiod=26, signalperiod=9)
upper, middle, lower = ferro_ta.BBANDS(close, timeperiod=20, nbdevup=2.0, nbdevdn=2.0)
```
---
## Known limitations
- finta cannot process raw NumPy arrays — a properly formatted DataFrame with
DatetimeIndex is always required.
- `TA.MACD` only returns `MACD` and `SIGNAL` columns; the histogram must be
computed manually as `MACD - SIGNAL`.
- Several finta indicators use non-standard formulas that may not match TA-Lib
conventions (e.g. STOCH uses a fixed 14-period window regardless of the
`fastk_period` argument).