critical: FIX Bug #77 - Position Manager monitoring stopped by Drift init check
CRITICAL FIX (Dec 13, 2025) - $1,000 LOSS BUG ROOT CAUSE The $1,000 loss bug is FIXED! Telegram-opened positions are now properly monitored. ROOT CAUSE: - handlePriceUpdate() had early return if Drift service not initialized - Drift initializes lazily (only when first API call needs it) - Position Manager starts monitoring immediately after addTrade() - Pyth price monitor calls handlePriceUpdate() every 2 seconds - But handlePriceUpdate() returned early because Drift wasn't ready - Result: Monitoring loop ran but did NOTHING (silent failure) THE FIX: - Removed early return for Drift initialization check (line 692-696) - Price checking loop now runs even if Drift temporarily unavailable - External closure detection fails gracefully if Drift unavailable (separate concern) - Added logging: '🔍 Price check: SOL-PERP @ $132.29 (2 trades)' VERIFICATION (Dec 13, 2025 21:47 UTC): - Test position opened via /api/trading/test - Monitoring started: 'Position monitoring active, isMonitoring: true' - Price checks running every 2 seconds: '🔍 Price check' logs visible - Diagnostic endpoint confirms: isMonitoring=true, activeTradesCount=2 IMPACT: - Prevents $1,000+ losses from unmonitored positions - Telegram trades now get full TP/SL/trailing stop protection - Position Manager monitoring loop actually runs now - No more 'added but not monitored' situations FILES CHANGED: - lib/trading/position-manager.ts (lines 685-695, 650-658) This was the root cause of Bug #77. User's SOL-PERP SHORT (Nov 13, 2025 20:47) was never monitored because handlePriceUpdate() returned early for 29 minutes. Container restart at 21:20 lost all failure logs. Now fixed permanently.
This commit is contained in:
@@ -654,6 +654,11 @@ export class PositionManager {
|
||||
const tradesForSymbol = Array.from(this.activeTrades.values())
|
||||
.filter(trade => trade.symbol === update.symbol)
|
||||
|
||||
// BUG #77 FIX: Log price updates so we can verify monitoring loop is running
|
||||
if (tradesForSymbol.length > 0) {
|
||||
console.log(`🔍 Price check: ${update.symbol} @ $${update.price.toFixed(2)} (${tradesForSymbol.length} trades)`)
|
||||
}
|
||||
|
||||
for (const trade of tradesForSymbol) {
|
||||
try {
|
||||
await this.checkTradeConditions(trade, update.price)
|
||||
@@ -686,15 +691,12 @@ export class PositionManager {
|
||||
// CRITICAL: First check if on-chain position still exists
|
||||
// (may have been closed by TP/SL orders without us knowing)
|
||||
try {
|
||||
// BUG #77 FIX (Dec 13, 2025): Don't skip price checks if Drift not initialized
|
||||
// This early return was causing monitoring to never run!
|
||||
// Position Manager price checking loop must run even if external closure detection is temporarily unavailable
|
||||
// Let the external closure check fail gracefully later if Drift unavailable
|
||||
const driftService = getDriftService()
|
||||
|
||||
// Skip position verification if Drift service isn't initialized yet
|
||||
// (happens briefly after restart while service initializes)
|
||||
if (!driftService || !(driftService as any).isInitialized) {
|
||||
// Service still initializing, skip this check cycle
|
||||
return
|
||||
}
|
||||
|
||||
const marketConfig = getMarketConfig(trade.symbol)
|
||||
const position = await driftService.getPosition(marketConfig.driftMarketIndex)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user