hedgequantx 2.6.161 → 2.6.162

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/package.json +1 -1
  2. package/src/menus/ai-agent-connect.js +181 -0
  3. package/src/menus/ai-agent-models.js +219 -0
  4. package/src/menus/ai-agent-oauth.js +292 -0
  5. package/src/menus/ai-agent-ui.js +141 -0
  6. package/src/menus/ai-agent.js +88 -1489
  7. package/src/pages/algo/copy-engine.js +449 -0
  8. package/src/pages/algo/copy-trading.js +11 -543
  9. package/src/pages/algo/smart-logs-data.js +218 -0
  10. package/src/pages/algo/smart-logs.js +9 -214
  11. package/src/pages/algo/ui-constants.js +144 -0
  12. package/src/pages/algo/ui-summary.js +184 -0
  13. package/src/pages/algo/ui.js +42 -526
  14. package/src/pages/stats-calculations.js +191 -0
  15. package/src/pages/stats-ui.js +381 -0
  16. package/src/pages/stats.js +14 -507
  17. package/src/services/ai/client-analysis.js +194 -0
  18. package/src/services/ai/client-models.js +333 -0
  19. package/src/services/ai/client.js +6 -489
  20. package/src/services/ai/index.js +2 -257
  21. package/src/services/ai/proxy-install.js +249 -0
  22. package/src/services/ai/proxy-manager.js +29 -411
  23. package/src/services/ai/proxy-remote.js +161 -0
  24. package/src/services/ai/supervisor-optimize.js +215 -0
  25. package/src/services/ai/supervisor-sync.js +178 -0
  26. package/src/services/ai/supervisor.js +50 -515
  27. package/src/services/ai/validation.js +250 -0
  28. package/src/services/hqx-server-events.js +110 -0
  29. package/src/services/hqx-server-handlers.js +217 -0
  30. package/src/services/hqx-server-latency.js +136 -0
  31. package/src/services/hqx-server.js +51 -403
  32. package/src/services/position-constants.js +28 -0
  33. package/src/services/position-manager.js +105 -554
  34. package/src/services/position-momentum.js +206 -0
  35. package/src/services/projectx/accounts.js +142 -0
  36. package/src/services/projectx/index.js +40 -289
  37. package/src/services/projectx/trading.js +180 -0
  38. package/src/services/rithmic/handlers.js +2 -208
  39. package/src/services/rithmic/index.js +32 -542
  40. package/src/services/rithmic/latency-tracker.js +182 -0
  41. package/src/services/rithmic/specs.js +146 -0
  42. package/src/services/rithmic/trade-history.js +254 -0
