hedgequantx 2.9.220 → 2.9.222
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
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "hedgequantx",
|
|
3
|
-
"version": "2.9.
|
|
3
|
+
"version": "2.9.222",
|
|
4
4
|
"description": "HedgeQuantX - Prop Futures Trading CLI",
|
|
5
5
|
"main": "src/app.js",
|
|
6
6
|
"bin": {
|
|
@@ -43,6 +43,7 @@
|
|
|
43
43
|
"dist/lib/",
|
|
44
44
|
"protos/",
|
|
45
45
|
"src/app.js",
|
|
46
|
+
"src/cli-daemon.js",
|
|
46
47
|
"src/api/",
|
|
47
48
|
"src/config/",
|
|
48
49
|
"src/lib/data.js",
|
package/src/app.js
CHANGED
|
@@ -39,9 +39,10 @@ let daemonClient = null;
|
|
|
39
39
|
* Create a proxy service that uses daemon for all operations
|
|
40
40
|
* @param {Object} client - DaemonClient instance
|
|
41
41
|
* @param {Object} propfirm - Propfirm info
|
|
42
|
+
* @param {Object} credentials - Optional credentials {username, password}
|
|
42
43
|
* @returns {Object} Service-like object
|
|
43
44
|
*/
|
|
44
|
-
function createDaemonProxyService(client, propfirm) {
|
|
45
|
+
function createDaemonProxyService(client, propfirm, credentials = null) {
|
|
45
46
|
const checkMarketHours = () => {
|
|
46
47
|
const now = new Date(), utcDay = now.getUTCDay(), utcHour = now.getUTCHours();
|
|
47
48
|
const isDST = now.getTimezoneOffset() < Math.max(
|
|
@@ -56,8 +57,11 @@ function createDaemonProxyService(client, propfirm) {
|
|
|
56
57
|
return { isOpen: true, message: 'Market is open' };
|
|
57
58
|
};
|
|
58
59
|
|
|
60
|
+
// Store credentials for algo trading (market data feed)
|
|
61
|
+
let storedCredentials = credentials;
|
|
62
|
+
|
|
59
63
|
return {
|
|
60
|
-
propfirm, propfirmKey: propfirm?.key, accounts: [], credentials:
|
|
64
|
+
propfirm, propfirmKey: propfirm?.key, accounts: [], credentials: storedCredentials,
|
|
61
65
|
async getTradingAccounts() { return client.getTradingAccounts(); },
|
|
62
66
|
async getPositions() { return client.getPositions(); },
|
|
63
67
|
async getOrders() { return client.getOrders(); },
|
|
@@ -70,9 +74,22 @@ function createDaemonProxyService(client, propfirm) {
|
|
|
70
74
|
getAccountPnL() { return { pnl: null, openPnl: null, closedPnl: null, balance: null }; },
|
|
71
75
|
getToken() { return 'daemon-connected'; },
|
|
72
76
|
getPropfirm() { return propfirm?.key || 'apex'; },
|
|
73
|
-
getRithmicCredentials() {
|
|
77
|
+
getRithmicCredentials() {
|
|
78
|
+
// Return credentials for algo trading market data connection
|
|
79
|
+
if (!storedCredentials) return null;
|
|
80
|
+
const { RITHMIC_ENDPOINTS } = require('./services/rithmic');
|
|
81
|
+
return {
|
|
82
|
+
userId: storedCredentials.username,
|
|
83
|
+
password: storedCredentials.password,
|
|
84
|
+
systemName: propfirm?.systemName || propfirm?.name || 'Apex',
|
|
85
|
+
gateway: RITHMIC_ENDPOINTS?.CHICAGO || 'wss://rprotocol.rithmic.com:443',
|
|
86
|
+
};
|
|
87
|
+
},
|
|
88
|
+
setCredentials(creds) { storedCredentials = creds; },
|
|
74
89
|
checkMarketHours,
|
|
75
90
|
async disconnect() { return { success: true }; },
|
|
91
|
+
// For algo - disconnect ticker before starting new market data connection
|
|
92
|
+
async disconnectTicker() { return { success: true }; },
|
|
76
93
|
};
|
|
77
94
|
}
|
|
78
95
|
|
|
@@ -266,8 +283,19 @@ const run = async () => {
|
|
|
266
283
|
// Daemon already has a connection, use it
|
|
267
284
|
const accountsResult = await daemonClient.getTradingAccounts();
|
|
268
285
|
if (accountsResult.success && accountsResult.accounts?.length > 0) {
|
|
286
|
+
// Get credentials for algo trading
|
|
287
|
+
let credentials = null;
|
|
288
|
+
try {
|
|
289
|
+
const credResult = await daemonClient.getCredentials();
|
|
290
|
+
if (credResult.success) {
|
|
291
|
+
credentials = credResult.credentials;
|
|
292
|
+
}
|
|
293
|
+
} catch (credErr) {
|
|
294
|
+
log.warn('Failed to get credentials', { error: credErr.message });
|
|
295
|
+
}
|
|
296
|
+
|
|
269
297
|
// Create a proxy service that uses daemon
|
|
270
|
-
currentService = createDaemonProxyService(daemonClient, status.propfirm);
|
|
298
|
+
currentService = createDaemonProxyService(daemonClient, status.propfirm, credentials);
|
|
271
299
|
connections.services.push({
|
|
272
300
|
type: 'rithmic',
|
|
273
301
|
service: currentService,
|
|
@@ -282,7 +310,18 @@ const run = async () => {
|
|
|
282
310
|
// Daemon not connected, try to restore session via daemon
|
|
283
311
|
const restoreResult = await daemonClient.restoreSession();
|
|
284
312
|
if (restoreResult.success) {
|
|
285
|
-
|
|
313
|
+
// Get credentials for algo trading
|
|
314
|
+
let credentials = null;
|
|
315
|
+
try {
|
|
316
|
+
const credResult = await daemonClient.getCredentials();
|
|
317
|
+
if (credResult.success) {
|
|
318
|
+
credentials = credResult.credentials;
|
|
319
|
+
}
|
|
320
|
+
} catch (credErr) {
|
|
321
|
+
log.warn('Failed to get credentials', { error: credErr.message });
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
currentService = createDaemonProxyService(daemonClient, restoreResult.propfirm, credentials);
|
|
286
325
|
connections.services.push({
|
|
287
326
|
type: 'rithmic',
|
|
288
327
|
service: currentService,
|
|
@@ -348,7 +387,8 @@ const run = async () => {
|
|
|
348
387
|
if (daemonClient?.connected) {
|
|
349
388
|
result = await daemonClient.login(selectedPropfirm.key, credentials.username, credentials.password);
|
|
350
389
|
if (result.success) {
|
|
351
|
-
|
|
390
|
+
// Pass credentials for algo trading market data
|
|
391
|
+
currentService = createDaemonProxyService(daemonClient, result.propfirm, credentials);
|
|
352
392
|
connections.services.push({
|
|
353
393
|
type: 'rithmic', service: currentService,
|
|
354
394
|
propfirm: selectedPropfirm.name, propfirmKey: selectedPropfirm.key, connectedAt: new Date(),
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* @fileoverview HQX Daemon Entry Point
|
|
4
|
+
* @module cli-daemon
|
|
5
|
+
*
|
|
6
|
+
* Standalone entry point for daemon process.
|
|
7
|
+
* Run with: node src/cli-daemon.js
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
'use strict';
|
|
11
|
+
|
|
12
|
+
// Load bytenode for protected modules
|
|
13
|
+
try {
|
|
14
|
+
require('bytenode');
|
|
15
|
+
} catch (_) {}
|
|
16
|
+
|
|
17
|
+
const { startDaemonForeground } = require('./services/daemon');
|
|
18
|
+
|
|
19
|
+
// Start daemon
|
|
20
|
+
startDaemonForeground().catch((err) => {
|
|
21
|
+
console.error('Daemon error:', err.message);
|
|
22
|
+
process.exit(1);
|
|
23
|
+
});
|
|
@@ -351,6 +351,14 @@ class DaemonClient extends EventEmitter {
|
|
|
351
351
|
return this._request(MSG_TYPE.SEARCH_CONTRACTS, { search });
|
|
352
352
|
}
|
|
353
353
|
|
|
354
|
+
/**
|
|
355
|
+
* Get credentials for algo trading
|
|
356
|
+
* @returns {Promise<Object>}
|
|
357
|
+
*/
|
|
358
|
+
async getCredentials() {
|
|
359
|
+
return this._request(MSG_TYPE.GET_CREDENTIALS);
|
|
360
|
+
}
|
|
361
|
+
|
|
354
362
|
/**
|
|
355
363
|
* Subscribe to market data
|
|
356
364
|
* @param {string} symbol
|
|
@@ -42,6 +42,7 @@ const MSG_TYPE = {
|
|
|
42
42
|
GET_STATUS: 'get_status',
|
|
43
43
|
GET_CONTRACTS: 'get_contracts',
|
|
44
44
|
SEARCH_CONTRACTS: 'search_contracts',
|
|
45
|
+
GET_CREDENTIALS: 'get_credentials',
|
|
45
46
|
|
|
46
47
|
// Data responses
|
|
47
48
|
ACCOUNTS: 'accounts',
|
|
@@ -50,6 +51,7 @@ const MSG_TYPE = {
|
|
|
50
51
|
PNL: 'pnl',
|
|
51
52
|
STATUS: 'status',
|
|
52
53
|
CONTRACTS: 'contracts',
|
|
54
|
+
CREDENTIALS: 'credentials',
|
|
53
55
|
|
|
54
56
|
// Trading
|
|
55
57
|
PLACE_ORDER: 'place_order',
|
|
@@ -262,6 +262,39 @@ function createHandlers(daemon) {
|
|
|
262
262
|
daemon._send(socket, createMessage(MSG_TYPE.ORDER_RESULT, result, id));
|
|
263
263
|
}
|
|
264
264
|
|
|
265
|
+
// ==================== CREDENTIALS HANDLER ====================
|
|
266
|
+
|
|
267
|
+
async function handleGetCredentials(socket, id) {
|
|
268
|
+
// Load credentials from saved session
|
|
269
|
+
const { storage } = require('../session');
|
|
270
|
+
const sessions = storage.load();
|
|
271
|
+
const rithmicSession = sessions.find(s => s.type === 'rithmic' && s.credentials);
|
|
272
|
+
|
|
273
|
+
if (!rithmicSession || !rithmicSession.credentials) {
|
|
274
|
+
daemon._send(socket, createMessage(MSG_TYPE.CREDENTIALS, {
|
|
275
|
+
success: false,
|
|
276
|
+
error: 'No credentials available',
|
|
277
|
+
}, id));
|
|
278
|
+
return;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
// Return credentials for algo trading market data
|
|
282
|
+
const { RITHMIC_ENDPOINTS } = require('../rithmic');
|
|
283
|
+
daemon._send(socket, createMessage(MSG_TYPE.CREDENTIALS, {
|
|
284
|
+
success: true,
|
|
285
|
+
credentials: {
|
|
286
|
+
username: rithmicSession.credentials.username,
|
|
287
|
+
password: rithmicSession.credentials.password,
|
|
288
|
+
},
|
|
289
|
+
rithmicCredentials: {
|
|
290
|
+
userId: rithmicSession.credentials.username,
|
|
291
|
+
password: rithmicSession.credentials.password,
|
|
292
|
+
systemName: daemon.propfirm?.name || rithmicSession.propfirm || 'Apex',
|
|
293
|
+
gateway: RITHMIC_ENDPOINTS?.CHICAGO || 'wss://rprotocol.rithmic.com:443',
|
|
294
|
+
},
|
|
295
|
+
}, id));
|
|
296
|
+
}
|
|
297
|
+
|
|
265
298
|
// ==================== CONTRACT HANDLERS ====================
|
|
266
299
|
|
|
267
300
|
async function handleGetContracts(socket, id) {
|
|
@@ -332,6 +365,7 @@ function createHandlers(daemon) {
|
|
|
332
365
|
handleGetPositions,
|
|
333
366
|
handleGetOrders,
|
|
334
367
|
handleGetPnL,
|
|
368
|
+
handleGetCredentials,
|
|
335
369
|
handlePlaceOrder,
|
|
336
370
|
handleCancelOrder,
|
|
337
371
|
handleCancelAll,
|
|
@@ -196,6 +196,10 @@ class DaemonServer extends EventEmitter {
|
|
|
196
196
|
await h.handleGetPnL(socket, id, data);
|
|
197
197
|
break;
|
|
198
198
|
|
|
199
|
+
case MSG_TYPE.GET_CREDENTIALS:
|
|
200
|
+
await h.handleGetCredentials(socket, id);
|
|
201
|
+
break;
|
|
202
|
+
|
|
199
203
|
case MSG_TYPE.PLACE_ORDER:
|
|
200
204
|
await h.handlePlaceOrder(socket, id, data);
|
|
201
205
|
break;
|