diff --git a/api/server.go b/api/server.go index 27556d05..70b6e3f5 100644 --- a/api/server.go +++ b/api/server.go @@ -1277,12 +1277,13 @@ func (s *Server) handleTraderList(c *gin.Context) { // 返回完整的 AIModelID(如 "admin_deepseek"),不要截断 // 前端需要完整 ID 来验证模型是否存在(与 handleGetTraderConfig 保持一致) result = append(result, map[string]interface{}{ - "trader_id": trader.ID, - "trader_name": trader.Name, - "ai_model": trader.AIModelID, // 使用完整 ID - "exchange_id": trader.ExchangeID, - "is_running": isRunning, - "initial_balance": trader.InitialBalance, + "trader_id": trader.ID, + "trader_name": trader.Name, + "ai_model": trader.AIModelID, // 使用完整 ID + "exchange_id": trader.ExchangeID, + "is_running": isRunning, + "initial_balance": trader.InitialBalance, + "system_prompt_template": trader.SystemPromptTemplate, }) } @@ -2170,16 +2171,17 @@ func (s *Server) handlePublicTraderList(c *gin.Context) { result := make([]map[string]interface{}, 0, len(traders)) for _, trader := range traders { result = append(result, map[string]interface{}{ - "trader_id": trader["trader_id"], - "trader_name": trader["trader_name"], - "ai_model": trader["ai_model"], - "exchange": trader["exchange"], - "is_running": trader["is_running"], - "total_equity": trader["total_equity"], - "total_pnl": trader["total_pnl"], - "total_pnl_pct": trader["total_pnl_pct"], - "position_count": trader["position_count"], - "margin_used_pct": trader["margin_used_pct"], + "trader_id": trader["trader_id"], + "trader_name": trader["trader_name"], + "ai_model": trader["ai_model"], + "exchange": trader["exchange"], + "is_running": trader["is_running"], + "total_equity": trader["total_equity"], + "total_pnl": trader["total_pnl"], + "total_pnl_pct": trader["total_pnl_pct"], + "position_count": trader["position_count"], + "margin_used_pct": trader["margin_used_pct"], + "system_prompt_template": trader["system_prompt_template"], }) } diff --git a/api/server_test.go b/api/server_test.go index 6b6b83c1..f59817bd 100644 --- a/api/server_test.go +++ b/api/server_test.go @@ -225,3 +225,81 @@ func TestUpdateTraderRequest_CompleteFields(t *testing.T) { t.Errorf("SystemPromptTemplate mismatch: expected %q, got %q", "nof1", req.SystemPromptTemplate) } } + +// TestTraderListResponse_SystemPromptTemplate 测试 handleTraderList API 返回的 trader 对象是否包含 system_prompt_template 字段 +func TestTraderListResponse_SystemPromptTemplate(t *testing.T) { + // 模拟 handleTraderList 中的 trader 对象构造 + trader := &config.TraderRecord{ + ID: "trader-001", + UserID: "user-1", + Name: "My Trader", + AIModelID: "gpt-4", + ExchangeID: "binance", + InitialBalance: 5000, + SystemPromptTemplate: "nof1", + IsRunning: true, + } + + // 构造 API 响应对象(与 api/server.go 中的逻辑一致) + response := map[string]interface{}{ + "trader_id": trader.ID, + "trader_name": trader.Name, + "ai_model": trader.AIModelID, + "exchange_id": trader.ExchangeID, + "is_running": trader.IsRunning, + "initial_balance": trader.InitialBalance, + "system_prompt_template": trader.SystemPromptTemplate, + } + + // ✅ 验证 system_prompt_template 字段存在 + if _, exists := response["system_prompt_template"]; !exists { + t.Errorf("Trader list response is missing 'system_prompt_template' field") + } + + // ✅ 验证 system_prompt_template 值正确 + if response["system_prompt_template"] != "nof1" { + t.Errorf("Expected system_prompt_template='nof1', got %v", response["system_prompt_template"]) + } +} + +// TestPublicTraderListResponse_SystemPromptTemplate 测试 handlePublicTraderList API 返回的 trader 对象是否包含 system_prompt_template 字段 +func TestPublicTraderListResponse_SystemPromptTemplate(t *testing.T) { + // 模拟 getConcurrentTraderData 返回的 trader 数据 + traderData := map[string]interface{}{ + "trader_id": "trader-002", + "trader_name": "Public Trader", + "ai_model": "claude", + "exchange": "binance", + "total_equity": 10000.0, + "total_pnl": 500.0, + "total_pnl_pct": 5.0, + "position_count": 3, + "margin_used_pct": 25.0, + "is_running": true, + "system_prompt_template": "default", + } + + // 构造 API 响应对象(与 api/server.go handlePublicTraderList 中的逻辑一致) + response := map[string]interface{}{ + "trader_id": traderData["trader_id"], + "trader_name": traderData["trader_name"], + "ai_model": traderData["ai_model"], + "exchange": traderData["exchange"], + "total_equity": traderData["total_equity"], + "total_pnl": traderData["total_pnl"], + "total_pnl_pct": traderData["total_pnl_pct"], + "position_count": traderData["position_count"], + "margin_used_pct": traderData["margin_used_pct"], + "system_prompt_template": traderData["system_prompt_template"], + } + + // ✅ 验证 system_prompt_template 字段存在 + if _, exists := response["system_prompt_template"]; !exists { + t.Errorf("Public trader list response is missing 'system_prompt_template' field") + } + + // ✅ 验证 system_prompt_template 值正确 + if response["system_prompt_template"] != "default" { + t.Errorf("Expected system_prompt_template='default', got %v", response["system_prompt_template"]) + } +} diff --git a/manager/trader_manager.go b/manager/trader_manager.go index 9e1e9fb7..2f0fb4fd 100644 --- a/manager/trader_manager.go +++ b/manager/trader_manager.go @@ -590,48 +590,51 @@ func (tm *TraderManager) getConcurrentTraderData(traders []*trader.AutoTrader) [ case account := <-accountChan: // 成功获取账户信息 traderData = map[string]interface{}{ - "trader_id": trader.GetID(), - "trader_name": trader.GetName(), - "ai_model": trader.GetAIModel(), - "exchange": trader.GetExchange(), - "total_equity": account["total_equity"], - "total_pnl": account["total_pnl"], - "total_pnl_pct": account["total_pnl_pct"], - "position_count": account["position_count"], - "margin_used_pct": account["margin_used_pct"], - "is_running": status["is_running"], + "trader_id": trader.GetID(), + "trader_name": trader.GetName(), + "ai_model": trader.GetAIModel(), + "exchange": trader.GetExchange(), + "total_equity": account["total_equity"], + "total_pnl": account["total_pnl"], + "total_pnl_pct": account["total_pnl_pct"], + "position_count": account["position_count"], + "margin_used_pct": account["margin_used_pct"], + "is_running": status["is_running"], + "system_prompt_template": trader.GetSystemPromptTemplate(), } case err := <-errorChan: // 获取账户信息失败 log.Printf("⚠️ 获取交易员 %s 账户信息失败: %v", trader.GetID(), err) traderData = map[string]interface{}{ - "trader_id": trader.GetID(), - "trader_name": trader.GetName(), - "ai_model": trader.GetAIModel(), - "exchange": trader.GetExchange(), - "total_equity": 0.0, - "total_pnl": 0.0, - "total_pnl_pct": 0.0, - "position_count": 0, - "margin_used_pct": 0.0, - "is_running": status["is_running"], - "error": "账户数据获取失败", + "trader_id": trader.GetID(), + "trader_name": trader.GetName(), + "ai_model": trader.GetAIModel(), + "exchange": trader.GetExchange(), + "total_equity": 0.0, + "total_pnl": 0.0, + "total_pnl_pct": 0.0, + "position_count": 0, + "margin_used_pct": 0.0, + "is_running": status["is_running"], + "system_prompt_template": trader.GetSystemPromptTemplate(), + "error": "账户数据获取失败", } case <-ctx.Done(): // 超时 log.Printf("⏰ 获取交易员 %s 账户信息超时", trader.GetID()) traderData = map[string]interface{}{ - "trader_id": trader.GetID(), - "trader_name": trader.GetName(), - "ai_model": trader.GetAIModel(), - "exchange": trader.GetExchange(), - "total_equity": 0.0, - "total_pnl": 0.0, - "total_pnl_pct": 0.0, - "position_count": 0, - "margin_used_pct": 0.0, - "is_running": status["is_running"], - "error": "获取超时", + "trader_id": trader.GetID(), + "trader_name": trader.GetName(), + "ai_model": trader.GetAIModel(), + "exchange": trader.GetExchange(), + "total_equity": 0.0, + "total_pnl": 0.0, + "total_pnl_pct": 0.0, + "position_count": 0, + "margin_used_pct": 0.0, + "is_running": status["is_running"], + "system_prompt_template": trader.GetSystemPromptTemplate(), + "error": "获取超时", } } diff --git a/web/src/pages/TraderDashboard.tsx b/web/src/pages/TraderDashboard.tsx index 9d165603..d66a141b 100644 --- a/web/src/pages/TraderDashboard.tsx +++ b/web/src/pages/TraderDashboard.tsx @@ -282,6 +282,8 @@ export default function TraderDashboard() { ) } + const highlightColor = '#60a5fa' + return (
{/* Trader Header */} @@ -346,7 +348,7 @@ export default function TraderDashboard() { style={{ color: selectedTrader.ai_model.includes('qwen') ? '#c084fc' - : '#60a5fa', + : highlightColor, }} > {getModelDisplayName( @@ -355,6 +357,10 @@ export default function TraderDashboard() { )} + + + Prompt: {selectedTrader.system_prompt_template || '-'} + {status && ( <> diff --git a/web/src/types.ts b/web/src/types.ts index 60ce44ed..f63be1b6 100644 --- a/web/src/types.ts +++ b/web/src/types.ts @@ -94,6 +94,7 @@ export interface TraderInfo { custom_prompt?: string use_coin_pool?: boolean use_oi_top?: boolean + system_prompt_template?: string } export interface AIModel {