hedgequantx 2.6.38 → 2.6.39
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.
package/package.json
CHANGED
|
@@ -449,20 +449,21 @@ const FillInfoPool = {
|
|
|
449
449
|
*/
|
|
450
450
|
fill(notif, receiveTime, latency) {
|
|
451
451
|
const o = this._template;
|
|
452
|
-
o.orderTag = notif.
|
|
452
|
+
o.orderTag = notif.userTag || null; // userTag contains our order tag
|
|
453
453
|
o.basketId = notif.basketId;
|
|
454
|
-
o.orderId = notif.orderId;
|
|
454
|
+
o.orderId = notif.exchangeOrderId || notif.orderId;
|
|
455
455
|
o.status = notif.status;
|
|
456
456
|
o.symbol = notif.symbol;
|
|
457
457
|
o.exchange = notif.exchange;
|
|
458
458
|
o.accountId = notif.accountId;
|
|
459
|
-
|
|
460
|
-
o.
|
|
461
|
-
o.
|
|
459
|
+
// Proto uses totalFillSize, not fillQuantity
|
|
460
|
+
o.fillQuantity = notif.totalFillSize || notif.fillQuantity || 0;
|
|
461
|
+
o.totalFillQuantity = notif.totalFillSize || notif.totalFillQuantity || 0;
|
|
462
|
+
o.remainingQuantity = notif.totalUnfilledSize || notif.remainingQuantity || 0;
|
|
462
463
|
o.avgFillPrice = parseFloat(notif.avgFillPrice || 0);
|
|
463
|
-
o.lastFillPrice = parseFloat(notif.fillPrice || 0);
|
|
464
|
+
o.lastFillPrice = parseFloat(notif.price || notif.fillPrice || 0);
|
|
464
465
|
o.transactionType = notif.transactionType;
|
|
465
|
-
o.orderType = notif.orderType;
|
|
466
|
+
o.orderType = notif.priceType || notif.orderType;
|
|
466
467
|
o.quantity = notif.quantity;
|
|
467
468
|
o.ssboe = notif.ssboe;
|
|
468
469
|
o.usecs = notif.usecs;
|
|
@@ -495,11 +496,13 @@ const handleOrderNotification = (service, data) => {
|
|
|
495
496
|
|
|
496
497
|
try {
|
|
497
498
|
const notif = proto.decode('RithmicOrderNotification', data);
|
|
498
|
-
|
|
499
|
+
// userTag contains our order tag (userMsg is not in this proto)
|
|
500
|
+
const orderTag = notif.userTag || null;
|
|
499
501
|
|
|
500
502
|
// FAST PATH: Check for fill immediately
|
|
501
|
-
|
|
502
|
-
const
|
|
503
|
+
// Proto uses total_fill_size (camelCase: totalFillSize), not fillQuantity
|
|
504
|
+
const fillQty = notif.totalFillSize || notif.totalFillQuantity || notif.fillQuantity || 0;
|
|
505
|
+
const isFill = fillQty > 0 || notif.status === 'complete';
|
|
503
506
|
|
|
504
507
|
// Calculate round-trip latency if this is a fill we're tracking
|
|
505
508
|
let roundTripLatency = null;
|
|
@@ -521,15 +524,18 @@ const handleOrderNotification = (service, data) => {
|
|
|
521
524
|
// Emit raw notification
|
|
522
525
|
service.emit('orderNotification', fillInfo);
|
|
523
526
|
|
|
524
|
-
// Emit fill event if this is a fill
|
|
527
|
+
// Emit fill event if this is a fill (status=complete means order is fully filled)
|
|
525
528
|
if (isFill) {
|
|
526
|
-
|
|
529
|
+
const actualFillQty = fillInfo.totalFillQuantity || fillInfo.fillQuantity || notif.quantity || 0;
|
|
530
|
+
const fillPrice = fillInfo.avgFillPrice || fillInfo.lastFillPrice || 0;
|
|
531
|
+
|
|
532
|
+
console.log(`[FILL] Received: ${orderTag} | ${fillInfo.transactionType === 1 ? 'BUY' : 'SELL'} ${actualFillQty}x @ ${fillPrice} | latency=${roundTripLatency}ms`);
|
|
527
533
|
|
|
528
534
|
debug('ORDER FILLED:', {
|
|
529
535
|
orderTag,
|
|
530
536
|
side: fillInfo.transactionType === 1 ? 'BUY' : 'SELL',
|
|
531
|
-
qty:
|
|
532
|
-
avgPrice:
|
|
537
|
+
qty: actualFillQty,
|
|
538
|
+
avgPrice: fillPrice,
|
|
533
539
|
latencyMs: roundTripLatency,
|
|
534
540
|
});
|
|
535
541
|
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
|
|
8
8
|
const EventEmitter = require('events');
|
|
9
9
|
const { RithmicConnection } = require('./connection');
|
|
10
|
-
const { RITHMIC_ENDPOINTS, RITHMIC_SYSTEMS } = require('./constants');
|
|
10
|
+
const { RITHMIC_ENDPOINTS, RITHMIC_SYSTEMS, REQ } = require('./constants');
|
|
11
11
|
const { createOrderHandler, createPnLHandler, LatencyTracker } = require('./handlers');
|
|
12
12
|
const {
|
|
13
13
|
fetchAccounts,
|
|
@@ -192,15 +192,18 @@ class RithmicService extends EventEmitter {
|
|
|
192
192
|
log.warn('Failed to fetch accounts', { error: err.message });
|
|
193
193
|
}
|
|
194
194
|
|
|
195
|
-
// Subscribe to order updates (required to receive fill notifications)
|
|
195
|
+
// Subscribe to order updates for each account (required to receive fill notifications)
|
|
196
196
|
try {
|
|
197
|
-
this.
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
197
|
+
for (const acc of this.accounts) {
|
|
198
|
+
this.orderConn.send('RequestSubscribeForOrderUpdates', {
|
|
199
|
+
templateId: REQ.ORDER_UPDATES,
|
|
200
|
+
userMsg: ['HQX'],
|
|
201
|
+
fcmId: acc.fcmId || data.fcmId,
|
|
202
|
+
ibId: acc.ibId || data.ibId,
|
|
203
|
+
accountId: acc.accountId,
|
|
204
|
+
});
|
|
205
|
+
log.debug('Subscribed to order updates for account', { accountId: acc.accountId });
|
|
206
|
+
}
|
|
204
207
|
} catch (err) {
|
|
205
208
|
log.warn('Failed to subscribe to order updates', { error: err.message });
|
|
206
209
|
}
|
|
@@ -40,6 +40,7 @@ const OrderPool = {
|
|
|
40
40
|
_template: {
|
|
41
41
|
templateId: REQ.NEW_ORDER,
|
|
42
42
|
userMsg: [''],
|
|
43
|
+
userTag: '', // Our order tag - returned in RithmicOrderNotification
|
|
43
44
|
fcmId: '',
|
|
44
45
|
ibId: '',
|
|
45
46
|
accountId: '',
|
|
@@ -63,6 +64,7 @@ const OrderPool = {
|
|
|
63
64
|
fill(orderTag, loginInfo, orderData) {
|
|
64
65
|
const o = this._template;
|
|
65
66
|
o.userMsg[0] = orderTag;
|
|
67
|
+
o.userTag = orderTag; // Set userTag for notification tracking
|
|
66
68
|
o.fcmId = loginInfo.fcmId;
|
|
67
69
|
o.ibId = loginInfo.ibId;
|
|
68
70
|
o.accountId = orderData.accountId;
|