chore: run go fmt to fix formatting issues

This commit is contained in:
ZhouYongyou
2025-11-04 17:39:00 +08:00
parent 5e1ddae348
commit 589f90feb0
5 changed files with 69 additions and 70 deletions

View File

@@ -88,7 +88,7 @@ func (s *Server) setupRoutes() {
// 系统提示词模板管理(无需认证) // 系统提示词模板管理(无需认证)
api.GET("/prompt-templates", s.handleGetPromptTemplates) api.GET("/prompt-templates", s.handleGetPromptTemplates)
api.GET("/prompt-templates/:name", s.handleGetPromptTemplate) api.GET("/prompt-templates/:name", s.handleGetPromptTemplate)
// 公开的竞赛数据(无需认证) // 公开的竞赛数据(无需认证)
api.GET("/traders", s.handlePublicTraderList) api.GET("/traders", s.handlePublicTraderList)
api.GET("/competition", s.handlePublicCompetition) api.GET("/competition", s.handlePublicCompetition)
@@ -168,7 +168,7 @@ func (s *Server) handleGetSystemConfig(c *gin.Context) {
if val, err := strconv.Atoi(altcoinLeverageStr); err == nil && val > 0 { if val, err := strconv.Atoi(altcoinLeverageStr); err == nil && val > 0 {
altcoinLeverage = val altcoinLeverage = val
} }
// 获取内测模式配置 // 获取内测模式配置
betaModeStr, _ := s.database.GetSystemConfig("beta_mode") betaModeStr, _ := s.database.GetSystemConfig("beta_mode")
betaMode := betaModeStr == "true" betaMode := betaModeStr == "true"
@@ -531,14 +531,14 @@ func (s *Server) handleDeleteTrader(c *gin.Context) {
func (s *Server) handleStartTrader(c *gin.Context) { func (s *Server) handleStartTrader(c *gin.Context) {
userID := c.GetString("user_id") userID := c.GetString("user_id")
traderID := c.Param("id") traderID := c.Param("id")
// 校验交易员是否属于当前用户 // 校验交易员是否属于当前用户
_, _, _, err := s.database.GetTraderConfig(userID, traderID) _, _, _, err := s.database.GetTraderConfig(userID, traderID)
if err != nil { if err != nil {
c.JSON(http.StatusNotFound, gin.H{"error": "交易员不存在或无访问权限"}) c.JSON(http.StatusNotFound, gin.H{"error": "交易员不存在或无访问权限"})
return return
} }
trader, err := s.traderManager.GetTrader(traderID) trader, err := s.traderManager.GetTrader(traderID)
if err != nil { if err != nil {
c.JSON(http.StatusNotFound, gin.H{"error": "交易员不存在"}) c.JSON(http.StatusNotFound, gin.H{"error": "交易员不存在"})
@@ -574,14 +574,14 @@ func (s *Server) handleStartTrader(c *gin.Context) {
func (s *Server) handleStopTrader(c *gin.Context) { func (s *Server) handleStopTrader(c *gin.Context) {
userID := c.GetString("user_id") userID := c.GetString("user_id")
traderID := c.Param("id") traderID := c.Param("id")
// 校验交易员是否属于当前用户 // 校验交易员是否属于当前用户
_, _, _, err := s.database.GetTraderConfig(userID, traderID) _, _, _, err := s.database.GetTraderConfig(userID, traderID)
if err != nil { if err != nil {
c.JSON(http.StatusNotFound, gin.H{"error": "交易员不存在或无访问权限"}) c.JSON(http.StatusNotFound, gin.H{"error": "交易员不存在或无访问权限"})
return return
} }
trader, err := s.traderManager.GetTrader(traderID) trader, err := s.traderManager.GetTrader(traderID)
if err != nil { if err != nil {
c.JSON(http.StatusNotFound, gin.H{"error": "交易员不存在"}) c.JSON(http.StatusNotFound, gin.H{"error": "交易员不存在"})
@@ -796,7 +796,7 @@ func (s *Server) handleTraderList(c *gin.Context) {
result = append(result, map[string]interface{}{ result = append(result, map[string]interface{}{
"trader_id": trader.ID, "trader_id": trader.ID,
"trader_name": trader.Name, "trader_name": trader.Name,
"ai_model": trader.AIModelID, // 使用完整 ID "ai_model": trader.AIModelID, // 使用完整 ID
"exchange_id": trader.ExchangeID, "exchange_id": trader.ExchangeID,
"is_running": isRunning, "is_running": isRunning,
"initial_balance": trader.InitialBalance, "initial_balance": trader.InitialBalance,
@@ -1574,7 +1574,7 @@ func (s *Server) handlePublicCompetition(c *gin.Context) {
}) })
return return
} }
c.JSON(http.StatusOK, competition) c.JSON(http.StatusOK, competition)
} }
@@ -1587,7 +1587,7 @@ func (s *Server) handleTopTraders(c *gin.Context) {
}) })
return return
} }
c.JSON(http.StatusOK, topTraders) c.JSON(http.StatusOK, topTraders)
} }
@@ -1596,7 +1596,7 @@ func (s *Server) handleEquityHistoryBatch(c *gin.Context) {
var requestBody struct { var requestBody struct {
TraderIDs []string `json:"trader_ids"` TraderIDs []string `json:"trader_ids"`
} }
// 尝试解析POST请求的JSON body // 尝试解析POST请求的JSON body
if err := c.ShouldBindJSON(&requestBody); err != nil { if err := c.ShouldBindJSON(&requestBody); err != nil {
// 如果JSON解析失败尝试从query参数获取兼容GET请求 // 如果JSON解析失败尝试从query参数获取兼容GET请求
@@ -1610,13 +1610,13 @@ func (s *Server) handleEquityHistoryBatch(c *gin.Context) {
}) })
return return
} }
traders, ok := topTraders["traders"].([]map[string]interface{}) traders, ok := topTraders["traders"].([]map[string]interface{})
if !ok { if !ok {
c.JSON(http.StatusInternalServerError, gin.H{"error": "交易员数据格式错误"}) c.JSON(http.StatusInternalServerError, gin.H{"error": "交易员数据格式错误"})
return return
} }
// 提取trader IDs // 提取trader IDs
traderIDs := make([]string, 0, len(traders)) traderIDs := make([]string, 0, len(traders))
for _, trader := range traders { for _, trader := range traders {
@@ -1624,24 +1624,24 @@ func (s *Server) handleEquityHistoryBatch(c *gin.Context) {
traderIDs = append(traderIDs, traderID) traderIDs = append(traderIDs, traderID)
} }
} }
result := s.getEquityHistoryForTraders(traderIDs) result := s.getEquityHistoryForTraders(traderIDs)
c.JSON(http.StatusOK, result) c.JSON(http.StatusOK, result)
return return
} }
// 解析逗号分隔的trader IDs // 解析逗号分隔的trader IDs
requestBody.TraderIDs = strings.Split(traderIDsParam, ",") requestBody.TraderIDs = strings.Split(traderIDsParam, ",")
for i := range requestBody.TraderIDs { for i := range requestBody.TraderIDs {
requestBody.TraderIDs[i] = strings.TrimSpace(requestBody.TraderIDs[i]) requestBody.TraderIDs[i] = strings.TrimSpace(requestBody.TraderIDs[i])
} }
} }
// 限制最多20个交易员防止请求过大 // 限制最多20个交易员防止请求过大
if len(requestBody.TraderIDs) > 20 { if len(requestBody.TraderIDs) > 20 {
requestBody.TraderIDs = requestBody.TraderIDs[:20] requestBody.TraderIDs = requestBody.TraderIDs[:20]
} }
result := s.getEquityHistoryForTraders(requestBody.TraderIDs) result := s.getEquityHistoryForTraders(requestBody.TraderIDs)
c.JSON(http.StatusOK, result) c.JSON(http.StatusOK, result)
} }
@@ -1651,31 +1651,31 @@ func (s *Server) getEquityHistoryForTraders(traderIDs []string) map[string]inter
result := make(map[string]interface{}) result := make(map[string]interface{})
histories := make(map[string]interface{}) histories := make(map[string]interface{})
errors := make(map[string]string) errors := make(map[string]string)
for _, traderID := range traderIDs { for _, traderID := range traderIDs {
if traderID == "" { if traderID == "" {
continue continue
} }
trader, err := s.traderManager.GetTrader(traderID) trader, err := s.traderManager.GetTrader(traderID)
if err != nil { if err != nil {
errors[traderID] = "交易员不存在" errors[traderID] = "交易员不存在"
continue continue
} }
// 获取历史数据(用于对比展示,限制数据量) // 获取历史数据(用于对比展示,限制数据量)
records, err := trader.GetDecisionLogger().GetLatestRecords(500) records, err := trader.GetDecisionLogger().GetLatestRecords(500)
if err != nil { if err != nil {
errors[traderID] = fmt.Sprintf("获取历史数据失败: %v", err) errors[traderID] = fmt.Sprintf("获取历史数据失败: %v", err)
continue continue
} }
// 构建收益率历史数据 // 构建收益率历史数据
history := make([]map[string]interface{}, 0, len(records)) history := make([]map[string]interface{}, 0, len(records))
for _, record := range records { for _, record := range records {
// 计算总权益(余额+未实现盈亏) // 计算总权益(余额+未实现盈亏)
totalEquity := record.AccountState.TotalBalance + record.AccountState.TotalUnrealizedProfit totalEquity := record.AccountState.TotalBalance + record.AccountState.TotalUnrealizedProfit
history = append(history, map[string]interface{}{ history = append(history, map[string]interface{}{
"timestamp": record.Timestamp, "timestamp": record.Timestamp,
"total_equity": totalEquity, "total_equity": totalEquity,
@@ -1683,16 +1683,16 @@ func (s *Server) getEquityHistoryForTraders(traderIDs []string) map[string]inter
"balance": record.AccountState.TotalBalance, "balance": record.AccountState.TotalBalance,
}) })
} }
histories[traderID] = history histories[traderID] = history
} }
result["histories"] = histories result["histories"] = histories
result["count"] = len(histories) result["count"] = len(histories)
if len(errors) > 0 { if len(errors) > 0 {
result["errors"] = errors result["errors"] = errors
} }
return result return result
} }
@@ -1726,4 +1726,3 @@ func (s *Server) handleGetPublicTraderConfig(c *gin.Context) {
c.JSON(http.StatusOK, result) c.JSON(http.StatusOK, result)
} }

