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.
- package/package.json +1 -1
- package/src/menus/ai-agent-connect.js +181 -0
- package/src/menus/ai-agent-models.js +219 -0
- package/src/menus/ai-agent-oauth.js +292 -0
- package/src/menus/ai-agent-ui.js +141 -0
- package/src/menus/ai-agent.js +88 -1489
- package/src/pages/algo/copy-engine.js +449 -0
- package/src/pages/algo/copy-trading.js +11 -543
- package/src/pages/algo/smart-logs-data.js +218 -0
- package/src/pages/algo/smart-logs.js +9 -214
- package/src/pages/algo/ui-constants.js +144 -0
- package/src/pages/algo/ui-summary.js +184 -0
- package/src/pages/algo/ui.js +42 -526
- package/src/pages/stats-calculations.js +191 -0
- package/src/pages/stats-ui.js +381 -0
- package/src/pages/stats.js +14 -507
- package/src/services/ai/client-analysis.js +194 -0
- package/src/services/ai/client-models.js +333 -0
- package/src/services/ai/client.js +6 -489
- package/src/services/ai/index.js +2 -257
- package/src/services/ai/proxy-install.js +249 -0
- package/src/services/ai/proxy-manager.js +29 -411
- package/src/services/ai/proxy-remote.js +161 -0
- package/src/services/ai/supervisor-optimize.js +215 -0
- package/src/services/ai/supervisor-sync.js +178 -0
- package/src/services/ai/supervisor.js +50 -515
- package/src/services/ai/validation.js +250 -0
- package/src/services/hqx-server-events.js +110 -0
- package/src/services/hqx-server-handlers.js +217 -0
- package/src/services/hqx-server-latency.js +136 -0
- package/src/services/hqx-server.js +51 -403
- package/src/services/position-constants.js +28 -0
- package/src/services/position-manager.js +105 -554
- package/src/services/position-momentum.js +206 -0
- package/src/services/projectx/accounts.js +142 -0
- package/src/services/projectx/index.js +40 -289
- package/src/services/projectx/trading.js +180 -0
- package/src/services/rithmic/handlers.js +2 -208
- package/src/services/rithmic/index.js +32 -542
- package/src/services/rithmic/latency-tracker.js +182 -0
- package/src/services/rithmic/specs.js +146 -0
- package/src/services/rithmic/trade-history.js +254 -0
|
@@ -14,151 +14,12 @@
|
|
|
14
14
|
const { proto, decodeAccountPnL, decodeInstrumentPnL } = require('./protobuf');
|
|
15
15
|
const { RES, STREAM } = require('./constants');
|
|
16
16
|
const { performance } = require('perf_hooks');
|
|
17
|
+
const { LatencyTracker, FillInfoPool } = require('./latency-tracker');
|
|
17
18
|
|
|
18
19
|
// Debug mode - use no-op function when disabled for zero overhead
|
|
19
20
|
const DEBUG = process.env.HQX_DEBUG === '1';
|
|
20
21
|
const debug = DEBUG ? (...args) => console.log('[Rithmic:Handler]', ...args) : () => {};
|
|
21
22
|
|
|
22
|
-
// ==================== HIGH-RESOLUTION TIMING ====================
|
|
23
|
-
// Use process.hrtime.bigint for sub-millisecond precision
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* Get high-resolution timestamp in nanoseconds
|
|
27
|
-
* @returns {bigint}
|
|
28
|
-
*/
|
|
29
|
-
const hrNow = () => process.hrtime.bigint();
|
|
30
|
-
|
|
31
|
-
/**
|
|
32
|
-
* Convert nanoseconds to milliseconds with precision
|
|
33
|
-
* @param {bigint} ns
|
|
34
|
-
* @returns {number}
|
|
35
|
-
*/
|
|
36
|
-
const nsToMs = (ns) => Number(ns) / 1_000_000;
|
|
37
|
-
|
|
38
|
-
// ==================== LATENCY TRACKING ====================
|
|
39
|
-
// Track order-to-fill latency for performance monitoring
|
|
40
|
-
// OPTIMIZED: Circular buffer (no array.shift), high-resolution timing
|
|
41
|
-
|
|
42
|
-
const LatencyTracker = {
|
|
43
|
-
_pending: new Map(), // orderTag -> entryTime (bigint nanoseconds)
|
|
44
|
-
_samples: null, // Pre-allocated Float64Array circular buffer
|
|
45
|
-
_maxSamples: 100,
|
|
46
|
-
_head: 0, // Next write position
|
|
47
|
-
_count: 0, // Number of valid samples
|
|
48
|
-
_initialized: false,
|
|
49
|
-
|
|
50
|
-
/**
|
|
51
|
-
* Initialize circular buffer (lazy init)
|
|
52
|
-
* @private
|
|
53
|
-
*/
|
|
54
|
-
_init() {
|
|
55
|
-
if (this._initialized) return;
|
|
56
|
-
this._samples = new Float64Array(this._maxSamples);
|
|
57
|
-
this._initialized = true;
|
|
58
|
-
},
|
|
59
|
-
|
|
60
|
-
/**
|
|
61
|
-
* Record order sent time with high-resolution timestamp
|
|
62
|
-
* @param {string} orderTag
|
|
63
|
-
* @param {number} entryTimeMs - Date.now() when order was sent (for compatibility)
|
|
64
|
-
*/
|
|
65
|
-
recordEntry(orderTag, entryTimeMs) {
|
|
66
|
-
// Store high-resolution time for precise measurement
|
|
67
|
-
this._pending.set(orderTag, hrNow());
|
|
68
|
-
},
|
|
69
|
-
|
|
70
|
-
/**
|
|
71
|
-
* Record fill received, calculate latency with sub-ms precision
|
|
72
|
-
* @param {string} orderTag
|
|
73
|
-
* @returns {number|null} Round-trip latency in ms (with decimal precision), or null if not tracked
|
|
74
|
-
*/
|
|
75
|
-
recordFill(orderTag) {
|
|
76
|
-
const entryTime = this._pending.get(orderTag);
|
|
77
|
-
if (!entryTime) return null;
|
|
78
|
-
|
|
79
|
-
this._pending.delete(orderTag);
|
|
80
|
-
const latencyNs = hrNow() - entryTime;
|
|
81
|
-
const latencyMs = nsToMs(latencyNs);
|
|
82
|
-
|
|
83
|
-
// Store in circular buffer (no shift, O(1))
|
|
84
|
-
this._init();
|
|
85
|
-
this._samples[this._head] = latencyMs;
|
|
86
|
-
this._head = (this._head + 1) % this._maxSamples;
|
|
87
|
-
if (this._count < this._maxSamples) this._count++;
|
|
88
|
-
|
|
89
|
-
return latencyMs;
|
|
90
|
-
},
|
|
91
|
-
|
|
92
|
-
/**
|
|
93
|
-
* Get average latency
|
|
94
|
-
* @returns {number|null}
|
|
95
|
-
*/
|
|
96
|
-
getAverage() {
|
|
97
|
-
if (this._count === 0) return null;
|
|
98
|
-
let sum = 0;
|
|
99
|
-
for (let i = 0; i < this._count; i++) {
|
|
100
|
-
sum += this._samples[i];
|
|
101
|
-
}
|
|
102
|
-
return sum / this._count;
|
|
103
|
-
},
|
|
104
|
-
|
|
105
|
-
/**
|
|
106
|
-
* Get min/max/avg stats with high precision
|
|
107
|
-
* @returns {Object}
|
|
108
|
-
*/
|
|
109
|
-
getStats() {
|
|
110
|
-
if (this._count === 0) {
|
|
111
|
-
return { min: null, max: null, avg: null, p50: null, p99: null, samples: 0 };
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
// Get valid samples
|
|
115
|
-
const valid = [];
|
|
116
|
-
for (let i = 0; i < this._count; i++) {
|
|
117
|
-
valid.push(this._samples[i]);
|
|
118
|
-
}
|
|
119
|
-
valid.sort((a, b) => a - b);
|
|
120
|
-
|
|
121
|
-
const sum = valid.reduce((a, b) => a + b, 0);
|
|
122
|
-
|
|
123
|
-
return {
|
|
124
|
-
min: valid[0],
|
|
125
|
-
max: valid[valid.length - 1],
|
|
126
|
-
avg: sum / valid.length,
|
|
127
|
-
p50: valid[Math.floor(valid.length * 0.5)],
|
|
128
|
-
p99: valid[Math.floor(valid.length * 0.99)] || valid[valid.length - 1],
|
|
129
|
-
samples: this._count,
|
|
130
|
-
};
|
|
131
|
-
},
|
|
132
|
-
|
|
133
|
-
/**
|
|
134
|
-
* Get last N latency samples
|
|
135
|
-
* @param {number} n
|
|
136
|
-
* @returns {number[]}
|
|
137
|
-
*/
|
|
138
|
-
getRecent(n = 10) {
|
|
139
|
-
if (this._count === 0) return [];
|
|
140
|
-
const result = [];
|
|
141
|
-
const start = this._count < this._maxSamples ? 0 : this._head;
|
|
142
|
-
for (let i = 0; i < Math.min(n, this._count); i++) {
|
|
143
|
-
const idx = (start + this._count - 1 - i + this._maxSamples) % this._maxSamples;
|
|
144
|
-
result.push(this._samples[idx]);
|
|
145
|
-
}
|
|
146
|
-
return result;
|
|
147
|
-
},
|
|
148
|
-
|
|
149
|
-
/**
|
|
150
|
-
* Clear all tracking data
|
|
151
|
-
*/
|
|
152
|
-
clear() {
|
|
153
|
-
this._pending.clear();
|
|
154
|
-
this._head = 0;
|
|
155
|
-
this._count = 0;
|
|
156
|
-
if (this._samples) {
|
|
157
|
-
this._samples.fill(0);
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
};
|
|
161
|
-
|
|
162
23
|
/**
|
|
163
24
|
* Create ORDER_PLANT message handler
|
|
164
25
|
* @param {RithmicService} service - The Rithmic service instance
|
|
@@ -436,74 +297,7 @@ const handleNewOrderResponse = (service, data) => {
|
|
|
436
297
|
}
|
|
437
298
|
};
|
|
438
299
|
|
|
439
|
-
//
|
|
440
|
-
// Reusable objects for hot path to avoid GC pressure
|
|
441
|
-
|
|
442
|
-
const FillInfoPool = {
|
|
443
|
-
// Pre-allocated fill info template
|
|
444
|
-
_template: {
|
|
445
|
-
orderTag: null,
|
|
446
|
-
basketId: null,
|
|
447
|
-
orderId: null,
|
|
448
|
-
status: null,
|
|
449
|
-
symbol: null,
|
|
450
|
-
exchange: null,
|
|
451
|
-
accountId: null,
|
|
452
|
-
fillQuantity: 0,
|
|
453
|
-
totalFillQuantity: 0,
|
|
454
|
-
remainingQuantity: 0,
|
|
455
|
-
avgFillPrice: 0,
|
|
456
|
-
lastFillPrice: 0,
|
|
457
|
-
transactionType: 0,
|
|
458
|
-
orderType: 0,
|
|
459
|
-
quantity: 0,
|
|
460
|
-
ssboe: 0,
|
|
461
|
-
usecs: 0,
|
|
462
|
-
localTimestamp: 0,
|
|
463
|
-
roundTripLatencyMs: null,
|
|
464
|
-
},
|
|
465
|
-
|
|
466
|
-
/**
|
|
467
|
-
* Fill template with notification data
|
|
468
|
-
* @param {Object} notif - Decoded notification
|
|
469
|
-
* @param {number} receiveTime - Local receive timestamp
|
|
470
|
-
* @param {number|null} latency - Round-trip latency
|
|
471
|
-
* @returns {Object}
|
|
472
|
-
*/
|
|
473
|
-
fill(notif, receiveTime, latency) {
|
|
474
|
-
const o = this._template;
|
|
475
|
-
o.orderTag = notif.userTag || null; // userTag contains our order tag
|
|
476
|
-
o.basketId = notif.basketId;
|
|
477
|
-
o.orderId = notif.exchangeOrderId || notif.orderId;
|
|
478
|
-
o.status = notif.status;
|
|
479
|
-
o.symbol = notif.symbol;
|
|
480
|
-
o.exchange = notif.exchange;
|
|
481
|
-
o.accountId = notif.accountId;
|
|
482
|
-
// Proto uses totalFillSize, not fillQuantity
|
|
483
|
-
o.fillQuantity = notif.totalFillSize || notif.fillQuantity || 0;
|
|
484
|
-
o.totalFillQuantity = notif.totalFillSize || notif.totalFillQuantity || 0;
|
|
485
|
-
o.remainingQuantity = notif.totalUnfilledSize || notif.remainingQuantity || 0;
|
|
486
|
-
o.avgFillPrice = parseFloat(notif.avgFillPrice || 0);
|
|
487
|
-
o.lastFillPrice = parseFloat(notif.price || notif.fillPrice || 0);
|
|
488
|
-
o.transactionType = notif.transactionType;
|
|
489
|
-
o.orderType = notif.priceType || notif.orderType;
|
|
490
|
-
o.quantity = notif.quantity;
|
|
491
|
-
o.ssboe = notif.ssboe;
|
|
492
|
-
o.usecs = notif.usecs;
|
|
493
|
-
o.localTimestamp = receiveTime;
|
|
494
|
-
o.roundTripLatencyMs = latency;
|
|
495
|
-
return o;
|
|
496
|
-
},
|
|
497
|
-
|
|
498
|
-
/**
|
|
499
|
-
* Create a copy for async operations that need to keep the data
|
|
500
|
-
* @param {Object} fillInfo
|
|
501
|
-
* @returns {Object}
|
|
502
|
-
*/
|
|
503
|
-
clone(fillInfo) {
|
|
504
|
-
return { ...fillInfo };
|
|
505
|
-
}
|
|
506
|
-
};
|
|
300
|
+
// FillInfoPool imported from ./latency-tracker
|
|
507
301
|
|
|
508
302
|
/**
|
|
509
303
|
* Handle order notification (351) - CRITICAL for fill tracking
|