- Startup validation now updates entryPrice to match Drift's actual value
- Prevents tracking with wrong entry price after container restarts
- Also updates positionSizeUSD to reflect current position (runner after TP1)
Bug: When reopening closed trades found on Drift, used stale DB entry price
Result: Stop loss calculated from wrong entry (41.51 vs actual 41.31)
Impact: 0.14% difference in SL placement (~$0.20 per SOL)
Fix: Query Drift for real entry price and update DB during restoration
Files: lib/startup/init-position-manager.ts
- Document build cache accumulation problem (40-50 GB typical)
- Add cleanup commands: image prune, builder prune, volume prune
- Recommend running after each deployment or weekly
- Typical space freed: 40-55 GB per cleanup
- Clarify what's safe vs not safe to delete
- Part of maintaining healthy development environment
**Problem 1: Rate Limit Cascade**
- Position Manager tried to close repeatedly, overwhelming Helius RPC (10 req/s limit)
- Base retry delay was too aggressive (2s → 4s → 8s)
- No graceful handling when 429 errors occur
**Problem 2: Orphaned Positions After Restart**
- Container restarts lost Position Manager state
- Positions marked 'closed' in DB but still open on Drift (failed close transactions)
- No cross-validation between database and actual Drift positions
**Solutions Implemented:**
1. **Increased retry delays (orders.ts)**:
- Base delay: 2s → 5s (progression now 5s → 10s → 20s)
- Reduces RPC pressure during rate limit situations
- Gives Helius time to recover between retries
- Documented Helius limits: 100 req/s burst, 10 req/s sustained (free tier)
2. **Startup position validation (init-position-manager.ts)**:
- Cross-checks last 24h of 'closed' trades against actual Drift positions
- If DB says closed but Drift shows open → reopens in DB to restore tracking
- Prevents unmonitored positions from existing after container restarts
- Logs detailed mismatch info for debugging
3. **Rate limit-aware exit handling (position-manager.ts)**:
- Detects 429 errors during position close
- Keeps trade in monitoring instead of removing it
- Natural retry on next price update (vs aggressive 2s loop)
- Prevents marking position as closed when transaction actually failed
**Impact:**
- Eliminates orphaned positions after restarts
- Reduces RPC pressure by 2.5x (5s vs 2s base delay)
- Graceful degradation under rate limits
- Position Manager continues monitoring even during temporary RPC issues
**Testing needed:**
- Monitor next container restart to verify position restoration works
- Check rate limit analytics after next close attempt
- Verify no more phantom 'closed' positions when Drift shows open
**Root Causes:**
1. Auto-flip logic could create phantom trades if close failed
2. Position size mismatches (0.01 SOL vs 11.92 SOL expected) not caught
3. Multiple trades for same symbol+direction in database
**Preventive Measures:**
1. **Startup Validation (lib/startup/init-position-manager.ts)**
- Validates all open trades against Drift positions on startup
- Auto-closes phantom trades with <50% expected size
- Logs size mismatches for manual review
- Prevents Position Manager from tracking ghost positions
2. **Duplicate Position Prevention (app/api/trading/execute/route.ts)**
- Blocks opening same-direction position on same symbol
- Returns 400 error if duplicate detected
- Only allows auto-flip (opposite direction close + open)
3. **Runtime Phantom Detection (lib/trading/position-manager.ts)**
- Checks position size every 2s monitoring cycle
- Auto-closes if size ratio <50% (extreme mismatch)
- Logs as 'manual' exit with AUTO_CLEANUP tx
- Removes from monitoring immediately
4. **Quality Score Fix (app/api/trading/check-risk/route.ts)**
- Hardcoded minScore=60 (removed non-existent config reference)
**Prevention Summary:**
- ✅ Startup validation catches historical phantoms
- ✅ Duplicate check prevents new phantoms
- ✅ Runtime detection catches size mismatches <30s after they occur
- ✅ All three layers work together for defense-in-depth
Issue: User had LONG (phantom) + SHORT (undersized 0.01 SOL vs 11.92 expected)
Fix: Both detected and closed, bot now clean with 0 active trades
- Added /close Telegram command for full position closure
- Updated /reduce to accept 10-100% (was 10-90%)
- Implemented auto-flip logic: automatically closes opposite position when signal reverses
- Fixed risk check to allow opposite direction trades (signal flips)
- Enhanced Position Manager to cancel orders when removing trades
- Added startup initialization for Position Manager (restores trades on restart)
- Fixed analytics to show stopped-out trades (manual DB update for orphaned trade)
- Updated reduce endpoint to route 100% closes through closePosition for proper cleanup
- All position closures now guarantee TP/SL order cancellation on Drift