import { FutureConnector } from '../../src/exchanges/binance/FutureConnector' import { TestHelpers } from '../utils/testHelpers' const describeBinancePerf = process.env.TEST_BINANCE === '1' ? describe : describe.skip // Mock Binance API client jest.mock('@binance/derivatives-trading-usds-futures', () => ({ DERIVATIVES_TRADING_USDS_FUTURES_REST_API_PROD_URL: 'https://fapi.binance.com', DerivativesTradingUsdsFutures: jest.fn(), DerivativesTradingUsdsFuturesRestAPI: { NewOrderSideEnum: { BUY: 'BUY', SELL: 'SELL', }, NewOrderPositionSideEnum: { LONG: 'LONG', SHORT: 'SHORT', BOTH: 'BOTH', }, NewOrderTimeInForceEnum: { GTC: 'GTC', IOC: 'IOC', FOK: 'FOK', GTX: 'GTX', GTD: 'GTD', }, NewOrderNewOrderRespTypeEnum: { ACK: 'ACK', RESULT: 'RESULT', FULL: 'FULL', }, ChangeMarginTypeMarginTypeEnum: { ISOLATED: 'ISOLATED', CROSSED: 'CROSSED', }, ModifyOrderSideEnum: { BUY: 'BUY', SELL: 'SELL', }, }, })) // 性能测试 describeBinancePerf('FutureConnector Performance Tests', () => { let connector: FutureConnector let mockClient: any beforeEach(() => { // 创建模拟的 API 客户端 mockClient = { restAPI: { accountInformationV3: jest.fn(), newOrder: jest.fn(), currentAllOpenOrders: jest.fn(), allOrders: jest.fn(), accountTradeList: jest.fn(), }, } // Mock 构造函数 const { DerivativesTradingUsdsFutures } = require('@binance/derivatives-trading-usds-futures') DerivativesTradingUsdsFutures.mockImplementation(() => mockClient) connector = new FutureConnector('test-api-key', 'test-api-secret') }) afterEach(() => { jest.clearAllMocks() }) describe('API Response Time', () => { test('should handle fast API responses', async () => { const startTime = Date.now() mockClient.restAPI.accountInformationV3.mockResolvedValue({ data: jest.fn().mockResolvedValue({ assets: TestHelpers.createMockAssets(), positions: TestHelpers.createMockPositions(), }), }) const result = await connector.getAssetsInfo() const endTime = Date.now() const responseTime = endTime - startTime expect(result).toBeDefined() expect(responseTime).toBeLessThan(1000) // 应该在1秒内完成 }) test('should handle slow API responses gracefully', async () => { const startTime = Date.now() // 模拟慢速 API 响应 mockClient.restAPI.accountInformationV3.mockImplementation(() => { return new Promise(resolve => { setTimeout(() => { resolve({ data: jest.fn().mockResolvedValue({ assets: TestHelpers.createMockAssets(), positions: TestHelpers.createMockPositions(), }), }) }, 2000) // 2秒延迟 }) }) const result = await connector.getAssetsInfo() const endTime = Date.now() const responseTime = endTime - startTime expect(result).toBeDefined() expect(responseTime).toBeGreaterThanOrEqual(2000) }) }) describe('Concurrent API Calls', () => { test('should handle multiple concurrent getAssetsInfo calls', async () => { const mockData = { assets: TestHelpers.createMockAssets(), positions: TestHelpers.createMockPositions(), } mockClient.restAPI.accountInformationV3.mockResolvedValue({ data: jest.fn().mockResolvedValue(mockData), }) const startTime = Date.now() // 并发调用 10 次 const promises = Array.from({ length: 10 }, () => connector.getAssetsInfo()) const results = await Promise.all(promises) const endTime = Date.now() const totalTime = endTime - startTime expect(results).toHaveLength(10) results.forEach(result => { expect(result).toEqual(mockData.assets.filter(asset => Number(asset.walletBalance) > 0)) }) // 验证 API 被调用了 10 次 expect(mockClient.restAPI.accountInformationV3).toHaveBeenCalledTimes(10) console.log(`并发调用 10 次 getAssetsInfo 总耗时: ${totalTime}ms`) }) test('should handle concurrent order operations', async () => { const mockOrderResult = TestHelpers.createMockOrderResult(12345, 'NEW') mockClient.restAPI.newOrder.mockResolvedValue({ data: jest.fn().mockResolvedValue(mockOrderResult), }) const startTime = Date.now() // 并发创建 5 个订单 const promises = Array.from({ length: 5 }, (_, index) => connector.openLimitOrder( 'BTCUSDT', 'long', 0.001, 50000 + index, // 不同的价格 'GTC', ), ) const results = await Promise.all(promises) const endTime = Date.now() const totalTime = endTime - startTime expect(results).toHaveLength(5) results.forEach(result => { expect(result).toEqual(mockOrderResult) }) expect(mockClient.restAPI.newOrder).toHaveBeenCalledTimes(5) console.log(`并发创建 5 个订单总耗时: ${totalTime}ms`) }) }) describe('Memory Usage', () => { test('should not leak memory with repeated API calls', async () => { const initialMemory = process.memoryUsage() mockClient.restAPI.accountInformationV3.mockResolvedValue({ data: jest.fn().mockResolvedValue({ assets: TestHelpers.createMockAssets(), positions: TestHelpers.createMockPositions(), }), }) // 执行 100 次 API 调用 for (let i = 0; i < 100; i++) { await connector.getAssetsInfo() } const finalMemory = process.memoryUsage() const memoryIncrease = finalMemory.heapUsed - initialMemory.heapUsed // 内存增长应该在合理范围内(小于 10MB) expect(memoryIncrease).toBeLessThan(10 * 1024 * 1024) console.log(`100 次 API 调用内存增长: ${(memoryIncrease / 1024 / 1024).toFixed(2)}MB`) }) }) describe('Error Recovery', () => { test('should handle API errors without performance degradation', async () => { let callCount = 0 mockClient.restAPI.accountInformationV3.mockImplementation(() => { callCount++ if (callCount <= 3) { // 前 3 次调用失败 return Promise.reject(new Error('API Error')) } else { // 后续调用成功 return Promise.resolve({ data: jest.fn().mockResolvedValue({ assets: TestHelpers.createMockAssets(), positions: TestHelpers.createMockPositions(), }), }) } }) const startTime = Date.now() // 重试机制应该能够处理错误 const result = await TestHelpers.retry( () => connector.getAssetsInfo(), 5, // 最多重试 5 次 100, // 每次重试间隔 100ms ) const endTime = Date.now() const totalTime = endTime - startTime expect(result).toBeDefined() expect(callCount).toBeGreaterThan(3) console.log(`错误恢复测试总耗时: ${totalTime}ms, API 调用次数: ${callCount}`) }) }) describe('Large Data Handling', () => { test('should handle large position data efficiently', async () => { // 创建大量持仓数据 const largePositions = Array.from({ length: 1000 }, (_, index) => ({ symbol: `SYMBOL${index}USDT`, positionAmt: (Math.random() * 100).toString(), unrealizedPnl: (Math.random() * 1000 - 500).toString(), entryPrice: (Math.random() * 100000).toString(), leverage: '10', isolated: false, initialMargin: '0.1', maintMargin: '0.1', positionInitialMargin: '0.1', openOrderInitialMargin: '0.0', maxNotional: '1000000', bidNotional: '0', askNotional: '0', positionSide: 'BOTH', updateTime: Date.now(), })) mockClient.restAPI.accountInformationV3.mockResolvedValue({ data: jest.fn().mockResolvedValue({ assets: TestHelpers.createMockAssets(), positions: largePositions, }), }) const startTime = Date.now() const result = await connector.getPositonInfo() const endTime = Date.now() const processingTime = endTime - startTime expect(result).toBeDefined() expect(Array.isArray(result)).toBe(true) // 处理 1000 条数据应该在合理时间内完成 expect(processingTime).toBeLessThan(5000) // 5秒内 console.log(`处理 1000 条持仓数据耗时: ${processingTime}ms`) }) test('should handle large order history efficiently', async () => { // 创建大量订单数据 const largeOrders = Array.from({ length: 500 }, (_, index) => ({ orderId: 10000 + index, symbol: 'BTCUSDT', status: index % 2 === 0 ? 'FILLED' : 'CANCELED', clientOrderId: `test_order_${index}`, price: (50000 + Math.random() * 1000).toString(), avgPrice: (50000 + Math.random() * 1000).toString(), origQty: (0.001 + Math.random() * 0.01).toString(), executedQty: (0.001 + Math.random() * 0.01).toString(), cumQuote: (50 + Math.random() * 100).toString(), timeInForce: 'GTC', type: index % 3 === 0 ? 'LIMIT' : 'MARKET', reduceOnly: false, closePosition: false, side: index % 2 === 0 ? 'BUY' : 'SELL', positionSide: 'LONG', stopPrice: '0', workingType: 'CONTRACT_PRICE', priceProtect: false, origType: index % 3 === 0 ? 'LIMIT' : 'MARKET', time: Date.now() - Math.random() * 86400000, // 过去24小时内 updateTime: Date.now() - Math.random() * 86400000, })) mockClient.restAPI.allOrders.mockResolvedValue({ data: jest.fn().mockResolvedValue(largeOrders), }) const startTime = Date.now() const result = await connector.getOrderHistory('BTCUSDT') const endTime = Date.now() const processingTime = endTime - startTime expect(result).toBeDefined() expect(Array.isArray(result)).toBe(true) expect(result).toHaveLength(500) // 处理 500 条订单数据应该在合理时间内完成 expect(processingTime).toBeLessThan(3000) // 3秒内 console.log(`处理 500 条订单历史耗时: ${processingTime}ms`) }) }) describe('Rate Limiting Simulation', () => { test('should handle rate limiting gracefully', async () => { let callCount = 0 const rateLimitDelay = 100 // 模拟 100ms 的速率限制 mockClient.restAPI.accountInformationV3.mockImplementation(() => { callCount++ return new Promise(resolve => { setTimeout(() => { resolve({ data: jest.fn().mockResolvedValue({ assets: TestHelpers.createMockAssets(), positions: TestHelpers.createMockPositions(), }), }) }, rateLimitDelay) }) }) const startTime = Date.now() // 连续调用 10 次 const promises = Array.from({ length: 10 }, () => connector.getAssetsInfo()) const results = await Promise.all(promises) const endTime = Date.now() const totalTime = endTime - startTime expect(results).toHaveLength(10) // 由于速率限制,总时间应该接近 10 * 100ms = 1000ms expect(totalTime).toBeGreaterThanOrEqual(rateLimitDelay * 10 * 0.8) // 允许 20% 的误差 console.log(`速率限制测试总耗时: ${totalTime}ms, 预期: ${rateLimitDelay * 10}ms`) }) }) })