/** * Performance tests for order execution latency * Tests that order execution meets the <100ms requirement */ import { HedgingManager } from '../../src/core/HedgingManager'; import { OrderCoordinator } from '../../src/core/OrderCoordinator'; import { HedgingOrderExecutorAdapter } from '../../src/core/HedgingOrderExecutorAdapter'; import { HedgingSessionRequest, HedgingOrder } from '../../src/types/hedging'; import { Logger } from '../../src/utils/Logger'; // Mock dependencies jest.mock('../../src/utils/Logger'); jest.mock('../../src/core/RiskManager'); jest.mock('../../src/core/HedgingStrategyEngine'); jest.mock('../../src/core/HedgingConfigManager'); jest.mock('../../src/core/OrderExecutor'); describe('Order Execution Performance Tests', () => { let hedgingManager: HedgingManager; let orderCoordinator: OrderCoordinator; let orderExecutorAdapter: HedgingOrderExecutorAdapter; let mockConfig: any; beforeEach(() => { mockConfig = { maxConcurrentSessions: 10, sessionTimeout: 60000, riskCheckInterval: 1000 }; hedgingManager = new HedgingManager(mockConfig); orderCoordinator = new OrderCoordinator({ maxConcurrentOrders: 20, orderTimeout: 30000, retryAttempts: 3, retryDelay: 1000 }); }); afterEach(() => { jest.clearAllMocks(); }); describe('Order Execution Latency Tests', () => { beforeEach(async () => { await hedgingManager.initialize(); await orderCoordinator.initialize(); }); it('should execute single order pair within 100ms', async () => { const hedgingOrder: HedgingOrder = { id: 'perf-test-order', sessionId: 'perf-test-session', strategyId: 'perf-test-strategy', orderPair: { buyOrder: { accountId: 'account1', side: 'buy', type: 'limit', size: 100, price: 2500 }, sellOrder: { accountId: 'account2', side: 'sell', type: 'limit', size: 100, price: 2500 } }, status: 'pending', fees: 0, slippage: 0, createdAt: new Date(), updatedAt: new Date() }; const startTime = performance.now(); const result = await orderCoordinator.executeHedgingOrderPair(hedgingOrder); const endTime = performance.now(); const executionTime = endTime - startTime; expect(executionTime).toBeLessThan(100); // Must be under 100ms expect(result).toBeDefined(); expect(result.success).toBeDefined(); console.log(`Single order pair execution time: ${executionTime.toFixed(2)}ms`); }); it('should execute multiple order pairs concurrently within 100ms', async () => { const orders: HedgingOrder[] = []; // Create 5 concurrent orders for (let i = 0; i < 5; i++) { orders.push({ id: `perf-concurrent-order-${i}`, sessionId: 'perf-concurrent-session', strategyId: 'perf-concurrent-strategy', orderPair: { buyOrder: { accountId: `account${i * 2 + 1}`, side: 'buy', type: 'limit', size: 100, price: 2500 }, sellOrder: { accountId: `account${i * 2 + 2}`, side: 'sell', type: 'limit', size: 100, price: 2500 } }, status: 'pending', fees: 0, slippage: 0, createdAt: new Date(), updatedAt: new Date() }); } const startTime = performance.now(); const results = await Promise.all( orders.map(order => orderCoordinator.executeHedgingOrderPair(order)) ); const endTime = performance.now(); const executionTime = endTime - startTime; expect(executionTime).toBeLessThan(100); // Must be under 100ms expect(results).toHaveLength(5); results.forEach(result => { expect(result).toBeDefined(); expect(result.success).toBeDefined(); }); console.log(`5 concurrent order pairs execution time: ${executionTime.toFixed(2)}ms`); }); it('should execute 10 order pairs within 100ms', async () => { const orders: HedgingOrder[] = []; // Create 10 orders for (let i = 0; i < 10; i++) { orders.push({ id: `perf-batch-order-${i}`, sessionId: 'perf-batch-session', strategyId: 'perf-batch-strategy', orderPair: { buyOrder: { accountId: `account${i * 2 + 1}`, side: 'buy', type: 'limit', size: 100, price: 2500 }, sellOrder: { accountId: `account${i * 2 + 2}`, side: 'sell', type: 'limit', size: 100, price: 2500 } }, status: 'pending', fees: 0, slippage: 0, createdAt: new Date(), updatedAt: new Date() }); } const startTime = performance.now(); const results = await Promise.all( orders.map(order => orderCoordinator.executeHedgingOrderPair(order)) ); const endTime = performance.now(); const executionTime = endTime - startTime; expect(executionTime).toBeLessThan(100); // Must be under 100ms expect(results).toHaveLength(10); results.forEach(result => { expect(result).toBeDefined(); expect(result.success).toBeDefined(); }); console.log(`10 order pairs execution time: ${executionTime.toFixed(2)}ms`); }); it('should execute 20 order pairs within 100ms', async () => { const orders: HedgingOrder[] = []; // Create 20 orders for (let i = 0; i < 20; i++) { orders.push({ id: `perf-stress-order-${i}`, sessionId: 'perf-stress-session', strategyId: 'perf-stress-strategy', orderPair: { buyOrder: { accountId: `account${i * 2 + 1}`, side: 'buy', type: 'limit', size: 100, price: 2500 }, sellOrder: { accountId: `account${i * 2 + 2}`, side: 'sell', type: 'limit', size: 100, price: 2500 } }, status: 'pending', fees: 0, slippage: 0, createdAt: new Date(), updatedAt: new Date() }); } const startTime = performance.now(); const results = await Promise.all( orders.map(order => orderCoordinator.executeHedgingOrderPair(order)) ); const endTime = performance.now(); const executionTime = endTime - startTime; expect(executionTime).toBeLessThan(100); // Must be under 100ms expect(results).toHaveLength(20); results.forEach(result => { expect(result).toBeDefined(); expect(result.success).toBeDefined(); }); console.log(`20 order pairs execution time: ${executionTime.toFixed(2)}ms`); }); it('should maintain performance under high load', async () => { const orders: HedgingOrder[] = []; // Create 50 orders for high load test for (let i = 0; i < 50; i++) { orders.push({ id: `perf-highload-order-${i}`, sessionId: 'perf-highload-session', strategyId: 'perf-highload-strategy', orderPair: { buyOrder: { accountId: `account${i * 2 + 1}`, side: 'buy', type: 'limit', size: 100, price: 2500 }, sellOrder: { accountId: `account${i * 2 + 2}`, side: 'sell', type: 'limit', size: 100, price: 2500 } }, status: 'pending', fees: 0, slippage: 0, createdAt: new Date(), updatedAt: new Date() }); } const startTime = performance.now(); const results = await Promise.all( orders.map(order => orderCoordinator.executeHedgingOrderPair(order)) ); const endTime = performance.now(); const executionTime = endTime - startTime; // High load test - allow up to 200ms for 50 orders expect(executionTime).toBeLessThan(200); expect(results).toHaveLength(50); results.forEach(result => { expect(result).toBeDefined(); expect(result.success).toBeDefined(); }); console.log(`50 order pairs (high load) execution time: ${executionTime.toFixed(2)}ms`); }); }); describe('Session Creation Performance Tests', () => { beforeEach(async () => { await hedgingManager.initialize(); }); it('should create session within 50ms', async () => { const sessionRequest: HedgingSessionRequest = { strategy: { symbol: 'ETH/USD', volumeDistribution: 'equal', priceRange: { min: 0.001, max: 0.01 }, timing: { minInterval: 30, maxInterval: 120, orderSize: { min: 100, max: 500 } }, riskLimits: { maxPositionSize: 0.1, stopLossThreshold: 0.05, maxSlippage: 0.02 }, orderTypes: { primary: 'limit', fallback: 'market' } }, accounts: ['account1', 'account2'], duration: 300000 }; const startTime = performance.now(); const session = await hedgingManager.createSession(sessionRequest); const endTime = performance.now(); const creationTime = endTime - startTime; expect(creationTime).toBeLessThan(50); // Must be under 50ms expect(session).toBeDefined(); expect(session.id).toBeDefined(); console.log(`Session creation time: ${creationTime.toFixed(2)}ms`); }); it('should create multiple sessions concurrently within 100ms', async () => { const sessionRequests: HedgingSessionRequest[] = []; // Create 5 concurrent session requests for (let i = 0; i < 5; i++) { sessionRequests.push({ strategy: { symbol: 'ETH/USD', volumeDistribution: 'equal', priceRange: { min: 0.001, max: 0.01 }, timing: { minInterval: 30, maxInterval: 120, orderSize: { min: 100, max: 500 } }, riskLimits: { maxPositionSize: 0.1, stopLossThreshold: 0.05, maxSlippage: 0.02 }, orderTypes: { primary: 'limit', fallback: 'market' } }, accounts: [`account${i * 2 + 1}`, `account${i * 2 + 2}`], duration: 300000 }); } const startTime = performance.now(); const sessions = await Promise.all( sessionRequests.map(request => hedgingManager.createSession(request)) ); const endTime = performance.now(); const creationTime = endTime - startTime; expect(creationTime).toBeLessThan(100); // Must be under 100ms expect(sessions).toHaveLength(5); sessions.forEach(session => { expect(session).toBeDefined(); expect(session.id).toBeDefined(); }); console.log(`5 concurrent session creation time: ${creationTime.toFixed(2)}ms`); }); }); describe('Risk Assessment Performance Tests', () => { beforeEach(async () => { await hedgingManager.initialize(); }); it('should assess risk within 10ms', async () => { const sessionRequest: HedgingSessionRequest = { strategy: { symbol: 'ETH/USD', volumeDistribution: 'equal', priceRange: { min: 0.001, max: 0.01 }, timing: { minInterval: 30, maxInterval: 120, orderSize: { min: 100, max: 500 } }, riskLimits: { maxPositionSize: 0.1, stopLossThreshold: 0.05, maxSlippage: 0.02 }, orderTypes: { primary: 'limit', fallback: 'market' } }, accounts: ['account1', 'account2'], duration: 300000 }; const session = await hedgingManager.createSession(sessionRequest); const startTime = performance.now(); const riskStatus = hedgingManager.getSessionRiskStatus(session.id); const endTime = performance.now(); const assessmentTime = endTime - startTime; expect(assessmentTime).toBeLessThan(10); // Must be under 10ms expect(riskStatus).toBeDefined(); expect(riskStatus.overallRisk).toBeDefined(); console.log(`Risk assessment time: ${assessmentTime.toFixed(2)}ms`); }); it('should assess risk for multiple sessions within 50ms', async () => { const sessions = []; // Create 10 sessions for (let i = 0; i < 10; i++) { const sessionRequest: HedgingSessionRequest = { strategy: { symbol: 'ETH/USD', volumeDistribution: 'equal', priceRange: { min: 0.001, max: 0.01 }, timing: { minInterval: 30, maxInterval: 120, orderSize: { min: 100, max: 500 } }, riskLimits: { maxPositionSize: 0.1, stopLossThreshold: 0.05, maxSlippage: 0.02 }, orderTypes: { primary: 'limit', fallback: 'market' } }, accounts: [`account${i * 2 + 1}`, `account${i * 2 + 2}`], duration: 300000 }; const session = await hedgingManager.createSession(sessionRequest); sessions.push(session); } const startTime = performance.now(); const riskStatuses = await Promise.all( sessions.map(session => hedgingManager.getSessionRiskStatus(session.id)) ); const endTime = performance.now(); const assessmentTime = endTime - startTime; expect(assessmentTime).toBeLessThan(50); // Must be under 50ms expect(riskStatuses).toHaveLength(10); riskStatuses.forEach(riskStatus => { expect(riskStatus).toBeDefined(); expect(riskStatus.overallRisk).toBeDefined(); }); console.log(`10 concurrent risk assessments time: ${assessmentTime.toFixed(2)}ms`); }); }); describe('Memory Usage Performance Tests', () => { beforeEach(async () => { await hedgingManager.initialize(); }); it('should not exceed memory limits during high volume operations', async () => { const initialMemory = process.memoryUsage(); // Create 100 sessions const sessions = []; for (let i = 0; i < 100; i++) { const sessionRequest: HedgingSessionRequest = { strategy: { symbol: 'ETH/USD', volumeDistribution: 'equal', priceRange: { min: 0.001, max: 0.01 }, timing: { minInterval: 30, maxInterval: 120, orderSize: { min: 100, max: 500 } }, riskLimits: { maxPositionSize: 0.1, stopLossThreshold: 0.05, maxSlippage: 0.02 }, orderTypes: { primary: 'limit', fallback: 'market' } }, accounts: [`account${i * 2 + 1}`, `account${i * 2 + 2}`], duration: 300000 }; const session = await hedgingManager.createSession(sessionRequest); sessions.push(session); } const finalMemory = process.memoryUsage(); const memoryIncrease = finalMemory.heapUsed - initialMemory.heapUsed; // Memory increase should be reasonable (less than 100MB) expect(memoryIncrease).toBeLessThan(100 * 1024 * 1024); console.log(`Memory increase for 100 sessions: ${(memoryIncrease / 1024 / 1024).toFixed(2)}MB`); }); it('should clean up memory after session completion', async () => { const sessionRequest: HedgingSessionRequest = { strategy: { symbol: 'ETH/USD', volumeDistribution: 'equal', priceRange: { min: 0.001, max: 0.01 }, timing: { minInterval: 30, maxInterval: 120, orderSize: { min: 100, max: 500 } }, riskLimits: { maxPositionSize: 0.1, stopLossThreshold: 0.05, maxSlippage: 0.02 }, orderTypes: { primary: 'limit', fallback: 'market' } }, accounts: ['account1', 'account2'], duration: 300000 }; const initialMemory = process.memoryUsage(); const session = await hedgingManager.createSession(sessionRequest); await hedgingManager.startSession(session.id); await hedgingManager.stopSession(session.id); // Force garbage collection if available if (global.gc) { global.gc(); } const finalMemory = process.memoryUsage(); const memoryIncrease = finalMemory.heapUsed - initialMemory.heapUsed; // Memory increase should be minimal after cleanup expect(memoryIncrease).toBeLessThan(10 * 1024 * 1024); // Less than 10MB console.log(`Memory increase after session cleanup: ${(memoryIncrease / 1024 / 1024).toFixed(2)}MB`); }); }); describe('Throughput Performance Tests', () => { beforeEach(async () => { await hedgingManager.initialize(); await orderCoordinator.initialize(); }); it('should handle 1000 orders per minute', async () => { const orders: HedgingOrder[] = []; // Create 1000 orders for (let i = 0; i < 1000; i++) { orders.push({ id: `throughput-order-${i}`, sessionId: 'throughput-session', strategyId: 'throughput-strategy', orderPair: { buyOrder: { accountId: `account${i * 2 + 1}`, side: 'buy', type: 'limit', size: 100, price: 2500 }, sellOrder: { accountId: `account${i * 2 + 2}`, side: 'sell', type: 'limit', size: 100, price: 2500 } }, status: 'pending', fees: 0, slippage: 0, createdAt: new Date(), updatedAt: new Date() }); } const startTime = performance.now(); const results = await Promise.all( orders.map(order => orderCoordinator.executeHedgingOrderPair(order)) ); const endTime = performance.now(); const totalTime = endTime - startTime; const ordersPerSecond = (1000 / totalTime) * 1000; const ordersPerMinute = ordersPerSecond * 60; expect(ordersPerMinute).toBeGreaterThan(1000); // Must handle 1000+ orders per minute expect(results).toHaveLength(1000); console.log(`Throughput: ${ordersPerMinute.toFixed(0)} orders per minute`); console.log(`Total time for 1000 orders: ${totalTime.toFixed(2)}ms`); }); }); });