critical: Fix Layer 2 ghost detection causing duplicate Telegram notifications
Bug: Trade #8 (SHORT SOL-PERP) sent 13 duplicate 'POSITION CLOSED' notifications - P&L compounded: $11.50 → $38.56 → $64.70 → ... → $155.05 - Root cause: Layer 2 ghost detection (failureCount > 20) didn't check closingInProgress flag - Called handleExternalClosure() every 2 seconds during rate limit storm (6,581 failures) - Each call sent Telegram notification with compounding P&L Fix: - Added closingInProgress check before Layer 2 ghost detection - Mark trade as closing BEFORE calling handleExternalClosure() - Prevents duplicate processing during async database updates Location: lib/trading/position-manager.ts lines 1477-1490 Prevents: Common Pitfall #49 (P&L compounding) in Layer 2 death spiral scenario Related: Common Pitfall #40 (ghost death spiral), #48 (closingInProgress flag) Impact: No more duplicate notifications, accurate P&L reporting
This commit is contained in:
@@ -1477,7 +1477,7 @@ export class PositionManager {
|
|||||||
|
|
||||||
// LAYER 2: Death spiral detector (Nov 15, 2025)
|
// LAYER 2: Death spiral detector (Nov 15, 2025)
|
||||||
// If we've failed 20+ times, check Drift API to see if it's a ghost position
|
// If we've failed 20+ times, check Drift API to see if it's a ghost position
|
||||||
if (trade.priceCheckCount > 20) {
|
if (trade.priceCheckCount > 20 && !trade.closingInProgress) {
|
||||||
try {
|
try {
|
||||||
const driftService = getDriftService()
|
const driftService = getDriftService()
|
||||||
const marketConfig = getMarketConfig(trade.symbol)
|
const marketConfig = getMarketConfig(trade.symbol)
|
||||||
@@ -1487,6 +1487,11 @@ export class PositionManager {
|
|||||||
if (!position || Math.abs(position.size) < 0.01) {
|
if (!position || Math.abs(position.size) < 0.01) {
|
||||||
console.log(`🔴 LAYER 2: Ghost detected after ${trade.priceCheckCount} failures`)
|
console.log(`🔴 LAYER 2: Ghost detected after ${trade.priceCheckCount} failures`)
|
||||||
console.log(` Drift shows position closed/missing - removing from monitoring`)
|
console.log(` Drift shows position closed/missing - removing from monitoring`)
|
||||||
|
|
||||||
|
// CRITICAL: Mark as closing to prevent duplicate processing
|
||||||
|
trade.closingInProgress = true
|
||||||
|
trade.closeConfirmedAt = Date.now()
|
||||||
|
|
||||||
await this.handleExternalClosure(trade, 'Layer 2: Ghost detected via Drift API')
|
await this.handleExternalClosure(trade, 'Layer 2: Ghost detected via Drift API')
|
||||||
return
|
return
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
Reference in New Issue
Block a user