diff --git a/api/server.go b/api/server.go index 898f85a9..fab0b5bd 100644 --- a/api/server.go +++ b/api/server.go @@ -212,6 +212,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"` @@ -334,6 +335,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, @@ -351,7 +358,7 @@ func (s *Server) handleCreateTrader(c *gin.Context) { OverrideBasePrompt: req.OverrideBasePrompt, SystemPromptTemplate: systemPromptTemplate, IsCrossMargin: isCrossMargin, - ScanIntervalMinutes: 3, // 默认3分钟 + ScanIntervalMinutes: scanIntervalMinutes, IsRunning: false, } @@ -381,16 +388,17 @@ 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"` + IsCrossMargin *bool `json:"is_cross_margin"` } // handleUpdateTrader 更新交易员配置 @@ -439,23 +447,30 @@ func (s *Server) handleUpdateTrader(c *gin.Context) { if altcoinLeverage <= 0 { altcoinLeverage = existingTrader.AltcoinLeverage // 保持原值 } - + + // 设置扫描间隔,允许更新 + scanIntervalMinutes := req.ScanIntervalMinutes + if scanIntervalMinutes <= 0 { + scanIntervalMinutes = existingTrader.ScanIntervalMinutes // 保持原值 + } + // 更新交易员配置 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: existingTrader.SystemPromptTemplate, // 保持原值 + IsCrossMargin: isCrossMargin, + ScanIntervalMinutes: scanIntervalMinutes, + IsRunning: existingTrader.IsRunning, // 保持原值 } // 更新数据库 @@ -803,30 +818,25 @@ func (s *Server) handleGetTraderConfig(c *gin.Context) { } } - // AIModelID 应该已经是 provider(如 "deepseek"),直接使用 - // 如果是旧数据格式(如 "admin_deepseek"),提取 provider 部分 + // 返回完整的模型ID,不做转换,保持与前端模型列表一致 aiModelID := traderConfig.AIModelID - // 兼容旧数据:如果包含下划线,提取最后一部分作为 provider - if strings.Contains(aiModelID, "_") { - parts := strings.Split(aiModelID, "_") - aiModelID = parts[len(parts)-1] - } 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/market/monitor.go b/market/monitor.go index 337640d8..23e126d9 100644 --- a/market/monitor.go +++ b/market/monitor.go @@ -106,8 +106,8 @@ func (m *WSMonitor) initializeHistoricalData() error { return } if len(klines4h) > 0 { - m.klineDataMap4h.Store(s, klines) - log.Printf("已加载 %s 的历史K线数据-4h: %d 条", s, len(klines)) + m.klineDataMap4h.Store(s, klines4h) + log.Printf("已加载 %s 的历史K线数据-4h: %d 条", s, len(klines4h)) } }(symbol) } 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; }