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).
|
- **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
|
- **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
|
- **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
|
- **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
|
- **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