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("") + } }