hedgequantx 1.2.71 → 1.2.73

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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/src/pages/algo.js +100 -25
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hedgequantx",
3
- "version": "1.2.71",
3
+ "version": "1.2.73",
4
4
  "description": "Prop Futures Algo Trading CLI - Connect to Topstep, Alpha Futures, and other prop firms",
5
5
  "main": "src/app.js",
6
6
  "bin": {
package/src/pages/algo.js CHANGED
@@ -307,6 +307,8 @@ const launchAlgo = async (service, account, contract, numContracts, dailyTarget,
307
307
  let algoRunning = false;
308
308
  let stopReason = null;
309
309
  let latency = 0;
310
+ let spinnerFrame = 0;
311
+ const spinnerChars = ['\u280B', '\u2819', '\u2839', '\u2838', '\u283C', '\u2834', '\u2826', '\u2827', '\u2807', '\u280F'];
310
312
 
311
313
  // Stats
312
314
  let stats = {
@@ -434,41 +436,104 @@ const launchAlgo = async (service, account, contract, numContracts, dailyTarget,
434
436
  console.log(chalk.cyan(V) + chalk.white(center(title2, W)) + chalk.cyan(V));
435
437
  console.log(chalk.cyan(MID));
436
438
 
437
- // Account line - build plain string first, then color
438
- const acc = accountName.length > 24 ? accountName.substring(0, 24) : accountName.padEnd(24);
439
- const sym = symbolName.length > 8 ? symbolName.substring(0, 8) : symbolName.padEnd(8);
440
- const qty = numContracts.toString().padEnd(2);
441
- const srv = serverStatus.padEnd(3);
442
- const lat = latencyStr.padEnd(6);
443
- const line1 = ` Account: ${acc} Symbol: ${sym} Qty: ${qty} Server: ${srv} ${lat}`;
444
- const line1Colored = ` Account: ${chalk.cyan(acc)} Symbol: ${chalk.yellow(sym)} Qty: ${chalk.cyan(qty)} Server: ${serverColor(srv)} ${latencyColor(lat)}`;
445
- console.log(chalk.cyan(V) + line1Colored + ' '.repeat(W - line1.length) + chalk.cyan(V));
439
+ // Grid layout for metrics - each in its own cell
440
+ // Row 1: Account | Symbol | Qty | Server | Latency
441
+ // Row 2: Target | Risk | P&L | Trades | W/L
442
+ const VS = '\u2502'; // Vertical separator (thin)
446
443
 
447
- // Target line
448
- const tgt = ('$' + dailyTarget.toFixed(2)).padEnd(10);
449
- const rsk = ('$' + maxRisk.toFixed(2)).padEnd(10);
450
- const pnl = pnlStr.padEnd(10);
451
- const trd = stats.trades.toString().padEnd(2);
452
- const win = stats.wins.toString();
453
- const los = stats.losses.toString();
454
- const line2 = ` Target: ${tgt} Risk: ${rsk} P&L: ${pnl} Trades: ${trd} W:${win} L:${los}`;
455
- const line2Colored = ` Target: ${chalk.green(tgt)} Risk: ${chalk.red(rsk)} P&L: ${pnlColor(pnl)} Trades: ${chalk.cyan(trd)} W:${chalk.green(win)} L:${chalk.red(los)}`;
456
- console.log(chalk.cyan(V) + line2Colored + ' '.repeat(W - line2.length) + chalk.cyan(V));
444
+ // Prepare values with fixed widths
445
+ const accLabel = 'Account';
446
+ const accVal = accountName.length > 26 ? accountName.substring(0, 26) : accountName;
447
+ const symLabel = 'Symbol';
448
+ const symVal = symbolName.length > 10 ? symbolName.substring(0, 10) : symbolName;
449
+ const qtyLabel = 'Qty';
450
+ const qtyVal = numContracts.toString();
451
+ const srvLabel = 'Server';
452
+ const srvVal = serverStatus;
453
+ const latLabel = 'Latency';
454
+ const latVal = latencyStr;
455
+
456
+ // Row 1 cells: widths = 36 + 18 + 10 + 14 + 14 = 92 + 4 separators = 96
457
+ const c1w = 36, c2w = 18, c3w = 10, c4w = 14, c5w = 14;
458
+
459
+ const cell1 = ` ${accLabel}: ${chalk.cyan(accVal)}`;
460
+ const cell1plain = ` ${accLabel}: ${accVal}`;
461
+ const cell2 = ` ${symLabel}: ${chalk.yellow(symVal)}`;
462
+ const cell2plain = ` ${symLabel}: ${symVal}`;
463
+ const cell3 = ` ${qtyLabel}: ${chalk.cyan(qtyVal)}`;
464
+ const cell3plain = ` ${qtyLabel}: ${qtyVal}`;
465
+ const cell4 = ` ${srvLabel}: ${serverColor(srvVal)}`;
466
+ const cell4plain = ` ${srvLabel}: ${srvVal}`;
467
+ const cell5 = ` ${latLabel}: ${latencyColor(latVal)}`;
468
+ const cell5plain = ` ${latLabel}: ${latVal}`;
469
+
470
+ const row1 = cell1 + ' '.repeat(c1w - cell1plain.length) + chalk.cyan(VS) +
471
+ cell2 + ' '.repeat(c2w - cell2plain.length) + chalk.cyan(VS) +
472
+ cell3 + ' '.repeat(c3w - cell3plain.length) + chalk.cyan(VS) +
473
+ cell4 + ' '.repeat(c4w - cell4plain.length) + chalk.cyan(VS) +
474
+ cell5 + ' '.repeat(c5w - cell5plain.length);
475
+
476
+ console.log(chalk.cyan(V) + row1 + chalk.cyan(V));
477
+
478
+ // Separator with intersections
479
+ const SEP = '\u2560' + '\u2550'.repeat(c1w) + '\u256A' + '\u2550'.repeat(c2w) + '\u256A' + '\u2550'.repeat(c3w) + '\u256A' + '\u2550'.repeat(c4w) + '\u256A' + '\u2550'.repeat(c5w) + '\u2563';
480
+ console.log(chalk.cyan(SEP));
481
+
482
+ // Row 2: Target | Risk | P&L | Trades | W/L
483
+ const tgtLabel = 'Target';
484
+ const tgtVal = '$' + dailyTarget.toFixed(2);
485
+ const rskLabel = 'Risk';
486
+ const rskVal = '$' + maxRisk.toFixed(2);
487
+ const pnlLabel = 'P&L';
488
+ const pnlVal = pnlStr;
489
+ const trdLabel = 'Trades';
490
+ const trdVal = stats.trades.toString();
491
+ const wlLabel = 'W/L';
492
+ const wlVal = `${stats.wins}/${stats.losses}`;
493
+
494
+ const cell6 = ` ${tgtLabel}: ${chalk.green(tgtVal)}`;
495
+ const cell6plain = ` ${tgtLabel}: ${tgtVal}`;
496
+ const cell7 = ` ${rskLabel}: ${chalk.red(rskVal)}`;
497
+ const cell7plain = ` ${rskLabel}: ${rskVal}`;
498
+ const cell8 = ` ${pnlLabel}: ${pnlColor(pnlVal)}`;
499
+ const cell8plain = ` ${pnlLabel}: ${pnlVal}`;
500
+ const cell9 = ` ${trdLabel}: ${chalk.cyan(trdVal)}`;
501
+ const cell9plain = ` ${trdLabel}: ${trdVal}`;
502
+ const cell10 = ` ${wlLabel}: ${chalk.green(stats.wins.toString())}/${chalk.red(stats.losses.toString())}`;
503
+ const cell10plain = ` ${wlLabel}: ${wlVal}`;
504
+
505
+ const row2 = cell6 + ' '.repeat(c1w - cell6plain.length) + chalk.cyan(VS) +
506
+ cell7 + ' '.repeat(c2w - cell7plain.length) + chalk.cyan(VS) +
507
+ cell8 + ' '.repeat(c3w - cell8plain.length) + chalk.cyan(VS) +
508
+ cell9 + ' '.repeat(c4w - cell9plain.length) + chalk.cyan(VS) +
509
+ cell10 + ' '.repeat(c5w - cell10plain.length);
510
+
511
+ console.log(chalk.cyan(V) + row2 + chalk.cyan(V));
457
512
  console.log(chalk.cyan(MID));
458
513
 
459
- // Activity log header
460
- const actLeft = ` Activity Log - ${dateStr}`;
514
+ // Activity log header with spinner and centered date
515
+ spinnerFrame = (spinnerFrame + 1) % spinnerChars.length;
516
+ const spinner = spinnerChars[spinnerFrame];
517
+ const actLeft = ` Activity Log ${chalk.cyan(spinner)}`;
518
+ const actLeftPlain = ` Activity Log ${spinner}`;
461
519
  const actRight = 'Press X to stop ';
462
- const actMid = W - actLeft.length - actRight.length;
463
- console.log(chalk.cyan(V) + chalk.white(actLeft) + ' '.repeat(actMid) + chalk.yellow(actRight) + chalk.cyan(V));
520
+ const dateCentered = `- ${dateStr} -`;
521
+ const leftLen = actLeftPlain.length;
522
+ const rightLen = actRight.length;
523
+ const midSpace = W - leftLen - rightLen;
524
+ const datePad = Math.floor((midSpace - dateCentered.length) / 2);
525
+ const dateSection = ' '.repeat(datePad) + chalk.gray(dateCentered) + ' '.repeat(midSpace - datePad - dateCentered.length);
526
+ console.log(chalk.cyan(V) + chalk.white(actLeft) + dateSection + chalk.yellow(actRight) + chalk.cyan(V));
464
527
  console.log(chalk.cyan(BOT));
465
528
 
466
- // Logs (without borders)
529
+ // Logs (without borders) - newest first
467
530
  console.log();
468
531
  if (logs.length === 0) {
469
532
  console.log(chalk.gray(' Waiting for activity...'));
470
533
  } else {
471
- logs.forEach(log => {
534
+ // Reverse to show newest first
535
+ const reversedLogs = [...logs].reverse();
536
+ reversedLogs.forEach(log => {
472
537
  const color = typeColors[log.type] || chalk.white;
473
538
  const icon = getIcon(log.type);
474
539
  console.log(color(` [${log.timestamp}] ${icon} ${log.message}`));
@@ -476,6 +541,13 @@ const launchAlgo = async (service, account, contract, numContracts, dailyTarget,
476
541
  }
477
542
  };
478
543
 
544
+ // Spinner interval to refresh UI
545
+ const spinnerInterval = setInterval(() => {
546
+ if (algoRunning) {
547
+ displayUI();
548
+ }
549
+ }, 100);
550
+
479
551
  // Connect to HQX Server
480
552
  const spinner = ora('Authenticating with HQX Server...').start();
481
553
 
@@ -650,6 +722,9 @@ const launchAlgo = async (service, account, contract, numContracts, dailyTarget,
650
722
  }
651
723
  });
652
724
 
725
+ // Clear spinner interval
726
+ clearInterval(spinnerInterval);
727
+
653
728
  // Stop algo
654
729
  console.log();
655
730
  if (!stopReason) {