diff --git a/trader/binance_futures.go b/trader/binance_futures.go index db6a443a..ae85afa4 100644 --- a/trader/binance_futures.go +++ b/trader/binance_futures.go @@ -5,6 +5,7 @@ import ( "fmt" "log" "strconv" + "sync" "time" "github.com/adshao/go-binance/v2/futures" @@ -13,19 +14,44 @@ import ( // FuturesTrader 币安合约交易器 type FuturesTrader struct { client *futures.Client + + // 余额缓存 + cachedBalance map[string]interface{} + balanceCacheTime time.Time + balanceCacheMutex sync.RWMutex + + // 持仓缓存 + cachedPositions []map[string]interface{} + positionsCacheTime time.Time + positionsCacheMutex sync.RWMutex + + // 缓存有效期(15秒) + cacheDuration time.Duration } // NewFuturesTrader 创建合约交易器 func NewFuturesTrader(apiKey, secretKey string) *FuturesTrader { client := futures.NewClient(apiKey, secretKey) return &FuturesTrader{ - client: client, + client: client, + cacheDuration: 15 * time.Second, // 15秒缓存 } } -// GetBalance 获取账户余额 +// GetBalance 获取账户余额(带缓存) func (t *FuturesTrader) GetBalance() (map[string]interface{}, error) { - log.Printf("🔄 正在调用币安API获取账户余额...") + // 先检查缓存是否有效 + t.balanceCacheMutex.RLock() + if t.cachedBalance != nil && time.Since(t.balanceCacheTime) < t.cacheDuration { + cacheAge := time.Since(t.balanceCacheTime) + t.balanceCacheMutex.RUnlock() + log.Printf("✓ 使用缓存的账户余额(缓存时间: %.1f秒前)", cacheAge.Seconds()) + return t.cachedBalance, nil + } + t.balanceCacheMutex.RUnlock() + + // 缓存过期或不存在,调用API + log.Printf("🔄 缓存过期,正在调用币安API获取账户余额...") account, err := t.client.NewGetAccountService().Do(context.Background()) if err != nil { log.Printf("❌ 币安API调用失败: %v", err) @@ -42,11 +68,29 @@ func (t *FuturesTrader) GetBalance() (map[string]interface{}, error) { account.AvailableBalance, account.TotalUnrealizedProfit) + // 更新缓存 + t.balanceCacheMutex.Lock() + t.cachedBalance = result + t.balanceCacheTime = time.Now() + t.balanceCacheMutex.Unlock() + return result, nil } -// GetPositions 获取所有持仓 +// GetPositions 获取所有持仓(带缓存) func (t *FuturesTrader) GetPositions() ([]map[string]interface{}, error) { + // 先检查缓存是否有效 + t.positionsCacheMutex.RLock() + if t.cachedPositions != nil && time.Since(t.positionsCacheTime) < t.cacheDuration { + cacheAge := time.Since(t.positionsCacheTime) + t.positionsCacheMutex.RUnlock() + log.Printf("✓ 使用缓存的持仓信息(缓存时间: %.1f秒前)", cacheAge.Seconds()) + return t.cachedPositions, nil + } + t.positionsCacheMutex.RUnlock() + + // 缓存过期或不存在,调用API + log.Printf("🔄 缓存过期,正在调用币安API获取持仓信息...") positions, err := t.client.NewGetPositionRiskService().Do(context.Background()) if err != nil { return nil, fmt.Errorf("获取持仓失败: %w", err) @@ -78,6 +122,12 @@ func (t *FuturesTrader) GetPositions() ([]map[string]interface{}, error) { result = append(result, posMap) } + // 更新缓存 + t.positionsCacheMutex.Lock() + t.cachedPositions = result + t.positionsCacheTime = time.Now() + t.positionsCacheMutex.Unlock() + return result, nil } diff --git a/web/src/App.tsx b/web/src/App.tsx index 7cd71e5b..69992f19 100644 --- a/web/src/App.tsx +++ b/web/src/App.tsx @@ -42,9 +42,9 @@ function App() { : null, () => api.getStatus(selectedTraderId), { - refreshInterval: 5000, - revalidateOnFocus: true, - dedupingInterval: 0, + refreshInterval: 15000, // 15秒刷新(配合后端15秒缓存) + revalidateOnFocus: false, // 禁用聚焦时重新验证,减少请求 + dedupingInterval: 10000, // 10秒去重,防止短时间内重复请求 } ); @@ -54,9 +54,9 @@ function App() { : null, () => api.getAccount(selectedTraderId), { - refreshInterval: 5000, - revalidateOnFocus: true, - dedupingInterval: 0, + refreshInterval: 15000, // 15秒刷新(配合后端15秒缓存) + revalidateOnFocus: false, // 禁用聚焦时重新验证,减少请求 + dedupingInterval: 10000, // 10秒去重,防止短时间内重复请求 } ); @@ -66,9 +66,9 @@ function App() { : null, () => api.getPositions(selectedTraderId), { - refreshInterval: 5000, - revalidateOnFocus: true, - dedupingInterval: 0, + refreshInterval: 15000, // 15秒刷新(配合后端15秒缓存) + revalidateOnFocus: false, // 禁用聚焦时重新验证,减少请求 + dedupingInterval: 10000, // 10秒去重,防止短时间内重复请求 } ); @@ -77,7 +77,11 @@ function App() { ? `decisions/latest-${selectedTraderId}` : null, () => api.getLatestDecisions(selectedTraderId), - { refreshInterval: 10000 } + { + refreshInterval: 30000, // 30秒刷新(决策更新频率较低) + revalidateOnFocus: false, + dedupingInterval: 20000, + } ); const { data: stats } = useSWR( @@ -85,7 +89,11 @@ function App() { ? `statistics-${selectedTraderId}` : null, () => api.getStatistics(selectedTraderId), - { refreshInterval: 10000 } + { + refreshInterval: 30000, // 30秒刷新(统计数据更新频率较低) + revalidateOnFocus: false, + dedupingInterval: 20000, + } ); useEffect(() => { diff --git a/web/src/components/AILearning.tsx b/web/src/components/AILearning.tsx index b7757e32..8ef1a840 100644 --- a/web/src/components/AILearning.tsx +++ b/web/src/components/AILearning.tsx @@ -50,7 +50,11 @@ export default function AILearning({ traderId }: AILearningProps) { const { data: performance, error } = useSWR( traderId ? `performance-${traderId}` : 'performance', () => api.getPerformance(traderId), - { refreshInterval: 10000 } + { + refreshInterval: 30000, // 30秒刷新(AI学习分析数据更新频率较低) + revalidateOnFocus: false, + dedupingInterval: 20000, + } ); if (error) { diff --git a/web/src/components/ComparisonChart.tsx b/web/src/components/ComparisonChart.tsx index 4f489458..a21e8593 100644 --- a/web/src/components/ComparisonChart.tsx +++ b/web/src/components/ComparisonChart.tsx @@ -33,8 +33,9 @@ export function ComparisonChart({ traders }: ComparisonChartProps) { return Promise.all(promises); }, { - refreshInterval: 10000, + refreshInterval: 30000, // 30秒刷新(对比图表数据更新频率较低) revalidateOnFocus: false, + dedupingInterval: 20000, } ); diff --git a/web/src/components/CompetitionPage.tsx b/web/src/components/CompetitionPage.tsx index bc549e38..ca67447c 100644 --- a/web/src/components/CompetitionPage.tsx +++ b/web/src/components/CompetitionPage.tsx @@ -11,8 +11,9 @@ export function CompetitionPage() { 'competition', api.getCompetition, { - refreshInterval: 5000, - revalidateOnFocus: true, + refreshInterval: 15000, // 15秒刷新(竞赛数据不需要太频繁更新) + revalidateOnFocus: false, + dedupingInterval: 10000, } ); diff --git a/web/src/components/EquityChart.tsx b/web/src/components/EquityChart.tsx index 4022c112..b8b846cf 100644 --- a/web/src/components/EquityChart.tsx +++ b/web/src/components/EquityChart.tsx @@ -34,7 +34,9 @@ export function EquityChart({ traderId }: EquityChartProps) { traderId ? `equity-history-${traderId}` : 'equity-history', () => api.getEquityHistory(traderId), { - refreshInterval: 10000, // 每10秒刷新 + refreshInterval: 30000, // 30秒刷新(历史数据更新频率较低) + revalidateOnFocus: false, + dedupingInterval: 20000, } ); @@ -42,7 +44,9 @@ export function EquityChart({ traderId }: EquityChartProps) { traderId ? `account-${traderId}` : 'account', () => api.getAccount(traderId), { - refreshInterval: 5000, + refreshInterval: 15000, // 15秒刷新(配合后端缓存) + revalidateOnFocus: false, + dedupingInterval: 10000, } );