@@ -20,6 +20,8 @@ const {
20
20
  const { getMarketHolidays, checkHoliday, checkMarketHours } = require('./market');
21
21
  const { calculateLifetimeStats, calculateDailyPnL, formatTrades } = require('./stats');
22
22
  const { logger } = require('../../utils/logger');
23
+ const trading = require('./trading');
24
+ const accounts = require('./accounts');
23
25
 
24
26
  const log = logger.scope('ProjectX');
25
27
 
@@ -203,322 +205,71 @@ class ProjectXService {
203
205
 
204
206
  /**
205
207
  * Get trading accounts with REAL P&L from API
206
- *
207
- * Data sources:
208
- * - /TradingAccount: accountId, accountName, balance, status, type
209
- * - /AccountTemplate/userTemplates: startingBalance
210
- * - /Position?accountId=X: profitAndLoss (unrealized P&L)
211
- *
212
208
  * @returns {Promise<{success: boolean, accounts: Array, error?: string}>}
213
209
  */
214
210
  async getTradingAccounts() {
215
- try {
216
- const response = await this._request(this.propfirm.userApi, '/TradingAccount', 'GET');
217
-
218
- if (response.statusCode !== 200) {
219
- return { success: false, accounts: [], error: 'Failed to get accounts' };
220
- }
221
-
222
- const accounts = Array.isArray(response.data) ? response.data : [];
223
-
224
- // Get account templates for startingBalance
225
- let templates = [];
226
- try {
227
- const templateRes = await this._request(this.propfirm.userApi, '/AccountTemplate/userTemplates', 'GET');
228
- if (templateRes.statusCode === 200 && Array.isArray(templateRes.data)) {
229
- templates = templateRes.data;
230
- }
231
- } catch {
232
- log.debug('Failed to get templates');
233
- }
234
-
235
- const enrichedAccounts = await Promise.all(
236
- accounts.map(account => this._enrichAccount(account, templates))
237
- );
238
-
239
- return { success: true, accounts: enrichedAccounts };
240
- } catch (err) {
241
- log.error('Failed to get accounts', { error: err.message });
242
- return { success: false, accounts: [], error: err.message };
243
- }
244
- }
245
-
246
- /**
247
- * Enrich account with P&L data
248
- * @private
249
- */
250
- async _enrichAccount(account, templates) {
251
- const template = templates.find(t =>
252
- account.accountName && (
253
- account.accountName.includes(t.title) ||
254
- t.title.includes(account.accountName)
255
- )
211
+ return accounts.getTradingAccounts(
212
+ (host, path, method, data) => this._request(host, path, method, data),
213
+ this.propfirm
256
214
  );
257
-
258
- const enriched = {
259
- accountId: account.accountId,
260
- accountName: account.accountName,
261
- balance: account.balance,
262
- status: account.status,
263
- type: account.type,
264
- startingBalance: template?.startingBalance || null,
265
- platform: 'ProjectX',
266
- propfirm: this.propfirm.name,
267
- openPnL: null,
268
- todayPnL: null,
269
- profitAndLoss: null,
270
- };
271
-
272
- // Only fetch P&L for active accounts
273
- if (account.status !== 0) {
274
- return enriched;
275
- }
276
-
277
- // Get unrealized P&L from open positions
278
- let openPnL = 0;
279
- try {
280
- const posRes = await this._request(
281
- this.propfirm.userApi,
282
- `/Position?accountId=${account.accountId}`,
283
- 'GET'
284
- );
285
-
286
- if (posRes.statusCode === 200 && Array.isArray(posRes.data)) {
287
- for (const pos of posRes.data) {
288
- if (pos.profitAndLoss != null) {
289
- openPnL += pos.profitAndLoss;
290
- }
291
- }
292
- }
293
- } catch {
294
- log.debug('Failed to get positions', { accountId: account.accountId });
295
- }
296
-
297
- // Get realized P&L from today's trades
298
- let todayPnL = 0;
299
- try {
300
- const today = new Date();
301
- today.setHours(0, 0, 0, 0);
302
-
303
- const tradesRes = await this._request(
304
- this.propfirm.gatewayApi,
305
- '/api/Trade/search',
306
- 'POST',
307
- {
308
- accountId: account.accountId,
309
- startTimestamp: today.toISOString(),
310
- endTimestamp: new Date().toISOString(),
311
- }
312
- );
313
-
314
- if (tradesRes.statusCode === 200) {
315
- const trades = Array.isArray(tradesRes.data) ? tradesRes.data : (tradesRes.data.trades || []);
316
- for (const trade of trades) {
317
- if (trade.profitAndLoss != null) {
318
- todayPnL += trade.profitAndLoss;
319
- }
320
- }
321
- }
322
- } catch {
323
- log.debug('Failed to get today trades', { accountId: account.accountId });
324
- }
325
-
326
- enriched.openPnL = openPnL;
327
- enriched.todayPnL = todayPnL;
328
- enriched.profitAndLoss = openPnL + todayPnL;
329
-
330
- return enriched;
331
215
  }
332
216
 
333
217
  // ==================== TRADING ====================
334
218
 
335
- /**
336
- * Get open positions
337
- * @param {number|string} accountId - Account ID
338
- * @returns {Promise<{success: boolean, positions: Array, error?: string}>}
339
- */
219
+ /** Get open positions */
340
220
  async getPositions(accountId) {
341
- try {
342
- const id = validateAccountId(accountId);
343
- const response = await this._request(
344
- this.propfirm.gatewayApi,
345
- '/api/Position/searchOpen',
346
- 'POST',
347
- { accountId: id }
348
- );
349
-
350
- if (response.statusCode === 200) {
351
- const positions = response.data.positions || response.data || [];
352
- return { success: true, positions: Array.isArray(positions) ? positions : [] };
353
- }
354
-
355
- return { success: true, positions: [] };
356
- } catch (err) {
357
- return { success: true, positions: [], error: err.message };
358
- }
221
+ return trading.getPositions(
222
+ (host, path, method, data) => this._request(host, path, method, data),
223
+ this.propfirm.gatewayApi, accountId
224
+ );
359
225
  }
360
226
 
361
- /**
362
- * Get open orders
363
- * @param {number|string} accountId - Account ID
364
- * @returns {Promise<{success: boolean, orders: Array, error?: string}>}
365
- */
227
+ /** Get open orders */
366
228
  async getOrders(accountId) {
367
- try {
368
- const id = validateAccountId(accountId);
369
- const response = await this._request(
370
- this.propfirm.gatewayApi,
371
- '/api/Order/searchOpen',
372
- 'POST',
373
- { accountId: id }
374
- );
375
-
376
- if (response.statusCode === 200) {
377
- const orders = response.data.orders || response.data || [];
378
- return { success: true, orders: Array.isArray(orders) ? orders : [] };
379
- }
380
-
381
- return { success: true, orders: [] };
382
- } catch (err) {
383
- return { success: true, orders: [], error: err.message };
384
- }
229
+ return trading.getOrders(
230
+ (host, path, method, data) => this._request(host, path, method, data),
231
+ this.propfirm.gatewayApi, accountId
232
+ );
385
233
  }
386
234
 
387
- /**
388
- * Get trades history for today
389
- * @param {number|string} accountId - Account ID
390
- * @returns {Promise<{success: boolean, trades: Array, error?: string}>}
391
- */
235
+ /** Get trades for today */
392
236
  async getTrades(accountId) {
393
- try {
394
- const id = validateAccountId(accountId);
395
-
396
- // Get today's trades (from midnight UTC)
397
- const now = new Date();
398
- const startOfDay = new Date(now);
399
- startOfDay.setUTCHours(0, 0, 0, 0);
400
-
401
- const response = await this._request(
402
- this.propfirm.gatewayApi,
403
- '/api/Trade/search',
404
- 'POST',
405
- {
406
- accountId: id,
407
- startTimestamp: startOfDay.toISOString(),
408
- endTimestamp: now.toISOString()
409
- }
410
- );
411
-
412
- if (response.statusCode === 200) {
413
- const trades = response.data.trades || response.data || [];
414
- return { success: true, trades: Array.isArray(trades) ? trades : [] };
415
- }
416
-
417
- return { success: true, trades: [] };
418
- } catch (err) {
419
- return { success: true, trades: [], error: err.message };
420
- }
237
+ return trading.getTrades(
238
+ (host, path, method, data) => this._request(host, path, method, data),
239
+ this.propfirm.gatewayApi, accountId
240
+ );
421
241
  }
422
242
 
423
- /**
424
- * Place an order
425
- * @param {Object} orderData - Order details
426
- * @returns {Promise<{success: boolean, order?: Object, error?: string}>}
427
- */
243
+ /** Place an order */
428
244
  async placeOrder(orderData) {
429
- try {
430
- const response = await this._request(
431
- this.propfirm.gatewayApi,
432
- '/api/Order/place',
433
- 'POST',
434
- orderData,
435
- 'orders'
436
- );
437
-
438
- if (response.statusCode === 200 && response.data.success) {
439
- log.info('Order placed', { orderId: response.data.orderId });
440
- return { success: true, order: response.data };
441
- }
442
-
443
- return { success: false, error: response.data.errorMessage || 'Order failed' };
444
- } catch (err) {
445
- return { success: false, error: err.message };
446
- }
245
+ return trading.placeOrder(
246
+ (host, path, method, data, limiter) => this._request(host, path, method, data, limiter),
247
+ this.propfirm.gatewayApi, orderData
248
+ );
447
249
  }
448
250
 
449
- /**
450
- * Cancel an order
451
- * @param {number|string} orderId - Order ID
452
- * @returns {Promise<{success: boolean, error?: string}>}
453
- */
251
+ /** Cancel an order */
454
252
  async cancelOrder(orderId) {
455
- try {
456
- const response = await this._request(
457
- this.propfirm.gatewayApi,
458
- '/api/Order/cancel',
459
- 'POST',
460
- { orderId: parseInt(orderId, 10) },
461
- 'orders'
462
- );
463
-
464
- return { success: response.statusCode === 200 && response.data.success };
465
- } catch (err) {
466
- return { success: false, error: err.message };
467
- }
253
+ return trading.cancelOrder(
254
+ (host, path, method, data, limiter) => this._request(host, path, method, data, limiter),
255
+ this.propfirm.gatewayApi, orderId
256
+ );
468
257
  }
469
258
 
470
- /**
471
- * Cancel all open orders for an account
472
- * @param {number|string} accountId - Account ID
473
- * @returns {Promise<{success: boolean, cancelled: number, error?: string}>}
474
- */
259
+ /** Cancel all open orders */
475
260
  async cancelAllOrders(accountId) {
476
- try {
477
- const id = validateAccountId(accountId);
478
- const ordersResult = await this.getOrders(id);
479
-
480
- if (!ordersResult.success || !ordersResult.orders?.length) {
481
- return { success: true, cancelled: 0 };
482
- }
483
-
484
- const pendingOrders = ordersResult.orders.filter(o =>
485
- o.status === 'Working' || o.status === 'Pending' ||
486
- o.status === 0 || o.status === 1
487
- );
488
-
489
- let cancelled = 0;
490
- for (const order of pendingOrders) {
491
- const result = await this.cancelOrder(order.orderId || order.id);
492
- if (result.success) cancelled++;
493
- }
494
-
495
- return { success: true, cancelled };
496
- } catch (err) {
497
- return { success: false, cancelled: 0, error: err.message };
498
- }
261
+ return trading.cancelAllOrders(
262
+ (host, path, method, data, limiter) => this._request(host, path, method, data, limiter),
263
+ this.propfirm.gatewayApi, accountId
264
+ );
499
265
  }
500
266
 
501
- /**
502
- * Close a position
503
- * @param {number|string} accountId - Account ID
504
- * @param {number|string} contractId - Contract ID
505
- * @returns {Promise<{success: boolean, error?: string}>}
506
- */
267
+ /** Close a position */
507
268
  async closePosition(accountId, contractId) {
508
- try {
509
- const id = validateAccountId(accountId);
510
- const response = await this._request(
511
- this.propfirm.gatewayApi,
512
- '/api/Position/closeContract',
513
- 'POST',
514
- { accountId: id, contractId },
515
- 'orders'
516
- );
517
-
518
- return { success: response.statusCode === 200 && response.data.success };
519
- } catch (err) {
520
- return { success: false, error: err.message };
521
- }
269
+ return trading.closePosition(
270
+ (host, path, method, data, limiter) => this._request(host, path, method, data, limiter),
271
+ this.propfirm.gatewayApi, accountId, contractId
272
+ );
522
273
  }
523
274
 
524
275
  // ==================== TRADES & STATS ====================
@@ -0,0 +1,180 @@
1
+ /**
2
+ * ProjectX Trading Operations
3
+ * @module services/projectx/trading
4
+ *
5
+ * Order management, position control, and trade history.
6
+ */
7
+
8
+ const { validateAccountId } = require('../../security');
9
+ const { logger } = require('../../utils/logger');
10
+
11
+ const log = logger.scope('ProjectX');
12
+
13
+ /**
14
+ * Get open positions
15
+ * @param {Function} request - Request function
16
+ * @param {string} gatewayApi - Gateway API host
17
+ * @param {number|string} accountId - Account ID
18
+ */
19
+ async function getPositions(request, gatewayApi, accountId) {
20
+ try {
21
+ const id = validateAccountId(accountId);
22
+ const response = await request(gatewayApi, '/api/Position/searchOpen', 'POST', { accountId: id });
23
+
24
+ if (response.statusCode === 200) {
25
+ const positions = response.data.positions || response.data || [];
26
+ return { success: true, positions: Array.isArray(positions) ? positions : [] };
27
+ }
28
+
29
+ return { success: true, positions: [] };
30
+ } catch (err) {
31
+ return { success: true, positions: [], error: err.message };
32
+ }
33
+ }
34
+
35
+ /**
36
+ * Get open orders
37
+ * @param {Function} request - Request function
38
+ * @param {string} gatewayApi - Gateway API host
39
+ * @param {number|string} accountId - Account ID
40
+ */
41
+ async function getOrders(request, gatewayApi, accountId) {
42
+ try {
43
+ const id = validateAccountId(accountId);
44
+ const response = await request(gatewayApi, '/api/Order/searchOpen', 'POST', { accountId: id });
45
+
46
+ if (response.statusCode === 200) {
47
+ const orders = response.data.orders || response.data || [];
48
+ return { success: true, orders: Array.isArray(orders) ? orders : [] };
49
+ }
50
+
51
+ return { success: true, orders: [] };
52
+ } catch (err) {
53
+ return { success: true, orders: [], error: err.message };
54
+ }
55
+ }
56
+
57
+ /**
58
+ * Get trades for today
59
+ * @param {Function} request - Request function
60
+ * @param {string} gatewayApi - Gateway API host
61
+ * @param {number|string} accountId - Account ID
62
+ */
63
+ async function getTrades(request, gatewayApi, accountId) {
64
+ try {
65
+ const id = validateAccountId(accountId);
66
+ const now = new Date();
67
+ const startOfDay = new Date(now);
68
+ startOfDay.setUTCHours(0, 0, 0, 0);
69
+
70
+ const response = await request(gatewayApi, '/api/Trade/search', 'POST', {
71
+ accountId: id,
72
+ startTimestamp: startOfDay.toISOString(),
73
+ endTimestamp: now.toISOString()
74
+ });
75
+
76
+ if (response.statusCode === 200) {
77
+ const trades = response.data.trades || response.data || [];
78
+ return { success: true, trades: Array.isArray(trades) ? trades : [] };
79
+ }
80
+
81
+ return { success: true, trades: [] };
82
+ } catch (err) {
83
+ return { success: true, trades: [], error: err.message };
84
+ }
85
+ }
86
+
87
+ /**
88
+ * Place an order
89
+ * @param {Function} request - Request function
90
+ * @param {string} gatewayApi - Gateway API host
91
+ * @param {Object} orderData - Order details
92
+ */
93
+ async function placeOrder(request, gatewayApi, orderData) {
94
+ try {
95
+ const response = await request(gatewayApi, '/api/Order/place', 'POST', orderData, 'orders');
96
+
97
+ if (response.statusCode === 200 && response.data.success) {
98
+ log.info('Order placed', { orderId: response.data.orderId });
99
+ return { success: true, order: response.data };
100
+ }
101
+
102
+ return { success: false, error: response.data.errorMessage || 'Order failed' };
103
+ } catch (err) {
104
+ return { success: false, error: err.message };
105
+ }
106
+ }
107
+
108
+ /**
109
+ * Cancel an order
110
+ * @param {Function} request - Request function
111
+ * @param {string} gatewayApi - Gateway API host
112
+ * @param {number|string} orderId - Order ID
113
+ */
114
+ async function cancelOrder(request, gatewayApi, orderId) {
115
+ try {
116
+ const response = await request(gatewayApi, '/api/Order/cancel', 'POST', { orderId: parseInt(orderId, 10) }, 'orders');
117
+ return { success: response.statusCode === 200 && response.data.success };
118
+ } catch (err) {
119
+ return { success: false, error: err.message };
120
+ }
121
+ }
122
+
123
+ /**
124
+ * Cancel all open orders for an account
125
+ * @param {Function} request - Request function
126
+ * @param {string} gatewayApi - Gateway API host
127
+ * @param {number|string} accountId - Account ID
128
+ */
129
+ async function cancelAllOrders(request, gatewayApi, accountId) {
130
+ try {
131
+ const id = validateAccountId(accountId);
132
+ const ordersResult = await getOrders(request, gatewayApi, id);
133
+
134
+ if (!ordersResult.success || !ordersResult.orders?.length) {
135
+ return { success: true, cancelled: 0 };
136
+ }
137
+
138
+ const pendingOrders = ordersResult.orders.filter(o =>
139
+ o.status === 'Working' || o.status === 'Pending' ||
140
+ o.status === 0 || o.status === 1
141
+ );
142
+
143
+ let cancelled = 0;
144
+ for (const order of pendingOrders) {
145
+ const result = await cancelOrder(request, gatewayApi, order.orderId || order.id);
146
+ if (result.success) cancelled++;
147
+ }
148
+
149
+ return { success: true, cancelled };
150
+ } catch (err) {
151
+ return { success: false, cancelled: 0, error: err.message };
152
+ }
153
+ }
154
+
155
+ /**
156
+ * Close a position
157
+ * @param {Function} request - Request function
158
+ * @param {string} gatewayApi - Gateway API host
159
+ * @param {number|string} accountId - Account ID
160
+ * @param {number|string} contractId - Contract ID
161
+ */
162
+ async function closePosition(request, gatewayApi, accountId, contractId) {
163
+ try {
164
+ const id = validateAccountId(accountId);
165
+ const response = await request(gatewayApi, '/api/Position/closeContract', 'POST', { accountId: id, contractId }, 'orders');
166
+ return { success: response.statusCode === 200 && response.data.success };
167
+ } catch (err) {
168
+ return { success: false, error: err.message };
169
+ }
170
+ }
171
+
172
+ module.exports = {
173
+ getPositions,
174
+ getOrders,
175
+ getTrades,
176
+ placeOrder,
177
+ cancelOrder,
178
+ cancelAllOrders,
179
+ closePosition,
180
+ };