diff --git a/CHANGELOG.md b/CHANGELOG.md index d8f1381..1cc4f3d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,13 @@ Format: [Keep a Changelog](https://keepachangelog.com/en/1.1.0/); versioning: [S ## [Unreleased] ### Fixed +- `utils.determine_strategy_side`: signal dtype was platform-dependent (int32 on + Windows); now always int64. +- `data.labeling.calculate_t_value_linear_regression`: constant series now returns + NaN (0/0 is undefined) as documented, instead of 0.0. +- `data.differentiation.fractional_difference_std`: result had object dtype; now float. +- Raw-string docstrings in `denoising`/`bekker_parkinson` (LaTeX `\(` raised + SyntaxWarning on Python 3.12). - `backtest.bet_sizing`: `avgActiveSignals`/`Signal` silently returned empty results — the module imported `mpPandasObj` while `RiskLabAI.hpc` exports `mp_pandas_obj`, so a placeholder returning an empty DataFrame always took over. The silent placeholder is removed; the real import is used. diff --git a/RiskLabAI/data/denoise/denoising.py b/RiskLabAI/data/denoise/denoising.py index 39fbfef..8d3f9f0 100644 --- a/RiskLabAI/data/denoise/denoising.py +++ b/RiskLabAI/data/denoise/denoising.py @@ -95,7 +95,7 @@ def fit_kde( def _mp_pdf_fit_error( variance: float, q: float, eigenvalues: np.ndarray, bandwidth: float ) -> float: # <-- FIX 2: Added bandwidth - """ + r""" Error function for fitting the MP PDF to observed eigenvalues. Calculates the sum of squared errors between the theoretical @@ -136,7 +136,7 @@ def _mp_pdf_fit_error( def find_max_eval( eigenvalues: np.ndarray, q: float, bandwidth: float ) -> Tuple[float, float]: - """ + r""" Find the maximum theoretical eigenvalue (\(\lambda_{max}\)) by fitting the Marcenko-Pastur distribution. diff --git a/RiskLabAI/data/differentiation/differentiation.py b/RiskLabAI/data/differentiation/differentiation.py index fc104be..f9ed7a7 100644 --- a/RiskLabAI/data/differentiation/differentiation.py +++ b/RiskLabAI/data/differentiation/differentiation.py @@ -111,7 +111,7 @@ def fractional_difference_std( weights_cumsum_abs /= weights_cumsum_abs[-1] skip = np.searchsorted(weights_cumsum_abs, threshold) - result_df = pd.DataFrame(index=series.index, columns=series.columns) + result_df = pd.DataFrame(index=series.index, columns=series.columns, dtype=float) for name in series.columns: # Use .ffill() - fillna(method=) is deprecated diff --git a/RiskLabAI/data/labeling/financial_labels.py b/RiskLabAI/data/labeling/financial_labels.py index 230ff60..dcea92a 100644 --- a/RiskLabAI/data/labeling/financial_labels.py +++ b/RiskLabAI/data/labeling/financial_labels.py @@ -41,8 +41,9 @@ def calculate_t_value_linear_regression(prices: pd.Series) -> float: return np.nan if ols.stderr == 0: - # Handle perfect fit (vertical line, or constant) - return np.sign(ols.slope) * np.inf if ols.slope != 0 else 0.0 + # Perfect trend: t -> +/- inf. Constant series: 0/0 -> undefined (NaN), + # consistent with the documented contract. + return np.sign(ols.slope) * np.inf if ols.slope != 0 else np.nan return ols.slope / ols.stderr diff --git a/RiskLabAI/features/microstructural_features/bekker_parkinson_volatility_estimator.py b/RiskLabAI/features/microstructural_features/bekker_parkinson_volatility_estimator.py index 91593dc..daf8826 100644 --- a/RiskLabAI/features/microstructural_features/bekker_parkinson_volatility_estimator.py +++ b/RiskLabAI/features/microstructural_features/bekker_parkinson_volatility_estimator.py @@ -52,7 +52,7 @@ def sigma_estimates(beta: pd.Series, gamma: pd.Series) -> pd.Series: def bekker_parkinson_volatility_estimates( high_prices: pd.Series, low_prices: pd.Series, window_span: int = 20 ) -> pd.Series: - """ + r""" Compute Bekker-Parkinson volatility estimates from high and low prices. This function first calculates the Corwin-Schultz \(\beta\) and \(\gamma\) diff --git a/RiskLabAI/utils/momentum_mean_reverting_strategy_sides.py b/RiskLabAI/utils/momentum_mean_reverting_strategy_sides.py index 4f8e8d3..1c352a2 100644 --- a/RiskLabAI/utils/momentum_mean_reverting_strategy_sides.py +++ b/RiskLabAI/utils/momentum_mean_reverting_strategy_sides.py @@ -58,7 +58,9 @@ def determine_strategy_side( slow_ma = prices.rolling(window=slow_window, min_periods=1).mean() # Create signal: 1 if fast > slow, -1 if fast < slow - signal = (fast_ma >= slow_ma).astype(int) * 2 - 1 + # Explicit int64: plain `int` maps to int32 on Windows, which makes the + # returned dtype platform-dependent. + signal = (fast_ma >= slow_ma).astype("int64") * 2 - 1 if mean_reversion: # Invert the signal for mean reversion