docs: Document entry price correction fix as Common Pitfall #33
Major Fix Summary: - Position Manager was tracking wrong entry price after orphaned position restoration - Used stale database value ($141.51) instead of Drift's actual entry ($141.31) - 0.14% difference in stop loss placement - could mean profit vs loss difference - Startup validation now queries Drift SDK for authoritative entry price Impact: Critical for accurate P&L tracking and stop loss placement Prevention: Always prefer on-chain data over cached DB values for trading params Added to Common Pitfalls section with full bug sequence, fix code, and lessons learned.
This commit is contained in:
36
.github/copilot-instructions.md
vendored
36
.github/copilot-instructions.md
vendored
@@ -1312,7 +1312,41 @@ trade.realizedPnL += actualRealizedPnL // NOT: result.realizedPnL from SDK
|
||||
- **Impact:** Protects user from unlimited risk during unavailable hours. Phantom trades are rare edge cases (oracle issues, exchange rejections).
|
||||
- **Database tracking:** `status='phantom'`, `exitReason='manual'`, enables analysis of phantom frequency and patterns
|
||||
|
||||
33. **Flip-flop price context using wrong data (CRITICAL - Fixed Nov 14, 2025):**
|
||||
33. **Wrong entry price after orphaned position restoration (CRITICAL - Fixed Nov 15, 2025):**
|
||||
- **Symptom:** Position Manager tracking SHORT at $141.51 entry, but Drift UI shows $141.31 actual entry
|
||||
- **Root Cause:** Startup validation restored orphaned position but used OLD database entry price instead of querying Drift for real value
|
||||
- **Bug sequence:**
|
||||
1. Position opened at $141.317 (per Drift order history)
|
||||
2. TP1 closed 70% at $140.942
|
||||
3. Database incorrectly saved entry as $141.508 (maybe averaged or from previous position)
|
||||
4. Container restart → startup validation found position on Drift
|
||||
5. Reopened trade in DB but used stale `trade.entryPrice` from database
|
||||
6. Position Manager tracked with wrong entry ($141.51 vs actual $141.31)
|
||||
7. Stop loss calculated from wrong base: $141.08 instead of $140.89
|
||||
- **Impact:** 0.14% difference ($0.20/SOL) in SL placement - could mean difference between small profit and small loss
|
||||
- **Fix:** Query Drift SDK for actual entry price during orphaned position restoration
|
||||
```typescript
|
||||
// In lib/startup/init-position-manager.ts (line 121-144):
|
||||
// When reopening closed trade found on Drift:
|
||||
const currentPrice = await driftService.getOraclePrice(marketConfig.driftMarketIndex)
|
||||
const positionSizeUSD = position.size * currentPrice
|
||||
|
||||
await prisma.trade.update({
|
||||
where: { id: trade.id },
|
||||
data: {
|
||||
status: 'open',
|
||||
exitReason: null,
|
||||
entryPrice: position.entryPrice, // CRITICAL: Use Drift's actual entry price
|
||||
positionSizeUSD: positionSizeUSD, // Update to current size (runner after TP1)
|
||||
}
|
||||
})
|
||||
```
|
||||
- **Drift SDK returns real entry:** `position.entryPrice` from `getPosition()` calculates from on-chain data (quoteAssetAmount / baseAssetAmount)
|
||||
- **Future-proofed:** All orphaned position restorations now use authoritative Drift entry price, not stale DB value
|
||||
- **Manual fix required once:** Had to manually UPDATE database for existing position, then restart container
|
||||
- **Lesson:** Always prefer on-chain data over cached database values for critical trading parameters
|
||||
|
||||
34. **Flip-flop price context using wrong data (CRITICAL - Fixed Nov 14, 2025):**
|
||||
- **Symptom:** Flip-flop detection showing "100% price move" when actual movement was 0.2%, allowing trades that should be blocked
|
||||
- **Root Cause:** `currentPrice` parameter not available in check-risk endpoint (trade hasn't opened yet), so calculation used undefined/zero
|
||||
- **Real incident:** Nov 14, 06:05 CET - SHORT allowed with 0.2% flip-flop, lost -$1.56 in 5 minutes
|
||||
|
||||
Reference in New Issue
Block a user