Fix Position Manager bug: prevent cancelling orders when tracking old trades
Bug: Position Manager was comparing ANY position on the symbol to the trade being tracked, without verifying entry price match. When a new position opened, it would think the old tracked trade 'closed externally' and cancel ALL orders - including the new position's exit orders. Fix: Added entry price verification (0.5% tolerance). If position entry price doesn't match the tracked trade, mark the old trade as 'lost tracking' and remove from monitoring WITHOUT cancelling orders (they belong to the new position). This prevents the catastrophic scenario where exit orders are repeatedly cancelled, leaving positions unprotected.
This commit is contained in:
@@ -289,6 +289,47 @@ export class PositionManager {
|
||||
if (position === null || position.size === 0) {
|
||||
// Position closed externally (by on-chain TP/SL order)
|
||||
console.log(`⚠️ Position ${trade.symbol} was closed externally (by on-chain order)`)
|
||||
} else {
|
||||
// CRITICAL: Verify this position matches the trade we're tracking
|
||||
// Different entry price means this is a NEW position, not ours
|
||||
const entryPriceDiff = Math.abs(position.entryPrice - trade.entryPrice)
|
||||
const entryPriceDiffPercent = (entryPriceDiff / trade.entryPrice) * 100
|
||||
|
||||
if (entryPriceDiffPercent > 0.5) {
|
||||
// Entry prices differ by >0.5% - this is a DIFFERENT position
|
||||
console.log(`⚠️ Position ${trade.symbol} entry mismatch: tracking $${trade.entryPrice.toFixed(4)} but found $${position.entryPrice.toFixed(4)}`)
|
||||
console.log(`🗑️ This is a different/newer position - removing old trade from monitoring`)
|
||||
|
||||
// Mark the old trade as closed (we lost track of it)
|
||||
try {
|
||||
await updateTradeExit({
|
||||
positionId: trade.positionId,
|
||||
exitPrice: trade.lastPrice,
|
||||
exitReason: 'SOFT_SL', // Unknown - just mark as closed
|
||||
realizedPnL: 0,
|
||||
exitOrderTx: 'UNKNOWN_CLOSURE',
|
||||
holdTimeSeconds: Math.floor((Date.now() - trade.entryTime) / 1000),
|
||||
maxDrawdown: 0,
|
||||
maxGain: trade.peakPnL,
|
||||
})
|
||||
console.log(`💾 Old trade marked as closed (lost tracking)`)
|
||||
} catch (dbError) {
|
||||
console.error('❌ Failed to save lost trade closure:', dbError)
|
||||
}
|
||||
|
||||
// Remove from monitoring WITHOUT cancelling orders (they belong to the new position!)
|
||||
console.log(`🗑️ Removing old trade WITHOUT cancelling orders`)
|
||||
this.activeTrades.delete(trade.id)
|
||||
|
||||
if (this.activeTrades.size === 0 && this.isMonitoring) {
|
||||
this.stopMonitoring()
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if (position === null || position.size === 0) {
|
||||
|
||||
// Save currentSize before it becomes 0
|
||||
const sizeBeforeClosure = trade.currentSize
|
||||
|
||||
Reference in New Issue
Block a user