diff --git a/factor_attribution.py b/factor_attribution.py index ee90b95..03d42f2 100644 --- a/factor_attribution.py +++ b/factor_attribution.py @@ -308,6 +308,8 @@ def run_factor_regression( fitted = x @ coefficients residuals = y.to_numpy() - fitted + residual_series = pd.Series(residuals, index=regression_frame.index) + residual_vol_ann = float(residual_series.std(ddof=1) * np.sqrt(TRADING_DAYS_PER_YEAR)) dof = n_obs - param_count if dof > 0: @@ -323,12 +325,10 @@ def run_factor_regression( where=standard_errors > 0, ) p_values = 2.0 * stats.t.sf(np.abs(t_stats), df=dof) - residual_vol_ann = float(pd.Series(residuals, index=regression_frame.index).std(ddof=1) * np.sqrt(TRADING_DAYS_PER_YEAR)) adj_r_squared_is_defined = True else: t_stats = np.full_like(coefficients, np.nan, dtype=float) p_values = np.full_like(coefficients, np.nan, dtype=float) - residual_vol_ann = float("nan") adj_r_squared_is_defined = False ss_total = float(((y - y.mean()) ** 2).sum()) diff --git a/tests/test_factor_attribution.py b/tests/test_factor_attribution.py index e615c0b..9b369db 100644 --- a/tests/test_factor_attribution.py +++ b/tests/test_factor_attribution.py @@ -499,7 +499,7 @@ class RegressionTests(unittest.TestCase): self.assertTrue(np.isnan(result["p_values"]["MKT_RF"])) self.assertTrue(np.isnan(result["p_values"]["SMB"])) self.assertTrue(np.isnan(result["adj_r_squared"])) - self.assertTrue(np.isnan(result["residual_vol_ann"])) + self.assertAlmostEqual(result["residual_vol_ann"], 0.0, places=12) def test_run_factor_regression_rejects_rank_deficient_designs(self): dates = pd.date_range("2024-01-01", periods=6, freq="B")