test_order_execution_latency.ts 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581
  1. /**
  2. * Performance tests for order execution latency
  3. * Tests that order execution meets the <100ms requirement
  4. */
  5. import { HedgingManager } from '../../src/core/HedgingManager';
  6. import { OrderCoordinator } from '../../src/core/OrderCoordinator';
  7. import { HedgingOrderExecutorAdapter } from '../../src/core/HedgingOrderExecutorAdapter';
  8. import { HedgingSessionRequest, HedgingOrder } from '../../src/types/hedging';
  9. import { Logger } from '../../src/utils/Logger';
  10. // Mock dependencies
  11. jest.mock('../../src/utils/Logger');
  12. jest.mock('../../src/core/RiskManager');
  13. jest.mock('../../src/core/HedgingStrategyEngine');
  14. jest.mock('../../src/core/HedgingConfigManager');
  15. jest.mock('../../src/core/OrderExecutor');
  16. describe('Order Execution Performance Tests', () => {
  17. let hedgingManager: HedgingManager;
  18. let orderCoordinator: OrderCoordinator;
  19. let orderExecutorAdapter: HedgingOrderExecutorAdapter;
  20. let mockConfig: any;
  21. beforeEach(() => {
  22. mockConfig = {
  23. maxConcurrentSessions: 10,
  24. sessionTimeout: 60000,
  25. riskCheckInterval: 1000
  26. };
  27. hedgingManager = new HedgingManager(mockConfig);
  28. orderCoordinator = new OrderCoordinator({
  29. maxConcurrentOrders: 20,
  30. orderTimeout: 30000,
  31. retryAttempts: 3,
  32. retryDelay: 1000
  33. });
  34. });
  35. afterEach(() => {
  36. jest.clearAllMocks();
  37. });
  38. describe('Order Execution Latency Tests', () => {
  39. beforeEach(async () => {
  40. await hedgingManager.initialize();
  41. await orderCoordinator.initialize();
  42. });
  43. it('should execute single order pair within 100ms', async () => {
  44. const hedgingOrder: HedgingOrder = {
  45. id: 'perf-test-order',
  46. sessionId: 'perf-test-session',
  47. strategyId: 'perf-test-strategy',
  48. orderPair: {
  49. buyOrder: {
  50. accountId: 'account1',
  51. side: 'buy',
  52. type: 'limit',
  53. size: 100,
  54. price: 2500
  55. },
  56. sellOrder: {
  57. accountId: 'account2',
  58. side: 'sell',
  59. type: 'limit',
  60. size: 100,
  61. price: 2500
  62. }
  63. },
  64. status: 'pending',
  65. fees: 0,
  66. slippage: 0,
  67. createdAt: new Date(),
  68. updatedAt: new Date()
  69. };
  70. const startTime = performance.now();
  71. const result = await orderCoordinator.executeHedgingOrderPair(hedgingOrder);
  72. const endTime = performance.now();
  73. const executionTime = endTime - startTime;
  74. expect(executionTime).toBeLessThan(100); // Must be under 100ms
  75. expect(result).toBeDefined();
  76. expect(result.success).toBeDefined();
  77. console.log(`Single order pair execution time: ${executionTime.toFixed(2)}ms`);
  78. });
  79. it('should execute multiple order pairs concurrently within 100ms', async () => {
  80. const orders: HedgingOrder[] = [];
  81. // Create 5 concurrent orders
  82. for (let i = 0; i < 5; i++) {
  83. orders.push({
  84. id: `perf-concurrent-order-${i}`,
  85. sessionId: 'perf-concurrent-session',
  86. strategyId: 'perf-concurrent-strategy',
  87. orderPair: {
  88. buyOrder: {
  89. accountId: `account${i * 2 + 1}`,
  90. side: 'buy',
  91. type: 'limit',
  92. size: 100,
  93. price: 2500
  94. },
  95. sellOrder: {
  96. accountId: `account${i * 2 + 2}`,
  97. side: 'sell',
  98. type: 'limit',
  99. size: 100,
  100. price: 2500
  101. }
  102. },
  103. status: 'pending',
  104. fees: 0,
  105. slippage: 0,
  106. createdAt: new Date(),
  107. updatedAt: new Date()
  108. });
  109. }
  110. const startTime = performance.now();
  111. const results = await Promise.all(
  112. orders.map(order => orderCoordinator.executeHedgingOrderPair(order))
  113. );
  114. const endTime = performance.now();
  115. const executionTime = endTime - startTime;
  116. expect(executionTime).toBeLessThan(100); // Must be under 100ms
  117. expect(results).toHaveLength(5);
  118. results.forEach(result => {
  119. expect(result).toBeDefined();
  120. expect(result.success).toBeDefined();
  121. });
  122. console.log(`5 concurrent order pairs execution time: ${executionTime.toFixed(2)}ms`);
  123. });
  124. it('should execute 10 order pairs within 100ms', async () => {
  125. const orders: HedgingOrder[] = [];
  126. // Create 10 orders
  127. for (let i = 0; i < 10; i++) {
  128. orders.push({
  129. id: `perf-batch-order-${i}`,
  130. sessionId: 'perf-batch-session',
  131. strategyId: 'perf-batch-strategy',
  132. orderPair: {
  133. buyOrder: {
  134. accountId: `account${i * 2 + 1}`,
  135. side: 'buy',
  136. type: 'limit',
  137. size: 100,
  138. price: 2500
  139. },
  140. sellOrder: {
  141. accountId: `account${i * 2 + 2}`,
  142. side: 'sell',
  143. type: 'limit',
  144. size: 100,
  145. price: 2500
  146. }
  147. },
  148. status: 'pending',
  149. fees: 0,
  150. slippage: 0,
  151. createdAt: new Date(),
  152. updatedAt: new Date()
  153. });
  154. }
  155. const startTime = performance.now();
  156. const results = await Promise.all(
  157. orders.map(order => orderCoordinator.executeHedgingOrderPair(order))
  158. );
  159. const endTime = performance.now();
  160. const executionTime = endTime - startTime;
  161. expect(executionTime).toBeLessThan(100); // Must be under 100ms
  162. expect(results).toHaveLength(10);
  163. results.forEach(result => {
  164. expect(result).toBeDefined();
  165. expect(result.success).toBeDefined();
  166. });
  167. console.log(`10 order pairs execution time: ${executionTime.toFixed(2)}ms`);
  168. });
  169. it('should execute 20 order pairs within 100ms', async () => {
  170. const orders: HedgingOrder[] = [];
  171. // Create 20 orders
  172. for (let i = 0; i < 20; i++) {
  173. orders.push({
  174. id: `perf-stress-order-${i}`,
  175. sessionId: 'perf-stress-session',
  176. strategyId: 'perf-stress-strategy',
  177. orderPair: {
  178. buyOrder: {
  179. accountId: `account${i * 2 + 1}`,
  180. side: 'buy',
  181. type: 'limit',
  182. size: 100,
  183. price: 2500
  184. },
  185. sellOrder: {
  186. accountId: `account${i * 2 + 2}`,
  187. side: 'sell',
  188. type: 'limit',
  189. size: 100,
  190. price: 2500
  191. }
  192. },
  193. status: 'pending',
  194. fees: 0,
  195. slippage: 0,
  196. createdAt: new Date(),
  197. updatedAt: new Date()
  198. });
  199. }
  200. const startTime = performance.now();
  201. const results = await Promise.all(
  202. orders.map(order => orderCoordinator.executeHedgingOrderPair(order))
  203. );
  204. const endTime = performance.now();
  205. const executionTime = endTime - startTime;
  206. expect(executionTime).toBeLessThan(100); // Must be under 100ms
  207. expect(results).toHaveLength(20);
  208. results.forEach(result => {
  209. expect(result).toBeDefined();
  210. expect(result.success).toBeDefined();
  211. });
  212. console.log(`20 order pairs execution time: ${executionTime.toFixed(2)}ms`);
  213. });
  214. it('should maintain performance under high load', async () => {
  215. const orders: HedgingOrder[] = [];
  216. // Create 50 orders for high load test
  217. for (let i = 0; i < 50; i++) {
  218. orders.push({
  219. id: `perf-highload-order-${i}`,
  220. sessionId: 'perf-highload-session',
  221. strategyId: 'perf-highload-strategy',
  222. orderPair: {
  223. buyOrder: {
  224. accountId: `account${i * 2 + 1}`,
  225. side: 'buy',
  226. type: 'limit',
  227. size: 100,
  228. price: 2500
  229. },
  230. sellOrder: {
  231. accountId: `account${i * 2 + 2}`,
  232. side: 'sell',
  233. type: 'limit',
  234. size: 100,
  235. price: 2500
  236. }
  237. },
  238. status: 'pending',
  239. fees: 0,
  240. slippage: 0,
  241. createdAt: new Date(),
  242. updatedAt: new Date()
  243. });
  244. }
  245. const startTime = performance.now();
  246. const results = await Promise.all(
  247. orders.map(order => orderCoordinator.executeHedgingOrderPair(order))
  248. );
  249. const endTime = performance.now();
  250. const executionTime = endTime - startTime;
  251. // High load test - allow up to 200ms for 50 orders
  252. expect(executionTime).toBeLessThan(200);
  253. expect(results).toHaveLength(50);
  254. results.forEach(result => {
  255. expect(result).toBeDefined();
  256. expect(result.success).toBeDefined();
  257. });
  258. console.log(`50 order pairs (high load) execution time: ${executionTime.toFixed(2)}ms`);
  259. });
  260. });
  261. describe('Session Creation Performance Tests', () => {
  262. beforeEach(async () => {
  263. await hedgingManager.initialize();
  264. });
  265. it('should create session within 50ms', async () => {
  266. const sessionRequest: HedgingSessionRequest = {
  267. strategy: {
  268. symbol: 'ETH/USD',
  269. volumeDistribution: 'equal',
  270. priceRange: { min: 0.001, max: 0.01 },
  271. timing: { minInterval: 30, maxInterval: 120, orderSize: { min: 100, max: 500 } },
  272. riskLimits: { maxPositionSize: 0.1, stopLossThreshold: 0.05, maxSlippage: 0.02 },
  273. orderTypes: { primary: 'limit', fallback: 'market' }
  274. },
  275. accounts: ['account1', 'account2'],
  276. duration: 300000
  277. };
  278. const startTime = performance.now();
  279. const session = await hedgingManager.createSession(sessionRequest);
  280. const endTime = performance.now();
  281. const creationTime = endTime - startTime;
  282. expect(creationTime).toBeLessThan(50); // Must be under 50ms
  283. expect(session).toBeDefined();
  284. expect(session.id).toBeDefined();
  285. console.log(`Session creation time: ${creationTime.toFixed(2)}ms`);
  286. });
  287. it('should create multiple sessions concurrently within 100ms', async () => {
  288. const sessionRequests: HedgingSessionRequest[] = [];
  289. // Create 5 concurrent session requests
  290. for (let i = 0; i < 5; i++) {
  291. sessionRequests.push({
  292. strategy: {
  293. symbol: 'ETH/USD',
  294. volumeDistribution: 'equal',
  295. priceRange: { min: 0.001, max: 0.01 },
  296. timing: { minInterval: 30, maxInterval: 120, orderSize: { min: 100, max: 500 } },
  297. riskLimits: { maxPositionSize: 0.1, stopLossThreshold: 0.05, maxSlippage: 0.02 },
  298. orderTypes: { primary: 'limit', fallback: 'market' }
  299. },
  300. accounts: [`account${i * 2 + 1}`, `account${i * 2 + 2}`],
  301. duration: 300000
  302. });
  303. }
  304. const startTime = performance.now();
  305. const sessions = await Promise.all(
  306. sessionRequests.map(request => hedgingManager.createSession(request))
  307. );
  308. const endTime = performance.now();
  309. const creationTime = endTime - startTime;
  310. expect(creationTime).toBeLessThan(100); // Must be under 100ms
  311. expect(sessions).toHaveLength(5);
  312. sessions.forEach(session => {
  313. expect(session).toBeDefined();
  314. expect(session.id).toBeDefined();
  315. });
  316. console.log(`5 concurrent session creation time: ${creationTime.toFixed(2)}ms`);
  317. });
  318. });
  319. describe('Risk Assessment Performance Tests', () => {
  320. beforeEach(async () => {
  321. await hedgingManager.initialize();
  322. });
  323. it('should assess risk within 10ms', async () => {
  324. const sessionRequest: HedgingSessionRequest = {
  325. strategy: {
  326. symbol: 'ETH/USD',
  327. volumeDistribution: 'equal',
  328. priceRange: { min: 0.001, max: 0.01 },
  329. timing: { minInterval: 30, maxInterval: 120, orderSize: { min: 100, max: 500 } },
  330. riskLimits: { maxPositionSize: 0.1, stopLossThreshold: 0.05, maxSlippage: 0.02 },
  331. orderTypes: { primary: 'limit', fallback: 'market' }
  332. },
  333. accounts: ['account1', 'account2'],
  334. duration: 300000
  335. };
  336. const session = await hedgingManager.createSession(sessionRequest);
  337. const startTime = performance.now();
  338. const riskStatus = hedgingManager.getSessionRiskStatus(session.id);
  339. const endTime = performance.now();
  340. const assessmentTime = endTime - startTime;
  341. expect(assessmentTime).toBeLessThan(10); // Must be under 10ms
  342. expect(riskStatus).toBeDefined();
  343. expect(riskStatus.overallRisk).toBeDefined();
  344. console.log(`Risk assessment time: ${assessmentTime.toFixed(2)}ms`);
  345. });
  346. it('should assess risk for multiple sessions within 50ms', async () => {
  347. const sessions = [];
  348. // Create 10 sessions
  349. for (let i = 0; i < 10; i++) {
  350. const sessionRequest: HedgingSessionRequest = {
  351. strategy: {
  352. symbol: 'ETH/USD',
  353. volumeDistribution: 'equal',
  354. priceRange: { min: 0.001, max: 0.01 },
  355. timing: { minInterval: 30, maxInterval: 120, orderSize: { min: 100, max: 500 } },
  356. riskLimits: { maxPositionSize: 0.1, stopLossThreshold: 0.05, maxSlippage: 0.02 },
  357. orderTypes: { primary: 'limit', fallback: 'market' }
  358. },
  359. accounts: [`account${i * 2 + 1}`, `account${i * 2 + 2}`],
  360. duration: 300000
  361. };
  362. const session = await hedgingManager.createSession(sessionRequest);
  363. sessions.push(session);
  364. }
  365. const startTime = performance.now();
  366. const riskStatuses = await Promise.all(
  367. sessions.map(session => hedgingManager.getSessionRiskStatus(session.id))
  368. );
  369. const endTime = performance.now();
  370. const assessmentTime = endTime - startTime;
  371. expect(assessmentTime).toBeLessThan(50); // Must be under 50ms
  372. expect(riskStatuses).toHaveLength(10);
  373. riskStatuses.forEach(riskStatus => {
  374. expect(riskStatus).toBeDefined();
  375. expect(riskStatus.overallRisk).toBeDefined();
  376. });
  377. console.log(`10 concurrent risk assessments time: ${assessmentTime.toFixed(2)}ms`);
  378. });
  379. });
  380. describe('Memory Usage Performance Tests', () => {
  381. beforeEach(async () => {
  382. await hedgingManager.initialize();
  383. });
  384. it('should not exceed memory limits during high volume operations', async () => {
  385. const initialMemory = process.memoryUsage();
  386. // Create 100 sessions
  387. const sessions = [];
  388. for (let i = 0; i < 100; i++) {
  389. const sessionRequest: HedgingSessionRequest = {
  390. strategy: {
  391. symbol: 'ETH/USD',
  392. volumeDistribution: 'equal',
  393. priceRange: { min: 0.001, max: 0.01 },
  394. timing: { minInterval: 30, maxInterval: 120, orderSize: { min: 100, max: 500 } },
  395. riskLimits: { maxPositionSize: 0.1, stopLossThreshold: 0.05, maxSlippage: 0.02 },
  396. orderTypes: { primary: 'limit', fallback: 'market' }
  397. },
  398. accounts: [`account${i * 2 + 1}`, `account${i * 2 + 2}`],
  399. duration: 300000
  400. };
  401. const session = await hedgingManager.createSession(sessionRequest);
  402. sessions.push(session);
  403. }
  404. const finalMemory = process.memoryUsage();
  405. const memoryIncrease = finalMemory.heapUsed - initialMemory.heapUsed;
  406. // Memory increase should be reasonable (less than 100MB)
  407. expect(memoryIncrease).toBeLessThan(100 * 1024 * 1024);
  408. console.log(`Memory increase for 100 sessions: ${(memoryIncrease / 1024 / 1024).toFixed(2)}MB`);
  409. });
  410. it('should clean up memory after session completion', async () => {
  411. const sessionRequest: HedgingSessionRequest = {
  412. strategy: {
  413. symbol: 'ETH/USD',
  414. volumeDistribution: 'equal',
  415. priceRange: { min: 0.001, max: 0.01 },
  416. timing: { minInterval: 30, maxInterval: 120, orderSize: { min: 100, max: 500 } },
  417. riskLimits: { maxPositionSize: 0.1, stopLossThreshold: 0.05, maxSlippage: 0.02 },
  418. orderTypes: { primary: 'limit', fallback: 'market' }
  419. },
  420. accounts: ['account1', 'account2'],
  421. duration: 300000
  422. };
  423. const initialMemory = process.memoryUsage();
  424. const session = await hedgingManager.createSession(sessionRequest);
  425. await hedgingManager.startSession(session.id);
  426. await hedgingManager.stopSession(session.id);
  427. // Force garbage collection if available
  428. if (global.gc) {
  429. global.gc();
  430. }
  431. const finalMemory = process.memoryUsage();
  432. const memoryIncrease = finalMemory.heapUsed - initialMemory.heapUsed;
  433. // Memory increase should be minimal after cleanup
  434. expect(memoryIncrease).toBeLessThan(10 * 1024 * 1024); // Less than 10MB
  435. console.log(`Memory increase after session cleanup: ${(memoryIncrease / 1024 / 1024).toFixed(2)}MB`);
  436. });
  437. });
  438. describe('Throughput Performance Tests', () => {
  439. beforeEach(async () => {
  440. await hedgingManager.initialize();
  441. await orderCoordinator.initialize();
  442. });
  443. it('should handle 1000 orders per minute', async () => {
  444. const orders: HedgingOrder[] = [];
  445. // Create 1000 orders
  446. for (let i = 0; i < 1000; i++) {
  447. orders.push({
  448. id: `throughput-order-${i}`,
  449. sessionId: 'throughput-session',
  450. strategyId: 'throughput-strategy',
  451. orderPair: {
  452. buyOrder: {
  453. accountId: `account${i * 2 + 1}`,
  454. side: 'buy',
  455. type: 'limit',
  456. size: 100,
  457. price: 2500
  458. },
  459. sellOrder: {
  460. accountId: `account${i * 2 + 2}`,
  461. side: 'sell',
  462. type: 'limit',
  463. size: 100,
  464. price: 2500
  465. }
  466. },
  467. status: 'pending',
  468. fees: 0,
  469. slippage: 0,
  470. createdAt: new Date(),
  471. updatedAt: new Date()
  472. });
  473. }
  474. const startTime = performance.now();
  475. const results = await Promise.all(
  476. orders.map(order => orderCoordinator.executeHedgingOrderPair(order))
  477. );
  478. const endTime = performance.now();
  479. const totalTime = endTime - startTime;
  480. const ordersPerSecond = (1000 / totalTime) * 1000;
  481. const ordersPerMinute = ordersPerSecond * 60;
  482. expect(ordersPerMinute).toBeGreaterThan(1000); // Must handle 1000+ orders per minute
  483. expect(results).toHaveLength(1000);
  484. console.log(`Throughput: ${ordersPerMinute.toFixed(0)} orders per minute`);
  485. console.log(`Total time for 1000 orders: ${totalTime.toFixed(2)}ms`);
  486. });
  487. });
  488. });