Files

146 lines
5.1 KiB
Markdown
Raw Permalink Normal View History

2026-07-09 05:08:16 +08:00
# 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).