critical: Cancel ghost orders after external closures
- Added order cancellation to Position Manager's external closure handler - When on-chain SL/TP orders close position, remaining orders now cancelled automatically - Prevents ghost orders from triggering unintended positions - Real incident: Nov 20 SHORT stop-out left 32 ghost orders on Drift - Risk: Ghost TP1 at $140.66 could fill later, creating unwanted LONG position - Fix: Import cancelAllOrders() and call after trade removed from monitoring - Non-blocking: Logs errors but doesn't fail trade closure if cancellation fails - Files: lib/trading/position-manager.ts (external closure handler ~line 920) - Documented as Common Pitfall #56
This commit is contained in:
@@ -924,6 +924,23 @@ export class PositionManager {
|
||||
console.log(`🗑️ Removed trade ${tradeId} from monitoring (BEFORE DB update to prevent duplicates)`)
|
||||
console.log(` Active trades remaining: ${this.activeTrades.size}`)
|
||||
|
||||
// CRITICAL: Cancel all remaining orders for this position (ghost order cleanup)
|
||||
// When position closes externally (on-chain SL/TP), TP/SL orders may remain active
|
||||
// These ghost orders can trigger unintended positions if price moves to those levels
|
||||
console.log(`🗑️ Cancelling remaining orders for ${trade.symbol}...`)
|
||||
try {
|
||||
const { cancelAllOrders } = await import('../drift/orders')
|
||||
const cancelResult = await cancelAllOrders(trade.symbol)
|
||||
if (cancelResult.success) {
|
||||
console.log(`✅ Cancelled ${cancelResult.cancelledCount || 0} ghost orders`)
|
||||
} else {
|
||||
console.error(`⚠️ Failed to cancel orders: ${cancelResult.error}`)
|
||||
}
|
||||
} catch (cancelError) {
|
||||
console.error('❌ Error cancelling ghost orders:', cancelError)
|
||||
// Don't fail the trade closure if order cancellation fails
|
||||
}
|
||||
|
||||
try {
|
||||
await updateTradeExit({
|
||||
positionId: trade.positionId,
|
||||
|
||||
Reference in New Issue
Block a user