hedgequantx 2.9.121 → 2.9.123
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
|
@@ -34,9 +34,9 @@ const executeAlgo = async ({ service, account, contract, config, strategy: strat
|
|
|
34
34
|
const accountName = showName
|
|
35
35
|
? (account.accountName || account.rithmicAccountId || account.accountId)
|
|
36
36
|
: 'HQX *****';
|
|
37
|
-
const symbolName = contract.name
|
|
38
|
-
const symbolCode = contract.symbol || contract.id; // Rithmic symbol
|
|
39
|
-
const contractId = contract.id;
|
|
37
|
+
const symbolName = contract.name || contract.baseSymbol || 'Unknown';
|
|
38
|
+
const symbolCode = contract.symbol || contract.baseSymbol || contract.id; // Rithmic symbol for subscription
|
|
39
|
+
const contractId = contract.symbol || contract.baseSymbol || contract.id; // For strategy tracking
|
|
40
40
|
const tickSize = contract.tickSize || 0.25;
|
|
41
41
|
|
|
42
42
|
const ui = new AlgoUI({
|
|
@@ -87,6 +87,10 @@ const executeAlgo = async ({ service, account, contract, config, strategy: strat
|
|
|
87
87
|
risk: maxRisk
|
|
88
88
|
});
|
|
89
89
|
|
|
90
|
+
// Log detailed contract info for debugging
|
|
91
|
+
sessionLogger.log('CONFIG', `symbolCode=${symbolCode} contractId=${contractId} exchange=${contract.exchange} tickSize=${tickSize}`);
|
|
92
|
+
sessionLogger.log('CONFIG', `account=${account.accountId} rithmicId=${account.rithmicAccountId || 'N/A'}`);
|
|
93
|
+
|
|
90
94
|
strategy.on('log', (log) => {
|
|
91
95
|
const type = log.type === 'debug' ? 'debug' : log.type === 'info' ? 'analysis' : 'system';
|
|
92
96
|
ui.addLog(type, log.message);
|
|
@@ -243,6 +247,12 @@ const executeAlgo = async ({ service, account, contract, config, strategy: strat
|
|
|
243
247
|
const now = Date.now();
|
|
244
248
|
const currentSecond = Math.floor(now / 1000);
|
|
245
249
|
|
|
250
|
+
// Debug first 5 ticks to verify data
|
|
251
|
+
if (tickCount <= 5) {
|
|
252
|
+
const p = Number(tick.price) || Number(tick.tradePrice) || 'NULL';
|
|
253
|
+
sessionLogger.log('TICK', `#${tickCount} price=${p} symbol=${tick.symbol || tick.contractId || 'N/A'}`);
|
|
254
|
+
}
|
|
255
|
+
|
|
246
256
|
// Count ticks per second
|
|
247
257
|
if (currentSecond === lastTickSecond) {
|
|
248
258
|
ticksPerSecond++;
|
|
@@ -347,13 +357,16 @@ const executeAlgo = async ({ service, account, contract, config, strategy: strat
|
|
|
347
357
|
lastBid = bid;
|
|
348
358
|
lastAsk = ask;
|
|
349
359
|
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
360
|
+
// Only process tick if we have a valid price
|
|
361
|
+
if (price && price > 0) {
|
|
362
|
+
strategy.processTick({
|
|
363
|
+
contractId: tick.contractId || contractId,
|
|
364
|
+
price: price, bid: bid, ask: ask,
|
|
365
|
+
volume: volume,
|
|
366
|
+
side: tick.side || tick.lastTradeSide || 'unknown',
|
|
367
|
+
timestamp: tick.timestamp || Date.now()
|
|
368
|
+
});
|
|
369
|
+
}
|
|
357
370
|
|
|
358
371
|
// Calculate latency from Rithmic ssboe/usecs or inter-tick timing
|
|
359
372
|
if (tick.ssboe && tick.usecs !== undefined) {
|
|
@@ -98,6 +98,18 @@ class RithmicService extends EventEmitter {
|
|
|
98
98
|
|
|
99
99
|
await this.orderConn.connect(config);
|
|
100
100
|
this.orderConn.on('message', createOrderHandler(this));
|
|
101
|
+
|
|
102
|
+
// Auto-reconnect on disconnect
|
|
103
|
+
this.orderConn.on('disconnected', async ({ code, reason }) => {
|
|
104
|
+
log.warn('ORDER_PLANT disconnected', { code, reason });
|
|
105
|
+
this.emit('disconnected', { plant: 'ORDER', code, reason });
|
|
106
|
+
|
|
107
|
+
// Auto-reconnect if we have credentials (not manual disconnect)
|
|
108
|
+
if (this.credentials && code !== 1000) {
|
|
109
|
+
log.info('Attempting auto-reconnect in 3s...');
|
|
110
|
+
setTimeout(() => this._autoReconnect(), 3000);
|
|
111
|
+
}
|
|
112
|
+
});
|
|
101
113
|
|
|
102
114
|
return new Promise((resolve) => {
|
|
103
115
|
const timeout = setTimeout(() => {
|
|
@@ -163,6 +175,13 @@ class RithmicService extends EventEmitter {
|
|
|
163
175
|
|
|
164
176
|
await this.pnlConn.connect(config);
|
|
165
177
|
this.pnlConn.on('message', createPnLHandler(this));
|
|
178
|
+
|
|
179
|
+
// Auto-reconnect PnL on disconnect
|
|
180
|
+
this.pnlConn.on('disconnected', ({ code }) => {
|
|
181
|
+
if (this.credentials && code !== 1000) {
|
|
182
|
+
setTimeout(() => this.connectPnL(this.credentials.username, this.credentials.password), 3000);
|
|
183
|
+
}
|
|
184
|
+
});
|
|
166
185
|
|
|
167
186
|
return new Promise((resolve) => {
|
|
168
187
|
const timeout = setTimeout(() => resolve(false), TIMEOUTS.RITHMIC_PNL);
|
|
@@ -200,6 +219,13 @@ class RithmicService extends EventEmitter {
|
|
|
200
219
|
};
|
|
201
220
|
|
|
202
221
|
await this.tickerConn.connect(config);
|
|
222
|
+
|
|
223
|
+
// Auto-reconnect Ticker on disconnect
|
|
224
|
+
this.tickerConn.on('disconnected', ({ code }) => {
|
|
225
|
+
if (this.credentials && code !== 1000) {
|
|
226
|
+
setTimeout(() => this.connectTicker(this.credentials.username, this.credentials.password), 3000);
|
|
227
|
+
}
|
|
228
|
+
});
|
|
203
229
|
|
|
204
230
|
return new Promise((resolve) => {
|
|
205
231
|
const timeout = setTimeout(() => {
|
|
@@ -383,9 +409,42 @@ class RithmicService extends EventEmitter {
|
|
|
383
409
|
return { isOpen: true, message: 'Market is open' };
|
|
384
410
|
}
|
|
385
411
|
|
|
412
|
+
// ==================== AUTO-RECONNECT ====================
|
|
413
|
+
|
|
414
|
+
async _autoReconnect() {
|
|
415
|
+
if (!this.credentials) {
|
|
416
|
+
log.warn('Cannot auto-reconnect: no credentials');
|
|
417
|
+
return;
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
const { username, password } = this.credentials;
|
|
421
|
+
log.info('Auto-reconnecting...');
|
|
422
|
+
this.emit('reconnecting');
|
|
423
|
+
|
|
424
|
+
try {
|
|
425
|
+
const result = await this.login(username, password);
|
|
426
|
+
if (result.success) {
|
|
427
|
+
log.info('Auto-reconnect successful');
|
|
428
|
+
this.emit('reconnected', { accounts: result.accounts });
|
|
429
|
+
} else {
|
|
430
|
+
log.warn('Auto-reconnect failed', { error: result.error });
|
|
431
|
+
this.emit('reconnectFailed', { error: result.error });
|
|
432
|
+
// Retry in 10s
|
|
433
|
+
setTimeout(() => this._autoReconnect(), 10000);
|
|
434
|
+
}
|
|
435
|
+
} catch (err) {
|
|
436
|
+
log.error('Auto-reconnect error', { error: err.message });
|
|
437
|
+
this.emit('reconnectFailed', { error: err.message });
|
|
438
|
+
// Retry in 10s
|
|
439
|
+
setTimeout(() => this._autoReconnect(), 10000);
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
|
|
386
443
|
// ==================== CLEANUP ====================
|
|
387
444
|
|
|
388
445
|
async disconnect() {
|
|
446
|
+
// Clear credentials to prevent auto-reconnect on manual disconnect
|
|
447
|
+
this.credentials = null;
|
|
389
448
|
const connections = [this.orderConn, this.pnlConn, this.tickerConn];
|
|
390
449
|
|
|
391
450
|
for (const conn of connections) {
|