import { logger } from '../../utils/logger.js' /** * 账户管理器 - 管理多个交易账户的状态和余额 */ export class AccountManager { constructor(cacheManager) { this.cacheManager = cacheManager this.accounts = [] this.clients = new Map() this.accountStates = new Map() } async initialize() { logger.info('AccountManager初始化') } async start() { logger.info('AccountManager启动') // 启动定期余额更新 this.startBalanceUpdates() } async stop() { logger.info('AccountManager停止') // 停止余额更新定时器 if (this.balanceUpdateInterval) { clearInterval(this.balanceUpdateInterval) this.balanceUpdateInterval = undefined } this.clients.clear() this.accountStates.clear() } getStatus() { return { name: 'AccountManager', status: 'running', lastUpdate: Date.now(), details: { accountCount: this.accounts.length, activeClients: this.clients.size, accountStates: this.accountStates.size, }, } } /** * 设置账户和客户端 */ setAccounts(accounts) { this.accounts = accounts this.initializeAccountStates() } /** * 获取账户列表 */ getAccounts() { return this.accounts } /** * 添加客户端 */ addClient(clientId, client) { this.clients.set(clientId, client) } /** * 获取客户端 */ getClient(clientId) { return this.clients.get(clientId) } /** * 获取所有客户端 */ getClients() { return this.clients } /** * 获取第一个可用的客户端 */ getFirstAvailableClient() { return this.clients.values().next().value } /** * 初始化账户状态 */ initializeAccountStates() { this.accounts.forEach((account, index) => { const accountId = `pacifica-${index + 1}` if (!this.accountStates.has(accountId)) { this.accountStates.set(accountId, { totalTrades: 0, netPosition: 0, totalVolume: 0, lastBalance: 0, availableBalance: 0, marginUsed: 0, needsRebalance: false, }) } }) } /** * 获取账户状态 */ getAccountState(accountId) { return this.accountStates.get(accountId) } /** * 获取所有账户状态 */ getAllAccountStates() { return this.accountStates } /** * 更新账户状态 */ updateAccountState(accountId, update) { const state = this.accountStates.get(accountId) if (state) { Object.assign(state, update) this.accountStates.set(accountId, state) } } /** * 获取账户余额(带缓存) */ async getAccountBalance(accountId) { try { const client = this.clients.get(accountId) if (!client) { logger.warn(`客户端 ${accountId} 不存在`) return 0 } const accountIndex = parseInt(accountId.split('-')[1]) - 1 const account = this.accounts[accountIndex] if (!account) { logger.warn(`账户信息 ${accountId} 不存在,accountIndex: ${accountIndex}, 总账户数: ${this.accounts.length}`) logger.debug( `可用账户:`, this.accounts.map((acc, idx) => ({ index: idx, id: acc.id, account: acc.account })), ) return 0 } // 使用缓存的余额数据 const cacheKey = `balance_${accountId}` const cachedBalance = this.cacheManager.get(cacheKey, this.cacheManager.getTTL('balance')) let result = cachedBalance if (!result) { // 缓存未命中,进行API调用 logger.debug(`调用API获取余额: ${accountId}, 账户地址: ${account.account}`) result = await client.getBalances(account.account) this.cacheManager.set(cacheKey, result, this.cacheManager.getTTL('balance')) } if (result.success && result.data) { const accountEquity = parseFloat(result.data.account_equity || '0') const availableToSpend = parseFloat(result.data.available_to_spend || '0') const marginUsed = parseFloat(result.data.total_margin_used || '0') // 更新账户状态 this.updateAccountState(accountId, { lastBalance: accountEquity, availableBalance: Math.max(0, availableToSpend), marginUsed: marginUsed, }) // 同时更新仓位信息 await this.updateAccountPosition(accountId) logger.debug( `账户 ${accountId} 财务更新: 权益$${accountEquity}, 可用$${availableToSpend}, 保证金$${marginUsed}`, ) return accountEquity } else { logger.warn(`获取账户余额失败: ${result.error}`) return this.accountStates.get(accountId)?.lastBalance || 0 } } catch (error) { logger.error(`获取账户余额出错: ${accountId}`, { error: error.message }) return this.accountStates.get(accountId)?.lastBalance || 0 } } /** * 更新账户仓位信息 */ async updateAccountPosition(accountId) { try { const client = this.clients.get(accountId) if (!client) { logger.warn(`客户端 ${accountId} 不存在`) return } const accountIndex = parseInt(accountId.split('-')[1]) - 1 const account = this.accounts[accountIndex] if (!account) { logger.warn(`账户信息 ${accountId} 不存在`) return } const result = await client.getPositions(account.account) if (result.success && result.data && Array.isArray(result.data)) { let totalNetPosition = 0 result.data.forEach(position => { if (position.symbol && position.symbol.includes('BTC')) { const amount = parseFloat(position.amount || '0') const side = position.side if (side === 'bid') { totalNetPosition += amount } else if (side === 'ask') { totalNetPosition -= amount } } }) this.updateAccountState(accountId, { netPosition: totalNetPosition }) logger.debug(`账户 ${accountId} 仓位更新: ${totalNetPosition.toFixed(4)} BTC`) } } catch (error) { logger.warn(`更新账户 ${accountId} 仓位失败`, { error: error.message }) } } /** * 更新所有账户余额 */ async updateAllAccountBalances() { const balancePromises = Array.from(this.accountStates.keys()).map(accountId => this.getAccountBalance(accountId)) try { await Promise.all(balancePromises) logger.debug('账户余额更新完成') } catch (error) { logger.warn('更新账户余额时部分失败', { error: error.message }) } } /** * 更新交易状态 */ updateTradeState(accountId, trade) { const state = this.accountStates.get(accountId) if (!state) return state.totalTrades++ if (trade.success) { const btcAmount = parseFloat(trade.amount) state.totalVolume += btcAmount // 更新净仓位 if (trade.side === 'bid') { state.netPosition += btcAmount } else if (trade.side === 'ask') { state.netPosition -= btcAmount } } this.accountStates.set(accountId, state) } /** * 获取账户统计信息 */ getAccountStats() { const states = Array.from(this.accountStates.values()) return { totalBalance: states.reduce((sum, state) => sum + state.lastBalance, 0), totalVolume: states.reduce((sum, state) => sum + state.totalVolume, 0), totalTrades: states.reduce((sum, state) => sum + state.totalTrades, 0), totalNetPosition: states.reduce((sum, state) => sum + state.netPosition, 0), } } /** * 启动定期余额更新 */ startBalanceUpdates() { // 每30秒更新一次余额 this.balanceUpdateInterval = setInterval(async () => { try { await this.updateAllAccountBalances() } catch (error) { logger.error('定期余额更新失败', { error: error.message }) } }, 30000) // 立即执行一次更新 this.updateAllAccountBalances().catch(error => { logger.error('初始余额更新失败', { error: error.message }) }) logger.info('定期余额更新已启动,间隔30秒') } }