diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index 8d8a92e..66d1f36 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -2798,6 +2798,92 @@ trade.realizedPnL += actualRealizedPnL // NOT: result.realizedPnL from SDK * `config/trading.ts` - Bot reads `MIN_SIGNAL_QUALITY_SCORE` (correct name) * `.env` file - Contains `MIN_SIGNAL_QUALITY_SCORE=60` (correct name) - **Fix:** + - **Lesson:** When creating settings UI, always use EXACT ENV variable names from actual bot code. Mismatched names cause silent failures where user actions have no effect. Test settings changes end-to-end (UI → .env → bot behavior). + +55. **BlockedSignalTracker using Pyth cache instead of Drift oracle (CRITICAL - Fixed Nov 20, 2025):** + - **Symptom:** All `priceAfter1Min/5Min/15Min/30Min` fields staying NULL, no price tracking happening + - **Root Cause:** BlockedSignalTracker was calling `getPythPriceMonitor().getCachedPrice()` which didn't have SOL-PERP prices + - **Real incident (Nov 20):** + * Multi-timeframe data collection running for 30+ hours + * 4 signals saved to BlockedSignal table (15min: 2, 60min: 2) + * Tracker running every 5 minutes: "📊 Tracking 4 blocked signals..." + * But logs showed: "⚠️ No price available for SOL-PERP, skipping" (repeated 100+ times) + * All priceAfter* fields remained NULL + * No analysisComplete transitions + * No wouldHitTP1/TP2/SL detection + - **Why Pyth cache empty:** + * Pyth price monitor used for Position Manager real-time monitoring + * BlockedSignalTracker runs every 5 minutes (not real-time) + * Cache may not have recent prices when tracker runs + * Wrong data source for background job + - **Impact:** Multi-timeframe data collection completely non-functional for Phase 1 analysis + - **Fix (Nov 20, 2025):** + ```typescript + // BEFORE (BROKEN - lib/analysis/blocked-signal-tracker.ts): + import { getPythPriceMonitor } from '../pyth/price-monitor' + + private async trackSignal(signal: BlockedSignalWithTracking): Promise { + const priceMonitor = getPythPriceMonitor() + const latestPrice = priceMonitor.getCachedPrice(signal.symbol) + + if (!latestPrice || !latestPrice.price) { + console.log(`⚠️ No price available for ${signal.symbol}, skipping`) + return + } + const currentPrice = latestPrice.price + // ... rest of tracking + } + + // AFTER (FIXED): + import { initializeDriftService } from '../drift/client' + import { SUPPORTED_MARKETS } from '../../config/trading' + + private async trackPrices(): Promise { + // Initialize Drift service ONCE before processing all signals + const driftService = await initializeDriftService() + if (!driftService) { + console.log('⚠️ Drift service not available, skipping price tracking') + return + } + // ... process signals + } + + private async trackSignal(signal: BlockedSignalWithTracking): Promise { + // Get current price from Drift oracle (always available) + const driftService = await initializeDriftService() + const marketConfig = SUPPORTED_MARKETS[signal.symbol] + + if (!marketConfig) { + console.log(`⚠️ No market config for ${signal.symbol}, skipping`) + return + } + + const currentPrice = await driftService.getOraclePrice(marketConfig.driftMarketIndex) + const entryPrice = Number(signal.entryPrice) + + if (entryPrice === 0) { + console.log(`⚠️ Entry price is 0 for ${signal.symbol}, skipping`) + return + } + // ... rest of tracking with actual prices + } + ``` + - **Behavior now:** + * Tracker gets fresh prices from Drift oracle every run + * Logs show: "📍 SOL-PERP long @ 1min: $142.34 (4.10%)" + * Database updates: priceAfter1Min, priceAfter5Min, priceAfter15Min, priceAfter30Min all populate + * analysisComplete transitions to true after 30 minutes + * wouldHitTP1/TP2/SL detection working based on ATR targets + - **Verification (Nov 20):** + * 2 signals now complete with full price tracking data + * 15min signal: wouldHitTP1=true, wouldHitTP2=true (both targets hit) + * 60min signal: wouldHitTP1=true (TP1 hit, TP2 pending) + * analysisComplete=true for both after 30min window + - **Files changed:** + * `lib/analysis/blocked-signal-tracker.ts` - Changed price source + added Drift init + - **Commits:** 6b00303 "fix: BlockedSignalTracker now uses Drift oracle prices" + - **Impact:** Multi-timeframe data collection now operational for Phase 1 analysis (50+ signals per timeframe target) + - **Lesson:** Background jobs should use Drift oracle prices (always available) not Pyth cache (real-time only). Always initialize external services before calling their methods. Verify background jobs are actually working by checking database state, not just logs. ```typescript // In app/api/settings/route.ts (lines ~150, ~270) // BEFORE (BROKEN):