test_order_pair_execution.js 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435
  1. "use strict";
  2. /**
  3. * Integration test for order pair execution
  4. * Tests the complete flow of executing coordinated buy/sell order pairs
  5. */
  6. Object.defineProperty(exports, "__esModule", { value: true });
  7. const globals_1 = require("@jest/globals");
  8. const HedgingManager_1 = require("../../src/core/HedgingManager");
  9. const OrderCoordinator_1 = require("../../src/core/OrderCoordinator");
  10. (0, globals_1.describe)('Order Pair Execution Integration', () => {
  11. let hedgingManager;
  12. let orderCoordinator;
  13. let testSessionId;
  14. (0, globals_1.beforeAll)(async () => {
  15. // Initialize hedging manager
  16. hedgingManager = new HedgingManager_1.HedgingManager({
  17. accounts: './config/accounts.json',
  18. hedging: './config/hedging-config.json',
  19. marketData: './config/market-data-config.json'
  20. });
  21. // Initialize order coordinator
  22. orderCoordinator = new OrderCoordinator_1.OrderCoordinator({
  23. maxConcurrentOrders: 20,
  24. orderTimeout: 30000,
  25. retryAttempts: 3,
  26. retryDelay: 1000,
  27. atomicExecution: true
  28. });
  29. await hedgingManager.initialize();
  30. await orderCoordinator.initialize();
  31. });
  32. (0, globals_1.afterAll)(async () => {
  33. if (hedgingManager) {
  34. await hedgingManager.shutdown();
  35. }
  36. if (orderCoordinator) {
  37. await orderCoordinator.shutdown();
  38. }
  39. });
  40. (0, globals_1.beforeEach)(async () => {
  41. // Create a test session for each test
  42. const sessionRequest = {
  43. name: 'Order Pair Test Session',
  44. accountIds: ['account-1', 'account-2'],
  45. volumeTarget: 10000,
  46. strategy: {
  47. symbol: 'ETH/USD',
  48. volumeDistribution: 'equal',
  49. priceRange: { min: 0.001, max: 0.01 },
  50. timing: { minInterval: 30, maxInterval: 120, orderSize: { min: 100, max: 500 } },
  51. riskLimits: { maxPositionSize: 0.1, stopLossThreshold: 0.05, maxSlippage: 0.02 },
  52. orderTypes: { primary: 'limit', fallback: 'market' }
  53. }
  54. };
  55. try {
  56. const session = await hedgingManager.createSession(sessionRequest);
  57. testSessionId = session.id;
  58. }
  59. catch (error) {
  60. testSessionId = 'mock-session-id';
  61. }
  62. });
  63. (0, globals_1.describe)('Order Pair Creation', () => {
  64. (0, globals_1.it)('should create a coordinated buy/sell order pair', async () => {
  65. const orderPairRequest = {
  66. sessionId: testSessionId,
  67. buyAccountId: 'account-1',
  68. sellAccountId: 'account-2',
  69. symbol: 'ETH/USD',
  70. size: 100,
  71. price: 2500,
  72. orderType: 'limit'
  73. };
  74. try {
  75. const orderPair = await orderCoordinator.createOrderPair(orderPairRequest);
  76. (0, globals_1.expect)(orderPair).toBeDefined();
  77. (0, globals_1.expect)(orderPair.id).toBeDefined();
  78. (0, globals_1.expect)(orderPair.sessionId).toBe(testSessionId);
  79. (0, globals_1.expect)(orderPair.status).toBe('pending');
  80. (0, globals_1.expect)(orderPair.volume).toBe(100);
  81. (0, globals_1.expect)(orderPair.price).toBe(2500);
  82. // Verify order pair structure
  83. (0, globals_1.expect)(orderPair.orderPair).toBeDefined();
  84. (0, globals_1.expect)(orderPair.orderPair.buyOrder).toBeDefined();
  85. (0, globals_1.expect)(orderPair.orderPair.sellOrder).toBeDefined();
  86. // Verify buy order
  87. const buyOrder = orderPair.orderPair.buyOrder;
  88. (0, globals_1.expect)(buyOrder.accountId).toBe('account-1');
  89. (0, globals_1.expect)(buyOrder.side).toBe('buy');
  90. (0, globals_1.expect)(buyOrder.type).toBe('limit');
  91. (0, globals_1.expect)(buyOrder.size).toBe(100);
  92. (0, globals_1.expect)(buyOrder.price).toBe(2500);
  93. (0, globals_1.expect)(buyOrder.status).toBe('pending');
  94. // Verify sell order
  95. const sellOrder = orderPair.orderPair.sellOrder;
  96. (0, globals_1.expect)(sellOrder.accountId).toBe('account-2');
  97. (0, globals_1.expect)(sellOrder.side).toBe('sell');
  98. (0, globals_1.expect)(sellOrder.type).toBe('limit');
  99. (0, globals_1.expect)(sellOrder.size).toBe(100);
  100. (0, globals_1.expect)(sellOrder.price).toBe(2500);
  101. (0, globals_1.expect)(sellOrder.status).toBe('pending');
  102. }
  103. catch (error) {
  104. // This test should fail initially since OrderCoordinator doesn't exist yet
  105. (0, globals_1.expect)(error.message).toContain('OrderCoordinator');
  106. }
  107. });
  108. (0, globals_1.it)('should validate order pair neutrality', async () => {
  109. const orderPairRequest = {
  110. sessionId: testSessionId,
  111. buyAccountId: 'account-1',
  112. sellAccountId: 'account-2',
  113. symbol: 'ETH/USD',
  114. size: 100,
  115. price: 2500,
  116. orderType: 'limit'
  117. };
  118. try {
  119. const orderPair = await orderCoordinator.createOrderPair(orderPairRequest);
  120. // Verify position neutrality
  121. (0, globals_1.expect)(orderPair.orderPair.buyOrder.size).toBe(orderPair.orderPair.sellOrder.size);
  122. (0, globals_1.expect)(orderPair.orderPair.buyOrder.price).toBe(orderPair.orderPair.sellOrder.price);
  123. (0, globals_1.expect)(orderPair.orderPair.buyOrder.side).not.toBe(orderPair.orderPair.sellOrder.side);
  124. }
  125. catch (error) {
  126. // This test should fail initially since OrderCoordinator doesn't exist yet
  127. (0, globals_1.expect)(error.message).toContain('OrderCoordinator');
  128. }
  129. });
  130. (0, globals_1.it)('should reject order pair with same account for buy and sell', async () => {
  131. const invalidOrderPairRequest = {
  132. sessionId: testSessionId,
  133. buyAccountId: 'account-1',
  134. sellAccountId: 'account-1', // Same account for both sides
  135. symbol: 'ETH/USD',
  136. size: 100,
  137. price: 2500,
  138. orderType: 'limit'
  139. };
  140. try {
  141. await orderCoordinator.createOrderPair(invalidOrderPairRequest);
  142. fail('Should have rejected order pair with same account');
  143. }
  144. catch (error) {
  145. (0, globals_1.expect)(error.message).toContain('same account');
  146. }
  147. });
  148. (0, globals_1.it)('should reject order pair with different sizes', async () => {
  149. const invalidOrderPairRequest = {
  150. sessionId: testSessionId,
  151. buyAccountId: 'account-1',
  152. sellAccountId: 'account-2',
  153. symbol: 'ETH/USD',
  154. buySize: 100,
  155. sellSize: 150, // Different sizes
  156. price: 2500,
  157. orderType: 'limit'
  158. };
  159. try {
  160. await orderCoordinator.createOrderPair(invalidOrderPairRequest);
  161. fail('Should have rejected order pair with different sizes');
  162. }
  163. catch (error) {
  164. (0, globals_1.expect)(error.message).toContain('size');
  165. }
  166. });
  167. });
  168. (0, globals_1.describe)('Order Pair Execution', () => {
  169. let testOrderPairId;
  170. (0, globals_1.beforeEach)(async () => {
  171. const orderPairRequest = {
  172. sessionId: testSessionId,
  173. buyAccountId: 'account-1',
  174. sellAccountId: 'account-2',
  175. symbol: 'ETH/USD',
  176. size: 100,
  177. price: 2500,
  178. orderType: 'limit'
  179. };
  180. try {
  181. const orderPair = await orderCoordinator.createOrderPair(orderPairRequest);
  182. testOrderPairId = orderPair.id;
  183. }
  184. catch (error) {
  185. testOrderPairId = 'mock-order-pair-id';
  186. }
  187. });
  188. (0, globals_1.it)('should execute order pair atomically', async () => {
  189. try {
  190. const result = await orderCoordinator.executeOrderPair(testOrderPairId);
  191. (0, globals_1.expect)(result).toBeDefined();
  192. (0, globals_1.expect)(result.success).toBe(true);
  193. (0, globals_1.expect)(result.orderPairId).toBe(testOrderPairId);
  194. (0, globals_1.expect)(result.executionTime).toBeDefined();
  195. (0, globals_1.expect)(result.executionTime).toBeGreaterThan(0);
  196. // Verify both orders were executed
  197. const orderPair = await orderCoordinator.getOrderPair(testOrderPairId);
  198. (0, globals_1.expect)(orderPair.status).toBe('filled');
  199. (0, globals_1.expect)(orderPair.orderPair.buyOrder.status).toBe('filled');
  200. (0, globals_1.expect)(orderPair.orderPair.sellOrder.status).toBe('filled');
  201. (0, globals_1.expect)(orderPair.executedAt).toBeDefined();
  202. (0, globals_1.expect)(orderPair.completedAt).toBeDefined();
  203. }
  204. catch (error) {
  205. // This test should fail initially since OrderCoordinator doesn't exist yet
  206. (0, globals_1.expect)(error.message).toContain('OrderCoordinator');
  207. }
  208. });
  209. (0, globals_1.it)('should handle partial fills correctly', async () => {
  210. try {
  211. // Mock partial fill scenario
  212. const result = await orderCoordinator.executeOrderPair(testOrderPairId);
  213. if (result.partialFill) {
  214. const orderPair = await orderCoordinator.getOrderPair(testOrderPairId);
  215. (0, globals_1.expect)(orderPair.status).toBe('partial');
  216. (0, globals_1.expect)(orderPair.orderPair.buyOrder.fillSize).toBeLessThan(orderPair.orderPair.buyOrder.size);
  217. (0, globals_1.expect)(orderPair.orderPair.sellOrder.fillSize).toBeLessThan(orderPair.orderPair.sellOrder.size);
  218. }
  219. }
  220. catch (error) {
  221. // This test should fail initially since OrderCoordinator doesn't exist yet
  222. (0, globals_1.expect)(error.message).toContain('OrderCoordinator');
  223. }
  224. });
  225. (0, globals_1.it)('should handle execution failures gracefully', async () => {
  226. try {
  227. // Mock execution failure scenario
  228. const result = await orderCoordinator.executeOrderPair(testOrderPairId);
  229. if (!result.success) {
  230. const orderPair = await orderCoordinator.getOrderPair(testOrderPairId);
  231. (0, globals_1.expect)(orderPair.status).toBe('failed');
  232. (0, globals_1.expect)(result.error).toBeDefined();
  233. (0, globals_1.expect)(result.error.message).toBeDefined();
  234. }
  235. }
  236. catch (error) {
  237. // This test should fail initially since OrderCoordinator doesn't exist yet
  238. (0, globals_1.expect)(error.message).toContain('OrderCoordinator');
  239. }
  240. });
  241. (0, globals_1.it)('should retry failed orders according to configuration', async () => {
  242. try {
  243. const result = await orderCoordinator.executeOrderPair(testOrderPairId);
  244. if (!result.success && result.retryCount) {
  245. (0, globals_1.expect)(result.retryCount).toBeGreaterThan(0);
  246. (0, globals_1.expect)(result.retryCount).toBeLessThanOrEqual(3); // Max retry attempts
  247. }
  248. }
  249. catch (error) {
  250. // This test should fail initially since OrderCoordinator doesn't exist yet
  251. (0, globals_1.expect)(error.message).toContain('OrderCoordinator');
  252. }
  253. });
  254. });
  255. (0, globals_1.describe)('Order Pair Monitoring', () => {
  256. let testOrderPairId;
  257. (0, globals_1.beforeEach)(async () => {
  258. const orderPairRequest = {
  259. sessionId: testSessionId,
  260. buyAccountId: 'account-1',
  261. sellAccountId: 'account-2',
  262. symbol: 'ETH/USD',
  263. size: 100,
  264. price: 2500,
  265. orderType: 'limit'
  266. };
  267. try {
  268. const orderPair = await orderCoordinator.createOrderPair(orderPairRequest);
  269. testOrderPairId = orderPair.id;
  270. }
  271. catch (error) {
  272. testOrderPairId = 'mock-order-pair-id';
  273. }
  274. });
  275. (0, globals_1.it)('should track order pair status changes', async () => {
  276. try {
  277. const initialOrderPair = await orderCoordinator.getOrderPair(testOrderPairId);
  278. (0, globals_1.expect)(initialOrderPair.status).toBe('pending');
  279. // Execute the order pair
  280. await orderCoordinator.executeOrderPair(testOrderPairId);
  281. const executedOrderPair = await orderCoordinator.getOrderPair(testOrderPairId);
  282. (0, globals_1.expect)(executedOrderPair.status).toBe('submitted');
  283. // Wait for execution to complete
  284. await new Promise(resolve => setTimeout(resolve, 100));
  285. const completedOrderPair = await orderCoordinator.getOrderPair(testOrderPairId);
  286. (0, globals_1.expect)(['filled', 'failed', 'partial']).toContain(completedOrderPair.status);
  287. }
  288. catch (error) {
  289. // This test should fail initially since OrderCoordinator doesn't exist yet
  290. (0, globals_1.expect)(error.message).toContain('OrderCoordinator');
  291. }
  292. });
  293. (0, globals_1.it)('should calculate execution metrics', async () => {
  294. try {
  295. const result = await orderCoordinator.executeOrderPair(testOrderPairId);
  296. if (result.success) {
  297. (0, globals_1.expect)(result.executionTime).toBeDefined();
  298. (0, globals_1.expect)(result.slippage).toBeDefined();
  299. (0, globals_1.expect)(result.fees).toBeDefined();
  300. (0, globals_1.expect)(result.executionTime).toBeGreaterThan(0);
  301. }
  302. }
  303. catch (error) {
  304. // This test should fail initially since OrderCoordinator doesn't exist yet
  305. (0, globals_1.expect)(error.message).toContain('OrderCoordinator');
  306. }
  307. });
  308. (0, globals_1.it)('should emit order pair events', async () => {
  309. const events = [];
  310. try {
  311. orderCoordinator.on('orderPairCreated', (orderPair) => {
  312. events.push('orderPairCreated');
  313. (0, globals_1.expect)(orderPair.id).toBe(testOrderPairId);
  314. });
  315. orderCoordinator.on('orderPairExecuted', (orderPair) => {
  316. events.push('orderPairExecuted');
  317. (0, globals_1.expect)(orderPair.id).toBe(testOrderPairId);
  318. });
  319. orderCoordinator.on('orderPairCompleted', (orderPair) => {
  320. events.push('orderPairCompleted');
  321. (0, globals_1.expect)(orderPair.id).toBe(testOrderPairId);
  322. });
  323. await orderCoordinator.executeOrderPair(testOrderPairId);
  324. (0, globals_1.expect)(events).toContain('orderPairCreated');
  325. (0, globals_1.expect)(events).toContain('orderPairExecuted');
  326. (0, globals_1.expect)(events).toContain('orderPairCompleted');
  327. }
  328. catch (error) {
  329. // This test should fail initially since OrderCoordinator doesn't exist yet
  330. (0, globals_1.expect)(error.message).toContain('OrderCoordinator');
  331. }
  332. });
  333. });
  334. (0, globals_1.describe)('Concurrent Order Execution', () => {
  335. (0, globals_1.it)('should handle multiple concurrent order pairs', async () => {
  336. const orderPairRequests = [
  337. {
  338. sessionId: testSessionId,
  339. buyAccountId: 'account-1',
  340. sellAccountId: 'account-2',
  341. symbol: 'ETH/USD',
  342. size: 100,
  343. price: 2500,
  344. orderType: 'limit'
  345. },
  346. {
  347. sessionId: testSessionId,
  348. buyAccountId: 'account-2',
  349. sellAccountId: 'account-1',
  350. symbol: 'ETH/USD',
  351. size: 150,
  352. price: 2501,
  353. orderType: 'limit'
  354. }
  355. ];
  356. try {
  357. const orderPairs = await Promise.all(orderPairRequests.map(request => orderCoordinator.createOrderPair(request)));
  358. (0, globals_1.expect)(orderPairs).toHaveLength(2);
  359. (0, globals_1.expect)(orderPairs[0].id).not.toBe(orderPairs[1].id);
  360. // Execute both order pairs concurrently
  361. const results = await Promise.all(orderPairs.map(orderPair => orderCoordinator.executeOrderPair(orderPair.id)));
  362. (0, globals_1.expect)(results).toHaveLength(2);
  363. results.forEach(result => {
  364. (0, globals_1.expect)(result).toBeDefined();
  365. (0, globals_1.expect)(result.orderPairId).toBeDefined();
  366. });
  367. }
  368. catch (error) {
  369. // This test should fail initially since OrderCoordinator doesn't exist yet
  370. (0, globals_1.expect)(error.message).toContain('OrderCoordinator');
  371. }
  372. });
  373. (0, globals_1.it)('should respect maximum concurrent orders limit', async () => {
  374. const orderPairRequests = Array(25).fill(null).map((_, index) => ({
  375. sessionId: testSessionId,
  376. buyAccountId: 'account-1',
  377. sellAccountId: 'account-2',
  378. symbol: 'ETH/USD',
  379. size: 100,
  380. price: 2500 + index,
  381. orderType: 'limit'
  382. }));
  383. try {
  384. const orderPairs = await Promise.all(orderPairRequests.map(request => orderCoordinator.createOrderPair(request)));
  385. // Try to execute all order pairs
  386. const results = await Promise.allSettled(orderPairs.map(orderPair => orderCoordinator.executeOrderPair(orderPair.id)));
  387. // Some should succeed, some should be rejected due to concurrency limit
  388. const successful = results.filter(r => r.status === 'fulfilled');
  389. const rejected = results.filter(r => r.status === 'rejected');
  390. (0, globals_1.expect)(successful.length + rejected.length).toBe(25);
  391. (0, globals_1.expect)(successful.length).toBeLessThanOrEqual(20); // Max concurrent orders
  392. }
  393. catch (error) {
  394. // This test should fail initially since OrderCoordinator doesn't exist yet
  395. (0, globals_1.expect)(error.message).toContain('OrderCoordinator');
  396. }
  397. });
  398. });
  399. (0, globals_1.describe)('Error Handling', () => {
  400. (0, globals_1.it)('should handle non-existent order pair operations gracefully', async () => {
  401. const nonExistentOrderPairId = 'non-existent-order-pair-id';
  402. try {
  403. await orderCoordinator.getOrderPair(nonExistentOrderPairId);
  404. fail('Should have thrown error for non-existent order pair');
  405. }
  406. catch (error) {
  407. (0, globals_1.expect)(error.message).toContain('not found');
  408. }
  409. });
  410. (0, globals_1.it)('should handle execution timeout', async () => {
  411. const orderPairRequest = {
  412. sessionId: testSessionId,
  413. buyAccountId: 'account-1',
  414. sellAccountId: 'account-2',
  415. symbol: 'ETH/USD',
  416. size: 100,
  417. price: 2500,
  418. orderType: 'limit'
  419. };
  420. try {
  421. const orderPair = await orderCoordinator.createOrderPair(orderPairRequest);
  422. // Mock timeout scenario
  423. const result = await orderCoordinator.executeOrderPair(orderPair.id);
  424. if (!result.success && result.timeout) {
  425. (0, globals_1.expect)(result.error.message).toContain('timeout');
  426. }
  427. }
  428. catch (error) {
  429. // This test should fail initially since OrderCoordinator doesn't exist yet
  430. (0, globals_1.expect)(error.message).toContain('OrderCoordinator');
  431. }
  432. });
  433. });
  434. });
  435. //# sourceMappingURL=test_order_pair_execution.js.map