diff --git a/.env b/.env index 940f490..08d4f25 100644 --- a/.env +++ b/.env @@ -34,7 +34,7 @@ API_SECRET_KEY=2a344f0149442c857fb56c038c0c7d1b113883b830bec792c76f1e0efa15d6bb # PRIMARY: Helius (ONLY PROVIDER THAT WORKS RELIABLY) # Drift SDK REQUIRES WebSocket subscriptions - Alchemy doesn't support this # Alchemy "working" state was temporary - always breaks after first trade or shortly after init -SOLANA_RPC_URL=https://mainnet.helius-rpc.com/?api-key=5e236449-f936-4af7-ae38-f15e2f1a3757 +SOLANA_RPC_URL=https://solana-mainnet.g.alchemy.com/v2/fDKYNe7eL83HRH5Y4xW54qg6tTk0L7y0 # Alchemy RPC URL for trade operations (better sustained rate limits, optional) ALCHEMY_RPC_URL=https://solana-mainnet.g.alchemy.com/v2/fDKYNe7eL83HRH5Y4xW54qg6tTk0L7y0 diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index 24f1645..faec5b1 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -1426,6 +1426,28 @@ trade.realizedPnL += actualRealizedPnL // NOT: result.realizedPnL from SDK - **Lesson:** Always validate input data for financial calculations, especially when data might not exist yet - **Monitoring:** Watch logs for "🔍 Flip-flop price check: $X → $Y = Z%" to verify correct calculations +35. **Phantom trades need exitReason for cleanup (CRITICAL - Fixed Nov 15, 2025):** + - **Symptom:** Position Manager keeps restoring phantom trade on every restart, triggers false runner stop loss alerts + - **Root Cause:** Phantom auto-closure sets `status='phantom'` but leaves `exitReason=NULL` + - **Bug:** Startup validator checks `exitReason !== null` (line 122 of init-position-manager.ts), ignores status field + - **Consequence:** Phantom trade with exitReason=NULL treated as "open" and restored to Position Manager + - **Real incident:** Nov 14 phantom trade (cmhy6xul20067nx077agh260n) caused 232% size mismatch, hundreds of false "🔴 RUNNER STOP LOSS" alerts + - **Fix:** When auto-closing phantom trades, MUST set exitReason: + ```typescript + // In app/api/trading/execute/route.ts (phantom detection): + await updateTradeExit({ + tradeId: trade.id, + exitPrice: currentPrice, + exitReason: 'manual', // CRITICAL: Must set exitReason for cleanup + realizedPnL: actualPnL, + status: 'phantom' + }) + ``` + - **Manual cleanup:** If phantom already exists: `UPDATE "Trade" SET "exitReason" = 'manual' WHERE status = 'phantom' AND "exitReason" IS NULL` + - **Impact:** Without exitReason, phantom trades create ghost positions that trigger false alerts and pollute monitoring + - **Verification:** After restart, check logs for "Found 0 open trades" (not "Found 1 open trades to restore") + - **Lesson:** status field is for classification, exitReason is for lifecycle management - both must be set on closure + ## File Conventions - **API routes:** `app/api/[feature]/[action]/route.ts` (Next.js 15 App Router)