"""Shared wrapper helpers for quantalib indicator modules. Auto-generated by generate_category_modules.py — DO NOT EDIT. """ from __future__ import annotations import numpy as np from numpy.typing import NDArray from ._bridge import _lib, _check, _dp, _ci, _cd # Optional pandas support try: import pandas as pd # type: ignore[import-untyped] except ImportError: # pragma: no cover pd = None # type: ignore[assignment] # --------------------------------------------------------------------------- # Internal helpers # --------------------------------------------------------------------------- _F64 = np.float64 def _arr(x: object) -> tuple[NDArray[np.float64], object]: """Return (contiguous float64 array, original_index_or_None).""" if x is None: raise ValueError("Input array must not be None") idx = None if pd is not None and isinstance(x, pd.Series): idx = x.index x = x.to_numpy(dtype=_F64, copy=False) elif pd is not None and isinstance(x, pd.DataFrame): idx = x.index x = x.iloc[:, 0].to_numpy(dtype=_F64, copy=False) arr = np.asarray(x, dtype=_F64) if not arr.flags["C_CONTIGUOUS"]: arr = np.ascontiguousarray(arr) if arr.ndim == 0 or len(arr) == 0: raise ValueError("Input array must not be empty") return arr, idx def _ptr(a: NDArray[np.float64]): # noqa: ANN202 """Get ctypes double* from array.""" return a.ctypes.data_as(_dp) def _out(n: int) -> NDArray[np.float64]: """Allocate output array.""" return np.empty(n, dtype=_F64) def _offset(arr: NDArray[np.float64], off: int) -> NDArray[np.float64]: """Apply offset (roll + NaN fill).""" if off != 0: arr = np.roll(arr, off) if off > 0: arr[:off] = np.nan else: arr[off:] = np.nan return arr def _wrap( arr: NDArray[np.float64], idx: object, name: str, category: str, offset: int = 0, ): """Wrap result: apply offset, optionally convert to pd.Series.""" arr = _offset(arr, offset) if idx is not None and pd is not None: s = pd.Series(arr, index=idx, name=name) s.attrs["category"] = category return s return arr def _wrap_multi( arrays: dict[str, NDArray[np.float64]], idx: object, category: str, offset: int = 0, ): """Wrap multi-output result into tuple or DataFrame.""" for k in arrays: arrays[k] = _offset(arrays[k], offset) if idx is not None and pd is not None: df = pd.DataFrame(arrays, index=idx) df.attrs["category"] = category return df return tuple(arrays.values()) # ═══════════════════════════════════════════════════════════════════════════ # Generic pattern helpers # ═══════════════════════════════════════════════════════════════════════════ def _pa( fn_name: str, close: object, length: int, offset: int, default_length: int, label: str, category: str, ) -> object: """Generic Pattern A wrapper: single-input + period.""" length = int(length) if length is not None else default_length offset = int(offset) if offset is not None else 0 src, idx = _arr(close) n = len(src) dst = _out(n) _check(getattr(_lib, fn_name)(_ptr(src), n, _ptr(dst), length)) return _wrap(dst, idx, f"{label}_{length}", category, offset) def _pa3( fn_name: str, close: object, offset: int, label: str, category: str, ) -> object: """Generic Pattern A3 wrapper: single-input, no params.""" offset = int(offset) if offset is not None else 0 src, idx = _arr(close) n = len(src) dst = _out(n) _check(getattr(_lib, fn_name)(_ptr(src), n, _ptr(dst))) return _wrap(dst, idx, label, category, offset) def _pf( fn_name: str, actual: object, predicted: object, length: int, offset: int, default_length: int, label: str, category: str, ) -> object: """Generic Pattern F wrapper: actual+predicted+period.""" length = int(length) if length is not None else default_length offset = int(offset) if offset is not None else 0 a, idx = _arr(actual) p, _ = _arr(predicted) n = len(a) dst = _out(n) _check(getattr(_lib, fn_name)(_ptr(a), _ptr(p), n, _ptr(dst), length)) return _wrap(dst, idx, f"{label}_{length}", category, offset) def _pg( fn_name: str, close: object, volume: object, offset: int, label: str, category: str, ) -> object: """Pattern G: source+volume, no period.""" offset = int(offset) if offset is not None else 0 c, idx = _arr(close) v, _ = _arr(volume) n = len(c) dst = _out(n) _check(getattr(_lib, fn_name)(_ptr(c), _ptr(v), n, _ptr(dst))) return _wrap(dst, idx, label, category, offset) def _pg2( fn_name: str, close: object, volume: object, length: int, offset: int, default_length: int, label: str, category: str, ) -> object: """Pattern G2: source+volume+period.""" length = int(length) if length is not None else default_length offset = int(offset) if offset is not None else 0 c, idx = _arr(close) v, _ = _arr(volume) n = len(c) dst = _out(n) _check(getattr(_lib, fn_name)(_ptr(c), _ptr(v), n, _ptr(dst), length)) return _wrap(dst, idx, f"{label}_{length}", category, offset) def _ph( fn_name: str, x: object, y: object, length: int, offset: int, default_length: int, label: str, category: str, ) -> object: """Pattern H: X+Y+period.""" length = int(length) if length is not None else default_length offset = int(offset) if offset is not None else 0 xarr, idx = _arr(x) yarr, _ = _arr(y) n = len(xarr) dst = _out(n) _check(getattr(_lib, fn_name)(_ptr(xarr), _ptr(yarr), n, _ptr(dst), length)) return _wrap(dst, idx, f"{label}_{length}", category, offset) def _ohlcv_bars_period( fn_name: str, open: object, high: object, low: object, close: object, volume: object, period: int, offset: int, default_period: int, label: str, category: str, ) -> object: """OHLCV bars + period → single output (BuildBars pattern).""" period = int(period) if period is not None else default_period offset = int(offset) if offset is not None else 0 o, idx = _arr(open) h, _ = _arr(high) l, _ = _arr(low) c, _ = _arr(close) v, _ = _arr(volume) n = len(o) dst = _out(n) _check(getattr(_lib, fn_name)( _ptr(o), _ptr(h), _ptr(l), _ptr(c), _ptr(v), period, n, _ptr(dst))) return _wrap(dst, idx, f"{label}_{period}", category, offset) def _hlc_period( fn_name: str, high: object, low: object, close: object, period: int, offset: int, default_period: int, label: str, category: str, ) -> object: """HLC + period → single output.""" period = int(period) if period is not None else default_period offset = int(offset) if offset is not None else 0 h, idx = _arr(high) l, _ = _arr(low) c, _ = _arr(close) n = len(h) dst = _out(n) _check(getattr(_lib, fn_name)( _ptr(h), _ptr(l), _ptr(c), period, n, _ptr(dst))) return _wrap(dst, idx, f"{label}_{period}", category, offset) def _src_period( fn_name: str, source: object, period: int, offset: int, default_period: int, label: str, category: str, ) -> object: """source + period → single output (BuildSeries pattern, src,period,n,dst).""" period = int(period) if period is not None else default_period offset = int(offset) if offset is not None else 0 src, idx = _arr(source) n = len(src) dst = _out(n) _check(getattr(_lib, fn_name)(_ptr(src), period, n, _ptr(dst))) return _wrap(dst, idx, f"{label}_{period}", category, offset)