mirror of
https://github.com/NoFxAiOS/nofx.git
synced 2026-07-03 19:11:02 +08:00
Reduce the request frequency to the Binance API and add backend caching.
This commit is contained in:
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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<Statistics>(
|
||||
@@ -85,7 +89,11 @@ function App() {
|
||||
? `statistics-${selectedTraderId}`
|
||||
: null,
|
||||
() => api.getStatistics(selectedTraderId),
|
||||
{ refreshInterval: 10000 }
|
||||
{
|
||||
refreshInterval: 30000, // 30秒刷新(统计数据更新频率较低)
|
||||
revalidateOnFocus: false,
|
||||
dedupingInterval: 20000,
|
||||
}
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
@@ -50,7 +50,11 @@ export default function AILearning({ traderId }: AILearningProps) {
|
||||
const { data: performance, error } = useSWR<PerformanceAnalysis>(
|
||||
traderId ? `performance-${traderId}` : 'performance',
|
||||
() => api.getPerformance(traderId),
|
||||
{ refreshInterval: 10000 }
|
||||
{
|
||||
refreshInterval: 30000, // 30秒刷新(AI学习分析数据更新频率较低)
|
||||
revalidateOnFocus: false,
|
||||
dedupingInterval: 20000,
|
||||
}
|
||||
);
|
||||
|
||||
if (error) {
|
||||
|
||||
@@ -33,8 +33,9 @@ export function ComparisonChart({ traders }: ComparisonChartProps) {
|
||||
return Promise.all(promises);
|
||||
},
|
||||
{
|
||||
refreshInterval: 10000,
|
||||
refreshInterval: 30000, // 30秒刷新(对比图表数据更新频率较低)
|
||||
revalidateOnFocus: false,
|
||||
dedupingInterval: 20000,
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
@@ -11,8 +11,9 @@ export function CompetitionPage() {
|
||||
'competition',
|
||||
api.getCompetition,
|
||||
{
|
||||
refreshInterval: 5000,
|
||||
revalidateOnFocus: true,
|
||||
refreshInterval: 15000, // 15秒刷新(竞赛数据不需要太频繁更新)
|
||||
revalidateOnFocus: false,
|
||||
dedupingInterval: 10000,
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
@@ -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,
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user