#!/usr/bin/env tsx /** * 手动减仓脚本 * 用于紧急情况下快速降低保证金使用率 */ import { PacificaAPIService } from '../src/services/PacificaAPIService'; import { readFileSync } from 'fs'; import { v4 as uuidv4 } from 'uuid'; interface AccountConfig { name: string; privateKey: string; publicKey: string; } async function reducePositions() { console.log('🚨 紧急减仓程序启动...\n'); // 减仓比例 const REDUCTION_RATIO = 0.5; // 50% // 加载账户配置 const accountsConfig: AccountConfig[] = JSON.parse( readFileSync('./config/accounts.json', 'utf-8') ); for (const accountConfig of accountsConfig) { console.log(`\n${'='.repeat(60)}`); console.log(`📋 处理账户: ${accountConfig.name}`); console.log(`${'='.repeat(60)}\n`); const apiService = new PacificaAPIService(accountConfig.privateKey); try { // 获取账户信息 const accountInfo = await apiService.getAccountInfo(); const equity = parseFloat(accountInfo.account_equity); const marginUsed = parseFloat(accountInfo.total_margin_used); const marginUsagePercent = equity > 0 ? (marginUsed / equity * 100).toFixed(2) : 'N/A'; console.log(`💰 当前保证金使用率: ${marginUsagePercent}%`); console.log(` 账户权益: ${equity.toFixed(2)} USDC`); console.log(` 已使用保证金: ${marginUsed.toFixed(2)} USDC\n`); // 获取持仓 const positions = await apiService.getPositions(); if (positions.length === 0) { console.log('✅ 没有持仓需要减仓\n'); continue; } console.log(`📈 当前持仓数量: ${positions.length}`); console.log(`📉 将减仓 ${(REDUCTION_RATIO * 100).toFixed(0)}%\n`); // 对每个持仓执行减仓 for (const position of positions) { const originalAmount = parseFloat(position.amount); const rawReduceAmount = originalAmount * REDUCTION_RATIO; // 确保满足最小订单要求和 lot size 倍数 const LOT_SIZE = 0.00001; const MIN_ORDER_SIZE = 0.00001; // 向下取整到 lot size 的倍数 const reduceAmount = Math.floor(rawReduceAmount / LOT_SIZE) * LOT_SIZE; if (reduceAmount < MIN_ORDER_SIZE) { console.log(`⚠️ ${position.symbol} 持仓太小,跳过减仓`); continue; } try { console.log(`🔄 ${position.symbol}:`); console.log(` 当前仓位: ${originalAmount} (${position.side === 'bid' ? '多' : '空'})`); console.log(` 减仓数量: ${reduceAmount.toFixed(5)}`); // 平仓订单:使用相反方向的市价单 const closeSide = position.side === 'bid' ? 'ask' : 'bid'; // 格式化amount,去掉多余的0 const formattedAmount = parseFloat(reduceAmount.toFixed(5)).toString(); const order = { symbol: position.symbol, amount: formattedAmount, side: closeSide, slippage_percent: '1.0', // 紧急平仓,允许较大滑点 reduce_only: true, client_order_id: uuidv4() }; const result = await apiService.createMarketOrder(order); console.log(` ✅ 减仓成功!`); console.log(` 订单ID: ${result.order_id || 'N/A'}`); // 短暂延迟避免API限流 await new Promise(resolve => setTimeout(resolve, 2000)); } catch (error) { console.error(` ❌ 减仓失败:`, error instanceof Error ? error.message : error); } } // 再次检查保证金使用率 await new Promise(resolve => setTimeout(resolve, 2000)); const updatedAccountInfo = await apiService.getAccountInfo(); const updatedEquity = parseFloat(updatedAccountInfo.account_equity); const updatedMarginUsed = parseFloat(updatedAccountInfo.total_margin_used); const updatedMarginUsagePercent = updatedEquity > 0 ? (updatedMarginUsed / updatedEquity * 100).toFixed(2) : 'N/A'; console.log(`\n✅ 减仓完成`); console.log(` 新的保证金使用率: ${updatedMarginUsagePercent}%`); console.log(` 账户权益: ${updatedEquity.toFixed(2)} USDC`); console.log(` 已使用保证金: ${updatedMarginUsed.toFixed(2)} USDC`); } catch (error) { console.error(`❌ 处理账户失败:`, error instanceof Error ? error.message : error); } // 延迟避免限流 await new Promise(resolve => setTimeout(resolve, 3000)); } console.log(`\n${'='.repeat(60)}`); console.log('✅ 减仓程序完成'); console.log(`${'='.repeat(60)}\n`); } reducePositions().catch(console.error);