From 5f44a0ca20b75bb7ae09ca07ba5b0e4369ee8a24 Mon Sep 17 00:00:00 2001 From: WrBug Date: Thu, 15 Jan 2026 02:28:11 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96=E8=AE=A2=E5=8D=95=E7=8A=B6?= =?UTF-8?q?=E6=80=81=E6=9B=B4=E6=96=B0=E5=92=8C=E7=BB=9F=E8=AE=A1=E6=9C=8D?= =?UTF-8?q?=E5=8A=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. 订单详情为 null 且已部分卖出的订单超时清理 - 新增 PARTIAL_SOLD_CLEANUP_WINDOW_MS 常量(1小时) - 超过1小时无法获取详情的已部分卖出订单自动清理 - 避免无效订单长期占用数据库空间 2. 优化买入订单分组排序逻辑 - 按最近买入订单时间排序,提升用户体验 - 修复日志中的错误描述(卖出订单列表) 3. 代码格式化优化 --- .../CopyTradingStatisticsService.kt | 34 ++++++++----- .../statistics/OrderStatusUpdateService.kt | 49 ++++++++++++++++--- 2 files changed, 62 insertions(+), 21 deletions(-) diff --git a/backend/src/main/kotlin/com/wrbug/polymarketbot/service/copytrading/statistics/CopyTradingStatisticsService.kt b/backend/src/main/kotlin/com/wrbug/polymarketbot/service/copytrading/statistics/CopyTradingStatisticsService.kt index 3d09291..cff81c4 100644 --- a/backend/src/main/kotlin/com/wrbug/polymarketbot/service/copytrading/statistics/CopyTradingStatisticsService.kt +++ b/backend/src/main/kotlin/com/wrbug/polymarketbot/service/copytrading/statistics/CopyTradingStatisticsService.kt @@ -611,22 +611,22 @@ class CopyTradingStatisticsService( // 4. 转换为分组数据并计算统计信息 val marketIds = groups.keys.toList() - + val list = marketIds.map { marketId -> val marketOrders = groups[marketId] ?: mutableListOf() - + // 计算统计信息 val count = marketOrders.size.toLong() val totalAmount = marketOrders.sumOf { order -> order.quantity.toSafeBigDecimal().multi(order.price) } - + // 计算订单状态统计 val fullyMatchedCount = marketOrders.count { it.status == "fully_matched" } val partiallyMatchedCount = marketOrders.count { it.status == "partially_matched" } val filledCount = marketOrders.count { it.status == "filled" } val fullyMatched = fullyMatchedCount == marketOrders.size - + val stats = MarketOrderStats( count = count, totalAmount = totalAmount.toString(), @@ -636,10 +636,10 @@ class CopyTradingStatisticsService( partiallyMatchedCount = partiallyMatchedCount.toLong(), filledCount = filledCount.toLong() ) - + // 排序(按创建时间倒序) marketOrders.sortByDescending { it.createdAt } - + // 转换为 DTO val orderDtos = marketOrders.map { order -> val amount = order.quantity.toSafeBigDecimal().multi(order.price) @@ -662,7 +662,7 @@ class CopyTradingStatisticsService( createdAt = order.createdAt ) } - + MarketOrderGroup( marketId = marketId, marketTitle = markets[marketId]?.title, @@ -672,27 +672,35 @@ class CopyTradingStatisticsService( stats = stats, orders = orderDtos as List ) - }.sortedByDescending { it.stats.count } - + }.sortedByDescending { group -> + // 找出该市场最近的买入订单时间 + group.orders.mapNotNull { order -> + when (order) { + is BuyOrderInfo -> order.createdAt + else -> null + } + }.maxOrNull() ?: 0L + } + // 5. 分页 val page = (request.page ?: 1) val limit = request.limit ?: 20 val total = list.size.toLong() - + val start = (page - 1) * limit val end = minOf(start + limit, list.size) val pagedList = if (start < list.size) list.subList(start, end) else emptyList() - + val response = MarketGroupedOrdersResponse( list = pagedList, total = total, page = page, limit = limit ) - + Result.success(response) } catch (e: Exception) { - logger.error("获取按市场分组的买入订单列表失败: copyTradingId=${request.copyTradingId}", e) + logger.error("获取按市场分组的卖出订单列表失败: copyTradingId=${request.copyTradingId}", e) Result.failure(e) } } diff --git a/backend/src/main/kotlin/com/wrbug/polymarketbot/service/copytrading/statistics/OrderStatusUpdateService.kt b/backend/src/main/kotlin/com/wrbug/polymarketbot/service/copytrading/statistics/OrderStatusUpdateService.kt index 65d6b27..d55f43d 100644 --- a/backend/src/main/kotlin/com/wrbug/polymarketbot/service/copytrading/statistics/OrderStatusUpdateService.kt +++ b/backend/src/main/kotlin/com/wrbug/polymarketbot/service/copytrading/statistics/OrderStatusUpdateService.kt @@ -49,6 +49,9 @@ class OrderStatusUpdateService( // 订单详情为 null 的重试时间窗口(1分钟) private val ORDER_NULL_RETRY_WINDOW_MS = 60000L + // 订单详情为 null 但已部分卖出的清理时间窗口(1小时) + private val PARTIAL_SOLD_CLEANUP_WINDOW_MS = 3600000L + @EventListener(ApplicationReadyEvent::class) fun onApplicationReady() { logger.info("订单状态更新服务已启动,将每5秒轮询一次") @@ -234,10 +237,25 @@ class OrderStatusUpdateService( // 检查订单是否已部分卖出,如果已部分卖出则保留订单用于统计 val hasMatchedDetails = sellMatchDetailRepository.findByTrackingId(order.id!!).isNotEmpty() if (hasMatchedDetails || order.matchedQuantity > BigDecimal.ZERO) { - logger.debug("订单详情为 null 但已部分卖出,保留订单用于统计: orderId=${order.buyOrderId}, copyOrderTrackingId=${order.id}, matchedQuantity=${order.matchedQuantity}") - // 清除缓存,下次重新检测 - orderNullDetectionTime.remove(order.buyOrderId) - continue + // 检查是否超过清理时间窗口(1小时) + val orderAge = currentTime - order.createdAt + if (orderAge >= PARTIAL_SOLD_CLEANUP_WINDOW_MS) { + logger.warn("订单详情为 null 且已部分卖出,但超过清理时间窗口,删除本地订单: orderId=${order.buyOrderId}, copyOrderTrackingId=${order.id}, matchedQuantity=${order.matchedQuantity}, 已等待=${orderAge / 1000}s") + try { + copyOrderTrackingRepository.deleteById(order.id!!) + logger.info("已删除本地订单(超时清理): orderId=${order.buyOrderId}, copyOrderTrackingId=${order.id}") + // 清除缓存 + orderNullDetectionTime.remove(order.buyOrderId) + } catch (e: Exception) { + logger.error("删除本地订单失败: orderId=${order.buyOrderId}, copyOrderTrackingId=${order.id}, error=${e.message}", e) + } + continue + } else { + logger.debug("订单详情为 null 但已部分卖出,保留订单用于统计: orderId=${order.buyOrderId}, copyOrderTrackingId=${order.id}, matchedQuantity=${order.matchedQuantity}, 已等待=${orderAge / 1000}s") + // 清除缓存,下次重新检测 + orderNullDetectionTime.remove(order.buyOrderId) + continue + } } // 检查是否超过重试时间窗口 @@ -645,10 +663,25 @@ class OrderStatusUpdateService( // 检查订单是否已部分卖出,如果已部分卖出则保留订单用于统计 val hasMatchedDetails = sellMatchDetailRepository.findByTrackingId(order.id!!).isNotEmpty() if (hasMatchedDetails || order.matchedQuantity > BigDecimal.ZERO) { - logger.debug("订单详情为 null 但已部分卖出,保留订单用于统计: orderId=${order.buyOrderId}, copyOrderTrackingId=${order.id}, matchedQuantity=${order.matchedQuantity}") - // 清除缓存,下次重新检测 - orderNullDetectionTime.remove(order.buyOrderId) - continue + // 检查是否超过清理时间窗口(1小时) + val orderAge = currentTime - order.createdAt + if (orderAge >= PARTIAL_SOLD_CLEANUP_WINDOW_MS) { + logger.warn("订单详情为 null 且已部分卖出,但超过清理时间窗口,删除本地订单: orderId=${order.buyOrderId}, copyOrderTrackingId=${order.id}, matchedQuantity=${order.matchedQuantity}, 已等待=${orderAge / 1000}s") + try { + copyOrderTrackingRepository.deleteById(order.id!!) + logger.info("已删除本地订单(超时清理): orderId=${order.buyOrderId}, copyOrderTrackingId=${order.id}") + // 清除缓存 + orderNullDetectionTime.remove(order.buyOrderId) + } catch (e: Exception) { + logger.error("删除本地订单失败: orderId=${order.buyOrderId}, copyOrderTrackingId=${order.id}, error=${e.message}", e) + } + continue + } else { + logger.debug("订单详情为 null 但已部分卖出,保留订单用于统计: orderId=${order.buyOrderId}, copyOrderTrackingId=${order.id}, matchedQuantity=${order.matchedQuantity}, 已等待=${orderAge / 1000}s") + // 清除缓存,下次重新检测 + orderNullDetectionTime.remove(order.buyOrderId) + continue + } } // 检查是否超过重试时间窗口