hedgequantx 2.9.165 → 2.9.167

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.165",
3
+ "version": "2.9.167",
4
4
  "description": "HedgeQuantX - Prop Futures Trading CLI",
5
5
  "main": "src/app.js",
6
6
  "bin": {
@@ -342,16 +342,23 @@ class RithmicBrokerDaemon {
342
342
  // Log service state for debugging
343
343
  const hasCredentials = !!conn.service.credentials;
344
344
  const hasTickerConn = !!conn.service.tickerConn;
345
- log('DEBUG', 'getContracts request', { propfirm: payload.propfirmKey, hasCredentials, hasTickerConn });
345
+ const tickerState = conn.service.tickerConn?.connectionState;
346
+ log('DEBUG', 'getContracts request', { propfirm: payload.propfirmKey, hasCredentials, hasTickerConn, tickerState });
346
347
 
347
348
  try {
348
349
  const result = await conn.service.getContracts();
350
+
351
+ // Log detailed result
352
+ const tickerStateAfter = conn.service.tickerConn?.connectionState;
349
353
  log('DEBUG', 'getContracts result', {
350
354
  propfirm: payload.propfirmKey,
351
355
  success: result.success,
352
356
  count: result.contracts?.length || 0,
357
+ source: result.source,
358
+ tickerStateAfter,
353
359
  error: result.error
354
360
  });
361
+
355
362
  return { type: 'contracts', payload: result, requestId };
356
363
  } catch (err) {
357
364
  log('ERROR', 'getContracts exception', { propfirm: payload.propfirmKey, error: err.message, stack: err.stack?.split('\n')[1] });
@@ -111,19 +111,38 @@ const connections = {
111
111
  log.info('Connection added', { type, propfirm: propfirm || type });
112
112
  },
113
113
 
114
+ /**
115
+ * Sanitize account data to prevent corrupted data from being saved
116
+ */
117
+ _sanitizeAccount(acc) {
118
+ if (!acc || typeof acc !== 'object' || !acc.accountId) return null;
119
+ return {
120
+ accountId: String(acc.accountId),
121
+ fcmId: acc.fcmId ? String(acc.fcmId) : undefined,
122
+ ibId: acc.ibId ? String(acc.ibId) : undefined,
123
+ accountName: acc.accountName ? String(acc.accountName) : undefined,
124
+ };
125
+ },
126
+
114
127
  saveToStorage() {
115
128
  // Load existing sessions to preserve AI agents
116
129
  const existingSessions = storage.load();
117
130
  const aiSessions = existingSessions.filter(s => s.type === 'ai');
118
131
 
119
132
  // Build Rithmic sessions - INCLUDE accounts to avoid Rithmic API limit on restore
120
- const rithmicSessions = this.services.map(conn => ({
121
- type: conn.type,
122
- propfirm: conn.propfirm,
123
- propfirmKey: conn.service.propfirmKey || conn.propfirmKey,
124
- credentials: conn.service.credentials,
125
- accounts: conn.service.accounts || [], // CRITICAL: Cache accounts to avoid 2000 GetAccounts limit
126
- }));
133
+ const rithmicSessions = this.services.map(conn => {
134
+ // Sanitize accounts to prevent corrupted data
135
+ const rawAccounts = conn.service.accounts || [];
136
+ const accounts = rawAccounts.map(a => this._sanitizeAccount(a)).filter(Boolean);
137
+
138
+ return {
139
+ type: conn.type,
140
+ propfirm: conn.propfirm,
141
+ propfirmKey: conn.service.propfirmKey || conn.propfirmKey,
142
+ credentials: conn.service.credentials,
143
+ accounts, // CRITICAL: Cache sanitized accounts to avoid 2000 GetAccounts limit
144
+ };
145
+ });
127
146
 
128
147
  // Merge: AI sessions + Rithmic sessions
129
148
  storage.save([...aiSessions, ...rithmicSessions]);
@@ -200,8 +219,17 @@ const connections = {
200
219
  if (type === 'rithmic' && session.credentials) {
201
220
  const client = new RithmicBrokerClient(propfirmKey || 'apex_rithmic');
202
221
 
203
- // CRITICAL: Pass cached accounts to avoid Rithmic's 2000 GetAccounts limit
204
- const loginOptions = session.accounts ? { cachedAccounts: session.accounts } : {};
222
+ // Validate cached accounts before using
223
+ let validAccounts = null;
224
+ if (session.accounts && Array.isArray(session.accounts)) {
225
+ validAccounts = session.accounts
226
+ .map(a => this._sanitizeAccount(a))
227
+ .filter(Boolean);
228
+ if (validAccounts.length === 0) validAccounts = null;
229
+ }
230
+
231
+ // CRITICAL: Pass validated cached accounts to avoid Rithmic's 2000 GetAccounts limit
232
+ const loginOptions = validAccounts ? { cachedAccounts: validAccounts } : {};
205
233
  const result = await client.login(session.credentials.username, session.credentials.password, loginOptions);
206
234
 
207
235
  if (result.success) {
@@ -212,7 +240,7 @@ const connections = {
212
240
  propfirmKey,
213
241
  connectedAt: new Date(),
214
242
  });
215
- log.debug('Rithmic session restored via broker', { hasCachedAccounts: !!session.accounts });
243
+ log.debug('Rithmic session restored via broker', { hasCachedAccounts: !!validAccounts, accountCount: validAccounts?.length || 0 });
216
244
  }
217
245
  }
218
246
  },