From 85cd753c85c7ba6bef4257662a48f171dd7a7a22 Mon Sep 17 00:00:00 2001 From: TPTBusiness Date: Thu, 9 Apr 2026 13:20:12 +0200 Subject: [PATCH] feat: Realistic backtesting with OHLCV data (P5 continued) Implemented realistic backtesting: - Load real OHLCV close prices from intraday_pv.h5 - Calculate real price returns (pct_change) - Apply signal positions to real returns with proper alignment - Include spread costs (1.5 bps per trade) - Fallback to factor proxy if OHLCV unavailable Note: Sharpe values now realistic (~0 for random strategies). Strategies need LLM to select predictive factors for positive Sharpe. Co-authored-by: Qwen-Coder --- .gitignore | 4 ++++ rdagent/components/coder/strategy_orchestrator.py | 15 ++++++++------- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/.gitignore b/.gitignore index ee173b43..7f032feb 100644 --- a/.gitignore +++ b/.gitignore @@ -109,3 +109,7 @@ predix_quick_daytrading.py predix_smart_strategy_gen.py test/backtesting/test_smart_strategy_gen.py docs/SMART_STRATEGY_GEN.md + +# OpenACP local workspace (contains secrets) +.openacp +CLAUDE.md diff --git a/rdagent/components/coder/strategy_orchestrator.py b/rdagent/components/coder/strategy_orchestrator.py index 3fe4c7c7..5d889223 100644 --- a/rdagent/components/coder/strategy_orchestrator.py +++ b/rdagent/components/coder/strategy_orchestrator.py @@ -618,21 +618,22 @@ signal = signal.rolling(window=3, min_periods=1).mean().round().astype(int) close = self.load_ohlcv_close() if close is not None: - # Align signal with close prices - common_idx = signal.index.intersection(close.index) - signal_aligned = signal.loc[common_idx].shift(1).fillna(0) - close_aligned = close.loc[common_idx] + # Use factor timestamps as the base (signal is generated on factor data) + # Resample OHLCV close to factor timestamps + signal_index = signal.index + close_aligned = close.reindex(signal_index).ffill() # Calculate real price returns price_returns = close_aligned.pct_change().fillna(0) - # Apply signal positions to real returns - returns = price_returns * signal_aligned + # Apply signal positions to real returns (lagged signal) + signal_positions = signal.shift(1).fillna(0) + returns = price_returns * signal_positions # Include spread costs (1.5 bps per trade = 0.00015) combined_factor = df_factors.mean(axis=1) SPREAD_COST = 0.00015 - signal_changes = signal_aligned.diff().abs().fillna(0) + signal_changes = signal_positions.diff().abs().fillna(0) spread_costs = signal_changes * SPREAD_COST returns = returns - spread_costs else: