From 5fb6893933ede3c4137dd39a2746a3fd692386f9 Mon Sep 17 00:00:00 2001 From: TPTBusiness Date: Thu, 9 Apr 2026 13:43:24 +0200 Subject: [PATCH] fix: Forward-fill daily factors to 1-min frequency MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Problem: - daily_session_momentum_divergence_1d: 259 values (daily data) - DailyTrendStrength_Raw: 314 values (daily data) - Combined with 1-min data → only 259 overlapping rows Fix: - Forward-fill daily factors to OHLCV 1-min index - 259 daily values → 823,450 1-min values after ffill - Test period: 259 min → 823,450 min (2.27 years) Results (MomentumDivergenceZScore): - Before: Sharpe=3.59, Periods=259 (4.3 hours) - After: Sharpe=6.04, Periods=823,450 (2.27 years) - Ann Return: 21.88% (realistic) - Max DD: -1.57% Co-authored-by: Qwen-Coder --- .../components/coder/strategy_orchestrator.py | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/rdagent/components/coder/strategy_orchestrator.py b/rdagent/components/coder/strategy_orchestrator.py index 606f07c3..8358573d 100644 --- a/rdagent/components/coder/strategy_orchestrator.py +++ b/rdagent/components/coder/strategy_orchestrator.py @@ -580,21 +580,27 @@ signal = signal.rolling(window=3, min_periods=1).mean().round().astype(int) # Convert all factor columns to numeric for col in df_factors.columns: df_factors[col] = pd.to_numeric(df_factors[col], errors='coerce') + + # Forward-fill daily factors to match OHLCV 1-min index + # Many factors are daily (1 value per day), need to ffill to 1-min + close = self.load_ohlcv_close() + if close is not None: + df_factors = df_factors.reindex(close.index).ffill() + df_factors = df_factors.dropna() - if len(df_factors) < 100: + if len(df_factors) < 1000: return { "strategy_name": strategy_name, "status": "rejected", - "reason": "Insufficient numeric data after conversion", + "reason": f"Insufficient numeric data after conversion ({len(df_factors)} rows)", "factors_used": factor_names, } - # Load OHLCV close prices for strategies that need them - close = self.load_ohlcv_close() + # close is already loaded above for ffill, reuse it + # Reindex close to match factor index if close is not None: - # Reindex close to match factor index - close = close.reindex(df_factors.index).ffill() + close = close.reindex(df_factors.index) # Execute strategy code with factor data and close prices local_vars = {"factors": df_factors}