hedgequantx 2.9.221 → 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.221",
3
+ "version": "2.9.222",
4
4
  "description": "HedgeQuantX - Prop Futures Trading CLI",
5
5
  "main": "src/app.js",
6
6
  "bin": {
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: null,
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() { return null; },
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
- currentService = createDaemonProxyService(daemonClient, restoreResult.propfirm);
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
- currentService = createDaemonProxyService(daemonClient, result.propfirm);
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(),
@@ -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;