hedgequantx 2.9.144 → 2.9.145

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.144",
3
+ "version": "2.9.145",
4
4
  "description": "HedgeQuantX - Prop Futures Trading CLI",
5
5
  "main": "src/app.js",
6
6
  "bin": {
@@ -358,45 +358,7 @@ class SmartLogsEngine {
358
358
 
359
359
  const t = [];
360
360
 
361
- // === BULLISH FLOW ===
362
- if (isBull) {
363
- t.push({ type: 'bullish', message: `${S} ${P} heavy paper on the bid | Size lifting offers ${D} | Tape running` });
364
- t.push({ type: 'bullish', message: `${SL} bid refreshing at ${P} | ${OFI} | Buyers in control` });
365
- t.push({ type: 'bullish', message: `Large prints on ${S} ${P} | ${VPIN} toxic | Institutions lifting` });
366
- t.push({ type: 'bullish', message: `${S} squeeze building at ${P} | Shorts underwater | ${D} accelerating` });
367
- t.push({ type: 'bullish', message: `Block buyer ${SL} ${P} | ${IMB} buy tape | Iceberg absorbing supply` });
368
- t.push({ type: 'bullish', message: `${S} momentum ignition at ${P} | DOM stacked bid | Offers lifted` });
369
- t.push({ type: 'bullish', message: `Aggressive buying ${S} at ${P} | ${ZS} | Sellers capitulating` });
370
- t.push({ type: 'bullish', message: `${S} ${P} bid wall holding | ${D} | Passive offers exhausted` });
371
- t.push({ type: 'bullish', message: `Dark pool bid ${SL} ${P} | ${VPIN} | Smart money accumulating` });
372
- t.push({ type: 'bullish', message: `${S} footprint bullish at ${P} | ${tps} tps | Institutional absorption` });
373
- }
374
- // === BEARISH FLOW ===
375
- else if (isBear) {
376
- t.push({ type: 'bearish', message: `${S} ${P} heavy paper on offer | Size hitting bids ${D} | Tape dumping` });
377
- t.push({ type: 'bearish', message: `${SL} offer refreshing at ${P} | ${OFI} | Sellers in control` });
378
- t.push({ type: 'bearish', message: `Large prints selling ${S} ${P} | ${VPIN} toxic | Institutions hitting` });
379
- t.push({ type: 'bearish', message: `${S} breakdown at ${P} | Longs underwater | ${D} accelerating` });
380
- t.push({ type: 'bearish', message: `Block seller ${SL} ${P} | ${IMB} sell tape | Iceberg absorbing demand` });
381
- t.push({ type: 'bearish', message: `${S} momentum breakdown at ${P} | DOM stacked offer | Bids hit` });
382
- t.push({ type: 'bearish', message: `Aggressive selling ${S} at ${P} | ${ZS} | Buyers capitulating` });
383
- t.push({ type: 'bearish', message: `${S} ${P} offer wall capping | ${D} | Passive bids exhausted` });
384
- t.push({ type: 'bearish', message: `Dark pool offer ${SL} ${P} | ${VPIN} | Smart money distributing` });
385
- t.push({ type: 'bearish', message: `${S} footprint bearish at ${P} | ${tps} tps | Institutional distribution` });
386
- }
387
- // === NEUTRAL/CHOP ===
388
- else {
389
- t.push({ type: 'analysis', message: `${S} ${P} two-way paper | ${D} flat | Locals making markets` });
390
- t.push({ type: 'analysis', message: `${SL} chopping at ${P} | Spread ${spd}t | No directional flow` });
391
- t.push({ type: 'analysis', message: `${S} balanced at ${P} | ${VPIN} | Waiting for size to show` });
392
- t.push({ type: 'analysis', message: `Range trade ${S} ${P} | Book symmetric | Mean reversion active` });
393
- t.push({ type: 'analysis', message: `${S} consolidating at ${P} | ${ZS} | No edge either side` });
394
- t.push({ type: 'analysis', message: `Quiet tape ${SL} ${P} | ${tps} tps | Institutions on sidelines` });
395
- t.push({ type: 'analysis', message: `${S} ${P} fair value auction | ${D} | Algos scalping spread` });
396
- t.push({ type: 'analysis', message: `Flow balanced ${S} at ${P} | ${OFI} | Awaiting catalyst` });
397
- }
398
-
399
- // === HQX-2B: Liquidity Sweep ===
361
+ // === HQX-2B: Liquidity Sweep Strategy ===
400
362
  if (isHQX2B) {
401
363
  if (phase === 'ready' && zones > 0) {
402
364
  t.push({ type: 'signal', message: `${chalk.green.bold('SWEEP')} ${S} ${P} | ${zones} stops triggered | Reversal confirmed` });
@@ -406,12 +368,24 @@ class SmartLogsEngine {
406
368
  t.push({ type: 'analysis', message: `${S} ${P} approaching liquidity | ${zones} clusters mapped | Sweep imminent` });
407
369
  t.push({ type: 'analysis', message: `Stop hunt setup ${SL} ${P} | ${swings} swings | Watching penetration` });
408
370
  t.push({ type: 'analysis', message: `${S} zone test at ${P} | ${zones} targets | Monitoring rejection` });
371
+ } else if (isBull) {
372
+ t.push({ type: 'bullish', message: `${S} ${P} bid absorption | ${D} | Stops below being hunted` });
373
+ t.push({ type: 'bullish', message: `${SL} liquidity building at ${P} | Sweep setup forming | ${swings} pivots` });
374
+ t.push({ type: 'bullish', message: `Institutional bid ${S} ${P} | ${OFI} | Retail shorts trapped` });
375
+ t.push({ type: 'bullish', message: `${S} false breakdown at ${P} | ${D} | Smart money buying dip` });
376
+ } else if (isBear) {
377
+ t.push({ type: 'bearish', message: `${S} ${P} offer absorption | ${D} | Stops above being hunted` });
378
+ t.push({ type: 'bearish', message: `${SL} liquidity building at ${P} | Sweep setup forming | ${swings} pivots` });
379
+ t.push({ type: 'bearish', message: `Institutional offer ${S} ${P} | ${OFI} | Retail longs trapped` });
380
+ t.push({ type: 'bearish', message: `${S} false breakout at ${P} | ${D} | Smart money selling rally` });
409
381
  } else {
410
- t.push({ type: 'system', message: `Mapping ${S} structure at ${P} | ${bars} bars | ${swings} swings | Zones` });
411
- t.push({ type: 'system', message: `${SL} topology at ${P} | ${tickCount} ticks | Detecting clusters` });
382
+ t.push({ type: 'system', message: `Mapping ${S} structure at ${P} | ${bars} bars | ${swings} swings` });
383
+ t.push({ type: 'system', message: `${SL} scanning zones at ${P} | ${tickCount} ticks | Detecting clusters` });
384
+ t.push({ type: 'analysis', message: `${S} ${P} consolidating | ${D} | Liquidity pooling at extremes` });
385
+ t.push({ type: 'analysis', message: `${SL} range at ${P} | Stops accumulating | Sweep pending` });
412
386
  }
413
387
  }
414
- // === ULTRA-SCALPING: Quant/Stats ===
388
+ // === ULTRA-SCALPING: Quant/Stats Strategy ===
415
389
  else {
416
390
  if (phase === 'ready') {
417
391
  t.push({ type: 'signal', message: `${chalk.green.bold('EDGE')} ${S} ${P} | ${ZS} breach | ${VPIN} | Execute` });
@@ -421,9 +395,19 @@ class SmartLogsEngine {
421
395
  t.push({ type: 'analysis', message: `${S} ${P} factors building | ${ZS} | Threshold proximity` });
422
396
  t.push({ type: 'analysis', message: `${SL} edge forming at ${P} | ${VPIN} | Monitoring` });
423
397
  t.push({ type: 'analysis', message: `Statistical setup ${S} ${P} | ${OFI} | Alignment ${IMB}` });
398
+ } else if (isBull) {
399
+ t.push({ type: 'bullish', message: `${S} ${P} heavy paper bid | ${D} | ${VPIN} rising` });
400
+ t.push({ type: 'bullish', message: `${SL} ${P} ${ZS} bullish | ${OFI} | Mean reversion long` });
401
+ t.push({ type: 'bullish', message: `${S} momentum ${P} | ${IMB} buy | Quant signal building` });
402
+ } else if (isBear) {
403
+ t.push({ type: 'bearish', message: `${S} ${P} heavy paper offer | ${D} | ${VPIN} rising` });
404
+ t.push({ type: 'bearish', message: `${SL} ${P} ${ZS} bearish | ${OFI} | Mean reversion short` });
405
+ t.push({ type: 'bearish', message: `${S} momentum ${P} | ${IMB} sell | Quant signal building` });
424
406
  } else {
425
407
  t.push({ type: 'system', message: `Calibrating ${S} models at ${P} | ${bars} bars | Computing factors` });
426
408
  t.push({ type: 'system', message: `${SL} tick analysis at ${P} | ${tickCount} samples | ${tps} tps` });
409
+ t.push({ type: 'analysis', message: `${S} ${P} neutral | ${ZS} | ${VPIN} | Awaiting edge` });
410
+ t.push({ type: 'analysis', message: `${SL} range at ${P} | ${D} | Statistical mean reversion` });
427
411
  }
428
412
  }
429
413
 
@@ -286,16 +286,22 @@ const executeMultiSymbol = async ({ service, account, contracts, config, strateg
286
286
  let startingPnL = null;
287
287
  const pollPnL = async () => {
288
288
  try {
289
- // Get P&L from cache (no API call)
290
289
  const accId = account.rithmicAccountId || account.accountId;
291
- const pnlData = service.getAccountPnL ? service.getAccountPnL(accId) : null;
292
290
 
293
- if (pnlData && pnlData.pnl !== null) {
291
+ // Get P&L from cache (sync for RithmicService, async for BrokerClient)
292
+ let pnlData = null;
293
+ if (service.getAccountPnL) {
294
+ const result = service.getAccountPnL(accId);
295
+ pnlData = result && result.then ? await result : result; // Handle both sync/async
296
+ }
297
+
298
+ if (pnlData && pnlData.pnl !== null && pnlData.pnl !== undefined && !isNaN(pnlData.pnl)) {
294
299
  if (startingPnL === null) startingPnL = pnlData.pnl;
295
- globalStats.pnl = pnlData.pnl - startingPnL;
300
+ const newPnl = pnlData.pnl - startingPnL;
301
+ if (!isNaN(newPnl)) globalStats.pnl = newPnl;
296
302
  }
297
303
 
298
- // Check positions (less frequent - every 10s instead of 2s)
304
+ // Check positions (less frequent - every 10s)
299
305
  if (Date.now() % 10000 < 2000) {
300
306
  const posResult = await service.getPositions(accId);
301
307
  if (posResult.success && posResult.positions) {
@@ -306,13 +312,15 @@ const executeMultiSymbol = async ({ service, account, contracts, config, strateg
306
312
  }
307
313
  }
308
314
 
309
- // Risk checks
310
- if (globalStats.pnl >= dailyTarget) {
311
- stopReason = 'target'; running = false;
312
- ui.addLog('fill_win', `TARGET REACHED! +$${globalStats.pnl.toFixed(2)}`);
313
- } else if (globalStats.pnl <= -maxRisk) {
314
- stopReason = 'risk'; running = false;
315
- ui.addLog('fill_loss', `MAX RISK! -$${Math.abs(globalStats.pnl).toFixed(2)}`);
315
+ // Risk checks (only if pnl is valid)
316
+ if (!isNaN(globalStats.pnl)) {
317
+ if (globalStats.pnl >= dailyTarget) {
318
+ stopReason = 'target'; running = false;
319
+ ui.addLog('fill_win', `TARGET REACHED! +$${globalStats.pnl.toFixed(2)}`);
320
+ } else if (globalStats.pnl <= -maxRisk) {
321
+ stopReason = 'risk'; running = false;
322
+ ui.addLog('fill_loss', `MAX RISK! -$${Math.abs(globalStats.pnl).toFixed(2)}`);
323
+ }
316
324
  }
317
325
  } catch (e) { /* silent */ }
318
326
  };
@@ -321,23 +329,29 @@ const executeMultiSymbol = async ({ service, account, contracts, config, strateg
321
329
  const pnlInterval = setInterval(() => { if (running) pollPnL(); }, 2000);
322
330
  pollPnL();
323
331
 
324
- // Live analysis logs every 1 second (rotates through symbols)
332
+ // Live analysis logs every 5 seconds (rotates through symbols with data)
325
333
  let liveLogSymbolIndex = 0;
326
- let lastLiveLogSecond = 0;
334
+ let lastLiveLogTime = 0;
327
335
  const liveLogInterval = setInterval(() => {
328
336
  if (!running) return;
329
- const now = Math.floor(Date.now() / 1000);
330
- if (now === lastLiveLogSecond) return;
331
- lastLiveLogSecond = now;
337
+ const now = Date.now();
338
+ if (now - lastLiveLogTime < 5000) return; // Every 5 seconds
339
+ lastLiveLogTime = now;
332
340
 
333
- // Get a symbol to log (rotate through all)
341
+ // Get symbols with tick data (skip symbols without data)
334
342
  const symbolCodes = Array.from(symbolData.keys());
335
343
  if (symbolCodes.length === 0) return;
336
344
 
337
- const symbolCode = symbolCodes[liveLogSymbolIndex % symbolCodes.length];
338
- liveLogSymbolIndex++;
345
+ // Find next symbol with data
346
+ let attempts = 0;
347
+ let symbolCode, data;
348
+ do {
349
+ symbolCode = symbolCodes[liveLogSymbolIndex % symbolCodes.length];
350
+ liveLogSymbolIndex++;
351
+ data = symbolData.get(symbolCode);
352
+ attempts++;
353
+ } while ((!data || data.stats.tickCount === 0) && attempts < symbolCodes.length);
339
354
 
340
- const data = symbolData.get(symbolCode);
341
355
  if (!data) return;
342
356
 
343
357
  const state = data.strategy.getAnalysisState?.(symbolCode, data.stats.lastPrice);
@@ -353,10 +367,13 @@ const executeMultiSymbol = async ({ service, account, contracts, config, strateg
353
367
  tickCount: data.stats.tickCount || 0,
354
368
  };
355
369
 
356
- logsEngine.setSymbol(symbolCode);
357
- const log = logsEngine.getLog(logState);
358
- ui.addLog(log.type, log.message);
359
- if (log.logToSession) sessionLogger.log('ANALYSIS', `[${symbolCode}] ${log.message}`);
370
+ // Only log if we have meaningful data
371
+ if (logState.price > 0 || logState.tickCount > 0) {
372
+ logsEngine.setSymbol(symbolCode);
373
+ const log = logsEngine.getLog(logState);
374
+ ui.addLog(log.type, log.message);
375
+ if (log.logToSession) sessionLogger.log('ANALYSIS', `[${symbolCode}] ${log.message}`);
376
+ }
360
377
  }, 1000);
361
378
 
362
379
  // Key handler
@@ -188,9 +188,9 @@ class AlgoUI {
188
188
  // Row 1: Account | Symbol(s)
189
189
  const accountName = String(stats.accountName || 'N/A').substring(0, 40);
190
190
  const isMultiSymbol = stats.symbolCount && stats.symbolCount > 1;
191
- const symbolDisplay = isMultiSymbol
192
- ? `${stats.symbolCount} symbols`
193
- : String(stats.symbol || stats.symbols || 'N/A').substring(0, 35);
191
+ // Show actual symbols list, truncate if too long
192
+ const symbolsStr = String(stats.symbols || stats.symbol || 'N/A');
193
+ const symbolDisplay = symbolsStr.length > 35 ? symbolsStr.substring(0, 32) + '...' : symbolsStr;
194
194
  const r1c1 = buildCell('Account', accountName, chalk.cyan, colL);
195
195
  const r1c2 = buildCell(isMultiSymbol ? 'Symbols' : 'Symbol', symbolDisplay, chalk.yellow, colR);
196
196
  row(r1c1.padded, r1c2.padded);
@@ -232,13 +232,13 @@ class RithmicBrokerClient extends EventEmitter {
232
232
  */
233
233
  getRithmicCredentials() {
234
234
  // Sync call - return cached credentials
235
- // For async, use _request('getRithmicCredentials')
236
- return this.credentials ? {
235
+ if (!this.credentials) return null;
236
+ return {
237
237
  userId: this.credentials.username,
238
238
  password: this.credentials.password,
239
239
  systemName: this.propfirm?.systemName || 'Apex',
240
- gateway: 'wss://rituz.rithmic.com:443',
241
- } : null;
240
+ gateway: 'wss://rprotocol.rithmic.com:443',
241
+ };
242
242
  }
243
243
 
244
244
  /**