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:
22
.github/copilot-instructions.md
vendored
22
.github/copilot-instructions.md
vendored
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user