package manager import ( "fmt" "log" "nofx/config" "nofx/trader" "sync" "time" ) // TraderManager 管理多个trader实例 type TraderManager struct { traders map[string]*trader.AutoTrader // key: trader ID mu sync.RWMutex } // NewTraderManager 创建trader管理器 func NewTraderManager() *TraderManager { return &TraderManager{ traders: make(map[string]*trader.AutoTrader), } } // AddTrader 添加一个trader func (tm *TraderManager) AddTrader(cfg config.TraderConfig, coinPoolURL string, maxDailyLoss, maxDrawdown float64, stopTradingMinutes int, leverage config.LeverageConfig) error { tm.mu.Lock() defer tm.mu.Unlock() if _, exists := tm.traders[cfg.ID]; exists { return fmt.Errorf("trader ID '%s' 已存在", cfg.ID) } // 构建AutoTraderConfig traderConfig := trader.AutoTraderConfig{ ID: cfg.ID, Name: cfg.Name, AIModel: cfg.AIModel, Exchange: cfg.Exchange, BinanceAPIKey: cfg.BinanceAPIKey, BinanceSecretKey: cfg.BinanceSecretKey, HyperliquidPrivateKey: cfg.HyperliquidPrivateKey, HyperliquidTestnet: cfg.HyperliquidTestnet, AsterUser: cfg.AsterUser, AsterSigner: cfg.AsterSigner, AsterPrivateKey: cfg.AsterPrivateKey, CoinPoolAPIURL: coinPoolURL, UseQwen: cfg.AIModel == "qwen", DeepSeekKey: cfg.DeepSeekKey, QwenKey: cfg.QwenKey, CustomAPIURL: cfg.CustomAPIURL, CustomAPIKey: cfg.CustomAPIKey, CustomModelName: cfg.CustomModelName, ScanInterval: cfg.GetScanInterval(), InitialBalance: cfg.InitialBalance, BTCETHLeverage: leverage.BTCETHLeverage, // 使用配置的杠杆倍数 AltcoinLeverage: leverage.AltcoinLeverage, // 使用配置的杠杆倍数 MaxDailyLoss: maxDailyLoss, MaxDrawdown: maxDrawdown, StopTradingTime: time.Duration(stopTradingMinutes) * time.Minute, } // 创建trader实例 at, err := trader.NewAutoTrader(traderConfig) if err != nil { return fmt.Errorf("创建trader失败: %w", err) } tm.traders[cfg.ID] = at log.Printf("✓ Trader '%s' (%s) 已添加", cfg.Name, cfg.AIModel) return nil } // GetTrader 获取指定ID的trader func (tm *TraderManager) GetTrader(id string) (*trader.AutoTrader, error) { tm.mu.RLock() defer tm.mu.RUnlock() t, exists := tm.traders[id] if !exists { return nil, fmt.Errorf("trader ID '%s' 不存在", id) } return t, nil } // GetAllTraders 获取所有trader func (tm *TraderManager) GetAllTraders() map[string]*trader.AutoTrader { tm.mu.RLock() defer tm.mu.RUnlock() result := make(map[string]*trader.AutoTrader) for id, t := range tm.traders { result[id] = t } return result } // GetTraderIDs 获取所有trader ID列表 func (tm *TraderManager) GetTraderIDs() []string { tm.mu.RLock() defer tm.mu.RUnlock() ids := make([]string, 0, len(tm.traders)) for id := range tm.traders { ids = append(ids, id) } return ids } // StartAll 启动所有trader func (tm *TraderManager) StartAll() { tm.mu.RLock() defer tm.mu.RUnlock() log.Println("🚀 启动所有Trader...") for id, t := range tm.traders { go func(traderID string, at *trader.AutoTrader) { log.Printf("▶️ 启动 %s...", at.GetName()) if err := at.Run(); err != nil { log.Printf("❌ %s 运行错误: %v", at.GetName(), err) } }(id, t) } } // StopAll 停止所有trader func (tm *TraderManager) StopAll() { tm.mu.RLock() defer tm.mu.RUnlock() log.Println("⏹ 停止所有Trader...") for _, t := range tm.traders { t.Stop() } } // GetComparisonData 获取对比数据 func (tm *TraderManager) GetComparisonData() (map[string]interface{}, error) { tm.mu.RLock() defer tm.mu.RUnlock() comparison := make(map[string]interface{}) traders := make([]map[string]interface{}, 0, len(tm.traders)) for _, t := range tm.traders { account, err := t.GetAccountInfo() if err != nil { continue } status := t.GetStatus() traders = append(traders, map[string]interface{}{ "trader_id": t.GetID(), "trader_name": t.GetName(), "ai_model": t.GetAIModel(), "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"], "call_count": status["call_count"], "is_running": status["is_running"], }) } comparison["traders"] = traders comparison["count"] = len(traders) return comparison, nil }