diff --git a/trader/binance_order_sync.go b/trader/binance_order_sync.go index 694812ac..459d5b8a 100644 --- a/trader/binance_order_sync.go +++ b/trader/binance_order_sync.go @@ -56,10 +56,6 @@ func (t *FuturesTrader) SyncOrdersFromBinance(traderID string, exchangeID string } } - // Record current time BEFORE querying, to avoid missing trades during sync - // This prevents race condition where trades happen between query and lastSyncTime update - syncStartTimeMs := nowMs - logger.Infof("🔄 Syncing Binance trades from: %s (UTC) [ms: %d, now: %d]", time.UnixMilli(lastSyncTimeMs).UTC().Format("2006-01-02 15:04:05"), lastSyncTimeMs, nowMs) @@ -121,10 +117,9 @@ func (t *FuturesTrader) SyncOrdersFromBinance(traderID string, exchangeID string if len(changedSymbols) == 0 { logger.Infof("📭 No symbols with new trades to sync") - // Update last sync time even if no changes - binanceSyncStateMutex.Lock() - binanceSyncState[exchangeID] = syncStartTimeMs - binanceSyncStateMutex.Unlock() + // DON'T update lastSyncTime to current time here! + // Keep using the last actual trade time from DB to avoid creating gaps + // The lastSyncTimeMs from DB already has +1000ms buffer added return nil } @@ -157,17 +152,12 @@ func (t *FuturesTrader) SyncOrdersFromBinance(traderID string, exchangeID string logger.Infof("📥 Received %d trades from Binance (%d API calls)", len(allTrades), apiCalls) - // Only update last sync time if ALL symbols were successfully queried - // This prevents data loss when some symbols fail due to rate limit or network issues - if len(failedSymbols) == 0 { - binanceSyncStateMutex.Lock() - binanceSyncState[exchangeID] = syncStartTimeMs - binanceSyncStateMutex.Unlock() - } else { - logger.Infof(" ⚠️ %d symbols failed, not updating lastSyncTime to retry next time: %v", len(failedSymbols), failedSymbols) - } - if len(allTrades) == 0 { + // No trades returned, but symbols were detected - might be false positive from COMMISSION/PnL detection + // Don't update lastSyncTime, keep using DB value + if len(failedSymbols) > 0 { + logger.Infof(" ⚠️ %d symbols failed: %v", len(failedSymbols), failedSymbols) + } return nil } @@ -281,6 +271,20 @@ func (t *FuturesTrader) SyncOrdersFromBinance(traderID string, exchangeID string trade.Time.UTC().Format("01-02 15:04:05")) } + // Update lastSyncTime to the LATEST trade time (not current time!) + // This ensures next sync starts from where we left off, not from "now" + // allTrades is already sorted by time ASC, so last element is the latest + if len(allTrades) > 0 && len(failedSymbols) == 0 { + latestTradeTimeMs := allTrades[len(allTrades)-1].Time.UTC().UnixMilli() + binanceSyncStateMutex.Lock() + binanceSyncState[exchangeID] = latestTradeTimeMs + binanceSyncStateMutex.Unlock() + logger.Infof("📅 Updated lastSyncTime to latest trade: %s (UTC)", + time.UnixMilli(latestTradeTimeMs).UTC().Format("2006-01-02 15:04:05")) + } else if len(failedSymbols) > 0 { + logger.Infof(" ⚠️ %d symbols failed, not updating lastSyncTime to retry next time: %v", len(failedSymbols), failedSymbols) + } + logger.Infof("✅ Binance order sync completed: %d new trades synced, %d skipped (already exist)", syncedCount, skippedCount) return nil }