refactor: 重构代码结构,按业务分类组织 Controller 和 Service
- 重构 API 路径为 /api/业务/xxx 格式 - 将 Controller 和 Service 按业务分类组织: * copytrading: 跟单相关(configs, leaders, statistics, templates) * accounts: 账户管理(公共模块) * markets: 市场数据(公共模块) * system: 系统管理(users, notifications, proxy, health) * auth: 认证 * announcement: 公告 - 将所有完整类名引用改为使用 import 导入 - 修复 calculatePositionValue 方法实现 - 更新前端 API 调用路径
This commit is contained in:
@@ -94,6 +94,13 @@ coverage/
|
||||
test-results/
|
||||
*.test.log
|
||||
|
||||
# Python
|
||||
__pycache__/
|
||||
*.py[cod]
|
||||
*$py.class
|
||||
*.so
|
||||
.Python
|
||||
|
||||
# Misc
|
||||
*.bak
|
||||
*.backup
|
||||
|
||||
@@ -227,7 +227,7 @@ data class CreateOrderRequest(
|
||||
|
||||
@Deprecated("使用 NewOrderRequest 代替")
|
||||
data class CreateOrdersBatchRequest(
|
||||
val orders: List<CreateOrderRequest>
|
||||
val orders: List<NewOrderRequest>
|
||||
)
|
||||
|
||||
data class CancelOrdersBatchRequest(
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package com.wrbug.polymarketbot.config
|
||||
|
||||
import com.wrbug.polymarketbot.service.ProxyConfigService
|
||||
import com.wrbug.polymarketbot.service.system.ProxyConfigService
|
||||
import jakarta.annotation.PostConstruct
|
||||
import org.slf4j.LoggerFactory
|
||||
import org.springframework.stereotype.Component
|
||||
|
||||
+3
-3
@@ -1,8 +1,8 @@
|
||||
package com.wrbug.polymarketbot.controller
|
||||
package com.wrbug.polymarketbot.controller.accounts
|
||||
|
||||
import com.wrbug.polymarketbot.dto.*
|
||||
import com.wrbug.polymarketbot.enums.ErrorCode
|
||||
import com.wrbug.polymarketbot.service.AccountService
|
||||
import com.wrbug.polymarketbot.service.accounts.AccountService
|
||||
import com.wrbug.polymarketbot.util.toSafeBigDecimal
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import org.slf4j.LoggerFactory
|
||||
@@ -15,7 +15,7 @@ import java.math.BigDecimal
|
||||
* 账户管理控制器
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/api/copy-trading/accounts")
|
||||
@RequestMapping("/api/accounts")
|
||||
class AccountController(
|
||||
private val accountService: AccountService,
|
||||
private val messageSource: MessageSource
|
||||
+2
-2
@@ -1,8 +1,8 @@
|
||||
package com.wrbug.polymarketbot.controller
|
||||
package com.wrbug.polymarketbot.controller.announcement
|
||||
|
||||
import com.wrbug.polymarketbot.dto.*
|
||||
import com.wrbug.polymarketbot.enums.ErrorCode
|
||||
import com.wrbug.polymarketbot.service.AnnouncementService
|
||||
import com.wrbug.polymarketbot.service.announcement.AnnouncementService
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import org.slf4j.LoggerFactory
|
||||
import org.springframework.context.MessageSource
|
||||
+2
-2
@@ -1,8 +1,8 @@
|
||||
package com.wrbug.polymarketbot.controller
|
||||
package com.wrbug.polymarketbot.controller.auth
|
||||
|
||||
import com.wrbug.polymarketbot.dto.*
|
||||
import com.wrbug.polymarketbot.enums.ErrorCode
|
||||
import com.wrbug.polymarketbot.service.AuthService
|
||||
import com.wrbug.polymarketbot.service.auth.AuthService
|
||||
import jakarta.servlet.http.HttpServletRequest
|
||||
import org.slf4j.LoggerFactory
|
||||
import org.springframework.context.MessageSource
|
||||
+4
-4
@@ -1,9 +1,9 @@
|
||||
package com.wrbug.polymarketbot.controller
|
||||
package com.wrbug.polymarketbot.controller.copytrading.configs
|
||||
|
||||
import com.wrbug.polymarketbot.dto.*
|
||||
import com.wrbug.polymarketbot.enums.ErrorCode
|
||||
import com.wrbug.polymarketbot.service.CopyTradingService
|
||||
import com.wrbug.polymarketbot.service.FilteredOrderService
|
||||
import com.wrbug.polymarketbot.service.copytrading.configs.CopyTradingService
|
||||
import com.wrbug.polymarketbot.service.copytrading.configs.FilteredOrderService
|
||||
import org.slf4j.LoggerFactory
|
||||
import org.springframework.context.MessageSource
|
||||
import org.springframework.http.ResponseEntity
|
||||
@@ -13,7 +13,7 @@ import org.springframework.web.bind.annotation.*
|
||||
* 跟单配置管理控制器(钱包-模板关联)
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/api/copy-trading")
|
||||
@RequestMapping("/api/copy-trading/configs")
|
||||
class CopyTradingController(
|
||||
private val copyTradingService: CopyTradingService,
|
||||
private val filteredOrderService: FilteredOrderService,
|
||||
+2
-2
@@ -1,8 +1,8 @@
|
||||
package com.wrbug.polymarketbot.controller
|
||||
package com.wrbug.polymarketbot.controller.copytrading.leaders
|
||||
|
||||
import com.wrbug.polymarketbot.dto.*
|
||||
import com.wrbug.polymarketbot.enums.ErrorCode
|
||||
import com.wrbug.polymarketbot.service.LeaderService
|
||||
import com.wrbug.polymarketbot.service.copytrading.leaders.LeaderService
|
||||
import org.slf4j.LoggerFactory
|
||||
import org.springframework.context.MessageSource
|
||||
import org.springframework.http.ResponseEntity
|
||||
+2
-2
@@ -1,8 +1,8 @@
|
||||
package com.wrbug.polymarketbot.controller
|
||||
package com.wrbug.polymarketbot.controller.copytrading.statistics
|
||||
|
||||
import com.wrbug.polymarketbot.dto.*
|
||||
import com.wrbug.polymarketbot.enums.ErrorCode
|
||||
import com.wrbug.polymarketbot.service.CopyTradingStatisticsService
|
||||
import com.wrbug.polymarketbot.service.copytrading.statistics.CopyTradingStatisticsService
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import org.slf4j.LoggerFactory
|
||||
import org.springframework.context.MessageSource
|
||||
+2
-2
@@ -1,8 +1,8 @@
|
||||
package com.wrbug.polymarketbot.controller
|
||||
package com.wrbug.polymarketbot.controller.copytrading.templates
|
||||
|
||||
import com.wrbug.polymarketbot.dto.*
|
||||
import com.wrbug.polymarketbot.enums.ErrorCode
|
||||
import com.wrbug.polymarketbot.service.CopyTradingTemplateService
|
||||
import com.wrbug.polymarketbot.service.copytrading.templates.CopyTradingTemplateService
|
||||
import org.slf4j.LoggerFactory
|
||||
import org.springframework.context.MessageSource
|
||||
import org.springframework.http.ResponseEntity
|
||||
+4
-4
@@ -1,10 +1,10 @@
|
||||
package com.wrbug.polymarketbot.controller
|
||||
package com.wrbug.polymarketbot.controller.markets
|
||||
|
||||
import com.wrbug.polymarketbot.api.LatestPriceResponse
|
||||
import com.wrbug.polymarketbot.dto.*
|
||||
import com.wrbug.polymarketbot.enums.ErrorCode
|
||||
import com.wrbug.polymarketbot.service.AccountService
|
||||
import com.wrbug.polymarketbot.service.PolymarketClobService
|
||||
import com.wrbug.polymarketbot.service.accounts.AccountService
|
||||
import com.wrbug.polymarketbot.service.common.PolymarketClobService
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import org.slf4j.LoggerFactory
|
||||
import org.springframework.context.MessageSource
|
||||
@@ -16,7 +16,7 @@ import org.springframework.web.bind.annotation.*
|
||||
* 提供市场相关的数据查询接口(价格、订单簿等)
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/api/copy-trading/markets")
|
||||
@RequestMapping("/api/markets")
|
||||
class MarketController(
|
||||
private val accountService: AccountService,
|
||||
private val clobService: PolymarketClobService,
|
||||
+2
-2
@@ -1,4 +1,4 @@
|
||||
package com.wrbug.polymarketbot.controller
|
||||
package com.wrbug.polymarketbot.controller.system
|
||||
|
||||
import org.springframework.http.ResponseEntity
|
||||
import org.springframework.web.bind.annotation.GetMapping
|
||||
@@ -11,7 +11,7 @@ import java.util.*
|
||||
* 用于 Docker 健康检查和监控
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/api/health")
|
||||
@RequestMapping("/api/system/health")
|
||||
class HealthController {
|
||||
|
||||
@GetMapping
|
||||
+4
-4
@@ -1,9 +1,9 @@
|
||||
package com.wrbug.polymarketbot.controller
|
||||
package com.wrbug.polymarketbot.controller.system
|
||||
|
||||
import com.wrbug.polymarketbot.dto.*
|
||||
import com.wrbug.polymarketbot.enums.ErrorCode
|
||||
import com.wrbug.polymarketbot.service.NotificationConfigService
|
||||
import com.wrbug.polymarketbot.service.TelegramNotificationService
|
||||
import com.wrbug.polymarketbot.service.system.NotificationConfigService
|
||||
import com.wrbug.polymarketbot.service.system.TelegramNotificationService
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import org.slf4j.LoggerFactory
|
||||
import org.springframework.context.MessageSource
|
||||
@@ -14,7 +14,7 @@ import org.springframework.web.bind.annotation.*
|
||||
* 消息推送配置控制器
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/api/notifications")
|
||||
@RequestMapping("/api/system/notifications")
|
||||
class NotificationController(
|
||||
private val notificationConfigService: NotificationConfigService,
|
||||
private val telegramNotificationService: TelegramNotificationService,
|
||||
+4
-4
@@ -1,9 +1,9 @@
|
||||
package com.wrbug.polymarketbot.controller
|
||||
package com.wrbug.polymarketbot.controller.system
|
||||
|
||||
import com.wrbug.polymarketbot.dto.*
|
||||
import com.wrbug.polymarketbot.enums.ErrorCode
|
||||
import com.wrbug.polymarketbot.service.ApiHealthCheckService
|
||||
import com.wrbug.polymarketbot.service.ProxyConfigService
|
||||
import com.wrbug.polymarketbot.service.system.ApiHealthCheckService
|
||||
import com.wrbug.polymarketbot.service.system.ProxyConfigService
|
||||
import jakarta.servlet.http.HttpServletRequest
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import org.slf4j.LoggerFactory
|
||||
@@ -15,7 +15,7 @@ import org.springframework.web.bind.annotation.*
|
||||
* 代理配置控制器
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/api/proxy-config")
|
||||
@RequestMapping("/api/system/proxy")
|
||||
class ProxyConfigController(
|
||||
private val proxyConfigService: ProxyConfigService,
|
||||
private val apiHealthCheckService: ApiHealthCheckService,
|
||||
+3
-3
@@ -1,9 +1,9 @@
|
||||
package com.wrbug.polymarketbot.controller
|
||||
package com.wrbug.polymarketbot.controller.system
|
||||
|
||||
import com.wrbug.polymarketbot.dto.*
|
||||
import com.wrbug.polymarketbot.enums.ErrorCode
|
||||
import com.wrbug.polymarketbot.service.SystemConfigService
|
||||
import com.wrbug.polymarketbot.service.RelayClientService
|
||||
import com.wrbug.polymarketbot.service.system.SystemConfigService
|
||||
import com.wrbug.polymarketbot.service.system.RelayClientService
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import org.slf4j.LoggerFactory
|
||||
import org.springframework.context.MessageSource
|
||||
+3
-3
@@ -1,8 +1,8 @@
|
||||
package com.wrbug.polymarketbot.controller
|
||||
package com.wrbug.polymarketbot.controller.system
|
||||
|
||||
import com.wrbug.polymarketbot.dto.*
|
||||
import com.wrbug.polymarketbot.enums.ErrorCode
|
||||
import com.wrbug.polymarketbot.service.UserService
|
||||
import com.wrbug.polymarketbot.service.system.UserService
|
||||
import jakarta.servlet.http.HttpServletRequest
|
||||
import org.slf4j.LoggerFactory
|
||||
import org.springframework.context.MessageSource
|
||||
@@ -13,7 +13,7 @@ import org.springframework.web.bind.annotation.*
|
||||
* 用户管理控制器
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/api/users")
|
||||
@RequestMapping("/api/system/users")
|
||||
class UserController(
|
||||
private val userService: UserService,
|
||||
private val messageSource: MessageSource
|
||||
+13
-5
@@ -1,4 +1,4 @@
|
||||
package com.wrbug.polymarketbot.service
|
||||
package com.wrbug.polymarketbot.service.accounts
|
||||
|
||||
import com.wrbug.polymarketbot.api.TradeResponse
|
||||
import com.wrbug.polymarketbot.dto.*
|
||||
@@ -8,6 +8,14 @@ import com.wrbug.polymarketbot.util.RetrofitFactory
|
||||
import com.wrbug.polymarketbot.util.toSafeBigDecimal
|
||||
import com.wrbug.polymarketbot.util.eq
|
||||
import com.wrbug.polymarketbot.util.JsonUtils
|
||||
import com.wrbug.polymarketbot.service.common.PolymarketClobService
|
||||
import com.wrbug.polymarketbot.service.common.BlockchainService
|
||||
import com.wrbug.polymarketbot.service.common.PolymarketApiKeyService
|
||||
import com.wrbug.polymarketbot.service.copytrading.orders.OrderPushService
|
||||
import com.wrbug.polymarketbot.service.copytrading.orders.OrderSigningService
|
||||
import com.wrbug.polymarketbot.service.system.TelegramNotificationService
|
||||
import com.wrbug.polymarketbot.service.system.RelayClientService
|
||||
import com.wrbug.polymarketbot.util.CryptoUtils
|
||||
import kotlinx.coroutines.*
|
||||
import org.slf4j.LoggerFactory
|
||||
import org.springframework.stereotype.Service
|
||||
@@ -27,7 +35,7 @@ class AccountService(
|
||||
private val apiKeyService: PolymarketApiKeyService,
|
||||
private val orderPushService: OrderPushService,
|
||||
private val orderSigningService: OrderSigningService,
|
||||
private val cryptoUtils: com.wrbug.polymarketbot.util.CryptoUtils,
|
||||
private val cryptoUtils: CryptoUtils,
|
||||
private val telegramNotificationService: TelegramNotificationService? = null, // 可选,避免循环依赖
|
||||
private val relayClientService: RelayClientService
|
||||
) {
|
||||
@@ -1070,7 +1078,7 @@ class AccountService(
|
||||
/**
|
||||
* 从订单表获取最优价(用于市价单)
|
||||
* 支持多元市场(二元、三元及以上)
|
||||
* 委托给 PolymarketClobService.getOptimalPrice 方法
|
||||
* 委托给 com.wrbug.polymarketbot.service.common.PolymarketClobService.getOptimalPrice 方法
|
||||
*
|
||||
* @param tokenId token ID(通过 marketId 和 outcomeIndex 计算得出)
|
||||
* @param isSellOrder 是否为卖出订单(true: 卖单,需要 bestBid;false: 买单,需要 bestAsk)
|
||||
@@ -1167,7 +1175,7 @@ class AccountService(
|
||||
/**
|
||||
* 获取可赎回仓位统计
|
||||
*/
|
||||
suspend fun getRedeemablePositionsSummary(accountId: Long? = null): Result<com.wrbug.polymarketbot.dto.RedeemablePositionsSummary> {
|
||||
suspend fun getRedeemablePositionsSummary(accountId: Long? = null): Result<RedeemablePositionsSummary> {
|
||||
return try {
|
||||
val positionsResult = getAllPositions()
|
||||
positionsResult.fold(
|
||||
@@ -1223,7 +1231,7 @@ class AccountService(
|
||||
* 赎回仓位
|
||||
* 支持多账户、多仓位赎回(自动按账户和市场分组)
|
||||
*/
|
||||
suspend fun redeemPositions(request: com.wrbug.polymarketbot.dto.PositionRedeemRequest): Result<com.wrbug.polymarketbot.dto.PositionRedeemResponse> {
|
||||
suspend fun redeemPositions(request: PositionRedeemRequest): Result<PositionRedeemResponse> {
|
||||
return try {
|
||||
// 检查 Builder API Key 是否已配置
|
||||
if (!relayClientService.isBuilderApiKeyConfigured()) {
|
||||
+7
-4
@@ -1,4 +1,4 @@
|
||||
package com.wrbug.polymarketbot.service
|
||||
package com.wrbug.polymarketbot.service.accounts
|
||||
|
||||
import com.wrbug.polymarketbot.dto.AccountPositionDto
|
||||
import com.wrbug.polymarketbot.entity.CopyOrderTracking
|
||||
@@ -18,6 +18,9 @@ import jakarta.annotation.PostConstruct
|
||||
import jakarta.annotation.PreDestroy
|
||||
import org.springframework.context.MessageSource
|
||||
import org.springframework.context.i18n.LocaleContextHolder
|
||||
import com.wrbug.polymarketbot.service.system.SystemConfigService
|
||||
import com.wrbug.polymarketbot.service.system.RelayClientService
|
||||
import com.wrbug.polymarketbot.service.system.TelegramNotificationService
|
||||
import org.springframework.stereotype.Service
|
||||
import java.math.BigDecimal
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
@@ -368,15 +371,15 @@ class PositionCheckService(
|
||||
if (position == null) {
|
||||
// 仓位不存在,更新所有订单状态为已卖出
|
||||
val currentPrice = getCurrentMarketPrice(marketId, outcomeIndex)
|
||||
updateOrdersAsSold(orders, currentPrice, copyTrading.id!!, marketId, outcomeIndex)
|
||||
updateOrdersAsSold(orders, currentPrice, copyTrading.id, marketId, outcomeIndex)
|
||||
} else {
|
||||
// 有仓位,按订单下单顺序(FIFO)更新状态
|
||||
// 如果仓位数量 >= 订单数量总和,所有订单完全成交
|
||||
// 如果仓位数量 < 订单数量总和,按FIFO顺序部分成交
|
||||
val totalUnmatchedQuantity = orders.sumOf { it.remainingQuantity.toSafeBigDecimal() }
|
||||
val positionQuantity = position.quantity.toSafeBigDecimal()
|
||||
val currentPrice = getCurrentMarketPrice(marketId, outcomeIndex)
|
||||
updateOrdersAsSoldByFIFO(orders, positionQuantity, currentPrice, copyTrading.id!!, marketId, outcomeIndex)
|
||||
updateOrdersAsSoldByFIFO(orders, positionQuantity, currentPrice,
|
||||
copyTrading.id, marketId, outcomeIndex)
|
||||
}
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package com.wrbug.polymarketbot.service
|
||||
package com.wrbug.polymarketbot.service.accounts
|
||||
|
||||
import com.wrbug.polymarketbot.dto.PositionListResponse
|
||||
import jakarta.annotation.PostConstruct
|
||||
+3
-2
@@ -1,6 +1,7 @@
|
||||
package com.wrbug.polymarketbot.service
|
||||
package com.wrbug.polymarketbot.service.accounts
|
||||
|
||||
import com.wrbug.polymarketbot.dto.AccountPositionDto
|
||||
import com.wrbug.polymarketbot.dto.PositionListResponse
|
||||
import com.wrbug.polymarketbot.dto.PositionPushMessage
|
||||
import com.wrbug.polymarketbot.dto.PositionPushMessageType
|
||||
import com.wrbug.polymarketbot.dto.getPositionKey
|
||||
@@ -155,7 +156,7 @@ class PositionPushService(
|
||||
* 处理仓位更新事件
|
||||
* 根据文档要求:每次轮训完成后向订阅者发送全量数据
|
||||
*/
|
||||
private fun handlePositionUpdate(positions: com.wrbug.polymarketbot.dto.PositionListResponse) {
|
||||
private fun handlePositionUpdate(positions: PositionListResponse) {
|
||||
// 更新快照
|
||||
lastCurrentPositions = positions.currentPositions.associateBy { it.getPositionKey() }
|
||||
lastHistoryPositions = positions.historyPositions.associateBy { it.getPositionKey() }
|
||||
+74
-75
@@ -1,6 +1,7 @@
|
||||
package com.wrbug.polymarketbot.service
|
||||
package com.wrbug.polymarketbot.service.announcement
|
||||
|
||||
import com.wrbug.polymarketbot.api.GitHubApi
|
||||
import com.wrbug.polymarketbot.api.GitHubCommentResponse
|
||||
import com.wrbug.polymarketbot.dto.AnnouncementDto
|
||||
import com.wrbug.polymarketbot.dto.AnnouncementListResponse
|
||||
import com.wrbug.polymarketbot.util.RetrofitFactory
|
||||
@@ -25,30 +26,30 @@ class AnnouncementService(
|
||||
@Value("\${github.announcement.issue.number:1}")
|
||||
private val issueNumber: Int
|
||||
) {
|
||||
|
||||
|
||||
private val logger = LoggerFactory.getLogger(AnnouncementService::class.java)
|
||||
|
||||
|
||||
// GitHub API 客户端(懒加载)
|
||||
private val githubApi: GitHubApi by lazy {
|
||||
retrofitFactory.createGitHubApi()
|
||||
}
|
||||
|
||||
|
||||
// 需要排除的 Issue ID(从 issue_url 中提取)
|
||||
private val excludedIssueId = "3703128976"
|
||||
|
||||
|
||||
// 缓存数据(1分钟有效期)
|
||||
private data class CachedData<T>(
|
||||
val data: T,
|
||||
val timestamp: Long
|
||||
)
|
||||
|
||||
|
||||
private var cachedList: CachedData<AnnouncementListResponse>? = null
|
||||
private var cachedAssignees: CachedData<List<String>>? = null
|
||||
private var cachedComments: CachedData<List<com.wrbug.polymarketbot.api.GitHubCommentResponse>>? = null
|
||||
|
||||
|
||||
// 缓存有效期:10分钟(毫秒)
|
||||
private val cacheExpiryTime = 10 * 60 * 1000L
|
||||
|
||||
|
||||
/**
|
||||
* 检查缓存是否有效
|
||||
*/
|
||||
@@ -57,7 +58,7 @@ class AnnouncementService(
|
||||
val now = System.currentTimeMillis()
|
||||
return (now - cached.timestamp) < cacheExpiryTime
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 检查是否被限流
|
||||
*/
|
||||
@@ -70,7 +71,7 @@ class AnnouncementService(
|
||||
val remaining = response.headers()["X-RateLimit-Remaining"]
|
||||
return remaining == "0"
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取 Issue 的 assignees 列表(通过 API 获取,带缓存)
|
||||
* @return Pair<assignees列表, 是否使用了缓存>
|
||||
@@ -81,14 +82,14 @@ class AnnouncementService(
|
||||
logger.debug("使用缓存的 assignees")
|
||||
return Pair(cachedAssignees!!.data, true)
|
||||
}
|
||||
|
||||
|
||||
return try {
|
||||
val response = githubApi.getIssue(
|
||||
owner = repoOwner,
|
||||
repo = repoName,
|
||||
issueNumber = issueNumber
|
||||
)
|
||||
|
||||
|
||||
// 如果被限流,使用缓存数据,不更新缓存
|
||||
if (isRateLimited(response)) {
|
||||
logger.warn("GitHub API 被限流,使用缓存的 assignees(不更新缓存)")
|
||||
@@ -98,14 +99,14 @@ class AnnouncementService(
|
||||
// 如果没有缓存,使用默认值
|
||||
return Pair(listOf("WrBug"), false)
|
||||
}
|
||||
|
||||
|
||||
val assignees = if (response.isSuccessful && response.body() != null) {
|
||||
response.body()!!.assignees.map { it.login }
|
||||
} else {
|
||||
logger.warn("获取 Issue assignees 失败,使用默认值: code=${response.code()}")
|
||||
listOf("WrBug") // 默认值
|
||||
}
|
||||
|
||||
|
||||
// 更新缓存
|
||||
cachedAssignees = CachedData(assignees, System.currentTimeMillis())
|
||||
Pair(assignees, false) // 返回新数据,标记为未使用缓存
|
||||
@@ -119,24 +120,24 @@ class AnnouncementService(
|
||||
Pair(listOf("WrBug"), false) // 默认值
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取 Issue 评论列表(带缓存)
|
||||
* @return Pair<评论列表, 是否使用了缓存>
|
||||
*/
|
||||
private suspend fun getIssueComments(forceRefresh: Boolean = false): Pair<List<com.wrbug.polymarketbot.api.GitHubCommentResponse>, Boolean> {
|
||||
private suspend fun getIssueComments(forceRefresh: Boolean = false): Pair<List<GitHubCommentResponse>, Boolean> {
|
||||
// 检查缓存
|
||||
if (!forceRefresh && isCacheValid(cachedComments)) {
|
||||
logger.debug("使用缓存的评论列表")
|
||||
return Pair(cachedComments!!.data, true)
|
||||
}
|
||||
|
||||
|
||||
val response = githubApi.getIssueComments(
|
||||
owner = repoOwner,
|
||||
repo = repoName,
|
||||
issueNumber = issueNumber
|
||||
)
|
||||
|
||||
|
||||
// 如果被限流,使用缓存数据,不更新缓存
|
||||
if (isRateLimited(response)) {
|
||||
logger.warn("GitHub API 被限流,使用缓存的评论列表(不更新缓存)")
|
||||
@@ -146,7 +147,7 @@ class AnnouncementService(
|
||||
// 如果没有缓存,抛出异常
|
||||
throw Exception("获取公告列表失败: GitHub API 被限流,且无缓存数据")
|
||||
}
|
||||
|
||||
|
||||
if (!response.isSuccessful || response.body() == null) {
|
||||
logger.error("获取 GitHub Issue 评论失败: code=${response.code()}, message=${response.message()}")
|
||||
// 如果缓存存在,使用缓存
|
||||
@@ -156,14 +157,14 @@ class AnnouncementService(
|
||||
}
|
||||
throw Exception("获取公告列表失败: HTTP ${response.code()}")
|
||||
}
|
||||
|
||||
|
||||
val comments = response.body()!!
|
||||
|
||||
|
||||
// 更新缓存
|
||||
cachedComments = CachedData(comments, System.currentTimeMillis())
|
||||
return Pair(comments, false) // 返回新数据,标记为未使用缓存
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取公告列表(最近10条)
|
||||
* @param forceRefresh 是否强制刷新缓存
|
||||
@@ -174,12 +175,12 @@ class AnnouncementService(
|
||||
logger.debug("使用缓存的公告列表")
|
||||
return Result.success(cachedList!!.data)
|
||||
}
|
||||
|
||||
|
||||
return try {
|
||||
// 强制刷新时,先尝试获取新数据
|
||||
val (assigneeList, assigneesFromCache) = getAssignees(forceRefresh)
|
||||
val (comments, commentsFromCache) = getIssueComments(forceRefresh)
|
||||
|
||||
|
||||
// 如果强制刷新时使用了缓存(被限流),直接返回缓存数据,不更新缓存
|
||||
if (forceRefresh && (assigneesFromCache || commentsFromCache)) {
|
||||
logger.warn("强制刷新时被限流,返回缓存的公告列表(不更新缓存)")
|
||||
@@ -187,48 +188,47 @@ class AnnouncementService(
|
||||
return Result.success(cachedList!!.data)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 筛选条件:
|
||||
// 1. assignees 发布的评论
|
||||
// 2. 排除 issueNumber 为 3703128976 的评论(从 issue_url 中提取)
|
||||
val filteredComments = comments
|
||||
.filter { comment ->
|
||||
// 检查是否为 assignee
|
||||
val isAssignee = assigneeList.contains(comment.user.login)
|
||||
|
||||
// 检查是否应该排除(从 issue_url 中提取 issue ID)
|
||||
val shouldExclude = comment.issue_url?.let { issueUrl ->
|
||||
// issue_url 格式:https://api.github.com/repos/owner/repo/issues/3703128976
|
||||
// 提取最后的数字
|
||||
val issueId = issueUrl.split("/").lastOrNull()
|
||||
issueId == excludedIssueId
|
||||
} ?: false
|
||||
|
||||
isAssignee && !shouldExclude
|
||||
}
|
||||
val filteredComments = comments.filter { comment ->
|
||||
// 检查是否为 assignee
|
||||
val isAssignee = assigneeList.contains(comment.user.login)
|
||||
|
||||
// 检查是否应该排除(从 issue_url 中提取 issue ID)
|
||||
val shouldExclude = comment.issue_url?.let { issueUrl ->
|
||||
// issue_url 格式:https://api.github.com/repos/owner/repo/issues/3703128976
|
||||
// 提取最后的数字
|
||||
val issueId = issueUrl.split("/").lastOrNull()
|
||||
issueId == excludedIssueId
|
||||
} ?: false
|
||||
|
||||
isAssignee && !shouldExclude
|
||||
}
|
||||
.sortedByDescending { comment ->
|
||||
parseGitHubTime(comment.created_at)
|
||||
}
|
||||
|
||||
|
||||
val total = filteredComments.size
|
||||
val hasMore = total > 10
|
||||
|
||||
|
||||
// 取前10条
|
||||
val latest10 = filteredComments.take(10).map { comment ->
|
||||
toAnnouncementDto(comment)
|
||||
}
|
||||
|
||||
|
||||
val result = AnnouncementListResponse(
|
||||
list = latest10,
|
||||
hasMore = hasMore,
|
||||
total = total
|
||||
)
|
||||
|
||||
|
||||
// 只有在数据正常返回时才更新缓存(不是从缓存获取的)
|
||||
if (!assigneesFromCache && !commentsFromCache) {
|
||||
cachedList = CachedData(result, System.currentTimeMillis())
|
||||
}
|
||||
|
||||
|
||||
Result.success(result)
|
||||
} catch (e: Exception) {
|
||||
logger.error("获取公告列表异常: ${e.message}", e)
|
||||
@@ -240,7 +240,7 @@ class AnnouncementService(
|
||||
Result.failure(e)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取公告详情
|
||||
* @param id 评论ID,如果为 null 则返回最新一条
|
||||
@@ -249,19 +249,18 @@ class AnnouncementService(
|
||||
suspend fun getAnnouncementDetail(id: Long?, forceRefresh: Boolean = false): Result<AnnouncementDto> {
|
||||
return try {
|
||||
// 获取 assignees
|
||||
val (assigneeList, assigneesFromCache) = getAssignees(forceRefresh)
|
||||
|
||||
val (assigneeList, _) = getAssignees(forceRefresh)
|
||||
|
||||
// 获取评论列表
|
||||
val (comments, commentsFromCache) = getIssueComments(forceRefresh)
|
||||
|
||||
val (comments, _) = getIssueComments(forceRefresh)
|
||||
|
||||
// 筛选条件:
|
||||
// 1. assignees 发布的评论
|
||||
// 2. 排除 issueNumber 为 3703128976 的评论(从 issue_url 中提取)
|
||||
val filteredComments = comments
|
||||
.filter { comment ->
|
||||
val filteredComments = comments.filter { comment ->
|
||||
// 检查是否为 assignee
|
||||
val isAssignee = assigneeList.contains(comment.user.login)
|
||||
|
||||
|
||||
// 检查是否应该排除(从 issue_url 中提取 issue ID)
|
||||
val shouldExclude = comment.issue_url?.let { issueUrl ->
|
||||
// issue_url 格式:https://api.github.com/repos/owner/repo/issues/3703128976
|
||||
@@ -269,37 +268,37 @@ class AnnouncementService(
|
||||
val issueId = issueUrl.split("/").lastOrNull()
|
||||
issueId == excludedIssueId
|
||||
} ?: false
|
||||
|
||||
|
||||
isAssignee && !shouldExclude
|
||||
}
|
||||
.sortedByDescending { comment ->
|
||||
parseGitHubTime(comment.created_at)
|
||||
}
|
||||
|
||||
|
||||
val targetComment = if (id != null) {
|
||||
filteredComments.find { it.id == id }
|
||||
} else {
|
||||
filteredComments.firstOrNull()
|
||||
}
|
||||
|
||||
|
||||
if (targetComment == null) {
|
||||
return Result.failure(IllegalArgumentException("公告不存在"))
|
||||
}
|
||||
|
||||
|
||||
Result.success(toAnnouncementDto(targetComment))
|
||||
} catch (e: Exception) {
|
||||
logger.error("获取公告详情异常: ${e.message}", e)
|
||||
Result.failure(e)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 将 GitHub 评论转换为 AnnouncementDto
|
||||
*/
|
||||
private fun toAnnouncementDto(comment: com.wrbug.polymarketbot.api.GitHubCommentResponse): AnnouncementDto {
|
||||
private fun toAnnouncementDto(comment: GitHubCommentResponse): AnnouncementDto {
|
||||
// 提取标题(第一行,移除 Markdown 格式)
|
||||
val title = extractTitle(comment.body)
|
||||
|
||||
|
||||
// 转换 reactions 数据
|
||||
val reactions = comment.reactions?.let { r ->
|
||||
com.wrbug.polymarketbot.dto.ReactionsDto(
|
||||
@@ -314,7 +313,7 @@ class AnnouncementService(
|
||||
total = r.total_count
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
return AnnouncementDto(
|
||||
id = comment.id,
|
||||
title = title,
|
||||
@@ -326,7 +325,7 @@ class AnnouncementService(
|
||||
reactions = reactions
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 从评论内容中提取标题(第一行,移除 Markdown 格式)
|
||||
* 支持的 Markdown 格式:
|
||||
@@ -342,49 +341,49 @@ class AnnouncementService(
|
||||
if (body.isBlank()) {
|
||||
return ""
|
||||
}
|
||||
|
||||
|
||||
// 获取第一行
|
||||
val firstLine = body.lines().firstOrNull()?.trim() ?: ""
|
||||
if (firstLine.isBlank()) {
|
||||
return ""
|
||||
}
|
||||
|
||||
|
||||
// 移除 Markdown 格式
|
||||
var title = firstLine
|
||||
|
||||
|
||||
// 移除标题标记(# ## ### 等)
|
||||
title = title.replace(Regex("^#{1,6}\\s+"), "")
|
||||
|
||||
|
||||
// 移除粗体标记(**text** 或 __text__)
|
||||
title = title.replace(Regex("\\*\\*([^*]+)\\*\\*"), "$1")
|
||||
title = title.replace(Regex("__([^_]+)__"), "$1")
|
||||
|
||||
|
||||
// 移除斜体标记(*text* 或 _text_)
|
||||
title = title.replace(Regex("(?<!\\*)\\*([^*]+)\\*(?!\\*)"), "$1")
|
||||
title = title.replace(Regex("(?<!_)_([^_]+)_(?!_)"), "$1")
|
||||
|
||||
|
||||
// 移除代码标记(`code`)
|
||||
title = title.replace(Regex("`([^`]+)`"), "$1")
|
||||
|
||||
|
||||
// 移除链接标记([text](url))
|
||||
title = title.replace(Regex("\\[([^\\]]+)\\]\\([^\\)]+\\)"), "$1")
|
||||
|
||||
|
||||
// 移除图片标记()
|
||||
title = title.replace(Regex("!\\[([^\\]]*)\\]\\([^\\)]+\\)"), "$1")
|
||||
|
||||
|
||||
// 移除删除线标记(~~text~~)
|
||||
title = title.replace(Regex("~~([^~]+)~~"), "$1")
|
||||
|
||||
|
||||
// 移除引用标记(> text)
|
||||
title = title.replace(Regex("^>\\s+"), "")
|
||||
|
||||
|
||||
// 移除列表标记(- * + 1. 等)
|
||||
title = title.replace(Regex("^[-*+]\\s+"), "")
|
||||
title = title.replace(Regex("^\\d+\\.\\s+"), "")
|
||||
|
||||
|
||||
return title.trim()
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 解析 GitHub 时间格式(ISO 8601)为时间戳(毫秒)
|
||||
* GitHub API 返回的时间格式:2025-12-07T14:30:00Z
|
||||
+2
-1
@@ -1,4 +1,4 @@
|
||||
package com.wrbug.polymarketbot.service
|
||||
package com.wrbug.polymarketbot.service.auth
|
||||
|
||||
import com.wrbug.polymarketbot.dto.CheckFirstUseResponse
|
||||
import com.wrbug.polymarketbot.dto.LoginResponse
|
||||
@@ -10,6 +10,7 @@ import jakarta.servlet.http.HttpServletRequest
|
||||
import org.slf4j.LoggerFactory
|
||||
import org.springframework.beans.factory.annotation.Value
|
||||
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder
|
||||
import com.wrbug.polymarketbot.service.common.RateLimitService
|
||||
import org.springframework.stereotype.Service
|
||||
import org.springframework.transaction.annotation.Transactional
|
||||
|
||||
+2
-1
@@ -1,4 +1,4 @@
|
||||
package com.wrbug.polymarketbot.service
|
||||
package com.wrbug.polymarketbot.service.common
|
||||
|
||||
import com.wrbug.polymarketbot.api.EthereumRpcApi
|
||||
import com.wrbug.polymarketbot.api.JsonRpcRequest
|
||||
@@ -11,6 +11,7 @@ import com.wrbug.polymarketbot.util.RetrofitFactory
|
||||
import com.wrbug.polymarketbot.util.createClient
|
||||
import org.slf4j.LoggerFactory
|
||||
import org.springframework.beans.factory.annotation.Value
|
||||
import com.wrbug.polymarketbot.service.system.RelayClientService
|
||||
import org.springframework.stereotype.Service
|
||||
import retrofit2.Retrofit
|
||||
import retrofit2.converter.gson.GsonConverterFactory
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package com.wrbug.polymarketbot.service
|
||||
package com.wrbug.polymarketbot.service.common
|
||||
|
||||
import com.wrbug.polymarketbot.api.ApiKeyResponse
|
||||
import com.wrbug.polymarketbot.api.PolymarketClobApi
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package com.wrbug.polymarketbot.service
|
||||
package com.wrbug.polymarketbot.service.common
|
||||
|
||||
import com.wrbug.polymarketbot.api.*
|
||||
import com.wrbug.polymarketbot.util.RetrofitFactory
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package com.wrbug.polymarketbot.service
|
||||
package com.wrbug.polymarketbot.service.common
|
||||
|
||||
import org.slf4j.LoggerFactory
|
||||
import org.springframework.beans.factory.annotation.Value
|
||||
+3
-1
@@ -1,9 +1,11 @@
|
||||
package com.wrbug.polymarketbot.service
|
||||
package com.wrbug.polymarketbot.service.common
|
||||
|
||||
import com.wrbug.polymarketbot.dto.OrderPushMessage
|
||||
import com.wrbug.polymarketbot.dto.PositionPushMessage
|
||||
import com.wrbug.polymarketbot.dto.WebSocketMessage as WsMessage
|
||||
import com.wrbug.polymarketbot.dto.WebSocketMessageType
|
||||
import com.wrbug.polymarketbot.service.accounts.PositionPushService
|
||||
import com.wrbug.polymarketbot.service.copytrading.orders.OrderPushService
|
||||
import kotlinx.coroutines.*
|
||||
import org.slf4j.LoggerFactory
|
||||
import org.springframework.stereotype.Service
|
||||
+2
-1
@@ -1,4 +1,4 @@
|
||||
package com.wrbug.polymarketbot.service
|
||||
package com.wrbug.polymarketbot.service.copytrading.configs
|
||||
|
||||
import com.wrbug.polymarketbot.api.OrderbookResponse
|
||||
import com.wrbug.polymarketbot.entity.CopyTrading
|
||||
@@ -7,6 +7,7 @@ import com.wrbug.polymarketbot.util.lt
|
||||
import com.wrbug.polymarketbot.util.multi
|
||||
import com.wrbug.polymarketbot.util.toSafeBigDecimal
|
||||
import org.slf4j.LoggerFactory
|
||||
import com.wrbug.polymarketbot.service.common.PolymarketClobService
|
||||
import org.springframework.stereotype.Service
|
||||
import java.math.BigDecimal
|
||||
|
||||
+7
-4
@@ -1,11 +1,14 @@
|
||||
package com.wrbug.polymarketbot.service
|
||||
package com.wrbug.polymarketbot.service.copytrading.configs
|
||||
|
||||
import com.wrbug.polymarketbot.dto.*
|
||||
import com.wrbug.polymarketbot.entity.Account
|
||||
import com.wrbug.polymarketbot.entity.CopyTrading
|
||||
import com.wrbug.polymarketbot.entity.Leader
|
||||
import com.wrbug.polymarketbot.repository.AccountRepository
|
||||
import com.wrbug.polymarketbot.repository.CopyTradingRepository
|
||||
import com.wrbug.polymarketbot.repository.CopyTradingTemplateRepository
|
||||
import com.wrbug.polymarketbot.repository.LeaderRepository
|
||||
import com.wrbug.polymarketbot.service.copytrading.monitor.CopyTradingMonitorService
|
||||
import com.wrbug.polymarketbot.util.toSafeBigDecimal
|
||||
import org.slf4j.LoggerFactory
|
||||
import org.springframework.stereotype.Service
|
||||
@@ -339,7 +342,7 @@ class CopyTradingService(
|
||||
fun getAccountTemplates(accountId: Long): Result<AccountTemplatesResponse> {
|
||||
return try {
|
||||
// 验证账户是否存在
|
||||
val account = accountRepository.findById(accountId).orElse(null)
|
||||
accountRepository.findById(accountId).orElse(null)
|
||||
?: return Result.failure(IllegalArgumentException("账户不存在"))
|
||||
|
||||
val copyTradings = copyTradingRepository.findByAccountId(accountId)
|
||||
@@ -380,8 +383,8 @@ class CopyTradingService(
|
||||
*/
|
||||
private fun toDto(
|
||||
copyTrading: CopyTrading,
|
||||
account: com.wrbug.polymarketbot.entity.Account,
|
||||
leader: com.wrbug.polymarketbot.entity.Leader
|
||||
account: Account,
|
||||
leader: Leader
|
||||
): CopyTradingDto {
|
||||
return CopyTradingDto(
|
||||
id = copyTrading.id!!,
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package com.wrbug.polymarketbot.service
|
||||
package com.wrbug.polymarketbot.service.copytrading.configs
|
||||
|
||||
import com.wrbug.polymarketbot.dto.FilteredOrderDto
|
||||
import com.wrbug.polymarketbot.dto.FilteredOrderListRequest
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package com.wrbug.polymarketbot.service
|
||||
package com.wrbug.polymarketbot.service.copytrading.leaders
|
||||
|
||||
import com.wrbug.polymarketbot.dto.*
|
||||
import com.wrbug.polymarketbot.entity.Leader
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package com.wrbug.polymarketbot.service
|
||||
package com.wrbug.polymarketbot.service.copytrading.monitor
|
||||
|
||||
import com.wrbug.polymarketbot.entity.CopyTrading
|
||||
import com.wrbug.polymarketbot.entity.Leader
|
||||
+4
-3
@@ -1,4 +1,4 @@
|
||||
package com.wrbug.polymarketbot.service
|
||||
package com.wrbug.polymarketbot.service.copytrading.monitor
|
||||
|
||||
import com.wrbug.polymarketbot.api.TradeResponse
|
||||
import com.wrbug.polymarketbot.api.UserActivityResponse
|
||||
@@ -9,6 +9,7 @@ import jakarta.annotation.PreDestroy
|
||||
import kotlinx.coroutines.*
|
||||
import org.slf4j.LoggerFactory
|
||||
import org.springframework.beans.factory.annotation.Value
|
||||
import com.wrbug.polymarketbot.service.copytrading.statistics.CopyOrderTrackingService
|
||||
import org.springframework.stereotype.Service
|
||||
import retrofit2.Response
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
@@ -72,7 +73,7 @@ class CopyTradingPollingService(
|
||||
return
|
||||
}
|
||||
|
||||
val leaderId = leader.id!!
|
||||
val leaderId = leader.id
|
||||
monitoredLeaders[leaderId] = leader
|
||||
// 初始化缓存的交易ID集合
|
||||
cachedTradeIds[leaderId] = mutableSetOf()
|
||||
@@ -178,7 +179,7 @@ class CopyTradingPollingService(
|
||||
return
|
||||
}
|
||||
|
||||
val leaderId = leader.id!!
|
||||
val leaderId = leader.id
|
||||
val leaderAddress = leader.leaderAddress
|
||||
|
||||
try {
|
||||
+3
-2
@@ -1,4 +1,4 @@
|
||||
package com.wrbug.polymarketbot.service
|
||||
package com.wrbug.polymarketbot.service.copytrading.monitor
|
||||
|
||||
import com.google.gson.Gson
|
||||
import com.google.gson.JsonObject
|
||||
@@ -11,6 +11,7 @@ import jakarta.annotation.PreDestroy
|
||||
import kotlinx.coroutines.*
|
||||
import org.slf4j.LoggerFactory
|
||||
import org.springframework.beans.factory.annotation.Value
|
||||
import com.wrbug.polymarketbot.service.copytrading.statistics.CopyOrderTrackingService
|
||||
import org.springframework.stereotype.Service
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
|
||||
@@ -65,7 +66,7 @@ class CopyTradingWebSocketService(
|
||||
return
|
||||
}
|
||||
|
||||
val leaderId = leader.id!!
|
||||
val leaderId = leader.id
|
||||
val leaderAddress = leader.leaderAddress.lowercase()
|
||||
leaderAddresses[leaderId] = leaderAddress
|
||||
|
||||
+17
-11
@@ -1,6 +1,7 @@
|
||||
package com.wrbug.polymarketbot.service
|
||||
package com.wrbug.polymarketbot.service.copytrading.orders
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper
|
||||
import com.wrbug.polymarketbot.api.MarketResponse
|
||||
import com.wrbug.polymarketbot.dto.OrderDetailDto
|
||||
import com.wrbug.polymarketbot.dto.OrderMessageDto
|
||||
import com.wrbug.polymarketbot.dto.OrderPushMessage
|
||||
@@ -13,6 +14,11 @@ import jakarta.annotation.PreDestroy
|
||||
import kotlinx.coroutines.*
|
||||
import org.slf4j.LoggerFactory
|
||||
import org.springframework.beans.factory.annotation.Value
|
||||
import com.wrbug.polymarketbot.service.common.PolymarketClobService
|
||||
import com.wrbug.polymarketbot.util.CryptoUtils
|
||||
import com.wrbug.polymarketbot.repository.CopyOrderTrackingRepository
|
||||
import com.wrbug.polymarketbot.repository.CopyTradingRepository
|
||||
import com.wrbug.polymarketbot.repository.LeaderRepository
|
||||
import org.springframework.stereotype.Service
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
|
||||
@@ -26,10 +32,10 @@ class OrderPushService(
|
||||
private val objectMapper: ObjectMapper,
|
||||
private val clobService: PolymarketClobService,
|
||||
private val retrofitFactory: RetrofitFactory, // 用于创建 Gamma API 客户端(不需要认证)
|
||||
private val cryptoUtils: com.wrbug.polymarketbot.util.CryptoUtils,
|
||||
private val copyOrderTrackingRepository: com.wrbug.polymarketbot.repository.CopyOrderTrackingRepository? = null, // 可选,避免循环依赖
|
||||
private val copyTradingRepository: com.wrbug.polymarketbot.repository.CopyTradingRepository? = null, // 可选,避免循环依赖
|
||||
private val leaderRepository: com.wrbug.polymarketbot.repository.LeaderRepository? = null // 可选,避免循环依赖
|
||||
private val cryptoUtils: CryptoUtils,
|
||||
private val copyOrderTrackingRepository: CopyOrderTrackingRepository? = null, // 可选,避免循环依赖
|
||||
private val copyTradingRepository: CopyTradingRepository? = null, // 可选,避免循环依赖
|
||||
private val leaderRepository: LeaderRepository? = null // 可选,避免循环依赖
|
||||
) {
|
||||
|
||||
private val logger = LoggerFactory.getLogger(OrderPushService::class.java)
|
||||
@@ -152,9 +158,9 @@ class OrderPushService(
|
||||
return account.apiKey != null &&
|
||||
account.apiSecret != null &&
|
||||
account.apiPassphrase != null &&
|
||||
account.apiKey!!.isNotBlank() &&
|
||||
account.apiSecret!!.isNotBlank() &&
|
||||
account.apiPassphrase!!.isNotBlank()
|
||||
account.apiKey.isNotBlank() &&
|
||||
account.apiSecret.isNotBlank() &&
|
||||
account.apiPassphrase.isNotBlank()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -378,7 +384,7 @@ class OrderPushService(
|
||||
|
||||
/**
|
||||
* 获取订单详情
|
||||
* 通过 PolymarketClobService 获取订单详情
|
||||
* 通过 com.wrbug.polymarketbot.service.common.PolymarketClobService 获取订单详情
|
||||
*/
|
||||
private suspend fun fetchOrderDetail(
|
||||
account: Account,
|
||||
@@ -391,7 +397,7 @@ class OrderPushService(
|
||||
return null
|
||||
}
|
||||
|
||||
// 通过 PolymarketClobService 获取订单详情(需要 L2 认证)
|
||||
// 通过 com.wrbug.polymarketbot.service.common.PolymarketClobService 获取订单详情(需要 L2 认证)
|
||||
// 解密 API 凭证
|
||||
val apiSecret = try {
|
||||
decryptApiSecret(account)
|
||||
@@ -453,7 +459,7 @@ class OrderPushService(
|
||||
* 使用 /markets 接口,通过 condition_ids 查询参数获取市场信息
|
||||
* 订单返回的 market 字段是 16 进制的 condition ID(如 "0x...")
|
||||
*/
|
||||
private suspend fun fetchMarketInfo(conditionId: String): com.wrbug.polymarketbot.api.MarketResponse? {
|
||||
private suspend fun fetchMarketInfo(conditionId: String): MarketResponse? {
|
||||
return try {
|
||||
// 创建 Gamma API 客户端(公开 API,不需要认证)
|
||||
val gammaApi = retrofitFactory.createGammaApi()
|
||||
+1
-5
@@ -1,4 +1,4 @@
|
||||
package com.wrbug.polymarketbot.service
|
||||
package com.wrbug.polymarketbot.service.copytrading.orders
|
||||
|
||||
import com.wrbug.polymarketbot.api.SignedOrderObject
|
||||
import com.wrbug.polymarketbot.util.toSafeBigDecimal
|
||||
@@ -77,10 +77,6 @@ class OrderSigningService {
|
||||
): OrderAmounts {
|
||||
val sizeDecimal = size.toSafeBigDecimal()
|
||||
val priceDecimal = price.toSafeBigDecimal()
|
||||
|
||||
// 舍入价格
|
||||
val roundedPrice = roundNormal(priceDecimal, roundConfig.price)
|
||||
|
||||
if (side.uppercase() == "BUY") {
|
||||
// BUY: makerAmount = price * size (USDC), takerAmount = size (shares)
|
||||
// makerAmount 是 USDC 金额,最多 2 位小数
|
||||
+19
-13
@@ -1,6 +1,7 @@
|
||||
package com.wrbug.polymarketbot.service
|
||||
package com.wrbug.polymarketbot.service.copytrading.statistics
|
||||
|
||||
import com.wrbug.polymarketbot.api.NewOrderRequest
|
||||
import com.wrbug.polymarketbot.api.PolymarketClobApi
|
||||
import com.wrbug.polymarketbot.api.TradeResponse
|
||||
import com.wrbug.polymarketbot.entity.*
|
||||
import com.wrbug.polymarketbot.repository.*
|
||||
@@ -9,6 +10,11 @@ import com.wrbug.polymarketbot.util.*
|
||||
import kotlinx.coroutines.*
|
||||
import org.slf4j.LoggerFactory
|
||||
import org.springframework.dao.DataIntegrityViolationException
|
||||
import com.wrbug.polymarketbot.service.copytrading.configs.CopyTradingFilterService
|
||||
import com.wrbug.polymarketbot.service.copytrading.orders.OrderSigningService
|
||||
import com.wrbug.polymarketbot.service.common.BlockchainService
|
||||
import com.wrbug.polymarketbot.service.system.TelegramNotificationService
|
||||
import com.wrbug.polymarketbot.util.CryptoUtils
|
||||
import org.springframework.stereotype.Service
|
||||
import org.springframework.transaction.annotation.Transactional
|
||||
import java.math.BigDecimal
|
||||
@@ -33,7 +39,7 @@ class CopyOrderTrackingService(
|
||||
private val orderSigningService: OrderSigningService,
|
||||
private val blockchainService: BlockchainService,
|
||||
private val retrofitFactory: RetrofitFactory,
|
||||
private val cryptoUtils: com.wrbug.polymarketbot.util.CryptoUtils,
|
||||
private val cryptoUtils: CryptoUtils,
|
||||
private val telegramNotificationService: TelegramNotificationService? = null // 可选,避免循环依赖
|
||||
) {
|
||||
|
||||
@@ -381,7 +387,7 @@ class CopyOrderTrackingService(
|
||||
side = "BUY",
|
||||
price = buyPrice.toString(),
|
||||
size = finalBuyQuantity.toString(),
|
||||
owner = account.apiKey!!,
|
||||
owner = account.apiKey,
|
||||
copyTradingId = copyTrading.id!!,
|
||||
tradeId = trade.id
|
||||
)
|
||||
@@ -759,7 +765,7 @@ class CopyOrderTrackingService(
|
||||
// 这样可以快速响应 Leader 的交易,避免订单长期挂单导致价格不匹配
|
||||
val orderRequest = NewOrderRequest(
|
||||
order = signedOrder,
|
||||
owner = account.apiKey!!,
|
||||
owner = account.apiKey,
|
||||
orderType = "FAK", // Fill-And-Kill
|
||||
deferExec = false
|
||||
)
|
||||
@@ -782,8 +788,8 @@ class CopyOrderTrackingService(
|
||||
side = "SELL",
|
||||
price = sellPrice.toString(),
|
||||
size = totalMatched.toString(),
|
||||
owner = account.apiKey!!,
|
||||
copyTradingId = copyTrading.id!!,
|
||||
owner = account.apiKey,
|
||||
copyTradingId = copyTrading.id,
|
||||
tradeId = leaderSellTrade.id
|
||||
)
|
||||
|
||||
@@ -830,11 +836,11 @@ class CopyOrderTrackingService(
|
||||
val totalRealizedPnl = matchDetails.sumOf { it.realizedPnl.toSafeBigDecimal() }
|
||||
|
||||
val matchRecord = SellMatchRecord(
|
||||
copyTradingId = copyTrading.id!!,
|
||||
copyTradingId = copyTrading.id,
|
||||
sellOrderId = realSellOrderId, // 使用真实订单ID
|
||||
leaderSellTradeId = leaderSellTrade.id,
|
||||
marketId = leaderSellTrade.market,
|
||||
side = leaderSellTrade.outcomeIndex?.toString() ?: "0", // 使用outcomeIndex作为side(兼容旧数据)
|
||||
side = leaderSellTrade.outcomeIndex.toString(), // 使用outcomeIndex作为side(兼容旧数据)
|
||||
outcomeIndex = leaderSellTrade.outcomeIndex, // 新增字段
|
||||
totalMatchedQuantity = totalMatched,
|
||||
sellPrice = sellPrice,
|
||||
@@ -857,7 +863,7 @@ class CopyOrderTrackingService(
|
||||
* 注意:重试时会重新生成salt并重新签名,确保每次重试都是新的订单
|
||||
*/
|
||||
private suspend fun createOrderWithRetry(
|
||||
clobApi: com.wrbug.polymarketbot.api.PolymarketClobApi,
|
||||
clobApi: PolymarketClobApi,
|
||||
privateKey: String,
|
||||
makerAddress: String,
|
||||
tokenId: String,
|
||||
@@ -914,7 +920,7 @@ class CopyOrderTrackingService(
|
||||
delay(1000) // 重试前等待1秒
|
||||
continue
|
||||
}
|
||||
return Result.failure(lastError!!)
|
||||
return Result.failure(lastError)
|
||||
}
|
||||
|
||||
val response = orderResponse.body()!!
|
||||
@@ -928,7 +934,7 @@ class CopyOrderTrackingService(
|
||||
delay(1000) // 重试前等待1秒
|
||||
continue
|
||||
}
|
||||
return Result.failure(lastError!!)
|
||||
return Result.failure(lastError)
|
||||
}
|
||||
|
||||
// 成功
|
||||
@@ -943,7 +949,7 @@ class CopyOrderTrackingService(
|
||||
delay(1000) // 重试前等待1秒
|
||||
continue
|
||||
}
|
||||
return Result.failure(lastError!!)
|
||||
return Result.failure(lastError)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1105,7 +1111,7 @@ class CopyOrderTrackingService(
|
||||
}
|
||||
|
||||
// 2. 检查每日亏损限制(需要计算今日已实现盈亏)
|
||||
val todaySellRecords = sellMatchRecordRepository.findByCopyTradingId(copyTrading.id!!)
|
||||
val todaySellRecords = sellMatchRecordRepository.findByCopyTradingId(copyTrading.id)
|
||||
.filter { it.createdAt >= todayStart }
|
||||
|
||||
val todayRealizedPnl = todaySellRecords.sumOf { it.totalRealizedPnl.toSafeBigDecimal() }
|
||||
+45
-10
@@ -1,4 +1,4 @@
|
||||
package com.wrbug.polymarketbot.service
|
||||
package com.wrbug.polymarketbot.service.copytrading.statistics
|
||||
|
||||
import com.wrbug.polymarketbot.dto.*
|
||||
import com.wrbug.polymarketbot.entity.*
|
||||
@@ -13,6 +13,8 @@ import org.slf4j.LoggerFactory
|
||||
import org.springframework.data.domain.PageRequest
|
||||
import org.springframework.data.domain.Pageable
|
||||
import org.springframework.data.domain.Sort
|
||||
import com.wrbug.polymarketbot.service.accounts.AccountService
|
||||
import com.wrbug.polymarketbot.service.common.BlockchainService
|
||||
import org.springframework.stereotype.Service
|
||||
import java.math.BigDecimal
|
||||
import java.math.RoundingMode
|
||||
@@ -30,7 +32,7 @@ class CopyTradingStatisticsService(
|
||||
private val accountRepository: AccountRepository,
|
||||
private val leaderRepository: LeaderRepository,
|
||||
private val accountService: AccountService,
|
||||
private val blockchainService: com.wrbug.polymarketbot.service.BlockchainService
|
||||
private val blockchainService: BlockchainService
|
||||
) {
|
||||
|
||||
private val logger = LoggerFactory.getLogger(CopyTradingStatisticsService::class.java)
|
||||
@@ -69,7 +71,10 @@ class CopyTradingStatisticsService(
|
||||
// 9. 计算未实现盈亏(使用链上实际持仓,而不是 remainingQuantity)
|
||||
val unrealizedPnl = calculateUnrealizedPnl(buyOrders, currentPrice, actualPositions)
|
||||
|
||||
// 9. 构建响应
|
||||
// 10. 计算持仓价值(使用链上实际持仓和当前价格)
|
||||
val positionValue = calculatePositionValue(buyOrders, currentPrice, actualPositions)
|
||||
|
||||
// 11. 构建响应
|
||||
val response = CopyTradingStatisticsResponse(
|
||||
copyTradingId = copyTradingId,
|
||||
accountId = copyTrading.accountId,
|
||||
@@ -85,7 +90,7 @@ class CopyTradingStatisticsService(
|
||||
totalSellOrders = statistics.totalSellOrders,
|
||||
totalSellAmount = statistics.totalSellAmount,
|
||||
currentPositionQuantity = statistics.currentPositionQuantity,
|
||||
currentPositionValue = calculatePositionValue(statistics.currentPositionQuantity, currentPrice),
|
||||
currentPositionValue = positionValue,
|
||||
totalRealizedPnl = statistics.totalRealizedPnl,
|
||||
totalUnrealizedPnl = unrealizedPnl,
|
||||
totalPnl = (statistics.totalRealizedPnl.toSafeBigDecimal().add(unrealizedPnl.toSafeBigDecimal())).toString(),
|
||||
@@ -105,7 +110,7 @@ class CopyTradingStatisticsService(
|
||||
fun getOrderList(request: OrderTrackingRequest): Result<OrderListResponse> {
|
||||
return try {
|
||||
// 1. 验证跟单关系
|
||||
val copyTrading = copyTradingRepository.findById(request.copyTradingId).orElse(null)
|
||||
copyTradingRepository.findById(request.copyTradingId).orElse(null)
|
||||
?: return Result.failure(IllegalArgumentException("跟单关系不存在: ${request.copyTradingId}"))
|
||||
|
||||
// 2. 根据类型查询
|
||||
@@ -354,7 +359,7 @@ class CopyTradingStatisticsService(
|
||||
* 获取链上实际持仓
|
||||
* 按 (marketId, outcomeIndex) 组合返回实际持仓数量
|
||||
*/
|
||||
private suspend fun getActualPositions(account: com.wrbug.polymarketbot.entity.Account?): Map<String, BigDecimal> {
|
||||
private suspend fun getActualPositions(account: Account?): Map<String, BigDecimal> {
|
||||
val positions = mutableMapOf<String, BigDecimal>()
|
||||
|
||||
if (account == null || account.proxyAddress.isBlank()) {
|
||||
@@ -424,11 +429,41 @@ class CopyTradingStatisticsService(
|
||||
|
||||
/**
|
||||
* 计算持仓价值
|
||||
* 使用链上实际持仓数量和当前市场价格计算
|
||||
*/
|
||||
private fun calculatePositionValue(positionQuantity: String, currentPrices: Map<String, String>): String {
|
||||
// 这里简化处理,实际应该根据每个市场的持仓分别计算
|
||||
// 暂时返回0,因为需要知道每个市场的持仓数量
|
||||
return "0"
|
||||
private fun calculatePositionValue(
|
||||
buyOrders: List<CopyOrderTracking>,
|
||||
currentPrices: Map<String, String>,
|
||||
actualPositions: Map<String, BigDecimal>
|
||||
): String {
|
||||
var totalPositionValue = BigDecimal.ZERO
|
||||
|
||||
for (order in buyOrders) {
|
||||
// 如果没有 outcomeIndex,跳过(无法确定价格和持仓)
|
||||
if (order.outcomeIndex == null) {
|
||||
logger.warn("订单缺少 outcomeIndex,跳过持仓价值计算: orderId=${order.buyOrderId}, marketId=${order.marketId}")
|
||||
continue
|
||||
}
|
||||
|
||||
// 使用 "marketId:outcomeIndex" 作为 key
|
||||
val key = "${order.marketId}:${order.outcomeIndex}"
|
||||
|
||||
// 获取链上实际持仓数量(如果存在),否则使用 remainingQuantity
|
||||
val actualQty = actualPositions[key] ?: order.remainingQuantity.toSafeBigDecimal()
|
||||
|
||||
// 如果实际持仓 <= 0,说明已全部卖出(包括手动卖出),跳过持仓价值计算
|
||||
if (actualQty.lte(BigDecimal.ZERO)) continue
|
||||
|
||||
// 获取当前市场价格
|
||||
val currentPrice = currentPrices[key]?.toSafeBigDecimal()
|
||||
?: continue // 如果没有当前价格,跳过
|
||||
|
||||
// 计算持仓价值:持仓数量 × 当前价格
|
||||
val positionValue = actualQty.multi(currentPrice)
|
||||
totalPositionValue = totalPositionValue.add(positionValue)
|
||||
}
|
||||
|
||||
return totalPositionValue.toString()
|
||||
}
|
||||
|
||||
/**
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package com.wrbug.polymarketbot.service
|
||||
package com.wrbug.polymarketbot.service.copytrading.templates
|
||||
|
||||
import com.wrbug.polymarketbot.dto.*
|
||||
import com.wrbug.polymarketbot.entity.CopyTradingTemplate
|
||||
+3
-1
@@ -1,4 +1,4 @@
|
||||
package com.wrbug.polymarketbot.service
|
||||
package com.wrbug.polymarketbot.service.system
|
||||
|
||||
import com.wrbug.polymarketbot.dto.ApiHealthCheckDto
|
||||
import com.wrbug.polymarketbot.dto.ApiHealthCheckResponse
|
||||
@@ -12,6 +12,8 @@ import org.springframework.beans.BeansException
|
||||
import org.springframework.context.ApplicationContext
|
||||
import org.springframework.context.ApplicationContextAware
|
||||
import org.springframework.beans.factory.annotation.Value
|
||||
import com.wrbug.polymarketbot.service.copytrading.orders.OrderPushService
|
||||
import com.wrbug.polymarketbot.service.copytrading.monitor.CopyTradingWebSocketService
|
||||
import org.springframework.stereotype.Service
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package com.wrbug.polymarketbot.service
|
||||
package com.wrbug.polymarketbot.service.system
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper
|
||||
import com.wrbug.polymarketbot.dto.*
|
||||
+3
-1
@@ -1,8 +1,10 @@
|
||||
package com.wrbug.polymarketbot.service
|
||||
package com.wrbug.polymarketbot.service.system
|
||||
|
||||
import com.wrbug.polymarketbot.dto.*
|
||||
import com.wrbug.polymarketbot.entity.ProxyConfig
|
||||
import com.wrbug.polymarketbot.repository.ProxyConfigRepository
|
||||
import com.wrbug.polymarketbot.service.copytrading.monitor.CopyTradingWebSocketService
|
||||
import com.wrbug.polymarketbot.service.copytrading.orders.OrderPushService
|
||||
import com.wrbug.polymarketbot.util.ProxyConfigProvider
|
||||
import com.wrbug.polymarketbot.util.TrustAllHostnameVerifier
|
||||
import com.wrbug.polymarketbot.util.createSSLSocketFactory
|
||||
+3
-3
@@ -1,4 +1,4 @@
|
||||
package com.wrbug.polymarketbot.service
|
||||
package com.wrbug.polymarketbot.service.system
|
||||
|
||||
import com.wrbug.polymarketbot.api.BuilderRelayerApi
|
||||
import com.wrbug.polymarketbot.api.EthereumRpcApi
|
||||
@@ -802,10 +802,10 @@ class RelayClientService(
|
||||
safeTxs: List<SafeTransaction>
|
||||
): Result<String> {
|
||||
// 批量执行:将多个交易合并为一个 execTransaction 调用
|
||||
// 当前实现:委托给 BlockchainService
|
||||
// 当前实现:委托给 com.wrbug.polymarketbot.service.common.BlockchainService
|
||||
return Result.failure(
|
||||
UnsupportedOperationException(
|
||||
"批量 Gasless 执行暂未实现。请使用 BlockchainService.redeemPositions() 方法。"
|
||||
"批量 Gasless 执行暂未实现。请使用 com.wrbug.polymarketbot.service.common.BlockchainService.redeemPositions() 方法。"
|
||||
)
|
||||
)
|
||||
}
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package com.wrbug.polymarketbot.service
|
||||
package com.wrbug.polymarketbot.service.system
|
||||
|
||||
import com.wrbug.polymarketbot.dto.SystemConfigDto
|
||||
import com.wrbug.polymarketbot.dto.SystemConfigUpdateRequest
|
||||
+3
-2
@@ -1,7 +1,8 @@
|
||||
package com.wrbug.polymarketbot.service
|
||||
package com.wrbug.polymarketbot.service.system
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode
|
||||
import com.fasterxml.jackson.databind.ObjectMapper
|
||||
import com.wrbug.polymarketbot.api.PolymarketClobApi
|
||||
import com.wrbug.polymarketbot.dto.NotificationConfigData
|
||||
import com.wrbug.polymarketbot.dto.TelegramConfigData
|
||||
import com.wrbug.polymarketbot.util.createClient
|
||||
@@ -65,7 +66,7 @@ class TelegramNotificationService(
|
||||
side: String,
|
||||
accountName: String? = null,
|
||||
walletAddress: String? = null,
|
||||
clobApi: com.wrbug.polymarketbot.api.PolymarketClobApi? = null,
|
||||
clobApi: PolymarketClobApi? = null,
|
||||
apiKey: String? = null,
|
||||
apiSecret: String? = null,
|
||||
apiPassphrase: String? = null,
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package com.wrbug.polymarketbot.service
|
||||
package com.wrbug.polymarketbot.service.system
|
||||
|
||||
import com.wrbug.polymarketbot.dto.UserCreateRequest
|
||||
import com.wrbug.polymarketbot.dto.UserDto
|
||||
+1
-1
@@ -3,7 +3,7 @@ package com.wrbug.polymarketbot.websocket
|
||||
import com.fasterxml.jackson.databind.ObjectMapper
|
||||
import com.wrbug.polymarketbot.dto.WebSocketMessage as WsMessage
|
||||
import com.wrbug.polymarketbot.dto.WebSocketMessageType
|
||||
import com.wrbug.polymarketbot.service.WebSocketSubscriptionService
|
||||
import com.wrbug.polymarketbot.service.common.WebSocketSubscriptionService
|
||||
import jakarta.annotation.PostConstruct
|
||||
import jakarta.annotation.PreDestroy
|
||||
import kotlinx.coroutines.*
|
||||
|
||||
@@ -145,31 +145,31 @@ export const apiService = {
|
||||
* 获取用户列表
|
||||
*/
|
||||
list: () =>
|
||||
apiClient.post<ApiResponse<any[]>>('/users/list', {}),
|
||||
apiClient.post<ApiResponse<any[]>>('/system/users/list', {}),
|
||||
|
||||
/**
|
||||
* 创建用户
|
||||
*/
|
||||
create: (data: { username: string; password: string }) =>
|
||||
apiClient.post<ApiResponse<any>>('/users/create', data),
|
||||
apiClient.post<ApiResponse<any>>('/system/users/create', data),
|
||||
|
||||
/**
|
||||
* 更新用户密码
|
||||
*/
|
||||
updatePassword: (data: { userId: number; newPassword: string }) =>
|
||||
apiClient.post<ApiResponse<void>>('/users/update-password', data),
|
||||
apiClient.post<ApiResponse<void>>('/system/users/update-password', data),
|
||||
|
||||
/**
|
||||
* 删除用户
|
||||
*/
|
||||
delete: (data: { userId: number }) =>
|
||||
apiClient.post<ApiResponse<void>>('/users/delete', data),
|
||||
apiClient.post<ApiResponse<void>>('/system/users/delete', data),
|
||||
|
||||
/**
|
||||
* 用户修改自己的密码
|
||||
*/
|
||||
updateOwnPassword: (data: { newPassword: string }) =>
|
||||
apiClient.post<ApiResponse<void>>('/users/update-own-password', data)
|
||||
apiClient.post<ApiResponse<void>>('/system/users/update-own-password', data)
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -203,61 +203,61 @@ export const apiService = {
|
||||
* 导入账户
|
||||
*/
|
||||
import: (data: any) =>
|
||||
apiClient.post<ApiResponse<any>>('/copy-trading/accounts/import', data),
|
||||
apiClient.post<ApiResponse<any>>('/accounts/import', data),
|
||||
|
||||
/**
|
||||
* 更新账户
|
||||
*/
|
||||
update: (data: any) =>
|
||||
apiClient.post<ApiResponse<any>>('/copy-trading/accounts/update', data),
|
||||
apiClient.post<ApiResponse<any>>('/accounts/update', data),
|
||||
|
||||
/**
|
||||
* 删除账户
|
||||
*/
|
||||
delete: (data: { accountId: number }) =>
|
||||
apiClient.post<ApiResponse<void>>('/copy-trading/accounts/delete', data),
|
||||
apiClient.post<ApiResponse<void>>('/accounts/delete', data),
|
||||
|
||||
/**
|
||||
* 查询账户列表
|
||||
*/
|
||||
list: () =>
|
||||
apiClient.post<ApiResponse<any>>('/copy-trading/accounts/list', {}),
|
||||
apiClient.post<ApiResponse<any>>('/accounts/list', {}),
|
||||
|
||||
/**
|
||||
* 查询账户详情
|
||||
*/
|
||||
detail: (data: { accountId?: number }) =>
|
||||
apiClient.post<ApiResponse<any>>('/copy-trading/accounts/detail', data),
|
||||
apiClient.post<ApiResponse<any>>('/accounts/detail', data),
|
||||
|
||||
/**
|
||||
* 查询账户余额
|
||||
*/
|
||||
balance: (data: { accountId?: number }) =>
|
||||
apiClient.post<ApiResponse<any>>('/copy-trading/accounts/balance', data),
|
||||
apiClient.post<ApiResponse<any>>('/accounts/balance', data),
|
||||
|
||||
/**
|
||||
* 查询所有账户的仓位列表
|
||||
*/
|
||||
positionsList: () =>
|
||||
apiClient.post<ApiResponse<any>>('/copy-trading/accounts/positions/list', {}),
|
||||
apiClient.post<ApiResponse<any>>('/accounts/positions/list', {}),
|
||||
|
||||
/**
|
||||
* 卖出仓位
|
||||
*/
|
||||
sellPosition: (data: any) =>
|
||||
apiClient.post<ApiResponse<any>>('/copy-trading/accounts/positions/sell', data),
|
||||
apiClient.post<ApiResponse<any>>('/accounts/positions/sell', data),
|
||||
|
||||
/**
|
||||
* 获取可赎回仓位统计
|
||||
*/
|
||||
getRedeemableSummary: (data: { accountId?: number }) =>
|
||||
apiClient.post<ApiResponse<any>>('/copy-trading/accounts/positions/redeemable-summary', data),
|
||||
apiClient.post<ApiResponse<any>>('/accounts/positions/redeemable-summary', data),
|
||||
|
||||
/**
|
||||
* 赎回仓位
|
||||
*/
|
||||
redeemPositions: (data: any) =>
|
||||
apiClient.post<ApiResponse<any>>('/copy-trading/accounts/positions/redeem', data),
|
||||
apiClient.post<ApiResponse<any>>('/accounts/positions/redeem', data),
|
||||
|
||||
},
|
||||
|
||||
@@ -269,13 +269,13 @@ export const apiService = {
|
||||
* 获取市场价格(通过 Gamma API)
|
||||
*/
|
||||
getMarketPrice: (data: { marketId: string; outcomeIndex?: number }) =>
|
||||
apiClient.post<ApiResponse<any>>('/copy-trading/markets/price', data),
|
||||
apiClient.post<ApiResponse<any>>('/markets/price', data),
|
||||
|
||||
/**
|
||||
* 获取最新价(从订单表获取,供前端下单时显示)
|
||||
*/
|
||||
getLatestPrice: (data: { tokenId: string }) =>
|
||||
apiClient.post<ApiResponse<any>>('/copy-trading/markets/latest-price', data)
|
||||
apiClient.post<ApiResponse<any>>('/markets/latest-price', data)
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -365,37 +365,37 @@ export const apiService = {
|
||||
* 2. 不提供 templateId:手动输入所有配置参数
|
||||
*/
|
||||
create: (data: any) =>
|
||||
apiClient.post<ApiResponse<any>>('/copy-trading/create', data),
|
||||
apiClient.post<ApiResponse<any>>('/copy-trading/configs/create', data),
|
||||
|
||||
/**
|
||||
* 更新跟单配置
|
||||
*/
|
||||
update: (data: any) =>
|
||||
apiClient.post<ApiResponse<any>>('/copy-trading/update', data),
|
||||
apiClient.post<ApiResponse<any>>('/copy-trading/configs/update', data),
|
||||
|
||||
/**
|
||||
* 查询跟单列表
|
||||
*/
|
||||
list: (data: { accountId?: number; leaderId?: number; enabled?: boolean } = {}) =>
|
||||
apiClient.post<ApiResponse<any>>('/copy-trading/list', data),
|
||||
apiClient.post<ApiResponse<any>>('/copy-trading/configs/list', data),
|
||||
|
||||
/**
|
||||
* 更新跟单状态(兼容旧接口)
|
||||
*/
|
||||
updateStatus: (data: { copyTradingId: number; enabled: boolean }) =>
|
||||
apiClient.post<ApiResponse<any>>('/copy-trading/update-status', data),
|
||||
apiClient.post<ApiResponse<any>>('/copy-trading/configs/update-status', data),
|
||||
|
||||
/**
|
||||
* 删除跟单
|
||||
*/
|
||||
delete: (data: { copyTradingId: number }) =>
|
||||
apiClient.post<ApiResponse<void>>('/copy-trading/delete', data),
|
||||
apiClient.post<ApiResponse<void>>('/copy-trading/configs/delete', data),
|
||||
|
||||
/**
|
||||
* 查询钱包绑定的跟单配置(兼容旧接口)
|
||||
*/
|
||||
getAccountTemplates: (data: { accountId: number }) =>
|
||||
apiClient.post<ApiResponse<any>>('/copy-trading/account-templates', data),
|
||||
apiClient.post<ApiResponse<any>>('/copy-trading/configs/account-templates', data),
|
||||
|
||||
/**
|
||||
* 查询被过滤订单列表
|
||||
@@ -408,7 +408,7 @@ export const apiService = {
|
||||
startTime?: number
|
||||
endTime?: number
|
||||
}) =>
|
||||
apiClient.post<ApiResponse<any>>('/copy-trading/filtered-orders', data)
|
||||
apiClient.post<ApiResponse<any>>('/copy-trading/configs/filtered-orders', data)
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -476,13 +476,13 @@ export const apiService = {
|
||||
* 获取当前代理配置
|
||||
*/
|
||||
get: () =>
|
||||
apiClient.post<ApiResponse<any>>('/proxy-config/get', {}),
|
||||
apiClient.post<ApiResponse<any>>('/system/proxy/get', {}),
|
||||
|
||||
/**
|
||||
* 获取所有代理配置
|
||||
*/
|
||||
list: () =>
|
||||
apiClient.post<ApiResponse<any[]>>('/proxy-config/list', {}),
|
||||
apiClient.post<ApiResponse<any[]>>('/system/proxy/list', {}),
|
||||
|
||||
/**
|
||||
* 保存 HTTP 代理配置
|
||||
@@ -494,7 +494,7 @@ export const apiService = {
|
||||
username?: string
|
||||
password?: string
|
||||
}) =>
|
||||
apiClient.post<ApiResponse<any>>('/proxy-config/http/save', data),
|
||||
apiClient.post<ApiResponse<any>>('/system/proxy/http/save', data),
|
||||
|
||||
/**
|
||||
* 检查代理是否可用
|
||||
@@ -504,13 +504,13 @@ export const apiService = {
|
||||
success: boolean
|
||||
message: string
|
||||
responseTime?: number
|
||||
}>>('/proxy-config/check', {}),
|
||||
}>>('/system/proxy/check', {}),
|
||||
|
||||
/**
|
||||
* 删除代理配置
|
||||
*/
|
||||
delete: (data: { id: number }) =>
|
||||
apiClient.post<ApiResponse<void>>('/proxy-config/delete', data),
|
||||
apiClient.post<ApiResponse<void>>('/system/proxy/delete', data),
|
||||
|
||||
/**
|
||||
* 检查所有 API 的健康状态
|
||||
@@ -524,7 +524,7 @@ export const apiService = {
|
||||
message: string
|
||||
responseTime?: number
|
||||
}>
|
||||
}>>('/proxy-config/api-health-check', {})
|
||||
}>>('/system/proxy/api-health-check', {})
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -535,49 +535,49 @@ export const apiService = {
|
||||
* 获取配置列表
|
||||
*/
|
||||
list: (data?: { type?: string }) =>
|
||||
apiClient.post<ApiResponse<NotificationConfig[]>>('/notifications/configs/list', data || {}),
|
||||
apiClient.post<ApiResponse<NotificationConfig[]>>('/system/notifications/configs/list', data || {}),
|
||||
|
||||
/**
|
||||
* 获取配置详情
|
||||
*/
|
||||
detail: (data: { id: number }) =>
|
||||
apiClient.post<ApiResponse<NotificationConfig>>('/notifications/configs/detail', data),
|
||||
apiClient.post<ApiResponse<NotificationConfig>>('/system/notifications/configs/detail', data),
|
||||
|
||||
/**
|
||||
* 创建配置
|
||||
*/
|
||||
create: (data: NotificationConfigRequest) =>
|
||||
apiClient.post<ApiResponse<NotificationConfig>>('/notifications/configs/create', data),
|
||||
apiClient.post<ApiResponse<NotificationConfig>>('/system/notifications/configs/create', data),
|
||||
|
||||
/**
|
||||
* 更新配置
|
||||
*/
|
||||
update: (data: NotificationConfigUpdateRequest) =>
|
||||
apiClient.post<ApiResponse<NotificationConfig>>('/notifications/configs/update', data),
|
||||
apiClient.post<ApiResponse<NotificationConfig>>('/system/notifications/configs/update', data),
|
||||
|
||||
/**
|
||||
* 更新启用状态
|
||||
*/
|
||||
updateEnabled: (data: { id: number; enabled: boolean }) =>
|
||||
apiClient.post<ApiResponse<NotificationConfig>>('/notifications/configs/update-enabled', data),
|
||||
apiClient.post<ApiResponse<NotificationConfig>>('/system/notifications/configs/update-enabled', data),
|
||||
|
||||
/**
|
||||
* 删除配置
|
||||
*/
|
||||
delete: (data: { id: number }) =>
|
||||
apiClient.post<ApiResponse<void>>('/notifications/configs/delete', data),
|
||||
apiClient.post<ApiResponse<void>>('/system/notifications/configs/delete', data),
|
||||
|
||||
/**
|
||||
* 测试通知
|
||||
*/
|
||||
test: (data?: { message?: string }) =>
|
||||
apiClient.post<ApiResponse<boolean>>('/notifications/test', data || {}),
|
||||
apiClient.post<ApiResponse<boolean>>('/system/notifications/test', data || {}),
|
||||
|
||||
/**
|
||||
* 获取 Telegram Chat IDs
|
||||
*/
|
||||
getTelegramChatIds: (data: { botToken: string }) =>
|
||||
apiClient.post<ApiResponse<string[]>>('/notifications/telegram/get-chat-ids', data)
|
||||
apiClient.post<ApiResponse<string[]>>('/system/notifications/telegram/get-chat-ids', data)
|
||||
},
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user