| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371 |
- 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`)
- })
- })
- })
|