View File

@@ -258,17 +258,17 @@ func (d *Database) initDefaultData() error {
// 初始化系统配置 - 创建所有字段设置默认值后续由config.json同步更新 // 初始化系统配置 - 创建所有字段设置默认值后续由config.json同步更新
systemConfigs := map[string]string{ systemConfigs := map[string]string{
"admin_mode": "true", // 默认开启管理员模式,便于首次使用 "admin_mode": "true", // 默认开启管理员模式,便于首次使用
"beta_mode": "false", // 默认关闭内测模式 "beta_mode": "false", // 默认关闭内测模式
"api_server_port": "8080", // 默认API端口 "api_server_port": "8080", // 默认API端口
"use_default_coins": "true", // 默认使用内置币种列表 "use_default_coins": "true", // 默认使用内置币种列表
"default_coins": `["BTCUSDT","ETHUSDT","SOLUSDT","BNBUSDT","XRPUSDT","DOGEUSDT","ADAUSDT","HYPEUSDT"]`, // 默认币种列表JSON格式 "default_coins": `["BTCUSDT","ETHUSDT","SOLUSDT","BNBUSDT","XRPUSDT","DOGEUSDT","ADAUSDT","HYPEUSDT"]`, // 默认币种列表JSON格式
"max_daily_loss": "10.0", // 最大日损失百分比 "max_daily_loss": "10.0", // 最大日损失百分比
"max_drawdown": "20.0", // 最大回撤百分比 "max_drawdown": "20.0", // 最大回撤百分比
"stop_trading_minutes": "60", // 停止交易时间(分钟) "stop_trading_minutes": "60", // 停止交易时间(分钟)
"btc_eth_leverage": "5", // BTC/ETH杠杆倍数 "btc_eth_leverage": "5", // BTC/ETH杠杆倍数
"altcoin_leverage": "5", // 山寨币杠杆倍数 "altcoin_leverage": "5", // 山寨币杠杆倍数
"jwt_secret": "", // JWT密钥默认为空由config.json或系统生成 "jwt_secret": "", // JWT密钥默认为空由config.json或系统生成
} }
for key, value := range systemConfigs { for key, value := range systemConfigs {
@@ -1037,7 +1037,7 @@ func (d *Database) LoadBetaCodesFromFile(filePath string) error {
log.Printf("插入内测码 %s 失败: %v", code, err) log.Printf("插入内测码 %s 失败: %v", code, err)
continue continue
} }
if rowsAffected, _ := result.RowsAffected(); rowsAffected > 0 { if rowsAffected, _ := result.RowsAffected(); rowsAffected > 0 {
insertedCount++ insertedCount++
} }

22
main.go
View File

@@ -64,15 +64,15 @@ func syncConfigToDatabase(database *config.Database) error {
// 同步各配置项到数据库 // 同步各配置项到数据库
configs := map[string]string{ configs := map[string]string{
"admin_mode": fmt.Sprintf("%t", configFile.AdminMode), "admin_mode": fmt.Sprintf("%t", configFile.AdminMode),
"beta_mode": fmt.Sprintf("%t", configFile.BetaMode), "beta_mode": fmt.Sprintf("%t", configFile.BetaMode),
"api_server_port": strconv.Itoa(configFile.APIServerPort), "api_server_port": strconv.Itoa(configFile.APIServerPort),
"use_default_coins": fmt.Sprintf("%t", configFile.UseDefaultCoins), "use_default_coins": fmt.Sprintf("%t", configFile.UseDefaultCoins),
"coin_pool_api_url": configFile.CoinPoolAPIURL, "coin_pool_api_url": configFile.CoinPoolAPIURL,
"oi_top_api_url": configFile.OITopAPIURL, "oi_top_api_url": configFile.OITopAPIURL,
"max_daily_loss": fmt.Sprintf("%.1f", configFile.MaxDailyLoss), "max_daily_loss": fmt.Sprintf("%.1f", configFile.MaxDailyLoss),
"max_drawdown": fmt.Sprintf("%.1f", configFile.MaxDrawdown), "max_drawdown": fmt.Sprintf("%.1f", configFile.MaxDrawdown),
"stop_trading_minutes": strconv.Itoa(configFile.StopTradingMinutes), "stop_trading_minutes": strconv.Itoa(configFile.StopTradingMinutes),
} }
// 同步default_coins转换为JSON字符串存储 // 同步default_coins转换为JSON字符串存储
@@ -112,7 +112,7 @@ func syncConfigToDatabase(database *config.Database) error {
// loadBetaCodesToDatabase 加载内测码文件到数据库 // loadBetaCodesToDatabase 加载内测码文件到数据库
func loadBetaCodesToDatabase(database *config.Database) error { func loadBetaCodesToDatabase(database *config.Database) error {
betaCodeFile := "beta_codes.txt" betaCodeFile := "beta_codes.txt"
// 检查内测码文件是否存在 // 检查内测码文件是否存在
if _, err := os.Stat(betaCodeFile); os.IsNotExist(err) { if _, err := os.Stat(betaCodeFile); os.IsNotExist(err) {
log.Printf("📄 内测码文件 %s 不存在,跳过加载", betaCodeFile) log.Printf("📄 内测码文件 %s 不存在,跳过加载", betaCodeFile)
@@ -126,7 +126,7 @@ func loadBetaCodesToDatabase(database *config.Database) error {
} }
log.Printf("🔄 发现内测码文件 %s (%.1f KB),开始加载...", betaCodeFile, float64(fileInfo.Size())/1024) log.Printf("🔄 发现内测码文件 %s (%.1f KB),开始加载...", betaCodeFile, float64(fileInfo.Size())/1024)
// 加载内测码到数据库 // 加载内测码到数据库
err = database.LoadBetaCodesFromFile(betaCodeFile) err = database.LoadBetaCodesFromFile(betaCodeFile)
if err != nil { if err != nil {

View File

@@ -23,9 +23,9 @@ type CompetitionCache struct {
// TraderManager 管理多个trader实例 // TraderManager 管理多个trader实例
type TraderManager struct { type TraderManager struct {
traders map[string]*trader.AutoTrader // key: trader ID traders map[string]*trader.AutoTrader // key: trader ID
competitionCache *CompetitionCache competitionCache *CompetitionCache
mu sync.RWMutex mu sync.RWMutex
} }
// NewTraderManager 创建trader管理器 // NewTraderManager 创建trader管理器
@@ -506,19 +506,19 @@ func (tm *TraderManager) GetCompetitionData() (map[string]interface{}, error) {
tm.competitionCache.mu.RUnlock() tm.competitionCache.mu.RUnlock()
tm.mu.RLock() tm.mu.RLock()
// 获取所有交易员列表 // 获取所有交易员列表
allTraders := make([]*trader.AutoTrader, 0, len(tm.traders)) allTraders := make([]*trader.AutoTrader, 0, len(tm.traders))
for _, t := range tm.traders { for _, t := range tm.traders {
allTraders = append(allTraders, t) allTraders = append(allTraders, t)
} }
tm.mu.RUnlock() tm.mu.RUnlock()
log.Printf("🔄 重新获取竞赛数据,交易员数量: %d", len(allTraders)) log.Printf("🔄 重新获取竞赛数据,交易员数量: %d", len(allTraders))
// 并发获取交易员数据 // 并发获取交易员数据
traders := tm.getConcurrentTraderData(allTraders) traders := tm.getConcurrentTraderData(allTraders)
// 按收益率排序(降序) // 按收益率排序(降序)
sort.Slice(traders, func(i, j int) bool { sort.Slice(traders, func(i, j int) bool {
pnlPctI, okI := traders[i]["total_pnl_pct"].(float64) pnlPctI, okI := traders[i]["total_pnl_pct"].(float64)
@@ -531,14 +531,14 @@ func (tm *TraderManager) GetCompetitionData() (map[string]interface{}, error) {
} }
return pnlPctI > pnlPctJ return pnlPctI > pnlPctJ
}) })
// 限制返回前50名 // 限制返回前50名
totalCount := len(traders) totalCount := len(traders)
limit := 50 limit := 50
if len(traders) > limit { if len(traders) > limit {
traders = traders[:limit] traders = traders[:limit]
} }
comparison := make(map[string]interface{}) comparison := make(map[string]interface{})
comparison["traders"] = traders comparison["traders"] = traders
comparison["count"] = len(traders) comparison["count"] = len(traders)
@@ -559,21 +559,21 @@ func (tm *TraderManager) getConcurrentTraderData(traders []*trader.AutoTrader) [
index int index int
data map[string]interface{} data map[string]interface{}
} }
// 创建结果通道 // 创建结果通道
resultChan := make(chan traderResult, len(traders)) resultChan := make(chan traderResult, len(traders))
// 并发获取每个交易员的数据 // 并发获取每个交易员的数据
for i, t := range traders { for i, t := range traders {
go func(index int, trader *trader.AutoTrader) { go func(index int, trader *trader.AutoTrader) {
// 设置单个交易员的超时时间为3秒 // 设置单个交易员的超时时间为3秒
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second) ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
defer cancel() defer cancel()
// 使用通道来实现超时控制 // 使用通道来实现超时控制
accountChan := make(chan map[string]interface{}, 1) accountChan := make(chan map[string]interface{}, 1)
errorChan := make(chan error, 1) errorChan := make(chan error, 1)
go func() { go func() {
account, err := trader.GetAccountInfo() account, err := trader.GetAccountInfo()
if err != nil { if err != nil {
@@ -582,10 +582,10 @@ func (tm *TraderManager) getConcurrentTraderData(traders []*trader.AutoTrader) [
accountChan <- account accountChan <- account
} }
}() }()
status := trader.GetStatus() status := trader.GetStatus()
var traderData map[string]interface{} var traderData map[string]interface{}
select { select {
case account := <-accountChan: case account := <-accountChan:
// 成功获取账户信息 // 成功获取账户信息
@@ -634,18 +634,18 @@ func (tm *TraderManager) getConcurrentTraderData(traders []*trader.AutoTrader) [
"error": "获取超时", "error": "获取超时",
} }
} }
resultChan <- traderResult{index: index, data: traderData} resultChan <- traderResult{index: index, data: traderData}
}(i, t) }(i, t)
} }
// 收集所有结果 // 收集所有结果
results := make([]map[string]interface{}, len(traders)) results := make([]map[string]interface{}, len(traders))
for i := 0; i < len(traders); i++ { for i := 0; i < len(traders); i++ {
result := <-resultChan result := <-resultChan
results[result.index] = result.data results[result.index] = result.data
} }
return results return results
} }
@@ -656,20 +656,20 @@ func (tm *TraderManager) GetTopTradersData() (map[string]interface{}, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
// 从竞赛数据中提取前5名 // 从竞赛数据中提取前5名
allTraders, ok := competitionData["traders"].([]map[string]interface{}) allTraders, ok := competitionData["traders"].([]map[string]interface{})
if !ok { if !ok {
return nil, fmt.Errorf("竞赛数据格式错误") return nil, fmt.Errorf("竞赛数据格式错误")
} }
// 限制返回前5名 // 限制返回前5名
limit := 5 limit := 5
topTraders := allTraders topTraders := allTraders
if len(allTraders) > limit { if len(allTraders) > limit {
topTraders = allTraders[:limit] topTraders = allTraders[:limit]
} }
result := map[string]interface{}{ result := map[string]interface{}{
"traders": topTraders, "traders": topTraders,
"count": len(topTraders), "count": len(topTraders),

View File

@@ -280,8 +280,8 @@ func isRetryableError(err error) bool {
"connection refused", "connection refused",
"temporary failure", "temporary failure",
"no such host", "no such host",
"stream error", // HTTP/2 stream 错误 "stream error", // HTTP/2 stream 错误
"INTERNAL_ERROR", // 服务端内部错误 "INTERNAL_ERROR", // 服务端内部错误
} }
for _, retryable := range retryableErrors { for _, retryable := range retryableErrors {
if strings.Contains(errStr, retryable) { if strings.Contains(errStr, retryable) {