Summary
VolumeFeatures.calculate_obv runs a Python loop accumulating OBV. yfinance frequently returns NaN for the most recent bar's volume. One NaN in the loop causes all subsequent OBV values to become NaN. handle_missing_data (ffill) then fills the entire NaN tail with the last valid OBV value, which may be weeks old.
Evidence
src/features/regime_features.py lines 403-413: no NaN guard in the OBV accumulation loop.
handle_missing_data is called at line 419, after the loop — after NaN has already propagated.
Fix
Guard at the start of the loop: vol = volume.fillna(0) before OBV accumulation (zero volume for unknown bars is the conventional treatment).
Summary
VolumeFeatures.calculate_obvruns a Python loop accumulating OBV. yfinance frequently returnsNaNfor the most recent bar's volume. OneNaNin the loop causes all subsequent OBV values to becomeNaN.handle_missing_data(ffill) then fills the entire NaN tail with the last valid OBV value, which may be weeks old.Evidence
src/features/regime_features.pylines 403-413: no NaN guard in the OBV accumulation loop.handle_missing_datais called at line 419, after the loop — after NaN has already propagated.Fix
Guard at the start of the loop:
vol = volume.fillna(0)before OBV accumulation (zero volume for unknown bars is the conventional treatment).