"use strict"; /** * Unit tests for OrderCoordinator */ Object.defineProperty(exports, "__esModule", { value: true }); const OrderCoordinator_1 = require("../../src/core/OrderCoordinator"); // Mock dependencies jest.mock('../../src/utils/Logger'); describe('OrderCoordinator', () => { let orderCoordinator; let mockConfig; beforeEach(() => { mockConfig = { maxConcurrentOrders: 10, orderTimeout: 30000, retryAttempts: 3, retryDelay: 1000 }; orderCoordinator = new OrderCoordinator_1.OrderCoordinator(mockConfig); }); afterEach(() => { jest.clearAllMocks(); }); describe('Initialization', () => { it('should initialize with correct configuration', async () => { await orderCoordinator.initialize(); const status = orderCoordinator.getStatus(); expect(status.isRunning).toBe(false); expect(status.totalOrders).toBe(0); }); it('should throw error if already initialized', async () => { await orderCoordinator.initialize(); await expect(orderCoordinator.initialize()).rejects.toThrow('OrderCoordinator is already initialized'); }); }); describe('Order Execution', () => { beforeEach(async () => { await orderCoordinator.initialize(); }); it('should execute hedging order pair', async () => { const hedgingOrder = { id: 'test-order', sessionId: 'test-session', strategyId: '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 result = await orderCoordinator.executeHedgingOrderPair(hedgingOrder); expect(result).toBeDefined(); expect(result.success).toBeDefined(); expect(typeof result.success).toBe('boolean'); }); it('should handle order execution failure', async () => { const invalidOrder = { id: 'invalid-order', sessionId: 'test-session', strategyId: 'test-strategy', orderPair: { buyOrder: { accountId: 'account1', side: 'buy', type: 'limit', size: -100, // Invalid negative size 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 result = await orderCoordinator.executeHedgingOrderPair(invalidOrder); expect(result.success).toBe(false); expect(result.error).toBeDefined(); }); it('should execute orders with retry mechanism', async () => { const hedgingOrder = { id: 'retry-order', sessionId: 'test-session', strategyId: '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() }; // Mock retry scenario jest.spyOn(orderCoordinator, 'executeOrderWithRetry') .mockResolvedValueOnce({ success: false, error: 'Network error' }) .mockResolvedValueOnce({ success: true, orderId: 'order-123' }); const result = await orderCoordinator.executeHedgingOrderPair(hedgingOrder); expect(result).toBeDefined(); }); }); describe('Order Validation', () => { beforeEach(async () => { await orderCoordinator.initialize(); }); it('should validate order details', () => { const validOrder = { accountId: 'account1', side: 'buy', type: 'limit', size: 100, price: 2500 }; const isValid = orderCoordinator.validateOrderDetails(validOrder); expect(isValid).toBe(true); }); it('should reject invalid order details', () => { const invalidOrder = { accountId: 'account1', side: 'buy', type: 'limit', size: -100, // Invalid negative size price: 2500 }; const isValid = orderCoordinator.validateOrderDetails(invalidOrder); expect(isValid).toBe(false); }); it('should validate order pair', () => { const validOrderPair = { buyOrder: { accountId: 'account1', side: 'buy', type: 'limit', size: 100, price: 2500 }, sellOrder: { accountId: 'account2', side: 'sell', type: 'limit', size: 100, price: 2500 } }; const isValid = orderCoordinator.validateOrderPair(validOrderPair); expect(isValid).toBe(true); }); it('should reject invalid order pair', () => { const invalidOrderPair = { buyOrder: { accountId: 'account1', side: 'buy', type: 'limit', size: 100, price: 2500 }, sellOrder: { accountId: 'account2', side: 'sell', type: 'limit', size: 50, // Different size price: 2500 } }; const isValid = orderCoordinator.validateOrderPair(invalidOrderPair); expect(isValid).toBe(false); }); }); describe('Order Tracking', () => { beforeEach(async () => { await orderCoordinator.initialize(); }); it('should track order execution', async () => { const hedgingOrder = { id: 'track-order', sessionId: 'test-session', strategyId: '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() }; await orderCoordinator.executeHedgingOrderPair(hedgingOrder); const trackedOrder = orderCoordinator.getOrder('track-order'); expect(trackedOrder).toBeDefined(); }); it('should return null for non-existent order', () => { const order = orderCoordinator.getOrder('non-existent'); expect(order).toBeNull(); }); it('should get all orders', async () => { const hedgingOrder1 = { id: 'order-1', sessionId: 'test-session', strategyId: '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 hedgingOrder2 = { id: 'order-2', sessionId: 'test-session', strategyId: '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() }; await orderCoordinator.executeHedgingOrderPair(hedgingOrder1); await orderCoordinator.executeHedgingOrderPair(hedgingOrder2); const allOrders = orderCoordinator.getAllOrders(); expect(allOrders).toHaveLength(2); }); it('should get orders by session', async () => { const hedgingOrder = { id: 'session-order', sessionId: 'test-session', strategyId: '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() }; await orderCoordinator.executeHedgingOrderPair(hedgingOrder); const sessionOrders = orderCoordinator.getSessionOrders('test-session'); expect(sessionOrders).toHaveLength(1); expect(sessionOrders[0].id).toBe('session-order'); }); }); describe('Order Cancellation', () => { beforeEach(async () => { await orderCoordinator.initialize(); }); it('should cancel hedging order pair', async () => { const hedgingOrder = { id: 'cancel-order', sessionId: 'test-session', strategyId: '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() }; await orderCoordinator.executeHedgingOrderPair(hedgingOrder); const result = await orderCoordinator.cancelHedgingOrderPair(hedgingOrder); expect(result).toBeDefined(); expect(result.success).toBeDefined(); }); it('should handle cancellation failure', async () => { const hedgingOrder = { id: 'cancel-fail-order', sessionId: 'test-session', strategyId: '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() }; // Mock cancellation failure jest.spyOn(orderCoordinator, 'cancelOrder') .mockRejectedValue(new Error('Cancellation failed')); const result = await orderCoordinator.cancelHedgingOrderPair(hedgingOrder); expect(result.success).toBe(false); expect(result.error).toBeDefined(); }); }); describe('Position Neutrality', () => { beforeEach(async () => { await orderCoordinator.initialize(); }); it('should ensure position neutrality', async () => { const hedgingOrder = { id: 'neutrality-order', sessionId: 'test-session', strategyId: '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 result = await orderCoordinator.executeHedgingOrderPair(hedgingOrder); if (result.success) { const isNeutral = orderCoordinator.checkPositionNeutrality('test-session'); expect(isNeutral).toBe(true); } }); it('should detect position imbalance', async () => { const hedgingOrder = { id: 'imbalance-order', sessionId: 'test-session', strategyId: 'test-strategy', orderPair: { buyOrder: { accountId: 'account1', side: 'buy', type: 'limit', size: 100, price: 2500 }, sellOrder: { accountId: 'account2', side: 'sell', type: 'limit', size: 50, // Different size causing imbalance price: 2500 } }, status: 'pending', fees: 0, slippage: 0, createdAt: new Date(), updatedAt: new Date() }; await orderCoordinator.executeHedgingOrderPair(hedgingOrder); const isNeutral = orderCoordinator.checkPositionNeutrality('test-session'); expect(isNeutral).toBe(false); }); }); describe('Statistics and Monitoring', () => { beforeEach(async () => { await orderCoordinator.initialize(); }); it('should return correct status', () => { const status = orderCoordinator.getStatus(); expect(status).toBeDefined(); expect(typeof status.isRunning).toBe('boolean'); expect(typeof status.totalOrders).toBe('number'); expect(typeof status.pendingOrders).toBe('number'); expect(typeof status.successfulOrders).toBe('number'); expect(typeof status.failedOrders).toBe('number'); }); it('should return correct statistics', () => { const stats = orderCoordinator.getStatistics(); expect(stats).toBeDefined(); expect(typeof stats.totalOrders).toBe('number'); expect(typeof stats.successfulOrders).toBe('number'); expect(typeof stats.failedOrders).toBe('number'); expect(typeof stats.successRate).toBe('number'); expect(typeof stats.averageExecutionTime).toBe('number'); expect(typeof stats.totalVolume).toBe('number'); }); it('should calculate success rate correctly', async () => { const hedgingOrder1 = { id: 'success-order', sessionId: 'test-session', strategyId: '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 hedgingOrder2 = { id: 'fail-order', sessionId: 'test-session', strategyId: 'test-strategy', orderPair: { buyOrder: { accountId: 'account1', side: 'buy', type: 'limit', size: -100, // Invalid size 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() }; await orderCoordinator.executeHedgingOrderPair(hedgingOrder1); await orderCoordinator.executeHedgingOrderPair(hedgingOrder2); const stats = orderCoordinator.getStatistics(); expect(stats.successRate).toBe(0.5); // 1 out of 2 successful }); }); describe('Event Emission', () => { beforeEach(async () => { await orderCoordinator.initialize(); }); it('should emit order executed event', async () => { const hedgingOrder = { id: 'event-order', sessionId: 'test-session', strategyId: '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 eventSpy = jest.fn(); orderCoordinator.on('orderExecuted', eventSpy); await orderCoordinator.executeHedgingOrderPair(hedgingOrder); expect(eventSpy).toHaveBeenCalled(); }); it('should emit order failed event', async () => { const hedgingOrder = { id: 'fail-event-order', sessionId: 'test-session', strategyId: 'test-strategy', orderPair: { buyOrder: { accountId: 'account1', side: 'buy', type: 'limit', size: -100, // Invalid size 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 eventSpy = jest.fn(); orderCoordinator.on('orderFailed', eventSpy); await orderCoordinator.executeHedgingOrderPair(hedgingOrder); expect(eventSpy).toHaveBeenCalled(); }); }); describe('Error Handling', () => { it('should handle initialization errors gracefully', async () => { const invalidConfig = { maxConcurrentOrders: -1, // Invalid negative value orderTimeout: 30000, retryAttempts: 3, retryDelay: 1000 }; const invalidCoordinator = new OrderCoordinator_1.OrderCoordinator(invalidConfig); await expect(invalidCoordinator.initialize()).rejects.toThrow(); }); it('should handle order execution errors gracefully', async () => { await orderCoordinator.initialize(); const invalidOrder = { id: 'error-order', sessionId: 'test-session', strategyId: '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() }; // Mock execution error jest.spyOn(orderCoordinator, 'executeOrderWithRetry') .mockRejectedValue(new Error('Execution failed')); const result = await orderCoordinator.executeHedgingOrderPair(invalidOrder); expect(result.success).toBe(false); expect(result.error).toBeDefined(); }); }); describe('Lifecycle Management', () => { it('should start and stop the coordinator', async () => { await orderCoordinator.initialize(); await orderCoordinator.start(); const status = orderCoordinator.getStatus(); expect(status.isRunning).toBe(true); await orderCoordinator.stop(); const stoppedStatus = orderCoordinator.getStatus(); expect(stoppedStatus.isRunning).toBe(false); }); it('should throw error when starting already running coordinator', async () => { await orderCoordinator.initialize(); await orderCoordinator.start(); await expect(orderCoordinator.start()).rejects.toThrow(); }); it('should throw error when stopping non-running coordinator', async () => { await orderCoordinator.initialize(); await expect(orderCoordinator.stop()).rejects.toThrow(); }); }); }); //# sourceMappingURL=test_order_coordinator.js.map