| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273 |
- 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秒')
- }
- }
|