- Extended getActualFillPriceFromTx() to also extract entry fill prices
- openPosition() now uses actual fill from tx logs (was using oracle price)
- closePosition() already fixed to use actual exit fills
- Both prices now extracted via Drift SDK LogParser OrderActionRecord events
- Eliminates ~0.08% entry and exit price discrepancies vs Drift UI
- P&L calculations now 100% accurate to actual execution prices
Files changed:
- lib/drift/orders.ts (entry extraction in openPosition)
- docs/COMMON_PITFALLS.md (updated Pitfall #89)
Expected impact: Entry AND exit prices match Drift exactly on all future trades
- Documented 5.7% P&L over-reporting bug (Drift $133.03 vs Database $140.56)
- Root cause: closePosition() used oracle price instead of actual fill price
- Fix: getActualFillPriceFromTx() helper extracts real fills from transaction logs
- WrappedEvent has properties directly on object, NOT nested under .data
- References commit c1bff0d (Jan 11, 2026)
- Added comprehensive documentation for TP/SL size mismatch bug
- Root cause: usdToBase() recalculated tokens at each exit price
- Fix: Pass positionSizeTokens from position fill, use tokensToBase()
- Updated Quick Reference Table (now 74 pitfalls)
- Updated last modified date to January 6, 2026
ROOT CAUSE: placePerpOrder() only places orders on Drift order book, doesn't fill.
SOLUTION: placeAndTakePerpOrder() places AND matches against makers atomically.
Real Incident (Dec 31, 2025):
- Dec 30 18:17: SHORT opened at $124.36
- Dec 31 00:30: LONG signal received - should flip position
- Transaction confirmed but Solscan showed 'Place' not 'Fill'
- Position remained open, eventually hit SL twice
- Total loss: ~$40.21
Files changed:
- lib/drift/orders.ts (line 662): placePerpOrder → placeAndTakePerpOrder
- docs/COMMON_PITFALLS.md: Added Bug #90 documentation
Deployment: Dec 31, 2025 11:38 CET (container trading-bot-v4)
- Part 1: Position Manager fractional remnant detection after close attempts
* Check if position < 1.5× minOrderSize after close transaction
* Log to persistent logger with FRACTIONAL_REMNANT_DETECTED
* Track closeAttempts, limit to 3 maximum
* Mark exitReason='FRACTIONAL_REMNANT' in database
* Remove from monitoring after 3 failed attempts
- Part 2: Pre-close validation in closePosition()
* Check if position viable before attempting close
* Reject positions < 1.5× minOrderSize with specific error
* Prevent wasted transaction attempts on too-small positions
* Return POSITION_TOO_SMALL_TO_CLOSE error with manual instructions
- Part 3: Health monitor detection for fractional remnants
* Query Trade table for FRACTIONAL_REMNANT exits in last 24h
* Alert operators with position details and manual cleanup instructions
* Provide trade IDs, symbols, and Drift UI link
- Database schema: Added closeAttempts Int? field to Track attempts
Root cause: Drift protocol exchange constraints can leave fractional positions
Evidence: 3 close transactions confirmed but 0.15 SOL remnant persisted
Financial impact: ,000+ risk from unprotected fractional positions
Status: Fix implemented, awaiting deployment verification
See: docs/COMMON_PITFALLS.md Bug #89 for complete incident details
- Created docs/COMMON_PITFALLS.md with all 72 pitfalls
- Organized by severity and category for better navigation
- Added quick reference table and cross-reference index
- Reduced copilot-instructions.md from 6,575 to 3,608 lines (45%)
- Kept Top 10 critical pitfalls in main instructions
- Preserved all git commits, dates, code examples
- Updated docs/README.md with references to new doc
Benefits:
- Faster AI agent context loading
- Easier maintenance and updates
- Better searchability by category
- Clear pattern recognition for similar issues
- Maintains comprehensive knowledge base
Co-authored-by: mindesbunister <32161838+mindesbunister@users.noreply.github.com>