From ddf6c44d6579c3b1c0499596d1daaeec438dcf16 Mon Sep 17 00:00:00 2001 From: Liu Xiang Qian Date: Mon, 3 Nov 2025 21:55:26 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0=20AI=20=E6=89=AB?= =?UTF-8?q?=E6=8F=8F=E5=86=B3=E7=AD=96=E9=97=B4=E9=9A=94=E9=85=8D=E7=BD=AE?= =?UTF-8?q?=E6=94=AF=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## 功能描述 在创建和编辑 Trader 时,支持配置 AI 扫描决策间隔(scan_interval_minutes),允许用户自定义 AI 决策的频率。 ## 修改内容 ### 后端修改 (api/server.go) 1. **CreateTraderRequest** 添加 `ScanIntervalMinutes` 字段 2. **UpdateTraderRequest** 添加 `ScanIntervalMinutes` 字段和 `SystemPromptTemplate` 字段 3. **handleCreateTrader** 处理扫描间隔默认值(默认 3 分钟) 4. **handleUpdateTrader** 支持更新扫描间隔 5. **handleGetTraderConfig** 返回中添加 `scan_interval_minutes` 字段 ### 前端修改 #### web/src/types.ts - `CreateTraderRequest` 添加 `scan_interval_minutes?` 可选字段 - `TraderConfigData` 添加 `scan_interval_minutes` 必填字段 #### web/src/components/TraderConfigModal.tsx - 本地 `TraderConfigData` 接口添加 `scan_interval_minutes` - 初始状态设置默认值为 3 分钟 - 添加 UI 输入框(范围 1-60 分钟) - Label 优化为 "AI 扫描决策间隔 (分钟)" #### web/src/components/AITradersPage.tsx - `handleSaveEditTrader` 的更新请求中添加 `scan_interval_minutes` #### web/src/components/landing/CommunitySection.tsx - 修复 TypeScript 编译错误:定义 `CardProps` 接口 - 修正 `TestimonialCard` 组件的 prop 名称(author → authorName) ## 功能特性 - ✅ 支持 1-60 分钟的自定义间隔 - ✅ 默认值为 3 分钟 - ✅ UI 提示建议范围:3-10 分钟 - ✅ 创建和编辑时均支持配置 - ✅ 后端验证和处理默认值 ## 测试步骤 1. 创建新 Trader,设置自定义扫描间隔(如 10 分钟) 2. 验证 Trader 创建成功 3. 编辑现有 Trader,修改扫描间隔 4. 验证修改保存成功 5. 确认 AI 决策按照新的间隔执行 --- api/server.go | 103 +++++++++++------- web/src/components/AITradersPage.tsx | 1 + web/src/components/TraderConfigModal.tsx | 24 +++- .../components/landing/CommunitySection.tsx | 13 ++- web/src/types.ts | 2 + 5 files changed, 100 insertions(+), 43 deletions(-) diff --git a/api/server.go b/api/server.go index 92270715..f3b6a543 100644 --- a/api/server.go +++ b/api/server.go @@ -210,6 +210,7 @@ type CreateTraderRequest struct { AIModelID string `json:"ai_model_id" binding:"required"` ExchangeID string `json:"exchange_id" binding:"required"` InitialBalance float64 `json:"initial_balance"` + ScanIntervalMinutes int `json:"scan_interval_minutes"` BTCETHLeverage int `json:"btc_eth_leverage"` AltcoinLeverage int `json:"altcoin_leverage"` TradingSymbols string `json:"trading_symbols"` @@ -332,6 +333,12 @@ func (s *Server) handleCreateTrader(c *gin.Context) { systemPromptTemplate = req.SystemPromptTemplate } + // 设置扫描间隔默认值 + scanIntervalMinutes := req.ScanIntervalMinutes + if scanIntervalMinutes <= 0 { + scanIntervalMinutes = 3 // 默认3分钟 + } + // 创建交易员配置(数据库实体) trader := &config.TraderRecord{ ID: traderID, @@ -349,7 +356,7 @@ func (s *Server) handleCreateTrader(c *gin.Context) { OverrideBasePrompt: req.OverrideBasePrompt, SystemPromptTemplate: systemPromptTemplate, IsCrossMargin: isCrossMargin, - ScanIntervalMinutes: 3, // 默认3分钟 + ScanIntervalMinutes: scanIntervalMinutes, IsRunning: false, } @@ -379,16 +386,18 @@ func (s *Server) handleCreateTrader(c *gin.Context) { // UpdateTraderRequest 更新交易员请求 type UpdateTraderRequest struct { - Name string `json:"name" binding:"required"` - AIModelID string `json:"ai_model_id" binding:"required"` - ExchangeID string `json:"exchange_id" binding:"required"` - InitialBalance float64 `json:"initial_balance"` - BTCETHLeverage int `json:"btc_eth_leverage"` - AltcoinLeverage int `json:"altcoin_leverage"` - TradingSymbols string `json:"trading_symbols"` - CustomPrompt string `json:"custom_prompt"` - OverrideBasePrompt bool `json:"override_base_prompt"` - IsCrossMargin *bool `json:"is_cross_margin"` + Name string `json:"name" binding:"required"` + AIModelID string `json:"ai_model_id" binding:"required"` + ExchangeID string `json:"exchange_id" binding:"required"` + InitialBalance float64 `json:"initial_balance"` + ScanIntervalMinutes int `json:"scan_interval_minutes"` + BTCETHLeverage int `json:"btc_eth_leverage"` + AltcoinLeverage int `json:"altcoin_leverage"` + TradingSymbols string `json:"trading_symbols"` + CustomPrompt string `json:"custom_prompt"` + OverrideBasePrompt bool `json:"override_base_prompt"` + SystemPromptTemplate string `json:"system_prompt_template"` + IsCrossMargin *bool `json:"is_cross_margin"` } // handleUpdateTrader 更新交易员配置 @@ -437,23 +446,36 @@ func (s *Server) handleUpdateTrader(c *gin.Context) { if altcoinLeverage <= 0 { altcoinLeverage = existingTrader.AltcoinLeverage // 保持原值 } - + + // 设置扫描间隔,允许更新 + scanIntervalMinutes := req.ScanIntervalMinutes + if scanIntervalMinutes <= 0 { + scanIntervalMinutes = existingTrader.ScanIntervalMinutes // 保持原值 + } + + // 设置系统提示词模板,允许更新 + systemPromptTemplate := req.SystemPromptTemplate + if systemPromptTemplate == "" { + systemPromptTemplate = existingTrader.SystemPromptTemplate // 保持原值 + } + // 更新交易员配置 trader := &config.TraderRecord{ - ID: traderID, - UserID: userID, - Name: req.Name, - AIModelID: req.AIModelID, - ExchangeID: req.ExchangeID, - InitialBalance: req.InitialBalance, - BTCETHLeverage: btcEthLeverage, - AltcoinLeverage: altcoinLeverage, - TradingSymbols: req.TradingSymbols, - CustomPrompt: req.CustomPrompt, - OverrideBasePrompt: req.OverrideBasePrompt, - IsCrossMargin: isCrossMargin, - ScanIntervalMinutes: existingTrader.ScanIntervalMinutes, // 保持原值 - IsRunning: existingTrader.IsRunning, // 保持原值 + ID: traderID, + UserID: userID, + Name: req.Name, + AIModelID: req.AIModelID, + ExchangeID: req.ExchangeID, + InitialBalance: req.InitialBalance, + BTCETHLeverage: btcEthLeverage, + AltcoinLeverage: altcoinLeverage, + TradingSymbols: req.TradingSymbols, + CustomPrompt: req.CustomPrompt, + OverrideBasePrompt: req.OverrideBasePrompt, + SystemPromptTemplate: systemPromptTemplate, + IsCrossMargin: isCrossMargin, + ScanIntervalMinutes: scanIntervalMinutes, + IsRunning: existingTrader.IsRunning, // 保持原值 } // 更新数据库 @@ -805,20 +827,21 @@ func (s *Server) handleGetTraderConfig(c *gin.Context) { aiModelID := traderConfig.AIModelID result := map[string]interface{}{ - "trader_id": traderConfig.ID, - "trader_name": traderConfig.Name, - "ai_model": aiModelID, - "exchange_id": traderConfig.ExchangeID, - "initial_balance": traderConfig.InitialBalance, - "btc_eth_leverage": traderConfig.BTCETHLeverage, - "altcoin_leverage": traderConfig.AltcoinLeverage, - "trading_symbols": traderConfig.TradingSymbols, - "custom_prompt": traderConfig.CustomPrompt, - "override_base_prompt": traderConfig.OverrideBasePrompt, - "is_cross_margin": traderConfig.IsCrossMargin, - "use_coin_pool": traderConfig.UseCoinPool, - "use_oi_top": traderConfig.UseOITop, - "is_running": isRunning, + "trader_id": traderConfig.ID, + "trader_name": traderConfig.Name, + "ai_model": aiModelID, + "exchange_id": traderConfig.ExchangeID, + "initial_balance": traderConfig.InitialBalance, + "scan_interval_minutes": traderConfig.ScanIntervalMinutes, + "btc_eth_leverage": traderConfig.BTCETHLeverage, + "altcoin_leverage": traderConfig.AltcoinLeverage, + "trading_symbols": traderConfig.TradingSymbols, + "custom_prompt": traderConfig.CustomPrompt, + "override_base_prompt": traderConfig.OverrideBasePrompt, + "is_cross_margin": traderConfig.IsCrossMargin, + "use_coin_pool": traderConfig.UseCoinPool, + "use_oi_top": traderConfig.UseOITop, + "is_running": isRunning, } c.JSON(http.StatusOK, result) diff --git a/web/src/components/AITradersPage.tsx b/web/src/components/AITradersPage.tsx index 9361fc80..d534c0b0 100644 --- a/web/src/components/AITradersPage.tsx +++ b/web/src/components/AITradersPage.tsx @@ -183,6 +183,7 @@ export function AITradersPage({ onTraderSelect }: AITradersPageProps) { ai_model_id: data.ai_model_id, exchange_id: data.exchange_id, initial_balance: data.initial_balance, + scan_interval_minutes: data.scan_interval_minutes, btc_eth_leverage: data.btc_eth_leverage, altcoin_leverage: data.altcoin_leverage, trading_symbols: data.trading_symbols, diff --git a/web/src/components/TraderConfigModal.tsx b/web/src/components/TraderConfigModal.tsx index 528f763f..2720bb3b 100644 --- a/web/src/components/TraderConfigModal.tsx +++ b/web/src/components/TraderConfigModal.tsx @@ -22,6 +22,7 @@ interface TraderConfigData { use_coin_pool: boolean; use_oi_top: boolean; initial_balance: number; + scan_interval_minutes: number; } interface TraderConfigModalProps { @@ -57,6 +58,7 @@ export function TraderConfigModal({ use_coin_pool: false, use_oi_top: false, initial_balance: 1000, + scan_interval_minutes: 3, }); const [isSaving, setIsSaving] = useState(false); const [availableCoins, setAvailableCoins] = useState([]); @@ -87,6 +89,7 @@ export function TraderConfigModal({ use_coin_pool: false, use_oi_top: false, initial_balance: 1000, + scan_interval_minutes: 3, }); } // 确保旧数据也有默认的 system_prompt_template @@ -181,6 +184,7 @@ export function TraderConfigModal({ use_coin_pool: formData.use_coin_pool, use_oi_top: formData.use_oi_top, initial_balance: formData.initial_balance, + scan_interval_minutes: formData.scan_interval_minutes, }; await onSave(saveData); onClose(); @@ -319,7 +323,25 @@ export function TraderConfigModal({ - {/* 第二行:杠杆设置 */} + {/* 第二行:AI 扫描决策间隔 */} +
+
+ + handleInputChange('scan_interval_minutes', Number(e.target.value))} + className="w-full px-3 py-2 bg-[#0B0E11] border border-[#2B3139] rounded text-[#EAECEF] focus:border-[#F0B90B] focus:outline-none" + min="1" + max="60" + step="1" + /> +

