"""
Math Operators & Math Transforms — TA-Lib compatibility shims.
Rolling functions (SUM, MAX, MIN, MAXINDEX, MININDEX) are implemented in Rust
using O(n) monotonic deque / prefix-sum algorithms. All other functions are
thin NumPy wrappers (element-wise operations).
Functions
---------
Math Operators:
ADD — Element-wise addition
SUB — Element-wise subtraction
MULT — Element-wise multiplication
DIV — Element-wise division
SUM — Rolling sum over *timeperiod* bars (Rust)
MAX — Rolling maximum over *timeperiod* bars (Rust)
MIN — Rolling minimum over *timeperiod* bars (Rust)
MAXINDEX — Index of rolling maximum over *timeperiod* bars (Rust)
MININDEX — Index of rolling minimum over *timeperiod* bars (Rust)
Math Transforms (element-wise):
ACOS ASIN ATAN CEIL COS COSH EXP FLOOR LN LOG10 SIN SINH SQRT TAN TANH
Rust backend
------------
Rolling operators delegate to::
from ferro_ta._ferro_ta import rolling_sum, rolling_max, rolling_min, ...
"""
from __future__ import annotations
import numpy as np
from numpy.typing import ArrayLike
# ---------------------------------------------------------------------------
# Import Rust rolling operators
# ---------------------------------------------------------------------------
from ferro_ta._ferro_ta import (
rolling_max as _rust_rolling_max,
)
from ferro_ta._ferro_ta import (
rolling_maxindex as _rust_rolling_maxindex,
)
from ferro_ta._ferro_ta import (
rolling_min as _rust_rolling_min,
)
from ferro_ta._ferro_ta import (
rolling_minindex as _rust_rolling_minindex,
)
from ferro_ta._ferro_ta import (
rolling_sum as _rust_rolling_sum,
)
from ferro_ta._utils import _to_f64
from ferro_ta.core.exceptions import _normalize_rust_error
# ---------------------------------------------------------------------------
# Math Operators
# ---------------------------------------------------------------------------
[docs]
def ADD(real0: ArrayLike, real1: ArrayLike) -> np.ndarray:
"""Element-wise addition: real0 + real1.
Parameters
----------
real0, real1 : array-like
Input arrays (same length).
Returns
-------
numpy.ndarray[float64]
"""
try:
return np.add(_to_f64(real0), _to_f64(real1))
except ValueError as e:
_normalize_rust_error(e)
[docs]
def SUB(real0: ArrayLike, real1: ArrayLike) -> np.ndarray:
"""Element-wise subtraction: real0 - real1.
Parameters
----------
real0, real1 : array-like
Input arrays (same length).
Returns
-------
numpy.ndarray[float64]
"""
try:
return np.subtract(_to_f64(real0), _to_f64(real1))
except ValueError as e:
_normalize_rust_error(e)
[docs]
def MULT(real0: ArrayLike, real1: ArrayLike) -> np.ndarray:
"""Element-wise multiplication: real0 * real1.
Parameters
----------
real0, real1 : array-like
Input arrays (same length).
Returns
-------
numpy.ndarray[float64]
"""
try:
return np.multiply(_to_f64(real0), _to_f64(real1))
except ValueError as e:
_normalize_rust_error(e)
[docs]
def DIV(real0: ArrayLike, real1: ArrayLike) -> np.ndarray:
"""Element-wise division: real0 / real1.
Parameters
----------
real0, real1 : array-like
Input arrays (same length).
Returns
-------
numpy.ndarray[float64]
"""
try:
# Suppress divide-by-zero warnings while preserving inf/NaN outputs.
with np.errstate(divide="ignore", invalid="ignore"):
return np.divide(_to_f64(real0), _to_f64(real1))
except ValueError as e:
_normalize_rust_error(e)
[docs]
def SUM(real: ArrayLike, timeperiod: int = 30) -> np.ndarray:
"""Rolling sum over *timeperiod* bars.
Parameters
----------
real : array-like
timeperiod : int, default 30
Returns
-------
numpy.ndarray[float64]
NaN for the first ``timeperiod - 1`` bars.
Notes
-----
Implemented in Rust using O(n) prefix-sum algorithm.
"""
try:
arr = _to_f64(real)
return np.asarray(_rust_rolling_sum(arr, timeperiod))
except ValueError as e:
_normalize_rust_error(e)
[docs]
def MAX(real: ArrayLike, timeperiod: int = 30) -> np.ndarray:
"""Rolling maximum over *timeperiod* bars.
Parameters
----------
real : array-like
timeperiod : int, default 30
Returns
-------
numpy.ndarray[float64]
NaN for the first ``timeperiod - 1`` bars.
Notes
-----
Implemented in Rust using O(n) monotonic deque algorithm.
"""
try:
arr = _to_f64(real)
return np.asarray(_rust_rolling_max(arr, timeperiod))
except ValueError as e:
_normalize_rust_error(e)
[docs]
def MIN(real: ArrayLike, timeperiod: int = 30) -> np.ndarray:
"""Rolling minimum over *timeperiod* bars.
Parameters
----------
real : array-like
timeperiod : int, default 30
Returns
-------
numpy.ndarray[float64]
NaN for the first ``timeperiod - 1`` bars.
Notes
-----
Implemented in Rust using O(n) monotonic deque algorithm.
"""
try:
arr = _to_f64(real)
return np.asarray(_rust_rolling_min(arr, timeperiod))
except ValueError as e:
_normalize_rust_error(e)
[docs]
def MAXINDEX(real: ArrayLike, timeperiod: int = 30) -> np.ndarray:
"""Index of the rolling maximum over *timeperiod* bars.
The index is the absolute position in the input array.
Parameters
----------
real : array-like
timeperiod : int, default 30
Returns
-------
numpy.ndarray[int64]
-1 for the first ``timeperiod - 1`` bars (warmup period).
Notes
-----
Implemented in Rust using O(n) monotonic deque algorithm.
"""
try:
arr = _to_f64(real)
return np.asarray(_rust_rolling_maxindex(arr, timeperiod))
except ValueError as e:
_normalize_rust_error(e)
[docs]
def MININDEX(real: ArrayLike, timeperiod: int = 30) -> np.ndarray:
"""Index of the rolling minimum over *timeperiod* bars.
The index is the absolute position in the input array.
Parameters
----------
real : array-like
timeperiod : int, default 30
Returns
-------
numpy.ndarray[int64]
-1 for the first ``timeperiod - 1`` bars (warmup period).
Notes
-----
Implemented in Rust using O(n) monotonic deque algorithm.
"""
try:
arr = _to_f64(real)
return np.asarray(_rust_rolling_minindex(arr, timeperiod))
except ValueError as e:
_normalize_rust_error(e)
# ---------------------------------------------------------------------------
# Math Transforms (element-wise)
# ---------------------------------------------------------------------------
[docs]
def ACOS(real: ArrayLike) -> np.ndarray:
"""Arc cosine (element-wise). Returns NaN outside [-1, 1]."""
with np.errstate(invalid="ignore"):
return np.arccos(_to_f64(real))
[docs]
def ASIN(real: ArrayLike) -> np.ndarray:
"""Arc sine (element-wise). Returns NaN outside [-1, 1]."""
with np.errstate(invalid="ignore"):
return np.arcsin(_to_f64(real))
[docs]
def ATAN(real: ArrayLike) -> np.ndarray:
"""Arc tangent (element-wise)."""
return np.arctan(_to_f64(real))
[docs]
def CEIL(real: ArrayLike) -> np.ndarray:
"""Ceiling (element-wise)."""
return np.ceil(_to_f64(real))
[docs]
def COS(real: ArrayLike) -> np.ndarray:
"""Cosine (element-wise)."""
return np.cos(_to_f64(real))
[docs]
def COSH(real: ArrayLike) -> np.ndarray:
"""Hyperbolic cosine (element-wise)."""
return np.cosh(_to_f64(real))
[docs]
def EXP(real: ArrayLike) -> np.ndarray:
"""Exponential (element-wise)."""
return np.exp(_to_f64(real))
[docs]
def FLOOR(real: ArrayLike) -> np.ndarray:
"""Floor (element-wise)."""
return np.floor(_to_f64(real))
[docs]
def LN(real: ArrayLike) -> np.ndarray:
"""Natural logarithm (element-wise). Returns NaN for non-positive inputs."""
with np.errstate(divide="ignore", invalid="ignore"):
return np.log(_to_f64(real))
[docs]
def LOG10(real: ArrayLike) -> np.ndarray:
"""Base-10 logarithm (element-wise). Returns NaN for non-positive inputs."""
with np.errstate(divide="ignore", invalid="ignore"):
return np.log10(_to_f64(real))
[docs]
def SIN(real: ArrayLike) -> np.ndarray:
"""Sine (element-wise)."""
return np.sin(_to_f64(real))
[docs]
def SINH(real: ArrayLike) -> np.ndarray:
"""Hyperbolic sine (element-wise)."""
return np.sinh(_to_f64(real))
[docs]
def SQRT(real: ArrayLike) -> np.ndarray:
"""Square root (element-wise). Returns NaN for negative inputs."""
with np.errstate(invalid="ignore"):
return np.sqrt(_to_f64(real))
[docs]
def TAN(real: ArrayLike) -> np.ndarray:
"""Tangent (element-wise)."""
return np.tan(_to_f64(real))
[docs]
def TANH(real: ArrayLike) -> np.ndarray:
"""Hyperbolic tangent (element-wise)."""
return np.tanh(_to_f64(real))
__all__ = [
# Math Operators
"ADD",
"SUB",
"MULT",
"DIV",
"SUM",
"MAX",
"MIN",
"MAXINDEX",
"MININDEX",
# Math Transforms
"ACOS",
"ASIN",
"ATAN",
"CEIL",
"COS",
"COSH",
"EXP",
"FLOOR",
"LN",
"LOG10",
"SIN",
"SINH",
"SQRT",
"TAN",
"TANH",
]