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:
54
app/api/analytics/process-historical/route.ts
Normal file
54
app/api/analytics/process-historical/route.ts
Normal file
@@ -0,0 +1,54 @@
|
||||
import { NextRequest, NextResponse } from 'next/server'
|
||||
import { getBlockedSignalTracker } from '@/lib/analysis/blocked-signal-tracker'
|
||||
|
||||
/**
|
||||
* ONE-TIME BATCH PROCESSING ENDPOINT
|
||||
*
|
||||
* Purpose: Process all BlockedSignals that have completed their tracking window
|
||||
* using historical MarketData for minute-precision timing analysis.
|
||||
*
|
||||
* This endpoint:
|
||||
* 1. Finds signals NOT yet analyzed (analysisComplete = false)
|
||||
* 2. Verifies enough historical MarketData exists
|
||||
* 3. Analyzes minute-by-minute price movements
|
||||
* 4. Records EXACT timing when TP1/TP2/SL hit
|
||||
* 5. Updates database with findings
|
||||
*
|
||||
* Usage: curl http://localhost:3001/api/analytics/process-historical
|
||||
*/
|
||||
export async function POST(request: NextRequest) {
|
||||
try {
|
||||
console.log('🔄 API: Starting batch processing of historical data...')
|
||||
|
||||
const tracker = getBlockedSignalTracker()
|
||||
|
||||
// This will process all signals with enough historical data
|
||||
await tracker.processCompletedSignals()
|
||||
|
||||
console.log('✅ API: Batch processing complete')
|
||||
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
message: 'Batch processing complete - check logs for details'
|
||||
})
|
||||
} catch (error: any) {
|
||||
console.error('❌ API: Error in batch processing:', error)
|
||||
return NextResponse.json({
|
||||
success: false,
|
||||
error: error.message,
|
||||
stack: error.stack
|
||||
}, { status: 500 })
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* GET endpoint to check status
|
||||
*/
|
||||
export async function GET() {
|
||||
return NextResponse.json({
|
||||
endpoint: '/api/analytics/process-historical',
|
||||
description: 'Batch process BlockedSignals using historical MarketData',
|
||||
method: 'POST',
|
||||
purpose: 'Minute-precision TP/SL timing analysis'
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user