123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135 |
- #!/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);
|