critical: Bug #82 EMERGENCY FIX - Disable Drift State Verifier automatic close
Problem: Verifier can't distinguish OLD positions from NEW positions at same symbol - User opened manual trade with SL working - Verifier detected 6 old closed DB records (150-1064 min ago) - All showed "15.45 tokens open on Drift" (user's CURRENT trade!) - Automatic retry close removed user's SL orders Root Cause: Lines 279-283 call closePosition() for every mismatch - No verification if Drift position is OLD (should close) or NEW (active trade) - No position ID/timestamp matching - Result: Closes ACTIVE trades when cleaning up old database records Solution: DISABLED automatic retry close (lines 276-298) - Added BUG #82 warning logs - Requires manual intervention if true orphan detected - Will add proper position verification in follow-up fix Impact: Stops SL removal on active trades User incident: After Bug #81 fix deployed, THIS bug was killing SLs Deployment: Dec 10, 2025 11:06 CET
This commit is contained in:
@@ -277,36 +277,51 @@ class DriftStateVerifier {
|
||||
const attemptTime = Date.now()
|
||||
this.recentCloseAttempts.set(mismatch.symbol, attemptTime)
|
||||
|
||||
const result = await closePosition({
|
||||
symbol: mismatch.symbol,
|
||||
percentToClose: 100,
|
||||
slippageTolerance: 0.05 // 5% slippage tolerance for market order
|
||||
})
|
||||
|
||||
if (result.success) {
|
||||
console.log(` ✅ Close transaction confirmed: ${result.transactionSignature}`)
|
||||
console.log(` P&L: $${result.realizedPnL?.toFixed(2) || 0}`)
|
||||
console.log(` ⏳ Drift API may take up to 5 minutes to reflect closure`)
|
||||
|
||||
// Update database with retry close timestamp to prevent loop
|
||||
await prisma.trade.update({
|
||||
where: { id: mismatch.tradeId },
|
||||
data: {
|
||||
exitOrderTx: result.transactionSignature || 'RETRY_CLOSE',
|
||||
realizedPnL: result.realizedPnL || 0,
|
||||
configSnapshot: {
|
||||
...trade?.configSnapshot as any,
|
||||
retryCloseAttempted: true,
|
||||
retryCloseTime: new Date(attemptTime).toISOString(),
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
console.log(` 📝 Cooldown recorded: ${mismatch.symbol} → ${new Date(attemptTime).toISOString()}`)
|
||||
} else {
|
||||
console.error(` ❌ Failed to close ${mismatch.symbol}: ${result.error}`)
|
||||
// Keep cooldown even on failure to prevent spam
|
||||
}
|
||||
// BUG #82 FIX (Dec 10, 2025): DISABLE automatic retry close
|
||||
// Problem: Can't distinguish OLD position (should close) from NEW position at same symbol (should NOT touch)
|
||||
// Result: Closes ACTIVE trades when trying to clean up old database records
|
||||
// User incident: 6 old closed trades (150-1064 min ago) all showed "15.45 tokens" on Drift
|
||||
// That was user's CURRENT manual trade, not 6 old ghosts
|
||||
// Automatic close removed user's SL orders
|
||||
// Solution: DISABLE automatic close until we add proper position ID/timestamp verification
|
||||
|
||||
console.warn(`⚠️ BUG #82 SAFETY: Automatic retry close DISABLED`)
|
||||
console.warn(` Would have closed ${mismatch.symbol} with 15.45 tokens`)
|
||||
console.warn(` But can't verify if it's OLD position or NEW active trade`)
|
||||
console.warn(` Manual intervention required if true orphan detected`)
|
||||
return
|
||||
|
||||
// ORIGINAL CODE (DISABLED):
|
||||
// const result = await closePosition({
|
||||
// symbol: mismatch.symbol,
|
||||
// percentToClose: 100,
|
||||
// slippageTolerance: 0.05 // 5% slippage tolerance for market order
|
||||
// })
|
||||
//
|
||||
// if (result.success) {
|
||||
// console.log(` ✅ Close transaction confirmed: ${result.transactionSignature}`)
|
||||
// console.log(` P&L: $${result.realizedPnL?.toFixed(2) || 0}`)
|
||||
// console.log(` ⏳ Drift API may take up to 5 minutes to reflect closure`)
|
||||
//
|
||||
// // Update database with retry close timestamp to prevent loop
|
||||
// await prisma.trade.update({
|
||||
// where: { id: mismatch.tradeId },
|
||||
// data: {
|
||||
// exitOrderTx: result.transactionSignature || 'RETRY_CLOSE',
|
||||
// realizedPnL: result.realizedPnL || 0,
|
||||
// configSnapshot: {
|
||||
// ...trade?.configSnapshot as any,
|
||||
// retryCloseAttempted: true,
|
||||
// retryCloseTime: new Date(attemptTime).toISOString(),
|
||||
// }
|
||||
// }
|
||||
// })
|
||||
//
|
||||
// console.log(` 📝 Cooldown recorded: ${mismatch.symbol} → ${new Date(attemptTime).toISOString()}`)
|
||||
// } else {
|
||||
// console.error(` ❌ Failed to close ${mismatch.symbol}: ${result.error}`)
|
||||
// // Keep cooldown even on failure to prevent spam
|
||||
// }
|
||||
} catch (error) {
|
||||
console.error(` ❌ Error retrying close for ${mismatch.symbol}:`, error)
|
||||
// On error, still record attempt time to prevent rapid retries
|
||||
|
||||
Reference in New Issue
Block a user