reduce-positions.ts 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. #!/usr/bin/env tsx
  2. /**
  3. * 手动减仓脚本
  4. * 用于紧急情况下快速降低保证金使用率
  5. */
  6. import { PacificaAPIService } from '../src/services/PacificaAPIService';
  7. import { readFileSync } from 'fs';
  8. import { v4 as uuidv4 } from 'uuid';
  9. interface AccountConfig {
  10. name: string;
  11. privateKey: string;
  12. publicKey: string;
  13. }
  14. async function reducePositions() {
  15. console.log('🚨 紧急减仓程序启动...\n');
  16. // 减仓比例
  17. const REDUCTION_RATIO = 0.5; // 50%
  18. // 加载账户配置
  19. const accountsConfig: AccountConfig[] = JSON.parse(
  20. readFileSync('./config/accounts.json', 'utf-8')
  21. );
  22. for (const accountConfig of accountsConfig) {
  23. console.log(`\n${'='.repeat(60)}`);
  24. console.log(`📋 处理账户: ${accountConfig.name}`);
  25. console.log(`${'='.repeat(60)}\n`);
  26. const apiService = new PacificaAPIService(accountConfig.privateKey);
  27. try {
  28. // 获取账户信息
  29. const accountInfo = await apiService.getAccountInfo();
  30. const equity = parseFloat(accountInfo.account_equity);
  31. const marginUsed = parseFloat(accountInfo.total_margin_used);
  32. const marginUsagePercent = equity > 0 ? (marginUsed / equity * 100).toFixed(2) : 'N/A';
  33. console.log(`💰 当前保证金使用率: ${marginUsagePercent}%`);
  34. console.log(` 账户权益: ${equity.toFixed(2)} USDC`);
  35. console.log(` 已使用保证金: ${marginUsed.toFixed(2)} USDC\n`);
  36. // 获取持仓
  37. const positions = await apiService.getPositions();
  38. if (positions.length === 0) {
  39. console.log('✅ 没有持仓需要减仓\n');
  40. continue;
  41. }
  42. console.log(`📈 当前持仓数量: ${positions.length}`);
  43. console.log(`📉 将减仓 ${(REDUCTION_RATIO * 100).toFixed(0)}%\n`);
  44. // 对每个持仓执行减仓
  45. for (const position of positions) {
  46. const originalAmount = parseFloat(position.amount);
  47. const rawReduceAmount = originalAmount * REDUCTION_RATIO;
  48. // 确保满足最小订单要求和 lot size 倍数
  49. const LOT_SIZE = 0.00001;
  50. const MIN_ORDER_SIZE = 0.00001;
  51. // 向下取整到 lot size 的倍数
  52. const reduceAmount = Math.floor(rawReduceAmount / LOT_SIZE) * LOT_SIZE;
  53. if (reduceAmount < MIN_ORDER_SIZE) {
  54. console.log(`⚠️ ${position.symbol} 持仓太小,跳过减仓`);
  55. continue;
  56. }
  57. try {
  58. console.log(`🔄 ${position.symbol}:`);
  59. console.log(` 当前仓位: ${originalAmount} (${position.side === 'bid' ? '多' : '空'})`);
  60. console.log(` 减仓数量: ${reduceAmount.toFixed(5)}`);
  61. // 平仓订单:使用相反方向的市价单
  62. const closeSide = position.side === 'bid' ? 'ask' : 'bid';
  63. // 格式化amount,去掉多余的0
  64. const formattedAmount = parseFloat(reduceAmount.toFixed(5)).toString();
  65. const order = {
  66. symbol: position.symbol,
  67. amount: formattedAmount,
  68. side: closeSide,
  69. slippage_percent: '1.0', // 紧急平仓,允许较大滑点
  70. reduce_only: true,
  71. client_order_id: uuidv4()
  72. };
  73. const result = await apiService.createMarketOrder(order);
  74. console.log(` ✅ 减仓成功!`);
  75. console.log(` 订单ID: ${result.order_id || 'N/A'}`);
  76. // 短暂延迟避免API限流
  77. await new Promise(resolve => setTimeout(resolve, 2000));
  78. } catch (error) {
  79. console.error(` ❌ 减仓失败:`, error instanceof Error ? error.message : error);
  80. }
  81. }
  82. // 再次检查保证金使用率
  83. await new Promise(resolve => setTimeout(resolve, 2000));
  84. const updatedAccountInfo = await apiService.getAccountInfo();
  85. const updatedEquity = parseFloat(updatedAccountInfo.account_equity);
  86. const updatedMarginUsed = parseFloat(updatedAccountInfo.total_margin_used);
  87. const updatedMarginUsagePercent = updatedEquity > 0
  88. ? (updatedMarginUsed / updatedEquity * 100).toFixed(2)
  89. : 'N/A';
  90. console.log(`\n✅ 减仓完成`);
  91. console.log(` 新的保证金使用率: ${updatedMarginUsagePercent}%`);
  92. console.log(` 账户权益: ${updatedEquity.toFixed(2)} USDC`);
  93. console.log(` 已使用保证金: ${updatedMarginUsed.toFixed(2)} USDC`);
  94. } catch (error) {
  95. console.error(`❌ 处理账户失败:`, error instanceof Error ? error.message : error);
  96. }
  97. // 延迟避免限流
  98. await new Promise(resolve => setTimeout(resolve, 3000));
  99. }
  100. console.log(`\n${'='.repeat(60)}`);
  101. console.log('✅ 减仓程序完成');
  102. console.log(`${'='.repeat(60)}\n`);
  103. }
  104. reducePositions().catch(console.error);