Merge pull request #421 from Im-Sue/fix/trader-manager-hyperliquid-testnet-clean

fix(trader): add missing HyperliquidTestnet configuration in loadSing…
This commit is contained in:
Shui
2025-11-04 22:04:13 -05:00
committed by GitHub

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),
@@ -889,6 +889,7 @@ func (tm *TraderManager) loadSingleTrader(traderCfg *config.TraderRecord, aiMode
DefaultCoins: defaultCoins, DefaultCoins: defaultCoins,
TradingCoins: tradingCoins, TradingCoins: tradingCoins,
SystemPromptTemplate: traderCfg.SystemPromptTemplate, // 系统提示词模板 SystemPromptTemplate: traderCfg.SystemPromptTemplate, // 系统提示词模板
HyperliquidTestnet: exchangeCfg.Testnet, // Hyperliquid测试网
} }
// 根据交易所类型设置API密钥 // 根据交易所类型设置API密钥