hedgequantx 2.7.15 → 2.7.17
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/app.js +10 -10
- package/src/lib/data.js +245 -471
- package/src/lib/m/s1-models.js +173 -0
- package/src/lib/m/s1.js +354 -735
- package/src/menus/dashboard.js +8 -5
- package/src/lib/api.js +0 -198
- package/src/lib/api2.js +0 -353
- package/src/lib/core.js +0 -539
- package/src/lib/core2.js +0 -341
- package/src/lib/data2.js +0 -492
- package/src/lib/decoder.js +0 -599
- package/src/lib/m/s2.js +0 -34
- package/src/lib/n/r1.js +0 -454
- package/src/lib/n/r2.js +0 -514
- package/src/lib/n/r3.js +0 -631
- package/src/lib/n/r4.js +0 -401
- package/src/lib/n/r5.js +0 -335
- package/src/lib/n/r6.js +0 -425
- package/src/lib/n/r7.js +0 -530
- package/src/lib/o/l1.js +0 -44
- package/src/lib/o/l2.js +0 -427
- package/src/lib/python-bridge.js +0 -206
package/src/lib/n/r6.js
DELETED
|
@@ -1,425 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Rithmic Connection Pool
|
|
3
|
-
* Manages reusable connections for optimal performance
|
|
4
|
-
* Prevents creating new connections for every request
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
const { RithmicMarketData } = require('./r4');
|
|
8
|
-
const { RithmicTrading } = require('./r3');
|
|
9
|
-
const { RithmicPnL } = require('./r5');
|
|
10
|
-
const { getPropFirmConfig, RITHMIC_GATEWAYS } = require('./r7');
|
|
11
|
-
|
|
12
|
-
class RithmicConnectionPool {
|
|
13
|
-
constructor(options = {}) {
|
|
14
|
-
// Pools for each plant type
|
|
15
|
-
this.marketDataPool = new Map(); // key -> RithmicMarketData
|
|
16
|
-
this.tradingPool = new Map(); // key -> RithmicTrading
|
|
17
|
-
this.pnlPool = new Map(); // key -> RithmicPnL
|
|
18
|
-
|
|
19
|
-
// Pending connections (mutex for concurrent requests)
|
|
20
|
-
this.pendingMarketData = new Map();
|
|
21
|
-
this.pendingTrading = new Map();
|
|
22
|
-
this.pendingPnL = new Map();
|
|
23
|
-
|
|
24
|
-
// Configuration
|
|
25
|
-
this.idleTimeout = options.idleTimeout || 30 * 60 * 1000; // 30 minutes
|
|
26
|
-
this.cleanupInterval = options.cleanupInterval || 60 * 1000; // 1 minute
|
|
27
|
-
this.debug = options.debug || false;
|
|
28
|
-
|
|
29
|
-
// Stats
|
|
30
|
-
this.stats = {
|
|
31
|
-
marketDataHits: 0,
|
|
32
|
-
marketDataMisses: 0,
|
|
33
|
-
tradingHits: 0,
|
|
34
|
-
tradingMisses: 0,
|
|
35
|
-
pnlHits: 0,
|
|
36
|
-
pnlMisses: 0
|
|
37
|
-
};
|
|
38
|
-
|
|
39
|
-
// Start cleanup timer
|
|
40
|
-
this._cleanupTimer = setInterval(() => this._cleanup(), this.cleanupInterval);
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
/**
|
|
44
|
-
* Generate pool key from credentials
|
|
45
|
-
*/
|
|
46
|
-
_getKey(userId, systemName) {
|
|
47
|
-
return `${userId}:${systemName}`;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
/**
|
|
51
|
-
* Get or create Market Data connection
|
|
52
|
-
*/
|
|
53
|
-
async getMarketData(credentials) {
|
|
54
|
-
const { userId, password, systemName, gateway } = credentials;
|
|
55
|
-
const key = this._getKey(userId, systemName);
|
|
56
|
-
|
|
57
|
-
// Check if pending
|
|
58
|
-
if (this.pendingMarketData.has(key)) {
|
|
59
|
-
return this.pendingMarketData.get(key);
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
// Check pool
|
|
63
|
-
let pooled = this.marketDataPool.get(key);
|
|
64
|
-
if (pooled && pooled.client.isConnected) {
|
|
65
|
-
pooled.lastUsed = Date.now();
|
|
66
|
-
this.stats.marketDataHits++;
|
|
67
|
-
return pooled.client;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
// Create new connection
|
|
71
|
-
this.stats.marketDataMisses++;
|
|
72
|
-
|
|
73
|
-
const connectPromise = this._createMarketData(credentials);
|
|
74
|
-
this.pendingMarketData.set(key, connectPromise);
|
|
75
|
-
|
|
76
|
-
try {
|
|
77
|
-
const client = await connectPromise;
|
|
78
|
-
this.marketDataPool.set(key, {
|
|
79
|
-
client,
|
|
80
|
-
userId,
|
|
81
|
-
systemName,
|
|
82
|
-
lastUsed: Date.now()
|
|
83
|
-
});
|
|
84
|
-
return client;
|
|
85
|
-
} finally {
|
|
86
|
-
this.pendingMarketData.delete(key);
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
/**
|
|
91
|
-
* Create new Market Data connection
|
|
92
|
-
*/
|
|
93
|
-
async _createMarketData(credentials) {
|
|
94
|
-
const propfirmConfig = getPropFirmConfig(credentials.propfirm);
|
|
95
|
-
const systemName = credentials.systemName || propfirmConfig?.systemName || 'Apex';
|
|
96
|
-
const gateway = credentials.gateway || propfirmConfig?.gateway || RITHMIC_GATEWAYS.CHICAGO;
|
|
97
|
-
|
|
98
|
-
const client = new RithmicMarketData({ debug: this.debug });
|
|
99
|
-
|
|
100
|
-
await client.connect({
|
|
101
|
-
userId: credentials.userId,
|
|
102
|
-
password: credentials.password,
|
|
103
|
-
systemName,
|
|
104
|
-
gateway
|
|
105
|
-
});
|
|
106
|
-
|
|
107
|
-
return client;
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
/**
|
|
111
|
-
* Get or create Trading connection
|
|
112
|
-
*/
|
|
113
|
-
async getTrading(credentials) {
|
|
114
|
-
const { userId, password, systemName, gateway } = credentials;
|
|
115
|
-
const key = this._getKey(userId, systemName);
|
|
116
|
-
|
|
117
|
-
// Check if pending
|
|
118
|
-
if (this.pendingTrading.has(key)) {
|
|
119
|
-
return this.pendingTrading.get(key);
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
// Check pool
|
|
123
|
-
let pooled = this.tradingPool.get(key);
|
|
124
|
-
if (pooled && pooled.client.isConnected) {
|
|
125
|
-
pooled.lastUsed = Date.now();
|
|
126
|
-
this.stats.tradingHits++;
|
|
127
|
-
return pooled.client;
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
// Create new connection
|
|
131
|
-
this.stats.tradingMisses++;
|
|
132
|
-
|
|
133
|
-
const connectPromise = this._createTrading(credentials);
|
|
134
|
-
this.pendingTrading.set(key, connectPromise);
|
|
135
|
-
|
|
136
|
-
try {
|
|
137
|
-
const client = await connectPromise;
|
|
138
|
-
this.tradingPool.set(key, {
|
|
139
|
-
client,
|
|
140
|
-
userId,
|
|
141
|
-
systemName,
|
|
142
|
-
lastUsed: Date.now()
|
|
143
|
-
});
|
|
144
|
-
return client;
|
|
145
|
-
} finally {
|
|
146
|
-
this.pendingTrading.delete(key);
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
/**
|
|
151
|
-
* Create new Trading connection
|
|
152
|
-
*/
|
|
153
|
-
async _createTrading(credentials) {
|
|
154
|
-
const propfirmConfig = getPropFirmConfig(credentials.propfirm);
|
|
155
|
-
const systemName = credentials.systemName || propfirmConfig?.systemName || 'Apex';
|
|
156
|
-
const gateway = credentials.gateway || propfirmConfig?.gateway || RITHMIC_GATEWAYS.CHICAGO;
|
|
157
|
-
|
|
158
|
-
const client = new RithmicTrading({ debug: this.debug });
|
|
159
|
-
|
|
160
|
-
await client.connect({
|
|
161
|
-
userId: credentials.userId,
|
|
162
|
-
password: credentials.password,
|
|
163
|
-
systemName,
|
|
164
|
-
gateway
|
|
165
|
-
});
|
|
166
|
-
|
|
167
|
-
return client;
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
/**
|
|
171
|
-
* Get or create P&L connection
|
|
172
|
-
*/
|
|
173
|
-
async getPnL(credentials) {
|
|
174
|
-
const { userId, password, systemName, gateway } = credentials;
|
|
175
|
-
const key = this._getKey(userId, systemName);
|
|
176
|
-
|
|
177
|
-
// Check if pending
|
|
178
|
-
if (this.pendingPnL.has(key)) {
|
|
179
|
-
return this.pendingPnL.get(key);
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
// Check pool
|
|
183
|
-
let pooled = this.pnlPool.get(key);
|
|
184
|
-
if (pooled && pooled.client.isConnected) {
|
|
185
|
-
pooled.lastUsed = Date.now();
|
|
186
|
-
this.stats.pnlHits++;
|
|
187
|
-
return pooled.client;
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
// Create new connection
|
|
191
|
-
this.stats.pnlMisses++;
|
|
192
|
-
|
|
193
|
-
const connectPromise = this._createPnL(credentials);
|
|
194
|
-
this.pendingPnL.set(key, connectPromise);
|
|
195
|
-
|
|
196
|
-
try {
|
|
197
|
-
const client = await connectPromise;
|
|
198
|
-
this.pnlPool.set(key, {
|
|
199
|
-
client,
|
|
200
|
-
userId,
|
|
201
|
-
systemName,
|
|
202
|
-
lastUsed: Date.now()
|
|
203
|
-
});
|
|
204
|
-
return client;
|
|
205
|
-
} finally {
|
|
206
|
-
this.pendingPnL.delete(key);
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
/**
|
|
211
|
-
* Create new P&L connection
|
|
212
|
-
*/
|
|
213
|
-
async _createPnL(credentials) {
|
|
214
|
-
const propfirmConfig = getPropFirmConfig(credentials.propfirm);
|
|
215
|
-
const systemName = credentials.systemName || propfirmConfig?.systemName || 'Apex';
|
|
216
|
-
const gateway = credentials.gateway || propfirmConfig?.gateway || RITHMIC_GATEWAYS.CHICAGO;
|
|
217
|
-
|
|
218
|
-
const client = new RithmicPnL({ debug: this.debug });
|
|
219
|
-
|
|
220
|
-
await client.connect({
|
|
221
|
-
userId: credentials.userId,
|
|
222
|
-
password: credentials.password,
|
|
223
|
-
systemName,
|
|
224
|
-
gateway
|
|
225
|
-
});
|
|
226
|
-
|
|
227
|
-
return client;
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
/**
|
|
231
|
-
* Release a connection (mark as available)
|
|
232
|
-
*/
|
|
233
|
-
release(userId, systemName) {
|
|
234
|
-
const key = this._getKey(userId, systemName);
|
|
235
|
-
|
|
236
|
-
for (const pool of [this.marketDataPool, this.tradingPool, this.pnlPool]) {
|
|
237
|
-
const pooled = pool.get(key);
|
|
238
|
-
if (pooled) {
|
|
239
|
-
pooled.lastUsed = Date.now();
|
|
240
|
-
}
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
/**
|
|
246
|
-
* Remove a connection from pool and disconnect
|
|
247
|
-
*/
|
|
248
|
-
async remove(userId, systemName) {
|
|
249
|
-
const key = this._getKey(userId, systemName);
|
|
250
|
-
|
|
251
|
-
const pools = [
|
|
252
|
-
{ pool: this.marketDataPool, name: 'MarketData' },
|
|
253
|
-
{ pool: this.tradingPool, name: 'Trading' },
|
|
254
|
-
{ pool: this.pnlPool, name: 'PnL' }
|
|
255
|
-
];
|
|
256
|
-
|
|
257
|
-
for (const { pool, name } of pools) {
|
|
258
|
-
const pooled = pool.get(key);
|
|
259
|
-
if (pooled) {
|
|
260
|
-
try {
|
|
261
|
-
await pooled.client.disconnect();
|
|
262
|
-
} catch (e) {
|
|
263
|
-
// Ignore disconnect errors
|
|
264
|
-
}
|
|
265
|
-
pool.delete(key);
|
|
266
|
-
}
|
|
267
|
-
}
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
/**
|
|
271
|
-
* Cleanup idle connections
|
|
272
|
-
*/
|
|
273
|
-
async _cleanup() {
|
|
274
|
-
const now = Date.now();
|
|
275
|
-
const toRemove = [];
|
|
276
|
-
|
|
277
|
-
const pools = [
|
|
278
|
-
{ pool: this.marketDataPool, name: 'MarketData' },
|
|
279
|
-
{ pool: this.tradingPool, name: 'Trading' },
|
|
280
|
-
{ pool: this.pnlPool, name: 'PnL' }
|
|
281
|
-
];
|
|
282
|
-
|
|
283
|
-
for (const { pool, name } of pools) {
|
|
284
|
-
for (const [key, pooled] of pool) {
|
|
285
|
-
const idle = now - pooled.lastUsed;
|
|
286
|
-
if (idle > this.idleTimeout) {
|
|
287
|
-
toRemove.push({ pool, key, name, client: pooled.client });
|
|
288
|
-
}
|
|
289
|
-
}
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
if (toRemove.length > 0) {
|
|
293
|
-
for (const { pool, key, name, client } of toRemove) {
|
|
294
|
-
try {
|
|
295
|
-
await client.disconnect();
|
|
296
|
-
} catch (e) {
|
|
297
|
-
// Ignore
|
|
298
|
-
}
|
|
299
|
-
pool.delete(key);
|
|
300
|
-
}
|
|
301
|
-
}
|
|
302
|
-
}
|
|
303
|
-
|
|
304
|
-
/**
|
|
305
|
-
* Get pool statistics
|
|
306
|
-
*/
|
|
307
|
-
getStats() {
|
|
308
|
-
return {
|
|
309
|
-
marketData: {
|
|
310
|
-
active: this.marketDataPool.size,
|
|
311
|
-
pending: this.pendingMarketData.size,
|
|
312
|
-
hits: this.stats.marketDataHits,
|
|
313
|
-
misses: this.stats.marketDataMisses
|
|
314
|
-
},
|
|
315
|
-
trading: {
|
|
316
|
-
active: this.tradingPool.size,
|
|
317
|
-
pending: this.pendingTrading.size,
|
|
318
|
-
hits: this.stats.tradingHits,
|
|
319
|
-
misses: this.stats.tradingMisses
|
|
320
|
-
},
|
|
321
|
-
pnl: {
|
|
322
|
-
active: this.pnlPool.size,
|
|
323
|
-
pending: this.pendingPnL.size,
|
|
324
|
-
hits: this.stats.pnlHits,
|
|
325
|
-
misses: this.stats.pnlMisses
|
|
326
|
-
},
|
|
327
|
-
total: {
|
|
328
|
-
active: this.marketDataPool.size + this.tradingPool.size + this.pnlPool.size,
|
|
329
|
-
hitRate: this._calculateHitRate()
|
|
330
|
-
}
|
|
331
|
-
};
|
|
332
|
-
}
|
|
333
|
-
|
|
334
|
-
/**
|
|
335
|
-
* Calculate overall hit rate
|
|
336
|
-
*/
|
|
337
|
-
_calculateHitRate() {
|
|
338
|
-
const hits = this.stats.marketDataHits + this.stats.tradingHits + this.stats.pnlHits;
|
|
339
|
-
const misses = this.stats.marketDataMisses + this.stats.tradingMisses + this.stats.pnlMisses;
|
|
340
|
-
const total = hits + misses;
|
|
341
|
-
return total > 0 ? ((hits / total) * 100).toFixed(1) + '%' : '0%';
|
|
342
|
-
}
|
|
343
|
-
|
|
344
|
-
/**
|
|
345
|
-
* Get all active connections info
|
|
346
|
-
*/
|
|
347
|
-
getConnections() {
|
|
348
|
-
const connections = [];
|
|
349
|
-
const now = Date.now();
|
|
350
|
-
|
|
351
|
-
for (const [key, pooled] of this.marketDataPool) {
|
|
352
|
-
connections.push({
|
|
353
|
-
type: 'MarketData',
|
|
354
|
-
key,
|
|
355
|
-
userId: pooled.userId,
|
|
356
|
-
systemName: pooled.systemName,
|
|
357
|
-
connected: pooled.client.isConnected,
|
|
358
|
-
idleSeconds: Math.floor((now - pooled.lastUsed) / 1000)
|
|
359
|
-
});
|
|
360
|
-
}
|
|
361
|
-
|
|
362
|
-
for (const [key, pooled] of this.tradingPool) {
|
|
363
|
-
connections.push({
|
|
364
|
-
type: 'Trading',
|
|
365
|
-
key,
|
|
366
|
-
userId: pooled.userId,
|
|
367
|
-
systemName: pooled.systemName,
|
|
368
|
-
connected: pooled.client.isConnected,
|
|
369
|
-
idleSeconds: Math.floor((now - pooled.lastUsed) / 1000)
|
|
370
|
-
});
|
|
371
|
-
}
|
|
372
|
-
|
|
373
|
-
for (const [key, pooled] of this.pnlPool) {
|
|
374
|
-
connections.push({
|
|
375
|
-
type: 'PnL',
|
|
376
|
-
key,
|
|
377
|
-
userId: pooled.userId,
|
|
378
|
-
systemName: pooled.systemName,
|
|
379
|
-
connected: pooled.client.isConnected,
|
|
380
|
-
idleSeconds: Math.floor((now - pooled.lastUsed) / 1000)
|
|
381
|
-
});
|
|
382
|
-
}
|
|
383
|
-
|
|
384
|
-
return connections;
|
|
385
|
-
}
|
|
386
|
-
|
|
387
|
-
/**
|
|
388
|
-
* Shutdown pool and disconnect all
|
|
389
|
-
*/
|
|
390
|
-
async shutdown() {
|
|
391
|
-
// Clear cleanup timer
|
|
392
|
-
if (this._cleanupTimer) {
|
|
393
|
-
clearInterval(this._cleanupTimer);
|
|
394
|
-
this._cleanupTimer = null;
|
|
395
|
-
}
|
|
396
|
-
|
|
397
|
-
// Disconnect all
|
|
398
|
-
const pools = [this.marketDataPool, this.tradingPool, this.pnlPool];
|
|
399
|
-
|
|
400
|
-
for (const pool of pools) {
|
|
401
|
-
for (const [, pooled] of pool) {
|
|
402
|
-
try {
|
|
403
|
-
await pooled.client.disconnect();
|
|
404
|
-
} catch (e) {
|
|
405
|
-
// Ignore
|
|
406
|
-
}
|
|
407
|
-
}
|
|
408
|
-
pool.clear();
|
|
409
|
-
}
|
|
410
|
-
}
|
|
411
|
-
}
|
|
412
|
-
|
|
413
|
-
// Singleton instance
|
|
414
|
-
const rithmicPool = new RithmicConnectionPool();
|
|
415
|
-
|
|
416
|
-
// Graceful shutdown on process exit
|
|
417
|
-
process.on('SIGINT', async () => {
|
|
418
|
-
await rithmicPool.shutdown();
|
|
419
|
-
});
|
|
420
|
-
|
|
421
|
-
process.on('SIGTERM', async () => {
|
|
422
|
-
await rithmicPool.shutdown();
|
|
423
|
-
});
|
|
424
|
-
|
|
425
|
-
module.exports = { RithmicConnectionPool, rithmicPool };
|