建议: 3-10分钟

+
+
+
+ + {/* 第三行:杠杆设置 */}
diff --git a/web/src/components/landing/CommunitySection.tsx b/web/src/components/landing/CommunitySection.tsx index 9edbf4d4..0e52d926 100644 --- a/web/src/components/landing/CommunitySection.tsx +++ b/web/src/components/landing/CommunitySection.tsx @@ -1,7 +1,16 @@ import { motion } from 'framer-motion' import AnimatedSection from './AnimatedSection' -function TestimonialCard({ quote, author, delay }: any) { +interface CardProps { + quote: string; + authorName: string; + handle: string; + avatarUrl: string; + tweetUrl: string; + delay: number; +} + +function TestimonialCard({ quote, authorName, delay }: CardProps) { return (
- {author} + {authorName}
diff --git a/web/src/types.ts b/web/src/types.ts index e4ba1199..7d115106 100644 --- a/web/src/types.ts +++ b/web/src/types.ts @@ -125,6 +125,7 @@ export interface CreateTraderRequest { ai_model_id: string; exchange_id: string; initial_balance: number; + scan_interval_minutes?: number; btc_eth_leverage?: number; altcoin_leverage?: number; trading_symbols?: string; @@ -198,5 +199,6 @@ export interface TraderConfigData { use_coin_pool: boolean; use_oi_top: boolean; initial_balance: number; + scan_interval_minutes: number; is_running: boolean; }