| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414 |
- import { logger } from '../../utils/logger.js'
- import { globalPriceManager } from '../price/PriceManager.js'
- /**
- * 交易引擎 - 负责信号生成和交易执行
- */
- export class TradingEngine {
- constructor(accountManager, riskManager, stopLossService, hedgeManager = null) {
- this.accountManager = accountManager
- this.riskManager = riskManager
- this.stopLossService = stopLossService
- this.hedgeManager = hedgeManager
- this.isRunning = false
- this.tradingIntervals = []
- this.stats = {
- totalTrades: 0,
- successfulTrades: 0,
- failedTrades: 0,
- totalVolume: 0,
- lastTradeTime: 0,
- sessionStartTime: Date.now(),
- }
- this.riskLimits = {
- maxPositionSize: 0.01,
- maxTotalExposure: 0.05,
- maxAccountBalance: 10000,
- minAccountBalance: 100,
- maxDailyTrades: 50,
- maxSlippage: 0.05,
- emergencyStopLoss: 0.1,
- enabled: true,
- }
- this.priceCache = {}
- this.orderbookPriceCache = {}
- }
- async initialize() {
- logger.info('TradingEngine初始化')
- }
- async start() {
- logger.info('TradingEngine启动')
- this.isRunning = true
- // 启动时预热orderbook价格缓存
- this.preloadOrderbookPrices()
- this.startTradingLoop()
- }
- async stop() {
- logger.info('TradingEngine停止')
- this.isRunning = false
- this.tradingIntervals.forEach(interval => clearInterval(interval))
- this.tradingIntervals = []
- }
- getStatus() {
- return {
- name: 'TradingEngine',
- status: this.isRunning ? 'running' : 'stopped',
- lastUpdate: Date.now(),
- details: {
- stats: this.stats,
- activeIntervals: this.tradingIntervals.length,
- },
- }
- }
- /**
- * 启动交易循环
- */
- startTradingLoop() {
- console.log('🔄 启动交易引擎')
- // 主交易信号生成器
- const mainInterval = setInterval(async () => {
- if (this.isRunning) {
- await this.generateTradingSignals()
- }
- }, 15000)
- this.tradingIntervals.push(mainInterval)
- // 高频刷量信号
- const volumeInterval = setInterval(async () => {
- if (this.isRunning) {
- await this.generateVolumeBoostSignals()
- }
- }, 8000)
- this.tradingIntervals.push(volumeInterval)
- console.log('✅ 交易引擎已启动')
- }
- /**
- * 生成交易信号
- */
- async generateTradingSignals() {
- const signals = []
- const randomFactor = Math.random()
- // 初始化账户状态
- this.accountManager.getAllAccountStates()
- // 检查是否需要资金平衡
- const needsBalancing = this.checkAccountBalance()
- if (needsBalancing) {
- const balanceSignal = this.generateBalanceSignal()
- if (balanceSignal) {
- signals.push(balanceSignal)
- // 高使用率时,执行降低使用率策略
- const accounts = Array.from(this.accountManager.getAllAccountStates().values())
- let maxUtilizationRate = 0
- let highUtilizationAccount = null
- accounts.forEach(account => {
- if (account.lastBalance > 0) {
- const utilizationRate = Math.abs(account.lastBalance - account.availableBalance) / account.lastBalance
- if (utilizationRate > maxUtilizationRate) {
- maxUtilizationRate = utilizationRate
- highUtilizationAccount = account
- }
- }
- })
- // 动态使用率平衡机制
- await this.executeUtilizationBalancing(accounts, maxUtilizationRate)
- if (maxUtilizationRate >= 0.9) {
- console.log(`🚨 [高使用率警报] 使用率${(maxUtilizationRate * 100).toFixed(1)}% >= 90%,启动紧急降低机制`)
- // 执行敞口平衡
- for (const signal of signals) {
- await this.handleTradingSignal(signal)
- }
- // 主动降低使用率:减少仓位
- await this.executeUtilizationReduction(highUtilizationAccount, maxUtilizationRate)
- return
- }
- }
- }
- // 根据使用率动态调整刷量策略
- const avgUtilizationRate = this.calculateAverageUtilizationRate()
- let shouldGenerateSignal = false
- if (avgUtilizationRate < 0.7) {
- // 使用率过低,积极刷量
- shouldGenerateSignal = randomFactor > 0.1 // 90%概率
- } else if (avgUtilizationRate <= 0.8) {
- // 在目标范围内,正常刷量
- shouldGenerateSignal = randomFactor > 0.3 // 70%概率
- } else if (avgUtilizationRate <= 0.9) {
- // 超出目标,减少刷量
- shouldGenerateSignal = randomFactor > 0.7 // 30%概率
- } else {
- // 使用率过高,基本不刷量
- shouldGenerateSignal = randomFactor > 0.9 // 10%概率
- }
- if (shouldGenerateSignal) {
- const shouldClosePosition = this.shouldCloseExistingPositions(avgUtilizationRate)
- if (shouldClosePosition) {
- const closeSignal = await this.generateCloseSignal()
- if (closeSignal && parseFloat(closeSignal.amount) > 0) {
- signals.push(closeSignal)
- }
- } else {
- const action = randomFactor > 0.6 ? 'buy' : 'sell'
- const amount = await this.calculateTradingAmount()
- // 只有当金额大于0时才添加信号
- if (parseFloat(amount) > 0) {
- signals.push({
- symbol: 'BTC-USD',
- action,
- amount,
- confidence: randomFactor,
- reason: `智能刷量(使用率${(avgUtilizationRate * 100).toFixed(1)}%) - ${
- action === 'buy' ? '买入建仓' : '卖出建仓'
- }`,
- })
- }
- }
- }
- // 对冲信号
- if (this.hedgeManager && randomFactor > 0.5) {
- const hedgeSignal = await this.generateSmartHedgeSignal()
- if (hedgeSignal && parseFloat(hedgeSignal.amount) > 0) {
- signals.push(hedgeSignal)
- }
- }
- // 发送信号
- for (const signal of signals) {
- await this.handleTradingSignal(signal)
- }
- }
- /**
- * 生成刷量信号
- */
- async generateVolumeBoostSignals() {
- if (!this.shouldTrade()) {
- return
- }
- const signals = []
- if (this.hedgeManager && Math.random() > 0.4) {
- const primaryAccountId = 'pacifica-1'
- const boostAmount = await this.calculateSmartTradeAmount(primaryAccountId, 'open')
- signals.push({
- symbol: 'BTC-USD',
- action: 'volume_boost',
- amount: boostAmount,
- confidence: 0.9,
- reason: `智能刷量 - 金额: ${boostAmount} BTC`,
- })
- }
- signals.forEach(signal => {
- this.handleTradingSignal(signal)
- })
- }
- /**
- * 处理交易信号
- */
- async handleTradingSignal(signal) {
- logger.info('收到交易信号', { signal })
- // 对于减仓信号,跳过常规交易检查(允许在高使用率时执行)
- const isReduceOnlySignal =
- signal.reduceOnly ||
- (signal.reason &&
- (signal.reason.includes('使用率控制') ||
- signal.reason.includes('降低使用率') ||
- signal.reason.includes('双向减仓')))
- if (isReduceOnlySignal) {
- console.log(`🔄 [强制执行] 减仓信号,跳过常规交易检查: ${signal.reason || 'reduceOnly'}`)
- } else if (!this.shouldTrade()) {
- logger.info('当前不适合交易,忽略信号')
- return
- }
- try {
- if (signal.action === 'hedge' && this.hedgeManager) {
- await this.executeHedgeSignal(signal)
- } else if (signal.action === 'volume_boost' && this.hedgeManager) {
- await this.executeVolumeBoost(signal)
- } else if (signal.action === 'balance_accounts') {
- await this.executeBalanceSignal(signal)
- } else if (signal.action === 'balance') {
- // 使用率控制平仓
- await this.executeUtilizationControlSignal(signal)
- } else if (signal.action === 'close_position') {
- await this.executeCloseSignal(signal)
- } else {
- await this.executeTradeSignal(signal)
- }
- } catch (error) {
- logger.error('交易信号处理失败', { signal, error: error.message })
- this.stats.failedTrades++
- }
- }
- /**
- * 执行使用率控制信号(强制平仓)
- */
- async executeUtilizationControlSignal(signal) {
- const clientId = signal.targetAccount || 'pacifica-1'
- const client = this.accountManager.getClient(clientId)
- if (!client) {
- throw new Error(`客户端 ${clientId} 不可用`)
- }
- console.log(`🔄 [使用率控制] 执行强制平仓: ${signal.amount} BTC, side=${signal.side}`)
- // 确保 side 映射正确
- const side = signal.side === 'buy' ? 'bid' : 'ask'
- // 获取账户信息以获取正确的账户地址
- const accountIndex = parseInt(clientId.split('-')[1]) - 1
- const accounts = this.accountManager.getAccounts()
- const account = accounts[accountIndex]
- if (!account) {
- throw new Error(`找不到账户 ${clientId} 的配置信息`)
- }
- const result = await client.marketOrder({
- account: account.account,
- symbol: 'BTCUSDT',
- amount: signal.amount,
- side: side,
- reduceOnly: true,
- slippagePercent: '5.0',
- })
- if (result.success) {
- this.stats.successfulTrades++
- this.stats.totalVolume += parseFloat(signal.amount)
- console.log(`✅ [使用率控制] 强制平仓成功: ${result.data?.order_id}`)
- this.accountManager.updateTradeState(clientId, {
- side: signal.side,
- amount: signal.amount,
- success: true,
- })
- } else {
- this.stats.failedTrades++
- throw new Error(`使用率控制平仓失败: ${result.error}`)
- }
- this.stats.totalTrades++
- this.stats.lastTradeTime = Date.now()
- }
- /**
- * 执行交易信号
- */
- async executeTradeSignal(signal) {
- const clientId = signal.targetAccount || 'pacifica-1'
- const client = this.accountManager.getClient(clientId)
- if (!client) {
- throw new Error(`客户端 ${clientId} 不可用`)
- }
- const side = signal.action === 'buy' ? 'bid' : 'ask'
- const accountStates = this.accountManager.getAllAccountStates()
- const firstAccountId = Array.from(accountStates.keys())[0]
- // 获取当前价格用于止盈止损
- const currentPrice = await this.getCurrentPrice(signal.symbol)
- // 执行订单
- const result = await client.createMarketOrder({
- account: firstAccountId,
- symbol: 'BTCUSDT',
- amount: signal.amount,
- side: side,
- reduceOnly: signal.reduceOnly || signal.action === 'sell',
- slippagePercent: '5.0',
- })
- if (result.success) {
- this.stats.successfulTrades++
- this.stats.totalVolume += parseFloat(signal.amount)
- this.stats.lastTradeTime = Date.now()
- logger.info('交易订单执行成功', { orderId: result.data?.order_id })
- console.log(`✅ ${signal.action.toUpperCase()} 订单成功: ${result.data?.order_id}`)
- // 更新账户状态
- this.accountManager.updateTradeState(clientId, { side, amount: signal.amount, success: true })
- // 设置止盈止损
- if (!signal.reduceOnly && result.data?.order_id) {
- await this.stopLossService.setupStopLossAndTakeProfit({
- parentOrderId: result.data.order_id,
- symbol: signal.symbol,
- amount: signal.amount,
- side: signal.action,
- currentPrice,
- clientId,
- stopLoss: signal.stopLoss,
- takeProfit: signal.takeProfit,
- enableTrailing: signal.enableTrailing,
- })
- }
- } else {
- this.stats.failedTrades++
- throw new Error(`订单失败: ${result.error}`)
- }
- this.stats.totalTrades++
- }
- /**
- * 执行对冲信号
- */
- async executeHedgeSignal(signal) {
- if (!this.hedgeManager) return
- const amount = parseFloat(signal.amount)
- if (!amount || amount <= 0 || !isFinite(amount)) {
- console.log(`❌ [订单跳过] 无效金额: ${signal.amount} → ${amount}`)
- return
- }
- const batchOrders = [
- {
- accountId: 'pacifica-1',
- symbol: 'BTC-USD',
- amount: amount,
- side: 'bid',
- orderType: 'market',
- },
- {
- accountId: 'pacifica-2',
- symbol: 'BTC-USD',
- amount: amount,
- side: 'ask',
- orderType: 'market',
- },
- ]
- const results = await this.hedgeManager.executeBatchHedge(batchOrders)
- this.processHedgeResults(results, batchOrders)
- }
- /**
- * 执行刷量信号
- */
- async executeVolumeBoost(signal) {
- if (!this.hedgeManager) return
- const boostSequence = [
- {
- accountId: 'pacifica-1',
- symbol: 'BTC-USD',
- amount: parseFloat(signal.amount),
- side: 'bid',
- orderType: 'market',
- reason: '刷量开仓-多头',
- },
- {
- accountId: 'pacifica-2',
- symbol: 'BTC-USD',
- amount: parseFloat(signal.amount),
- side: 'ask',
- orderType: 'market',
- reason: '刷量开仓-空头',
- },
- ]
- const results = await this.hedgeManager.executeBatchHedge(boostSequence)
- this.processVolumeBoostResults(results, boostSequence, signal.amount)
- }
- /**
- * 执行平衡信号
- */
- async executeBalanceSignal(signal) {
- if (!this.hedgeManager || !signal.targetAccount) return
- const balanceOrders = this.generateBalanceOrders(signal)
- const results = await this.hedgeManager.executeBatchHedge(balanceOrders)
- let successCount = 0
- results.forEach((result, index) => {
- if (result.success) {
- successCount++
- }
- })
- this.stats.totalTrades += results.length
- this.stats.successfulTrades += successCount
- this.stats.failedTrades += results.length - successCount
- const successRate = results.length > 0 ? ((successCount / results.length) * 100).toFixed(1) : '0.0'
- console.log(`⚖️ [平衡完成] 成功率: ${successRate}% (${successCount}/${results.length})`)
- }
- /**
- * 执行平仓信号
- */
- async executeCloseSignal(signal) {
- const clientId = signal.targetAccount || 'pacifica-1'
- const client = this.accountManager.getClient(clientId)
- if (!client) {
- throw new Error(`客户端 ${clientId} 不可用`)
- }
- const side = signal.action === 'buy' ? 'bid' : 'ask'
- const accountStates = this.accountManager.getAllAccountStates()
- const firstAccountId = Array.from(accountStates.keys())[0]
- const result = await client.createMarketOrder({
- account: firstAccountId,
- symbol: 'BTCUSDT',
- amount: signal.amount,
- side: side,
- reduceOnly: true,
- slippagePercent: '5.0',
- })
- if (result.success) {
- this.stats.successfulTrades++
- this.stats.totalVolume += parseFloat(signal.amount)
- console.log(`✅ 平仓成功: ${result.data?.order_id}`)
- this.accountManager.updateTradeState(clientId, { side, amount: signal.amount, success: true })
- } else {
- this.stats.failedTrades++
- throw new Error(`平仓失败: ${result.error}`)
- }
- this.stats.totalTrades++
- this.stats.lastTradeTime = Date.now()
- }
- // Helper methods
- checkAccountBalance() {
- const accounts = Array.from(this.accountManager.getAllAccountStates().values())
- if (accounts.length < 2) return false
- const totalNetExposure = accounts.reduce((sum, account) => sum + account.netPosition, 0)
- const exposureThreshold = this.riskManager.calculateDynamicExposureThreshold()
- return Math.abs(totalNetExposure) > exposureThreshold
- }
- generateBalanceSignal() {
- const accountsArray = Array.from(this.accountManager.getAllAccountStates().entries())
- if (accountsArray.length < 2) return null
- const totalNetExposure = accountsArray.reduce((sum, [_, state]) => sum + state.netPosition, 0)
- const dynamicThreshold = this.riskManager.calculateDynamicExposureThreshold()
- if (Math.abs(totalNetExposure) > dynamicThreshold) {
- const sortedAccounts = accountsArray.sort((a, b) => Math.abs(b[1].netPosition) - Math.abs(a[1].netPosition))
- const [targetAccountId] = sortedAccounts[0]
- const adjustmentAmount = Math.min(Math.abs(totalNetExposure) * 0.5, 0.001)
- const action = totalNetExposure > 0 ? 'sell' : 'buy'
- return {
- symbol: 'BTC-USD',
- action: 'balance_accounts',
- side: action,
- amount: adjustmentAmount.toFixed(4),
- confidence: 0.95,
- reason: `敞口平衡 - 总净敞口${totalNetExposure.toFixed(4)} BTC`,
- targetAccount: targetAccountId,
- reduceOnly: false,
- }
- }
- return null
- }
- /**
- * 计算平均使用率
- */
- calculateAverageUtilizationRate() {
- const accounts = Array.from(this.accountManager.getAllAccountStates().values())
- if (accounts.length === 0) return 0
- let totalUtilization = 0
- let validAccounts = 0
- accounts.forEach(account => {
- if (account.lastBalance > 0) {
- const utilizationRate = Math.abs(account.lastBalance - account.availableBalance) / account.lastBalance
- totalUtilization += utilizationRate
- validAccounts++
- }
- })
- return validAccounts > 0 ? totalUtilization / validAccounts : 0
- }
- shouldCloseExistingPositions(avgUtilizationRate) {
- const utilizationRate = avgUtilizationRate || this.calculateAverageUtilizationRate()
- // 根据使用率调整平仓概率
- if (utilizationRate >= 0.85) {
- return Math.random() < 0.6 // 高使用率时,60%概率平仓
- } else if (utilizationRate >= 0.75) {
- return Math.random() < 0.4 // 中高使用率时,40%概率平仓
- } else if (utilizationRate >= 0.65) {
- return Math.random() < 0.2 // 正常使用率时,20%概率平仓
- } else {
- return Math.random() < 0.1 // 低使用率时,10%概率平仓
- }
- }
- async generateCloseSignal() {
- const accountsArray = Array.from(this.accountManager.getAllAccountStates().entries())
- const accountWithMaxPosition = accountsArray.reduce((max, current) => {
- return Math.abs(current[1].netPosition) > Math.abs(max[1].netPosition) ? current : max
- })
- const [accountId, accountState] = accountWithMaxPosition
- if (Math.abs(accountState.netPosition) > 0.0001) {
- const smartCloseAmount = await this.calculateSmartTradeAmount(accountId, 'close')
- const action = accountState.netPosition > 0 ? 'sell' : 'buy'
- return {
- symbol: 'BTC-USD',
- action: action,
- amount: smartCloseAmount,
- confidence: 0.9,
- reason: `智能平仓 - 减少${accountState.netPosition > 0 ? '多头' : '空头'}仓位`,
- reduceOnly: true,
- targetAccount: accountId,
- }
- }
- return null
- }
- async generateSmartHedgeSignal() {
- if (!this.hedgeManager) return null
- const hedgeAmount = await this.calculateHedgeAmount()
- return {
- symbol: 'BTC-USD',
- action: 'hedge',
- amount: hedgeAmount,
- confidence: 0.85,
- reason: '常规对冲刷量',
- }
- }
- async calculateTradingAmount() {
- return await this.calculateSmartTradeAmount('pacifica-1', 'open')
- }
- async calculateSmartTradeAmount(accountId, action) {
- const state = this.accountManager.getAccountState(accountId)
- // 获取实时余额(与calculateHedgeAmount保持一致)
- const freshBalance = await this.accountManager.getAccountBalance(accountId)
- // Pacifica最小订单要求: 10 USDT
- const minOrderAmountUsd = 10
- const currentBtcPrice = this.getCurrentPriceSync('BTC-USD') // 获取实时BTC价格
- // 边界检查:确保价格有效
- if (!currentBtcPrice || currentBtcPrice <= 0 || !isFinite(currentBtcPrice)) {
- console.log(`⚠️ [价格异常] BTC价格无效: ${currentBtcPrice}, 跳过此次交易`)
- return '0' // 返回0表示跳过交易
- }
- const minOrderAmountBtc = minOrderAmountUsd / currentBtcPrice
- // 边界检查:确保最小订单金额有效
- if (!isFinite(minOrderAmountBtc) || minOrderAmountBtc <= 0 || minOrderAmountBtc > 1) {
- console.log(`⚠️ [金额异常] 计算的最小BTC金额异常: ${minOrderAmountBtc}, 跳过此次交易`)
- return '0' // 返回0表示跳过交易
- }
- const minAmountStr = minOrderAmountBtc.toFixed(6)
- // 使用实时余额进行判断
- const availableBalance = freshBalance || 0
- const utilizationRate =
- state?.lastBalance && state.lastBalance > 0
- ? Math.abs(state.lastBalance - availableBalance) / state.lastBalance
- : 0
- // 如果账户余额不足以支持最小订单,跳过交易
- if (availableBalance < minOrderAmountUsd) {
- console.log(
- `⚠️ [交易跳过] 账户${accountId}可用余额$${availableBalance.toFixed(2)} < 最小订单要求$${minOrderAmountUsd}`,
- )
- return '0'
- }
- if (!state) {
- return minAmountStr
- }
- if (action === 'open') {
- // 根据使用率智能调整开仓大小
- let targetAmount
- if (utilizationRate >= 0.8) {
- // 使用率已在目标上限,使用最小金额
- targetAmount = minOrderAmountBtc
- } else if (utilizationRate >= 0.7) {
- // 在目标范围内,保持适中
- targetAmount = Math.max((availableBalance * 0.05) / currentBtcPrice, minOrderAmountBtc)
- targetAmount = Math.min(targetAmount, 0.0003)
- } else if (utilizationRate >= 0.5) {
- // 低于目标,适度增加
- targetAmount = Math.max((availableBalance * 0.08) / currentBtcPrice, minOrderAmountBtc)
- targetAmount = Math.min(targetAmount, 0.0005)
- } else {
- // 使用率过低,积极开仓
- targetAmount = Math.max((availableBalance * 0.1) / currentBtcPrice, minOrderAmountBtc)
- targetAmount = Math.min(targetAmount, 0.001)
- }
- // 最终边界检查
- let finalAmount = Math.max(targetAmount, minOrderAmountBtc)
- // Pacifica lot size精度调整: 必须是0.00001的倍数
- const lotSize = 0.00001
- finalAmount = Math.round(finalAmount / lotSize) * lotSize
- // 确保调整后仍满足最小要求
- if (finalAmount < minOrderAmountBtc) {
- finalAmount = Math.ceil(minOrderAmountBtc / lotSize) * lotSize
- }
- const result = finalAmount.toFixed(5) // 5位小数精度匹配lot size
- console.log(
- `📊 [开仓金额] ${accountId}: $${availableBalance.toFixed(2)} 可用 → ${result} BTC (${(
- finalAmount * currentBtcPrice
- ).toFixed(2)} USDT) [lot调整]`,
- )
- return result
- } else {
- // 平仓策略:根据使用率和仓位大小决定
- const positionSize = Math.abs(state.netPosition)
- if (positionSize === 0) return minAmountStr
- let closeRatio = 0.3 // 默认平仓30%
- if (utilizationRate >= 0.85) {
- closeRatio = 0.5 // 高使用率时加大平仓比例
- } else if (utilizationRate <= 0.65) {
- closeRatio = 0.2 // 低使用率时减少平仓比例
- }
- const closeAmount = Math.min(positionSize * closeRatio, 0.002)
- let finalAmount = Math.max(closeAmount, minOrderAmountBtc)
- // Pacifica lot size精度调整: 必须是0.00001的倍数
- const lotSize = 0.00001
- finalAmount = Math.round(finalAmount / lotSize) * lotSize
- // 确保调整后仍满足最小要求
- if (finalAmount < minOrderAmountBtc) {
- finalAmount = Math.ceil(minOrderAmountBtc / lotSize) * lotSize
- }
- const result = finalAmount.toFixed(5) // 5位小数精度匹配lot size
- console.log(
- `📊 [平仓金额] ${accountId}: ${positionSize.toFixed(4)} BTC 仓位 → ${result} BTC (${(
- finalAmount * currentBtcPrice
- ).toFixed(2)} USDT) [lot调整]`,
- )
- return result
- }
- }
- async calculateHedgeAmount() {
- try {
- const account1Balance = await this.accountManager.getAccountBalance('pacifica-1')
- const account2Balance = await this.accountManager.getAccountBalance('pacifica-2')
- const minBalance = Math.min(account1Balance || 0, account2Balance || 0)
- // Pacifica最小订单要求: 10 USDT
- const minOrderAmountUsd = 10
- const currentBTCPrice = this.getCurrentPriceSync('BTC-USD')
- // 边界检查:确保价格有效
- if (!currentBTCPrice || currentBTCPrice <= 0 || !isFinite(currentBTCPrice)) {
- console.log(`⚠️ [对冲价格异常] BTC价格无效: ${currentBTCPrice}, 跳过对冲交易`)
- return '0' // 返回0表示跳过交易
- }
- const minOrderAmountBtc = minOrderAmountUsd / currentBTCPrice
- // 边界检查:确保最小订单金额有效
- if (!isFinite(minOrderAmountBtc) || minOrderAmountBtc <= 0 || minOrderAmountBtc > 1) {
- console.log(`⚠️ [对冲金额异常] 计算的最小BTC金额异常: ${minOrderAmountBtc}, 跳过对冲交易`)
- return '0'
- }
- if (minBalance < minOrderAmountUsd) {
- console.log(`⚠️ [对冲跳过] 最小账户余额$${minBalance.toFixed(2)} < 最小订单要求$${minOrderAmountUsd}`)
- return '0'
- }
- const baseAmount = (minBalance * 0.01) / currentBTCPrice
- const amount = baseAmount * (0.8 + Math.random() * 0.4)
- // 确保不低于最小订单金额
- let finalAmount = Math.max(minOrderAmountBtc, Math.min(0.001, amount))
- // Pacifica lot size精度调整: 必须是0.00001的倍数
- const lotSize = 0.00001
- finalAmount = Math.round(finalAmount / lotSize) * lotSize
- // 确保调整后仍满足最小要求
- if (finalAmount < minOrderAmountBtc) {
- finalAmount = Math.ceil(minOrderAmountBtc / lotSize) * lotSize
- }
- const result = finalAmount.toFixed(5) // 5位小数精度匹配lot size
- console.log(
- `📊 [对冲金额] 最小余额: $${minBalance.toFixed(2)} → ${result} BTC (${(finalAmount * currentBTCPrice).toFixed(
- 2,
- )} USDT) [lot调整]`,
- )
- return result
- } catch (error) {
- logger.error('计算对冲数量时出错', { error: error.message })
- // 安全的错误处理
- console.log(`⚠️ [对冲计算错误] 跳过此次对冲交易`)
- return '0' // 错误时跳过交易
- }
- }
- shouldTrade() {
- if (this.stats.totalTrades >= this.riskLimits.maxDailyTrades) {
- return false
- }
- const timeSinceLastTrade = Date.now() - this.stats.lastTradeTime
- if (timeSinceLastTrade < 5000) {
- return false
- }
- // 检查使用率是否过高
- if (this.shouldSkipTradeForUtilization()) {
- return false
- }
- return true
- }
- async getCurrentPrice(symbol) {
- return this.getCurrentPriceSync(symbol)
- }
- getCurrentPriceSync(symbol) {
- try {
- // 直接从全局价格管理器获取实时价格
- const price = globalPriceManager.getPrice(symbol)
- if (price > 0) {
- logger.debug(`📊 [实时价格] ${symbol}: $${price.toFixed(2)}`)
- return price
- }
- // 如果没有价格数据,使用fallback价格确保利用率控制能正常工作
- const fallbackPrice = this.getFallbackPrice(symbol)
- if (fallbackPrice > 0) {
- logger.warn(`⚠️ [价格回退] ${symbol}使用回退价格: $${fallbackPrice.toFixed(2)}`, {
- priceManagerStatus: globalPriceManager.getStatus(),
- availableSymbols: Array.from(globalPriceManager.getAllPrices().keys()).slice(0, 5),
- })
- return fallbackPrice
- }
- return 0
- } catch (error) {
- logger.error('获取价格失败', { symbol, error: error.message })
- return this.getFallbackPrice(symbol)
- }
- }
- /**
- * 获取回退价格,确保使用率控制机制能正常工作
- */
- getFallbackPrice(symbol) {
- const symbolUpper = symbol.toUpperCase()
- // 基于当前市场的合理回退价格
- if (symbolUpper.includes('BTC')) {
- return 95000 // BTC 回退价格
- }
- if (symbolUpper.includes('ETH')) {
- return 3800 // ETH 回退价格
- }
- if (symbolUpper.includes('SOL')) {
- return 220 // SOL 回退价格
- }
- if (symbolUpper.includes('USD') || symbolUpper.includes('USDT') || symbolUpper.includes('USDC')) {
- return 1 // 稳定币回退价格
- }
- // 默认回退价格(对于未知交易对)
- return 100
- }
- fetchRealTimePriceSync(symbol) {
- try {
- // 尝试从最近的orderbook数据获取价格
- const midPrice = this.getLastKnownPrice(symbol)
- if (midPrice > 0) {
- return midPrice
- }
- // 尝试从外部API获取实时价格
- const externalPrice = this.getExternalPrice(symbol)
- if (externalPrice > 0) {
- console.log(`📊 [外部价格] ${symbol}: $${externalPrice}`)
- return externalPrice
- }
- // 最后的Fallback: 从现有的orderbook缓存中获取历史价格
- const historicalPrice = this.getHistoricalPrice(symbol)
- if (historicalPrice > 0) {
- console.log(`📊 [历史价格] ${symbol}: $${historicalPrice}`)
- return historicalPrice
- }
- // 如果都失败,使用fallback
- if (symbol.includes('BTC')) {
- console.log(`🔄 [最终fallback] ${symbol}: $65000 (所有尝试失败)`)
- return 65000
- }
- throw new Error(`无法获取${symbol}的有效价格`)
- } catch (error) {
- logger.warn('获取实时价格失败', { symbol, error })
- // 提供最终的fallback而不是抛出错误
- if (symbol.includes('BTC')) {
- console.log(`🔄 [catch fallback] ${symbol}: $65000 (异常处理)`)
- return 65000
- }
- throw error
- }
- }
- /**
- * 从外部API获取实时价格(使用Pacifica prices API)
- */
- getExternalPrice(symbol) {
- try {
- const client = this.accountManager.getFirstAvailableClient()
- if (client && client.getPrices) {
- // 首先检查是否已有orderbook缓存数据
- const cached = this.orderbookPriceCache[symbol]
- if (cached && Date.now() - cached.timestamp < 180 * 1000) {
- // 3分钟有效期
- const midPrice = (cached.bid + cached.ask) / 2
- console.log(
- `📊 [缓存价格] ${symbol}: $${midPrice.toFixed(2)} (bid=${cached.bid.toFixed(2)}, ask=${cached.ask.toFixed(
- 2,
- )})`,
- )
- return midPrice
- }
- // 异步获取价格数据
- this.updatePricesAsync(symbol)
- // 同时触发orderbook更新
- this.updateOrderbookPriceAsync(symbol)
- }
- return 0 // 异步获取,这次返回0
- } catch (error) {
- return 0
- }
- }
- /**
- * 异步更新价格数据
- */
- async updatePricesAsync(symbol) {
- try {
- const client = this.accountManager.getFirstAvailableClient()
- if (!client || !client.getPrices) {
- return
- }
- const pricesData = await client.getPrices()
- if (pricesData && pricesData.data) {
- // 查找对应symbol的价格
- const symbolPrice = pricesData.data.find(
- item =>
- item.symbol === symbol ||
- item.symbol === symbol.replace('-', '') ||
- item.symbol === symbol.replace('USD', 'USDT'),
- )
- if (symbolPrice && symbolPrice.price) {
- const price = parseFloat(symbolPrice.price)
- if (!isNaN(price) && price > 0) {
- // 更新价格缓存
- const cacheKey = `price_${symbol}`
- this.priceCache[cacheKey] = {
- price: price,
- timestamp: Date.now(),
- }
- console.log(`📊 [价格API] ${symbol}: $${price.toFixed(2)}`)
- }
- }
- }
- } catch (error) {
- logger.debug('更新价格API数据失败', { symbol, error: error.message })
- }
- }
- /**
- * 从历史orderbook缓存获取价格
- */
- getHistoricalPrice(symbol) {
- try {
- // 检查所有缓存的orderbook数据,即使过期的也可以作为最后的参考
- const cacheKey = symbol
- const cached = this.orderbookPriceCache[cacheKey]
- if (cached && cached.bid > 0 && cached.ask > 0) {
- const midPrice = (cached.bid + cached.ask) / 2
- const ageMinutes = (Date.now() - cached.timestamp) / 1000 / 60
- console.log(`📊 [历史缓存] ${symbol}: $${midPrice.toFixed(2)} (${ageMinutes.toFixed(1)}分钟前)`)
- return midPrice
- }
- return 0
- } catch (error) {
- return 0
- }
- }
- getLastKnownPrice(symbol) {
- try {
- // 检查是否有缓存的orderbook价格
- const cacheKey = symbol
- const cached = this.orderbookPriceCache[cacheKey]
- if (cached && Date.now() - cached.timestamp < 120 * 1000) {
- // 延长到2分钟有效期
- const midPrice = (cached.bid + cached.ask) / 2
- return midPrice
- }
- // 如果没有缓存,触发异步获取
- this.updateOrderbookPriceAsync(symbol)
- // 返回BTC的保守估算价格,避免订单金额为0
- if (symbol.includes('BTC')) {
- console.log(`🔄 [估算价格] ${symbol}: $65000 (缓存过期)`)
- return 65000
- }
- return 0
- } catch (error) {
- // 错误时也返回估算价格
- if (symbol.includes('BTC')) {
- console.log(`⚠️ [错误价格] ${symbol}: $65000 (获取失败)`)
- return 65000
- }
- return 0
- }
- }
- async updateOrderbookPriceAsync(symbol) {
- console.log(`🔄 [价格获取] 开始获取 ${symbol} orderbook数据`)
- try {
- const client = this.accountManager.getFirstAvailableClient()
- console.log(`🔄 [价格获取] 获取到客户端:`, !!client, '有getOrderBook方法:', !!client?.getOrderBook)
- if (!client || !client.getOrderBook) {
- console.log(
- `⚠️ [价格获取] 客户端或getOrderBook方法不可用 - client: ${!!client}, getOrderBook: ${!!client?.getOrderBook}`,
- )
- return
- }
- // 调用正确的方法名
- const response = await client.getOrderBook(symbol, 5)
- if (!response) {
- console.log(`⚠️ [价格获取] orderbook响应为空`)
- return
- }
- // 原始orderbook数据已获取
- // 解析Pacifica API的orderbook格式
- const orderbook = this.parseOrderbookData(response)
- if (
- !orderbook ||
- !orderbook.bids ||
- !orderbook.asks ||
- orderbook.bids.length === 0 ||
- orderbook.asks.length === 0
- ) {
- console.log(`⚠️ [价格获取] orderbook数据解析后无效:`, orderbook)
- return
- }
- const bestBid = parseFloat(orderbook.bids[0].price)
- const bestAsk = parseFloat(orderbook.asks[0].price)
- if (!isNaN(bestBid) && !isNaN(bestAsk) && bestBid > 0 && bestAsk > 0) {
- this.orderbookPriceCache[symbol] = {
- bid: bestBid,
- ask: bestAsk,
- timestamp: Date.now(),
- }
- const midPrice = (bestBid + bestAsk) / 2
- console.log(`📊 [价格] ${symbol}: $${midPrice.toFixed(2)}`)
- }
- } catch (error) {
- logger.debug('更新orderbook价格失败', { symbol, error: error.message })
- }
- }
- /**
- * 预热orderbook价格缓存
- */
- async preloadOrderbookPrices() {
- const symbols = ['BTC-USD', 'BTCUSDT']
- for (const symbol of symbols) {
- try {
- await this.updateOrderbookPriceAsync(symbol)
- // 避免请求过快
- await new Promise(resolve => setTimeout(resolve, 200))
- } catch (error) {
- logger.debug('预热价格缓存失败', { symbol })
- }
- }
- console.log('📊 [价格缓存] orderbook价格缓存已预热')
- }
- /**
- * 解析Pacifica API的orderbook数据格式
- */
- parseOrderbookData(response) {
- try {
- const payload = response?.data ?? response
- // 格式1: payload.l = [bids[], asks[]] - 每个元素是 {p: price, a: amount, n: numOrders}
- if (Array.isArray(payload?.l) && payload.l.length >= 2) {
- const rawBids = Array.isArray(payload.l[0]) ? payload.l[0] : []
- const rawAsks = Array.isArray(payload.l[1]) ? payload.l[1] : []
- const bids = rawBids
- .map(lvl => ({
- price: String(lvl?.p ?? lvl?.price ?? ''),
- qty: String(lvl?.a ?? lvl?.amount ?? ''),
- }))
- .filter(x => x.price && x.qty && parseFloat(x.price) > 0)
- const asks = rawAsks
- .map(lvl => ({
- price: String(lvl?.p ?? lvl?.price ?? ''),
- qty: String(lvl?.a ?? lvl?.amount ?? ''),
- }))
- .filter(x => x.price && x.qty && parseFloat(x.price) > 0)
- if (bids.length > 0 && asks.length > 0) {
- return { bids, asks }
- }
- }
- // 格式2: Fallback - bids/asks 作为 [price, qty] 数组
- if (payload?.bids || payload?.asks) {
- const bids = (payload?.bids ?? [])
- .map(x => ({ price: String(x[0] ?? ''), qty: String(x[1] ?? '') }))
- .filter(x => x.price && x.qty && parseFloat(x.price) > 0)
- const asks = (payload?.asks ?? [])
- .map(x => ({ price: String(x[0] ?? ''), qty: String(x[1] ?? '') }))
- .filter(x => x.price && x.qty && parseFloat(x.price) > 0)
- if (bids.length > 0 && asks.length > 0) {
- return { bids, asks }
- }
- }
- // 格式3: 直接的bids/asks对象数组格式
- if (Array.isArray(payload?.bids) && Array.isArray(payload?.asks)) {
- const bids = payload.bids
- .map(x => ({
- price: String(x?.price ?? x?.p ?? ''),
- qty: String(x?.qty ?? x?.q ?? x?.amount ?? x?.a ?? ''),
- }))
- .filter(x => x.price && x.qty && parseFloat(x.price) > 0)
- const asks = payload.asks
- .map(x => ({
- price: String(x?.price ?? x?.p ?? ''),
- qty: String(x?.qty ?? x?.q ?? x?.amount ?? x?.a ?? ''),
- }))
- .filter(x => x.price && x.qty && parseFloat(x.price) > 0)
- if (bids.length > 0 && asks.length > 0) {
- return { bids, asks }
- }
- }
- console.log(`⚠️ [价格解析] 无法识别的orderbook格式:`, JSON.stringify(payload, null, 2))
- return null
- } catch (error) {
- console.log(`❌ [价格解析] orderbook解析出错:`, error.message)
- return null
- }
- }
- generateBalanceOrders(signal) {
- if (!signal.targetAccount) return []
- const amount = parseFloat(signal.amount)
- const side = signal.side === 'buy' ? 'bid' : 'ask'
- return [
- {
- accountId: signal.targetAccount,
- symbol: 'BTC-USD',
- amount,
- side: side,
- orderType: 'market',
- reason: `敞口平衡-${signal.side}-${amount}`,
- },
- ]
- }
- processHedgeResults(results, orders) {
- let successCount = 0
- results.forEach((result, index) => {
- if (result.success) {
- successCount++
- this.stats.successfulTrades++
- const order = orders[index]
- this.accountManager.updateTradeState(order.accountId, {
- side: order.side,
- amount: order.amount.toString(),
- success: true,
- })
- } else {
- this.stats.failedTrades++
- }
- })
- this.stats.totalTrades += results.length
- this.stats.lastTradeTime = Date.now()
- console.log(`🔄 对冲执行完成: ${successCount}/${results.length} 成功`)
- }
- processVolumeBoostResults(results, orders, amount) {
- let successCount = 0
- results.forEach((result, index) => {
- if (result.success) {
- successCount++
- console.log(`✅ 刷量订单${index + 1}成功: ${result.orderId || result.order_id || 'N/A'}`)
- this.stats.totalVolume += parseFloat(amount)
- const order = orders[index]
- this.accountManager.updateTradeState(order.accountId, {
- side: order.side,
- amount: order.amount.toString(),
- success: true,
- })
- } else {
- console.log(`❌ 刷量订单${index + 1}失败: ${result.error}`)
- }
- })
- this.stats.totalTrades += results.length
- this.stats.successfulTrades += successCount
- this.stats.failedTrades += results.length - successCount
- this.stats.lastTradeTime = Date.now()
- console.log(
- `⚡ 刷量执行完成: ${successCount}/${results.length} 成功 - 增加交易量: ${(
- parseFloat(amount) * successCount
- ).toFixed(4)} BTC`,
- )
- }
- /**
- * 动态使用率平衡机制 - 保持70-80%目标使用率
- */
- async executeUtilizationBalancing(accounts, maxUtilizationRate) {
- const targetMinUtilization = 0.7
- const targetMaxUtilization = 0.8
- try {
- // 检查是否需要动态平衡
- if (maxUtilizationRate >= targetMinUtilization && maxUtilizationRate <= targetMaxUtilization) {
- console.log(`🎯 [动态平衡] 使用率${(maxUtilizationRate * 100).toFixed(1)}%在目标范围(70-80%)内,保持当前状态`)
- return
- }
- if (maxUtilizationRate > targetMaxUtilization && maxUtilizationRate < 0.9) {
- // 超出目标上限但未达到危险级别:适度减仓
- console.log(`📉 [动态平衡] 使用率${(maxUtilizationRate * 100).toFixed(1)}%超出目标上限,执行适度减仓`)
- await this.executeModerateReduction(accounts, maxUtilizationRate)
- } else if (maxUtilizationRate < targetMinUtilization) {
- // 低于目标下限:适度增仓
- console.log(`📈 [动态平衡] 使用率${(maxUtilizationRate * 100).toFixed(1)}%低于目标下限,执行适度增仓`)
- await this.executeModerateIncrease(accounts, maxUtilizationRate)
- }
- } catch (error) {
- logger.error('动态使用率平衡失败', { error: error.message, maxUtilizationRate })
- }
- }
- /**
- * 执行双向同步减仓
- */
- async executeModerateReduction(accounts, utilizationRate) {
- if (!this.hedgeManager) return
- console.log(`🔄 [双向减仓] 开始执行双向同步减仓,当前使用率: ${(utilizationRate * 100).toFixed(1)}%`)
- // 获取两个主要账户状态
- const account1State = this.accountManager.getAccountState('pacifica-1')
- const account2State = this.accountManager.getAccountState('pacifica-2')
- if (!account1State || !account2State) {
- console.log('⚠️ [双向减仓] 账户状态不可用,跳过减仓')
- return
- }
- // 检查两个账户是否都有仓位
- const pos1 = Math.abs(account1State.netPosition)
- const pos2 = Math.abs(account2State.netPosition)
- if (pos1 < 0.0001 && pos2 < 0.0001) {
- console.log('ℹ️ [双向减仓] 当前无仓位,无需减仓')
- return
- }
- // 计算减仓数量 - 根据使用率动态调整
- let reductionRatio = 0.15 // 基础减仓比例15%
- if (utilizationRate >= 0.95) {
- reductionRatio = 0.3 // 高使用率时加大减仓比例
- } else if (utilizationRate >= 0.9) {
- reductionRatio = 0.2
- }
- const reduceAmount = Math.min(Math.max(pos1, pos2) * reductionRatio, 0.002)
- if (reduceAmount < 0.0001) {
- console.log('⚠️ [双向减仓] 计算的减仓数量过小,跳过')
- return
- }
- console.log(`📊 [双向减仓] 减仓数量: ${reduceAmount.toFixed(4)} BTC (比例: ${(reductionRatio * 100).toFixed(1)}%)`)
- // 同步双向减仓
- const reductionOrders = []
- // 账户1减仓
- if (pos1 > 0.0001) {
- const side1 = account1State.netPosition > 0 ? 'ask' : 'bid' // 平多仓用ask,平空仓用bid
- reductionOrders.push({
- accountId: 'pacifica-1',
- symbol: 'BTC-USD',
- amount: reduceAmount,
- side: side1,
- orderType: 'market',
- reason: `双向减仓-降低使用率`,
- })
- }
- // 账户2减仓
- if (pos2 > 0.0001) {
- const side2 = account2State.netPosition > 0 ? 'ask' : 'bid' // 平多仓用ask,平空仓用bid
- reductionOrders.push({
- accountId: 'pacifica-2',
- symbol: 'BTC-USD',
- amount: reduceAmount,
- side: side2,
- orderType: 'market',
- reason: `双向减仓-降低使用率`,
- })
- }
- if (reductionOrders.length > 0) {
- const results = await this.hedgeManager.executeBatchHedge(reductionOrders)
- console.log(`📉 [适度减仓] 执行${results.length}笔减仓订单,目标:降低使用率至70-80%`)
- }
- }
- /**
- * 执行适度增仓
- */
- async executeModerateIncrease(accounts, utilizationRate) {
- if (!this.hedgeManager) return
- // 找到有可用余额的账户进行增仓
- const availableAccounts = accounts
- .filter(account => account.availableBalance > 5) // 至少有5美元可用余额
- .sort((a, b) => b.availableBalance - a.availableBalance)
- .slice(0, 2) // 取前两个最有资金的账户
- const increaseOrders = []
- for (const account of availableAccounts) {
- const maxIncrease = Math.min((account.availableBalance * 0.1) / 65000, 0.0008) // 使用10%可用余额,最多0.0008 BTC
- if (maxIncrease >= 0.0001) {
- const increaseAction = Math.random() > 0.5 ? 'bid' : 'ask'
- increaseOrders.push({
- accountId: account.id || 'pacifica-1',
- symbol: 'BTC-USD',
- amount: maxIncrease,
- side: increaseAction,
- orderType: 'market',
- reason: `适度增仓-提升使用率至目标范围`,
- })
- }
- }
- if (increaseOrders.length > 0) {
- const results = await this.hedgeManager.executeBatchHedge(increaseOrders)
- console.log(`📈 [适度增仓] 执行${results.length}笔增仓订单,目标:提升使用率至70-80%`)
- }
- }
- /**
- * 紧急双向减仓
- */
- async executeEmergencyReduction(accounts, utilizationRate) {
- if (!this.hedgeManager) return
- console.log(`🚨 [紧急减仓] 执行大幅双向减仓,使用率: ${(utilizationRate * 100).toFixed(1)}%`)
- // 获取两个主要账户状态
- const account1State = this.accountManager.getAccountState('pacifica-1')
- const account2State = this.accountManager.getAccountState('pacifica-2')
- if (!account1State || !account2State) {
- console.log('⚠️ [紧急减仓] 账户状态不可用,跳过减仓')
- return
- }
- const pos1 = Math.abs(account1State.netPosition)
- const pos2 = Math.abs(account2State.netPosition)
- if (pos1 < 0.0001 && pos2 < 0.0001) {
- console.log('ℹ️ [紧急减仓] 当前无仓位,无需减仓')
- return
- }
- // 紧急减仓:减少50%仓位
- const reductionRatio = 0.5
- const reduceAmount = Math.min(Math.max(pos1, pos2) * reductionRatio, 0.003)
- if (reduceAmount < 0.0001) {
- console.log('⚠️ [紧急减仓] 计算的减仓数量过小,跳过')
- return
- }
- console.log(
- `🚨 [紧急减仓] 大幅减仓数量: ${reduceAmount.toFixed(4)} BTC (比例: ${(reductionRatio * 100).toFixed(1)}%)`,
- )
- // 同步双向减仓
- const emergencyOrders = []
- // 账户1减仓
- if (pos1 > 0.0001) {
- const side1 = account1State.netPosition > 0 ? 'ask' : 'bid'
- emergencyOrders.push({
- accountId: 'pacifica-1',
- symbol: 'BTC-USD',
- amount: reduceAmount,
- side: side1,
- orderType: 'market',
- reason: `紧急双向减仓-降低高使用率`,
- })
- }
- // 账户2减仓
- if (pos2 > 0.0001) {
- const side2 = account2State.netPosition > 0 ? 'ask' : 'bid'
- emergencyOrders.push({
- accountId: 'pacifica-2',
- symbol: 'BTC-USD',
- amount: reduceAmount,
- side: side2,
- orderType: 'market',
- reason: `紧急双向减仓-降低高使用率`,
- })
- }
- if (emergencyOrders.length > 0) {
- try {
- const results = await this.hedgeManager.executeBatchHedge(emergencyOrders)
- console.log(`🚨 [紧急减仓] 执行${results.length}笔紧急减仓订单`)
- } catch (error) {
- logger.error('紧急减仓执行失败', { error: error.message })
- }
- }
- }
- /**
- * 执行降低使用率策略
- */
- async executeUtilizationReduction(account, utilizationRate) {
- if (!account || !this.hedgeManager) return
- try {
- console.log(`📉 [紧急降低使用率] 开始处理账户使用率: ${(utilizationRate * 100).toFixed(1)}%`)
- // 紧急情况下执行大幅双向减仓
- const accounts = Array.from(this.accountManager.getAllAccountStates().values())
- await this.executeEmergencyReduction(accounts, utilizationRate)
- // 策略2: 暂时降低交易频率
- if (utilizationRate >= 0.95) {
- console.log(`⏸️ [使用率控制] 极高使用率(${(utilizationRate * 100).toFixed(1)}%),暂停10秒交易`)
- await new Promise(resolve => setTimeout(resolve, 10000))
- } else if (utilizationRate >= 0.9) {
- console.log(`⏸️ [使用率控制] 高使用率(${(utilizationRate * 100).toFixed(1)}%),暂停5秒交易`)
- await new Promise(resolve => setTimeout(resolve, 5000))
- }
- // 策略3: 动态调整交易规模
- await this.adjustTradingSizeForUtilization(utilizationRate)
- } catch (error) {
- logger.error('执行降低使用率策略失败', { error: error.message, utilizationRate })
- }
- }
- /**
- * 根据使用率动态调整交易规模和策略
- */
- async adjustTradingSizeForUtilization(utilizationRate) {
- // 目标使用率范围:70-80%
- const targetMinUtilization = 0.7
- const targetMaxUtilization = 0.8
- if (utilizationRate >= 0.9) {
- // 过高使用率:强制减仓
- this.riskLimits.maxPositionSize = 0.002
- console.log(`📊 [使用率控制] 过高使用率${(utilizationRate * 100).toFixed(1)}%,执行强制减仓`)
- await this.executeUtilizationRebalance('reduce', utilizationRate)
- } else if (utilizationRate > targetMaxUtilization) {
- // 超出目标上限:适度减仓
- this.riskLimits.maxPositionSize = 0.005
- console.log(`📊 [使用率控制] 超出目标上限${(utilizationRate * 100).toFixed(1)}%,执行适度减仓`)
- await this.executeUtilizationRebalance('reduce', utilizationRate)
- } else if (utilizationRate >= targetMinUtilization && utilizationRate <= targetMaxUtilization) {
- // 目标范围内:保持平衡
- this.riskLimits.maxPositionSize = 0.007
- console.log(`🎯 [动态平衡] 使用率${(utilizationRate * 100).toFixed(1)}%在目标范围(70-80%)内`)
- } else if (utilizationRate >= 0.5) {
- // 低于目标:适度增仓
- this.riskLimits.maxPositionSize = 0.008
- console.log(`📈 [使用率控制] 使用率${(utilizationRate * 100).toFixed(1)}%偏低,执行适度增仓`)
- await this.executeUtilizationRebalance('increase', utilizationRate)
- } else {
- // 使用率过低:积极增仓
- this.riskLimits.maxPositionSize = 0.01
- console.log(`🚀 [使用率控制] 使用率${(utilizationRate * 100).toFixed(1)}%过低,执行积极增仓`)
- await this.executeUtilizationRebalance('increase', utilizationRate)
- }
- }
- /**
- * 执行使用率再平衡操作
- */
- async executeUtilizationRebalance(action, currentUtilization) {
- try {
- const accounts = await this.accountManager.getAllAccountStates()
- const targetUtilization = 0.75 // 目标使用率75%
- for (const [accountId, state] of Object.entries(accounts)) {
- if (state.lastBalance <= 0) continue
- const utilizationRate = Math.abs(state.lastBalance - state.availableBalance) / state.lastBalance
- if (action === 'reduce' && utilizationRate > 0.8) {
- // 减仓:通过平仓部分仓位来降低使用率
- const targetReduction = (utilizationRate - targetUtilization) * state.lastBalance
- const positionToClose = Math.min(
- targetReduction / (await this.getCurrentPriceSync('BTC-USD')),
- Math.abs(state.netPosition) * 0.3,
- )
- if (positionToClose > 0.00001) {
- // 至少0.00001 BTC才值得平仓
- console.log(
- `📉 [减仓操作] ${accountId}: 当前使用率${(utilizationRate * 100).toFixed(
- 1,
- )}% → 目标75%, 平仓${positionToClose.toFixed(5)} BTC`,
- )
- const signal = await this.generateTradeSignal({
- accountId,
- symbol: 'BTC-USD',
- action: 'close',
- amount: positionToClose.toFixed(5),
- side: state.netPosition > 0 ? 'ask' : 'bid',
- reason: `使用率控制平仓 - 当前${(utilizationRate * 100).toFixed(1)}%`,
- })
- if (signal) {
- await this.executeHedgeSignal(signal)
- }
- }
- } else if (action === 'increase' && utilizationRate < 0.7) {
- // 增仓:通过开仓来提高使用率
- const targetIncrease = (targetUtilization - utilizationRate) * state.lastBalance
- const positionToOpen = targetIncrease / (await this.getCurrentPriceSync('BTC-USD'))
- if (positionToOpen > 0.00001 && state.availableBalance > 15) {
- // 确保有足够余额
- console.log(
- `📈 [增仓操作] ${accountId}: 当前使用率${(utilizationRate * 100).toFixed(
- 1,
- )}% → 目标75%, 开仓${positionToOpen.toFixed(5)} BTC`,
- )
- const signal = await this.generateTradeSignal({
- accountId,
- symbol: 'BTC-USD',
- action: 'open',
- amount: positionToOpen.toFixed(5),
- side: Math.random() > 0.5 ? 'bid' : 'ask',
- reason: `使用率控制开仓 - 当前${(utilizationRate * 100).toFixed(1)}%`,
- })
- if (signal) {
- await this.executeHedgeSignal(signal)
- }
- }
- }
- }
- } catch (error) {
- logger.error('执行使用率再平衡失败', { action, currentUtilization, error: error.message })
- }
- }
- /**
- * 检查是否因使用率过高需要跳过交易
- */
- shouldSkipTradeForUtilization() {
- const accounts = Array.from(this.accountManager.getAllAccountStates().values())
- let maxUtilizationRate = 0
- let highUtilizationAccount = null
- accounts.forEach(account => {
- if (account.lastBalance > 0) {
- const utilizationRate = Math.abs(account.lastBalance - account.availableBalance) / account.lastBalance
- if (utilizationRate > maxUtilizationRate) {
- maxUtilizationRate = utilizationRate
- highUtilizationAccount = account
- }
- }
- })
- if (maxUtilizationRate >= 0.95) {
- console.log(`🚨 [使用率控制] 使用率${(maxUtilizationRate * 100).toFixed(1)}%过高,启动主动降低机制`)
- // 主动执行降低使用率操作,而不是仅仅跳过交易
- this.executeEmergencyUtilizationReduction(highUtilizationAccount, maxUtilizationRate).catch(error => {
- logger.error('紧急降低使用率失败', { error: error.message })
- })
- return true // 仍然跳过常规交易,但已触发降低机制
- }
- return false
- }
- /**
- * 紧急降低使用率机制 - 当使用率>=95%时触发
- */
- async executeEmergencyUtilizationReduction(account, utilizationRate) {
- console.log(`🚨 [紧急使用率控制] 启动主动降低机制,当前使用率: ${(utilizationRate * 100).toFixed(1)}%`)
- // 直接调用现有的强力降低使用率方法
- await this.executeUtilizationReduction(account, utilizationRate)
- console.log(`✅ [紧急使用率控制] 主动降低机制执行完成`)
- }
- getStats() {
- return { ...this.stats }
- }
- }
|