hedgequantx 2.9.149 → 2.9.151

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.149",
3
+ "version": "2.9.151",
4
4
  "description": "HedgeQuantX - Prop Futures Trading CLI",
5
5
  "main": "src/app.js",
6
6
  "bin": {
@@ -328,7 +328,13 @@ const executeAlgo = async ({ service, account, contract, config, strategy: strat
328
328
  try {
329
329
  // Try sync (RithmicService) then async (BrokerClient)
330
330
  let rithmicCredentials = service.getRithmicCredentials?.();
331
- if (!rithmicCredentials && service.getRithmicCredentialsAsync) rithmicCredentials = await service.getRithmicCredentialsAsync();
331
+ if (!rithmicCredentials && service.getRithmicCredentialsAsync) {
332
+ try {
333
+ rithmicCredentials = await service.getRithmicCredentialsAsync();
334
+ } catch (credErr) {
335
+ throw new Error(`Broker error: ${credErr.message} - try "hqx login"`);
336
+ }
337
+ }
332
338
  if (!rithmicCredentials) throw new Error('Rithmic credentials not available - try "hqx login"');
333
339
  if (service.disconnectTicker) await service.disconnectTicker(); // Avoid TICKER conflict
334
340
  await marketFeed.connect(rithmicCredentials);
@@ -191,7 +191,11 @@ const launchCopyTrading = async (config) => {
191
191
  // Try sync first (RithmicService), then async (RithmicBrokerClient)
192
192
  let rithmicCredentials = leadService.getRithmicCredentials?.();
193
193
  if (!rithmicCredentials && leadService.getRithmicCredentialsAsync) {
194
- rithmicCredentials = await leadService.getRithmicCredentialsAsync();
194
+ try {
195
+ rithmicCredentials = await leadService.getRithmicCredentialsAsync();
196
+ } catch (credErr) {
197
+ throw new Error(`Broker error: ${credErr.message} - try "hqx login"`);
198
+ }
195
199
  }
196
200
  if (!rithmicCredentials) {
197
201
  throw new Error('Rithmic credentials not available - try "hqx login"');
@@ -270,7 +270,11 @@ const executeMultiSymbol = async ({ service, account, contracts, config, strateg
270
270
  // Try sync first (RithmicService), then async (RithmicBrokerClient)
271
271
  let rithmicCredentials = service.getRithmicCredentials?.();
272
272
  if (!rithmicCredentials && service.getRithmicCredentialsAsync) {
273
- rithmicCredentials = await service.getRithmicCredentialsAsync();
273
+ try {
274
+ rithmicCredentials = await service.getRithmicCredentialsAsync();
275
+ } catch (credErr) {
276
+ throw new Error(`Broker error: ${credErr.message} - try "hqx login"`);
277
+ }
274
278
  }
275
279
  if (!rithmicCredentials) throw new Error('Rithmic credentials not available - try "hqx login"');
276
280
 
@@ -301,12 +301,13 @@ const oneAccountMenu = async (service) => {
301
301
  */
302
302
  const selectMultipleSymbols = async (service, account) => {
303
303
  const spinner = ora({ text: 'Loading symbols...', color: 'yellow' }).start();
304
-
305
- // Debug: log service type
306
304
  const serviceType = service.constructor?.name || 'Unknown';
307
305
 
308
- // Ensure we have a logged-in service
309
- if (!service.loginInfo && service.credentials) {
306
+ // Check if service needs reconnection:
307
+ // - RithmicService: check loginInfo
308
+ // - RithmicBrokerClient: check connected (already connected to daemon)
309
+ const needsReconnect = !service.loginInfo && !service.connected && service.credentials;
310
+ if (needsReconnect) {
310
311
  spinner.text = 'Reconnecting to broker...';
311
312
  const loginResult = await service.login(service.credentials.username, service.credentials.password);
312
313
  if (!loginResult.success) {
@@ -383,12 +384,13 @@ const selectMultipleSymbols = async (service, account) => {
383
384
  */
384
385
  const selectSymbol = async (service, account) => {
385
386
  const spinner = ora({ text: 'Loading symbols...', color: 'yellow' }).start();
386
-
387
- // Debug: log service type
388
387
  const serviceType = service.constructor?.name || 'Unknown';
389
388
 
390
- // Ensure we have a logged-in service (for direct RithmicService, not BrokerClient)
391
- if (!service.loginInfo && service.credentials && typeof service.login === 'function') {
389
+ // Check if service needs reconnection:
390
+ // - RithmicService: check loginInfo
391
+ // - RithmicBrokerClient: check connected (already connected to daemon)
392
+ const needsReconnect = !service.loginInfo && !service.connected && service.credentials;
393
+ if (needsReconnect && typeof service.login === 'function') {
392
394
  spinner.text = 'Reconnecting to broker...';
393
395
  const loginResult = await service.login(service.credentials.username, service.credentials.password);
394
396
  if (!loginResult.success) {
@@ -249,9 +249,14 @@ class RithmicBrokerClient extends EventEmitter {
249
249
 
250
250
  /**
251
251
  * Get async Rithmic credentials from daemon
252
+ * @returns {Object|null} Credentials object or null
253
+ * @throws {Error} If daemon returns error
252
254
  */
253
255
  async getRithmicCredentialsAsync() {
254
256
  const result = await this._request('getRithmicCredentials', { propfirmKey: this.propfirmKey });
257
+ if (result.error) {
258
+ throw new Error(result.error);
259
+ }
255
260
  return result.payload || null;
256
261
  }
257
262
 
@@ -332,8 +332,20 @@ class RithmicBrokerDaemon {
332
332
 
333
333
  _handleGetCredentials(payload, requestId) {
334
334
  const conn = this.connections.get(payload.propfirmKey);
335
- if (!conn?.service) return { error: 'Not connected', requestId };
336
- return { type: 'credentials', payload: conn.service.getRithmicCredentials?.() || null, requestId };
335
+ if (!conn) {
336
+ log('WARN', 'getCredentials: propfirm not found', { propfirm: payload.propfirmKey });
337
+ return { error: `Propfirm "${payload.propfirmKey}" not connected - run "hqx login"`, requestId };
338
+ }
339
+ if (!conn.service) {
340
+ log('WARN', 'getCredentials: service is null', { propfirm: payload.propfirmKey, status: conn.status });
341
+ return { error: `Connection lost for "${payload.propfirmKey}" - run "hqx login"`, requestId };
342
+ }
343
+ const creds = conn.service.getRithmicCredentials?.();
344
+ if (!creds) {
345
+ log('WARN', 'getCredentials: credentials null', { propfirm: payload.propfirmKey });
346
+ return { error: `Credentials not available for "${payload.propfirmKey}"`, requestId };
347
+ }
348
+ return { type: 'credentials', payload: creds, requestId };
337
349
  }
338
350
 
339
351
  /**
@@ -146,6 +146,17 @@ const connections = {
146
146
  const accountsResult = await client.getTradingAccounts();
147
147
  client.accounts = accountsResult.accounts || [];
148
148
 
149
+ // Cache credentials locally for sync access (fetch from daemon)
150
+ try {
151
+ const creds = await client.getRithmicCredentialsAsync();
152
+ if (creds && creds.userId && creds.password) {
153
+ client.credentials = { username: creds.userId, password: creds.password };
154
+ client.propfirm = { name: conn.propfirmKey, systemName: creds.systemName, gateway: creds.gateway };
155
+ }
156
+ } catch (e) {
157
+ log.warn('Failed to cache credentials', { propfirm: conn.propfirmKey, error: e.message });
158
+ }
159
+
149
160
  this.services.push({
150
161
  type: 'rithmic',
151
162
  service: client,
@@ -153,7 +164,7 @@ const connections = {
153
164
  propfirmKey: conn.propfirmKey,
154
165
  connectedAt: new Date(conn.connectedAt),
155
166
  });
156
- log.debug('Restored from broker', { propfirm: conn.propfirmKey });
167
+ log.debug('Restored from broker', { propfirm: conn.propfirmKey, hasCreds: !!client.credentials });
157
168
  }
158
169
 
159
170
  return this.services.length > 0;