docs: Add Common Pitfall #35 - phantom trades need exitReason

- Documented bug where phantom auto-closure sets status='phantom' but left exitReason=NULL
- Startup validator only checks exitReason, not status field
- Ghost positions created false runner stop loss alerts (232% size mismatch)
- Fix: MUST set exitReason when closing phantom trades
- Manual cleanup: UPDATE Trade SET exitReason='manual' WHERE status='phantom' AND exitReason IS NULL
- Verified: System now shows 'Found 0 open trades' after cleanup
This commit is contained in:
mindesbunister
2025-11-15 12:24:00 +01:00
parent fa4b187f46
commit 1a990054ab
2 changed files with 23 additions and 1 deletions

View File

@@ -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)