"""
Volatility Indicators — Measure the magnitude of price fluctuations.
Functions
---------
ATR — Average True Range
NATR — Normalized Average True Range
TRANGE — True Range
CHAIKIN_VOL — Chaikin Volatility
MASS — Mass Index
BBPERCENT — Bollinger %B
BBWIDTH — Bollinger Bandwidth
HISTORICAL_VOLATILITY — Annualized close-to-close volatility
ULCER_INDEX — Ulcer Index
STARC — Stoller Average Range Channels
"""
from __future__ import annotations
import numpy as np
from numpy.typing import ArrayLike
from ferro_ta._ferro_ta import (
atr as _atr,
)
from ferro_ta._ferro_ta import (
bbpercent as _bbpercent,
)
from ferro_ta._ferro_ta import (
bbwidth as _bbwidth,
)
from ferro_ta._ferro_ta import (
chaikin_vol as _chaikin_vol,
)
from ferro_ta._ferro_ta import (
historical_volatility as _historical_volatility,
)
from ferro_ta._ferro_ta import (
mass as _mass,
)
from ferro_ta._ferro_ta import (
natr as _natr,
)
from ferro_ta._ferro_ta import (
starc as _starc,
)
from ferro_ta._ferro_ta import (
trange as _trange,
)
from ferro_ta._ferro_ta import (
ulcer_index as _ulcer_index,
)
from ferro_ta._utils import _to_f64, apply_nan_policy
from ferro_ta.core.exceptions import _normalize_rust_error
[docs]
def ATR(
high: ArrayLike,
low: ArrayLike,
close: ArrayLike,
timeperiod: int = 14,
*,
nan_policy: str = "propagate",
) -> np.ndarray:
"""Average True Range.
Parameters
----------
high : array-like
Sequence of high prices.
low : array-like
Sequence of low prices.
close : array-like
Sequence of closing prices.
timeperiod : int, optional
Smoothing period (default 14).
nan_policy : {"propagate", "skip"}, optional
``"propagate"`` (default, TA-Lib semantics): a NaN input poisons every
later value. ``"skip"``: rows with a non-finite input are dropped, the
indicator runs on the remaining rows, and NaN is written back at the
dropped rows (matches the streaming classes tick for tick).
Returns
-------
numpy.ndarray
Array of ATR values; leading ``timeperiod - 1`` entries are ``NaN``.
"""
try:
return apply_nan_policy(
lambda hi, lo, cl: _atr(hi, lo, cl, timeperiod),
(_to_f64(high), _to_f64(low), _to_f64(close)),
nan_policy,
)
except ValueError as e:
_normalize_rust_error(e)
[docs]
def NATR(
high: ArrayLike,
low: ArrayLike,
close: ArrayLike,
timeperiod: int = 14,
) -> np.ndarray:
"""Normalized Average True Range.
Parameters
----------
high : array-like
Sequence of high prices.
low : array-like
Sequence of low prices.
close : array-like
Sequence of closing prices.
timeperiod : int, optional
Smoothing period (default 14).
Returns
-------
numpy.ndarray
Array of NATR values (percentage); leading ``timeperiod - 1`` entries are ``NaN``.
"""
try:
return _natr(_to_f64(high), _to_f64(low), _to_f64(close), timeperiod)
except ValueError as e:
_normalize_rust_error(e)
[docs]
def TRANGE(
high: ArrayLike,
low: ArrayLike,
close: ArrayLike,
) -> np.ndarray:
"""True Range.
Parameters
----------
high : array-like
Sequence of high prices.
low : array-like
Sequence of low prices.
close : array-like
Sequence of closing prices.
Returns
-------
numpy.ndarray
Array of True Range values.
"""
try:
return _trange(_to_f64(high), _to_f64(low), _to_f64(close))
except ValueError as e:
_normalize_rust_error(e)
[docs]
def CHAIKIN_VOL(
high: ArrayLike,
low: ArrayLike,
timeperiod: int = 10,
rocperiod: int = 10,
) -> np.ndarray:
"""Chaikin Volatility — ROC of an EMA of the high–low range.
Parameters
----------
high : array-like
Sequence of high prices.
low : array-like
Sequence of low prices.
timeperiod : int, optional
EMA period of the range (default 10).
rocperiod : int, optional
Rate-of-change lookback of that EMA (default 10).
Returns
-------
numpy.ndarray
Array of Chaikin Volatility values (percent).
"""
try:
return _chaikin_vol(_to_f64(high), _to_f64(low), timeperiod, rocperiod)
except ValueError as e:
_normalize_rust_error(e)
[docs]
def MASS(
high: ArrayLike,
low: ArrayLike,
timeperiod: int = 9,
sumperiod: int = 25,
) -> np.ndarray:
"""Mass Index — rolling sum of the single/double EMA ratio of the range.
Parameters
----------
high : array-like
Sequence of high prices.
low : array-like
Sequence of low prices.
timeperiod : int, optional
EMA period (default 9).
sumperiod : int, optional
Rolling-sum length of the EMA ratio (default 25).
Returns
-------
numpy.ndarray
Array of Mass Index values.
"""
try:
return _mass(_to_f64(high), _to_f64(low), timeperiod, sumperiod)
except ValueError as e:
_normalize_rust_error(e)
[docs]
def BBPERCENT(
close: ArrayLike,
timeperiod: int = 5,
nbdevup: float = 2.0,
nbdevdn: float = 2.0,
) -> np.ndarray:
"""Bollinger %B — ``(close - lower) / (upper - lower)``.
Parameters
----------
close : array-like
Sequence of closing prices.
timeperiod : int, optional
Bollinger window (default 5).
nbdevup : float, optional
Upper-band standard deviations (default 2.0).
nbdevdn : float, optional
Lower-band standard deviations (default 2.0).
Returns
-------
numpy.ndarray
Array of %B values. Leading ``timeperiod - 1`` entries are ``NaN``.
"""
try:
return _bbpercent(_to_f64(close), timeperiod, nbdevup, nbdevdn)
except ValueError as e:
_normalize_rust_error(e)
[docs]
def BBWIDTH(
close: ArrayLike,
timeperiod: int = 5,
nbdevup: float = 2.0,
nbdevdn: float = 2.0,
) -> np.ndarray:
"""Bollinger Bandwidth — ``(upper - lower) / middle``.
Parameters
----------
close : array-like
Sequence of closing prices.
timeperiod : int, optional
Bollinger window (default 5).
nbdevup : float, optional
Upper-band standard deviations (default 2.0).
nbdevdn : float, optional
Lower-band standard deviations (default 2.0).
Returns
-------
numpy.ndarray
Array of bandwidth values. Leading ``timeperiod - 1`` entries are ``NaN``.
"""
try:
return _bbwidth(_to_f64(close), timeperiod, nbdevup, nbdevdn)
except ValueError as e:
_normalize_rust_error(e)
[docs]
def HISTORICAL_VOLATILITY(
close: ArrayLike,
timeperiod: int = 20,
annual: float = 252.0,
) -> np.ndarray:
"""Close-to-close historical volatility, annualized and in percent.
Parameters
----------
close : array-like
Sequence of closing prices.
timeperiod : int, optional
Log-return window (default 20).
annual : float, optional
Annualization factor (default 252).
Returns
-------
numpy.ndarray
``stddev(ln returns) * sqrt(annual) * 100``. First valid value is
at index ``timeperiod``.
"""
try:
return _historical_volatility(_to_f64(close), timeperiod, annual)
except ValueError as e:
_normalize_rust_error(e)
[docs]
def ULCER_INDEX(close: ArrayLike, timeperiod: int = 14) -> np.ndarray:
"""Ulcer Index — RMS of percent drawdowns versus the rolling peak.
Parameters
----------
close : array-like
Sequence of closing prices.
timeperiod : int, optional
Peak and RMS lookback (default 14).
Returns
-------
numpy.ndarray
Array of Ulcer Index values.
"""
try:
return _ulcer_index(_to_f64(close), timeperiod)
except ValueError as e:
_normalize_rust_error(e)
[docs]
def STARC(
high: ArrayLike,
low: ArrayLike,
close: ArrayLike,
timeperiod: int = 15,
atr_period: int = 15,
multiplier: float = 2.0,
) -> tuple[np.ndarray, np.ndarray, np.ndarray]:
"""Stoller Average Range Channels — SMA(close) ± ``multiplier * ATR``.
Parameters
----------
high : array-like
Sequence of high prices.
low : array-like
Sequence of low prices.
close : array-like
Sequence of closing prices.
timeperiod : int, optional
SMA period of close (default 15).
atr_period : int, optional
ATR period (default 15).
multiplier : float, optional
ATR multiple (default 2.0).
Returns
-------
tuple[numpy.ndarray, numpy.ndarray, numpy.ndarray]
``(upper, middle, lower)``.
"""
try:
return _starc(
_to_f64(high),
_to_f64(low),
_to_f64(close),
timeperiod,
atr_period,
multiplier,
)
except ValueError as e:
_normalize_rust_error(e)
__all__ = [
"ATR",
"NATR",
"TRANGE",
"CHAIKIN_VOL",
"MASS",
"BBPERCENT",
"BBWIDTH",
"HISTORICAL_VOLATILITY",
"ULCER_INDEX",
"STARC",
]