From e115d459f7e9e3dfe6d90394af373021d2f97b8e Mon Sep 17 00:00:00 2001 From: WrBug Date: Wed, 28 Jan 2026 15:16:12 +0800 Subject: [PATCH] =?UTF-8?q?refactor:=20=E4=BC=98=E5=8C=96=E8=BF=87?= =?UTF-8?q?=E6=BB=A4=E5=8E=9F=E5=9B=A0=E6=96=87=E6=A1=88=E7=9A=84=E6=95=B0?= =?UTF-8?q?=E5=80=BC=E6=98=BE=E7=A4=BA=E6=A0=BC=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 优化内容: 1. 新增 DateUtils.formatDuration() 函数:将毫秒转换为可读格式(X天X小时X分钟) 2. 优化市场截止时间过滤原因:使用格式化后的时间显示,避免显示过长的毫秒数 3. 优化所有过滤原因中的 BigDecimal 数值显示: - 价格区间检查:去除尾随零 - 价差检查:去除尾随零 - 订单深度检查:去除尾随零 - 仓位金额检查:去除尾随零 优化效果: - 时间显示:1009163461ms (280小时) -> 11天16小时26分钟 - 数值显示:0.50000000000000000000 -> 0.5 影响范围: - DateUtils.kt - CopyTradingFilterService.kt --- .../configs/CopyTradingFilterService.kt | 29 ++++++++++++---- .../com/wrbug/polymarketbot/util/DateUtils.kt | 33 +++++++++++++++++++ 2 files changed, 56 insertions(+), 6 deletions(-) diff --git a/backend/src/main/kotlin/com/wrbug/polymarketbot/service/copytrading/configs/CopyTradingFilterService.kt b/backend/src/main/kotlin/com/wrbug/polymarketbot/service/copytrading/configs/CopyTradingFilterService.kt index c161db1..f4642c9 100644 --- a/backend/src/main/kotlin/com/wrbug/polymarketbot/service/copytrading/configs/CopyTradingFilterService.kt +++ b/backend/src/main/kotlin/com/wrbug/polymarketbot/service/copytrading/configs/CopyTradingFilterService.kt @@ -7,6 +7,7 @@ import com.wrbug.polymarketbot.util.lt import com.wrbug.polymarketbot.util.multi import com.wrbug.polymarketbot.util.toSafeBigDecimal import com.wrbug.polymarketbot.util.JsonUtils +import com.wrbug.polymarketbot.util.DateUtils import org.slf4j.LoggerFactory import com.wrbug.polymarketbot.service.common.PolymarketClobService import com.wrbug.polymarketbot.service.accounts.AccountService @@ -202,12 +203,16 @@ class CopyTradingFilterService( // 检查最低价格 if (copyTrading.minPrice != null && tradePrice.lt(copyTrading.minPrice)) { - return FilterResult.priceRangeFailed("价格低于最低限制: $tradePrice < ${copyTrading.minPrice}") + val priceStr = tradePrice.stripTrailingZeros().toPlainString() + val minPriceStr = copyTrading.minPrice.stripTrailingZeros().toPlainString() + return FilterResult.priceRangeFailed("价格低于最低限制: $priceStr < $minPriceStr") } // 检查最高价格 if (copyTrading.maxPrice != null && tradePrice.gt(copyTrading.maxPrice)) { - return FilterResult.priceRangeFailed("价格高于最高限制: $tradePrice > ${copyTrading.maxPrice}") + val priceStr = tradePrice.stripTrailingZeros().toPlainString() + val maxPriceStr = copyTrading.maxPrice.stripTrailingZeros().toPlainString() + return FilterResult.priceRangeFailed("价格高于最高限制: $priceStr > $maxPriceStr") } return FilterResult.passed() @@ -245,7 +250,9 @@ class CopyTradingFilterService( val spread = bestAsk.subtract(bestBid) if (spread.gt(copyTrading.maxSpread)) { - return FilterResult.spreadFailed("价差过大: $spread > ${copyTrading.maxSpread}", orderbook) + val spreadStr = spread.stripTrailingZeros().toPlainString() + val maxSpreadStr = copyTrading.maxSpread.stripTrailingZeros().toPlainString() + return FilterResult.spreadFailed("价差过大: $spreadStr > $maxSpreadStr", orderbook) } return FilterResult.passed() @@ -285,7 +292,9 @@ class CopyTradingFilterService( val totalDepth = bidsDepth.add(asksDepth) if (totalDepth.lt(copyTrading.minOrderDepth)) { - return FilterResult.orderDepthFailed("订单深度不足: $totalDepth < ${copyTrading.minOrderDepth}", orderbook) + val totalDepthStr = totalDepth.stripTrailingZeros().toPlainString() + val minDepthStr = copyTrading.minOrderDepth.stripTrailingZeros().toPlainString() + return FilterResult.orderDepthFailed("订单深度不足: $totalDepthStr < $minDepthStr", orderbook) } return FilterResult.passed() @@ -348,8 +357,14 @@ class CopyTradingFilterService( val totalValueAfterOrder = currentPositionValue.add(copyOrderAmount) if (totalValueAfterOrder.gt(copyTrading.maxPositionValue)) { + val currentValueStr = currentPositionValue.stripTrailingZeros().toPlainString() + val dbValueStr = dbValue.stripTrailingZeros().toPlainString() + val extValueStr = extValue.stripTrailingZeros().toPlainString() + val orderAmountStr = copyOrderAmount.stripTrailingZeros().toPlainString() + val totalValueStr = totalValueAfterOrder.stripTrailingZeros().toPlainString() + val maxValueStr = copyTrading.maxPositionValue.stripTrailingZeros().toPlainString() return FilterResult.maxPositionValueFailed( - "超过最大仓位金额限制: 市场=$marketId, 方向=$outcomeIndex, 当前仓位(取最大值)=${currentPositionValue} USDC (DB=${dbValue}, Ext=${extValue}), 跟单金额=${copyOrderAmount} USDC, 总计=${totalValueAfterOrder} USDC > 最大限制=${copyTrading.maxPositionValue} USDC" + "超过最大仓位金额限制: 市场=$marketId, 方向=$outcomeIndex, 当前仓位(取最大值)=${currentValueStr} USDC (DB=${dbValueStr}, Ext=${extValueStr}), 跟单金额=${orderAmountStr} USDC, 总计=${totalValueStr} USDC > 最大限制=${maxValueStr} USDC" ) } } @@ -420,8 +435,10 @@ class CopyTradingFilterService( val remainingTime = marketEndDate - currentTime if (remainingTime > copyTrading.maxMarketEndDate) { + val remainingTimeFormatted = DateUtils.formatDuration(remainingTime) + val maxLimitFormatted = DateUtils.formatDuration(copyTrading.maxMarketEndDate) return FilterResult.marketEndDateFailed( - "市场截止时间超出限制: 剩余时间=${remainingTime}ms (${remainingTime / (1000 * 60 * 60)}小时) > 最大限制=${copyTrading.maxMarketEndDate}ms (${copyTrading.maxMarketEndDate / (1000 * 60 * 60)}小时)" + "市场截止时间超出限制: 剩余时间=${remainingTimeFormatted} > 最大限制=${maxLimitFormatted}" ) } diff --git a/backend/src/main/kotlin/com/wrbug/polymarketbot/util/DateUtils.kt b/backend/src/main/kotlin/com/wrbug/polymarketbot/util/DateUtils.kt index 9d5211f..93abcd5 100644 --- a/backend/src/main/kotlin/com/wrbug/polymarketbot/util/DateUtils.kt +++ b/backend/src/main/kotlin/com/wrbug/polymarketbot/util/DateUtils.kt @@ -84,5 +84,38 @@ object DateUtils { } return displayFormatter.format(instant) } + + /** + * 将时间间隔(毫秒)格式化为可读的字符串 + * 格式:X天X小时X分钟 或 X小时X分钟 或 X分钟 + * 只显示有意义的单位,不显示0值单位 + * + * @param milliseconds 时间间隔(毫秒) + * @return 格式化的时间间隔字符串,如 "2天3小时15分钟"、"5小时30分钟"、"45分钟" + */ + fun formatDuration(milliseconds: Long): String { + if (milliseconds < 0) { + return "0分钟" + } + + val totalSeconds = milliseconds / 1000 + val days = totalSeconds / (24 * 60 * 60) + val hours = (totalSeconds % (24 * 60 * 60)) / (60 * 60) + val minutes = (totalSeconds % (60 * 60)) / 60 + + val parts = mutableListOf() + + if (days > 0) { + parts.add("${days}天") + } + if (hours > 0) { + parts.add("${hours}小时") + } + if (minutes > 0 || parts.isEmpty()) { + parts.add("${minutes}分钟") + } + + return parts.joinToString("") + } }