From f907af23d70b88a0566cfbf9d333c690748b037f Mon Sep 17 00:00:00 2001 From: Stefan Jansen Date: Tue, 11 Aug 2026 13:31:55 -0400 Subject: [PATCH] fix: prevent stale RSI cache in StochRSI --- .../engineer/features/momentum/stochrsi.py | 60 ++++++++++--------- 1 file changed, 33 insertions(+), 27 deletions(-) diff --git a/src/ml4t/engineer/features/momentum/stochrsi.py b/src/ml4t/engineer/features/momentum/stochrsi.py index c84565f..0495f8d 100644 --- a/src/ml4t/engineer/features/momentum/stochrsi.py +++ b/src/ml4t/engineer/features/momentum/stochrsi.py @@ -17,37 +17,14 @@ @jit(nopython=True, cache=True, fastmath=False) # type: ignore[misc] -def stochrsi_fastk_numba( - close: npt.NDArray[np.float64], - timeperiod: int = 14, +def _stochrsi_fastk_from_rsi_numba( + rsi_values: npt.NDArray[np.float64], fastk_period: int = 5, ) -> npt.NDArray[np.float64]: - """ - Calculate STOCHRSI %K using Numba for performance. - - Parameters - ---------- - close : npt.NDArray - Price data (typically closing close) - timeperiod : int, default 14 - Period for RSI calculation - fastk_period : int, default 5 - Period for Stochastic calculation on RSI - - Returns - ------- - npt.NDArray - The STOCHRSI %K close (0-100 scale) - """ - n = len(close) - - # Calculate RSI first - rsi_values = rsi_numba(close, timeperiod) - - # Initialize output array + """Calculate STOCHRSI %K from precomputed RSI values.""" + n = len(rsi_values) fastk = np.full(n, np.nan) - # Find first valid RSI first_rsi = -1 for i in range(n): if not np.isnan(rsi_values[i]): @@ -82,6 +59,35 @@ def stochrsi_fastk_numba( return fastk +def stochrsi_fastk_numba( + close: npt.NDArray[np.float64], + timeperiod: int = 14, + fastk_period: int = 5, +) -> npt.NDArray[np.float64]: + """ + Calculate STOCHRSI %K using Numba for performance. + + RSI is computed outside the cached StochRSI kernel so a cached caller cannot + retain an older compiled RSI implementation after a package upgrade. + + Parameters + ---------- + close : npt.NDArray + Price data (typically closing close) + timeperiod : int, default 14 + Period for RSI calculation + fastk_period : int, default 5 + Period for Stochastic calculation on RSI + + Returns + ------- + npt.NDArray + The STOCHRSI %K close (0-100 scale) + """ + rsi_values = rsi_numba(close, timeperiod) + return _stochrsi_fastk_from_rsi_numba(rsi_values, fastk_period) + + def stochrsi_numba( close: npt.NDArray[np.float64], timeperiod: int = 14,