critical: Fix ghost detection P&L compounding - delete from Map BEFORE check
Bug: Multiple monitoring loops detect ghost simultaneously - Loop 1: has(tradeId) → true → proceeds - Loop 2: has(tradeId) → true → ALSO proceeds (race condition) - Both send Telegram notifications with compounding P&L Real incident (Dec 2, 2025): - Manual SHORT at $138.84 - 23 duplicate notifications - P&L compounded: -$47.96 → -$1,129.24 (23× accumulation) - Database shows single trade with final compounded value Fix: Map.delete() returns true if key existed, false if already removed - Call delete() FIRST - Check return value proceeds - All other loops get false → skip immediately - Atomic operation prevents race condition Pattern: This is variant of Common Pitfalls #48, #49, #59, #60, #61 - All had "check then delete" pattern - All vulnerable to async timing issues - Solution: "delete then check" pattern - Map.delete() is synchronous and atomic Files changed: - lib/trading/position-manager.ts lines 390-410 Related: DUPLICATE PREVENTED message was working but too late
This commit is contained in:
@@ -205,6 +205,13 @@ model BlockedSignal {
|
||||
wouldHitTP2 Boolean? // Would TP2 have been hit?
|
||||
wouldHitSL Boolean? // Would SL have been hit?
|
||||
|
||||
// EXACT TIMING (Dec 2, 2025): Minute-precision timestamps for TP/SL hits
|
||||
// Purpose: Answer "EXACTLY when TP1/TP2 would have been hit" using 1-minute granular data
|
||||
// Uses: MarketData query instead of Drift oracle polling (480 data points vs. 8 checkpoints)
|
||||
tp1HitTime DateTime? @map("tp1_hit_time") // Exact timestamp when TP1 first hit
|
||||
tp2HitTime DateTime? @map("tp2_hit_time") // Exact timestamp when TP2 first hit
|
||||
slHitTime DateTime? @map("sl_hit_time") // Exact timestamp when SL first hit
|
||||
|
||||
// Max favorable/adverse excursion (mirror Trade model)
|
||||
maxFavorablePrice Float? // Price at max profit
|
||||
maxAdversePrice Float? // Price at max loss
|
||||
|
||||
Reference in New Issue
Block a user