mirror of
https://github.com/NoFxAiOS/nofx.git
synced 2026-07-05 12:00:59 +08:00
fix(decision+trader): limit candidate coins & fix news collection
## Changes ### 1. decision/engine.go - Fix calculateMaxCandidates to enforce proper limits (was returning all candidates) - Dynamic limits based on position count: * 0 positions: max 30 candidates * 1 position: max 25 candidates * 2 positions: max 20 candidates * 3+ positions: max 15 candidates - Prevents Prompt bloat when users configure many coins ### 2. trader/auto_trader.go - Fix news collection to use actual positions + candidates (was hardcoded to BTC only) - Add extractNewsSymbols() helper function - Collect news for: * All current positions (highest priority) * Top 5 candidate coins * Always include BTC (market indicator) * Max 10 coins total (avoid excessive API calls) - Properly convert symbols for news API (lowercase, remove USDT suffix) ## Impact - Prevents excessive market data fetching - Makes news feature actually useful (was only fetching BTC news) - Better resource utilization 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -222,10 +222,31 @@ func fetchMarketDataForContext(ctx *Context) error {
|
|||||||
|
|
||||||
// calculateMaxCandidates 根据账户状态计算需要分析的候选币种数量
|
// calculateMaxCandidates 根据账户状态计算需要分析的候选币种数量
|
||||||
func calculateMaxCandidates(ctx *Context) int {
|
func calculateMaxCandidates(ctx *Context) int {
|
||||||
// 直接返回候选池的全部币种数量
|
// ⚠️ 重要:限制候选币种数量,避免 Prompt 过大
|
||||||
// 因为候选池已经在 auto_trader.go 中筛选过了
|
// 根据持仓数量动态调整:持仓越少,可以分析更多候选币
|
||||||
// 固定分析前20个评分最高的币种(来自AI500)
|
const (
|
||||||
return len(ctx.CandidateCoins)
|
maxCandidatesWhenEmpty = 30 // 无持仓时最多分析30个候选币
|
||||||
|
maxCandidatesWhenHolding1 = 25 // 持仓1个时最多分析25个候选币
|
||||||
|
maxCandidatesWhenHolding2 = 20 // 持仓2个时最多分析20个候选币
|
||||||
|
maxCandidatesWhenHolding3 = 15 // 持仓3个时最多分析15个候选币(避免 Prompt 过大)
|
||||||
|
)
|
||||||
|
|
||||||
|
positionCount := len(ctx.Positions)
|
||||||
|
var maxCandidates int
|
||||||
|
|
||||||
|
switch positionCount {
|
||||||
|
case 0:
|
||||||
|
maxCandidates = maxCandidatesWhenEmpty
|
||||||
|
case 1:
|
||||||
|
maxCandidates = maxCandidatesWhenHolding1
|
||||||
|
case 2:
|
||||||
|
maxCandidates = maxCandidatesWhenHolding2
|
||||||
|
default: // 3+ 持仓
|
||||||
|
maxCandidates = maxCandidatesWhenHolding3
|
||||||
|
}
|
||||||
|
|
||||||
|
// 返回实际候选币数量和上限中的较小值
|
||||||
|
return min(len(ctx.CandidateCoins), maxCandidates)
|
||||||
}
|
}
|
||||||
|
|
||||||
// buildSystemPromptWithCustom 构建包含自定义内容的 System Prompt
|
// buildSystemPromptWithCustom 构建包含自定义内容的 System Prompt
|
||||||
|
|||||||
@@ -761,20 +761,28 @@ func (at *AutoTrader) buildTradingContext() (*decision.Context, error) {
|
|||||||
performance = nil
|
performance = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// 6.提取新闻内容
|
// 6. 提取新闻内容(根据持仓和候选币种动态收集)
|
||||||
newsItem := make(map[string][]news.NewsItem)
|
newsItem := make(map[string][]news.NewsItem)
|
||||||
for _, newspro := range at.newsProcessor {
|
for _, newspro := range at.newsProcessor {
|
||||||
// TODO: 此出是为后续扩展考虑,当前随意给了个值占位
|
// 收集需要新闻的币种(持仓 + 候选币前几个)
|
||||||
newsMap, err := newspro.FetchNews([]string{"btc"}, 100)
|
newsSymbols := at.extractNewsSymbols(positionInfos, candidateCoins)
|
||||||
|
|
||||||
|
if len(newsSymbols) == 0 {
|
||||||
|
log.Printf("⚠️ 没有需要收集新闻的币种,跳过新闻收集")
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
newsMap, err := newspro.FetchNews(newsSymbols, 100)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("⚠️ 获取新闻内容失败: %v", err)
|
log.Printf("⚠️ 获取新闻内容失败: %v", err)
|
||||||
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
for symbol, value := range newsMap {
|
for symbol, value := range newsMap {
|
||||||
newsItem[symbol] = append(newsItem[symbol], value...)
|
newsItem[symbol] = append(newsItem[symbol], value...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log.Printf("📰 收集了 %d 个币种的新闻: %v", len(newsSymbols), newsSymbols)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 7. 构建上下文
|
// 7. 构建上下文
|
||||||
@@ -1583,6 +1591,49 @@ func normalizeSymbol(symbol string) string {
|
|||||||
return symbol
|
return symbol
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// extractNewsSymbols 提取需要收集新闻的币种(持仓 + 候选币前几个 + BTC)
|
||||||
|
func (at *AutoTrader) extractNewsSymbols(positions []decision.PositionInfo, candidates []decision.CandidateCoin) []string {
|
||||||
|
const (
|
||||||
|
maxNewsSymbols = 10 // 最多收集10个币种的新闻(避免请求过多)
|
||||||
|
maxCandidatesForNews = 5 // 从候选币中取前5个
|
||||||
|
)
|
||||||
|
|
||||||
|
symbolSet := make(map[string]bool)
|
||||||
|
result := make([]string, 0, maxNewsSymbols)
|
||||||
|
|
||||||
|
// 1. 总是包含 BTC(市场风向标)
|
||||||
|
symbolSet["btc"] = true
|
||||||
|
result = append(result, "btc")
|
||||||
|
|
||||||
|
// 2. 添加所有持仓币种(这些是最重要的)
|
||||||
|
for _, pos := range positions {
|
||||||
|
// 转换为新闻 API 格式(小写,移除 USDT 后缀)
|
||||||
|
baseSymbol := strings.ToLower(strings.TrimSuffix(pos.Symbol, "USDT"))
|
||||||
|
if !symbolSet[baseSymbol] && len(result) < maxNewsSymbols {
|
||||||
|
symbolSet[baseSymbol] = true
|
||||||
|
result = append(result, baseSymbol)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. 添加候选币种(前几个,按优先级)
|
||||||
|
for i, coin := range candidates {
|
||||||
|
if i >= maxCandidatesForNews {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if len(result) >= maxNewsSymbols {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
baseSymbol := strings.ToLower(strings.TrimSuffix(coin.Symbol, "USDT"))
|
||||||
|
if !symbolSet[baseSymbol] {
|
||||||
|
symbolSet[baseSymbol] = true
|
||||||
|
result = append(result, baseSymbol)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
// detectAutoClosedPositions 检测自动平仓的持仓(止损/止盈触发)
|
// detectAutoClosedPositions 检测自动平仓的持仓(止损/止盈触发)
|
||||||
func (at *AutoTrader) detectAutoClosedPositions(currentPositions []decision.PositionInfo) []logger.DecisionAction {
|
func (at *AutoTrader) detectAutoClosedPositions(currentPositions []decision.PositionInfo) []logger.DecisionAction {
|
||||||
var autoClosedActions []logger.DecisionAction
|
var autoClosedActions []logger.DecisionAction
|
||||||
|
|||||||
Reference in New Issue
Block a user