hedgequantx 1.2.77 → 1.2.79

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 +58 -35
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hedgequantx",
3
- "version": "1.2.77",
3
+ "version": "1.2.79",
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
@@ -455,8 +455,8 @@ const launchAlgo = async (service, account, contract, numContracts, dailyTarget,
455
455
  const latLabel = 'WS';
456
456
  const latVal = latencyStr;
457
457
 
458
- // Row 1 cells: widths = 36 + 18 + 10 + 14 + 14 = 92 + 4 separators = 96
459
- const c1w = 36, c2w = 18, c3w = 10, c4w = 14, c5w = 14;
458
+ // Row 1 cells: widths = 36 + 17 + 9 + 13 + 13 = 88 + 4 separators + 4 spaces = 96
459
+ const c1w = 36, c2w = 17, c3w = 9, c4w = 13, c5w = 17;
460
460
 
461
461
  // Safe padding function
462
462
  const safePad = (len) => ' '.repeat(Math.max(0, len));
@@ -478,11 +478,14 @@ const launchAlgo = async (service, account, contract, numContracts, dailyTarget,
478
478
  cell4 + safePad(c4w - cell4plain.length) + chalk.cyan(VS) +
479
479
  cell5 + safePad(c5w - cell5plain.length);
480
480
 
481
+ // Top separator for grid (after HQX Ultra-Scalping)
482
+ const GRID_TOP = '\u2560' + '\u2550'.repeat(c1w) + '\u2564' + '\u2550'.repeat(c2w) + '\u2564' + '\u2550'.repeat(c3w) + '\u2564' + '\u2550'.repeat(c4w) + '\u2564' + '\u2550'.repeat(c5w) + '\u2563';
483
+ console.log(chalk.cyan(GRID_TOP));
484
+
481
485
  console.log(chalk.cyan(V) + row1 + chalk.cyan(V));
482
486
 
483
- // Separator with intersections
484
- const SEP = '\u2560' + '\u2550'.repeat(c1w) + '\u256A' + '\u2550'.repeat(c2w) + '\u256A' + '\u2550'.repeat(c3w) + '\u256A' + '\u2550'.repeat(c4w) + '\u256A' + '\u2550'.repeat(c5w) + '\u2563';
485
- console.log(chalk.cyan(SEP));
487
+ // Middle separator with intersections (between row1 and row2)
488
+ const GRID_MID = '\u2560' + '\u2550'.repeat(c1w) + '\u256A' + '\u2550'.repeat(c2w) + '\u256A' + '\u2550'.repeat(c3w) + '\u256A' + '\u2550'.repeat(c4w) + '\u256A' + '\u2550'.repeat(c5w) + '\u2563';
486
489
 
487
490
  // Row 2: Target | Risk | P&L | Trades | W/L
488
491
  const tgtLabel = 'Target';
@@ -513,8 +516,12 @@ const launchAlgo = async (service, account, contract, numContracts, dailyTarget,
513
516
  cell9 + safePad(c4w - cell9plain.length) + chalk.cyan(VS) +
514
517
  cell10 + safePad(c5w - cell10plain.length);
515
518
 
519
+ console.log(chalk.cyan(GRID_MID));
516
520
  console.log(chalk.cyan(V) + row2 + chalk.cyan(V));
517
- console.log(chalk.cyan(MID));
521
+
522
+ // Bottom of grid (before Activity Log)
523
+ const GRID_BOT = '\u2560' + '\u2550'.repeat(c1w) + '\u2567' + '\u2550'.repeat(c2w) + '\u2567' + '\u2550'.repeat(c3w) + '\u2567' + '\u2550'.repeat(c4w) + '\u2567' + '\u2550'.repeat(c5w) + '\u2563';
524
+ console.log(chalk.cyan(GRID_BOT));
518
525
 
519
526
  // Activity log header with spinner and centered date
520
527
  spinnerFrame = (spinnerFrame + 1) % spinnerChars.length;
@@ -653,11 +660,21 @@ const launchAlgo = async (service, account, contract, numContracts, dailyTarget,
653
660
 
654
661
  hqxServer.on('error', (data) => {
655
662
  printLog('error', data.message || 'Unknown error');
663
+ // Stop algo on connection error
664
+ if (!stopReason) {
665
+ stopReason = 'connection_error';
666
+ algoRunning = false;
667
+ }
656
668
  });
657
669
 
658
670
  hqxServer.on('disconnected', () => {
659
671
  hqxConnected = false;
660
- printLog('warning', 'Disconnected from HQX Server');
672
+ printLog('error', 'Connection lost - Stopping algo');
673
+ // Stop algo on disconnect
674
+ if (!stopReason) {
675
+ stopReason = 'disconnected';
676
+ algoRunning = false;
677
+ }
661
678
  });
662
679
 
663
680
  // Display header once
@@ -790,15 +807,18 @@ const launchAlgo = async (service, account, contract, numContracts, dailyTarget,
790
807
  console.log(chalk.green.bold(' [OK] Daily target reached! Algo stopped.'));
791
808
  } else if (stopReason === 'risk') {
792
809
  console.log(chalk.red.bold(' [X] Max risk reached! Algo stopped.'));
810
+ } else if (stopReason === 'disconnected' || stopReason === 'connection_error') {
811
+ console.log(chalk.red.bold(' [X] Connection lost! Algo stopped.'));
793
812
  } else {
794
813
  console.log(chalk.yellow(' [OK] Algo stopped by user'));
795
814
  }
796
815
  console.log();
797
816
 
798
- // Final stats in a grid box
799
- const V = '\u2551';
800
- const VS = '\u2502';
801
- const H = '\u2550';
817
+ // Final stats in a grid box - must match main UI width of 96
818
+ const summaryV = '\u2551';
819
+ const summaryVS = '\u2502';
820
+ const summaryH = '\u2550';
821
+ const summaryW = 96; // Same as main UI
802
822
 
803
823
  // Calculate session duration
804
824
  const sessionDuration = Date.now() - sessionStartTime;
@@ -811,50 +831,53 @@ const launchAlgo = async (service, account, contract, numContracts, dailyTarget,
811
831
  ? `${durationMin}m ${durationSec % 60}s`
812
832
  : `${durationSec}s`;
813
833
 
814
- // Cell widths: 4 cells of 24 each = 96
815
- const cw = 24;
816
- const W = cw * 4;
834
+ // 4 cells + 3 separators = 96 inner chars
835
+ // 96 - 3 separators = 93, divided by 4 = 23.25, so use 24+23+24+23 = 94... need 96
836
+ // Let's use: 24 + 24 + 24 + 21 = 93 + 3 sep = 96
837
+ const sc1 = 24, sc2 = 24, sc3 = 24, sc4 = 21;
817
838
 
818
- const TOP = '\u2554' + H.repeat(cw) + '\u2564' + H.repeat(cw) + '\u2564' + H.repeat(cw) + '\u2564' + H.repeat(cw) + '\u2557';
819
- const MID = '\u2560' + H.repeat(cw) + '\u256A' + H.repeat(cw) + '\u256A' + H.repeat(cw) + '\u256A' + H.repeat(cw) + '\u2563';
820
- const BOT = '\u255A' + H.repeat(cw) + '\u2567' + H.repeat(cw) + '\u2567' + H.repeat(cw) + '\u2567' + H.repeat(cw) + '\u255D';
821
-
822
- const cell = (label, value, width) => {
839
+ const summaryCell = (label, value, width) => {
823
840
  const text = ` ${label}: ${value}`;
824
841
  const stripped = text.replace(/\x1b\[[0-9;]*m/g, '');
825
842
  const padding = Math.max(0, width - stripped.length);
826
843
  return text + ' '.repeat(padding);
827
844
  };
828
845
 
829
- const centerTitle = (text, width) => {
846
+ const centerSummaryTitle = (text, width) => {
830
847
  const pad = Math.floor((width - text.length) / 2);
831
848
  return ' '.repeat(pad) + text + ' '.repeat(width - pad - text.length);
832
849
  };
833
850
 
834
851
  const pnlValue = stats.pnl >= 0 ? chalk.green('+$' + stats.pnl.toFixed(2)) : chalk.red('-$' + Math.abs(stats.pnl).toFixed(2));
835
852
 
853
+ // Build separator lines
854
+ const SUMMARY_TOP = '\u2554' + summaryH.repeat(summaryW) + '\u2557';
855
+ const SUMMARY_GRID_TOP = '\u2560' + summaryH.repeat(sc1) + '\u2564' + summaryH.repeat(sc2) + '\u2564' + summaryH.repeat(sc3) + '\u2564' + summaryH.repeat(sc4) + '\u2563';
856
+ const SUMMARY_GRID_MID = '\u2560' + summaryH.repeat(sc1) + '\u256A' + summaryH.repeat(sc2) + '\u256A' + summaryH.repeat(sc3) + '\u256A' + summaryH.repeat(sc4) + '\u2563';
857
+ const SUMMARY_BOT = '\u255A' + summaryH.repeat(sc1) + '\u2567' + summaryH.repeat(sc2) + '\u2567' + summaryH.repeat(sc3) + '\u2567' + summaryH.repeat(sc4) + '\u255D';
858
+
836
859
  console.log();
837
- console.log(chalk.cyan('\u2554' + H.repeat(W) + '\u2557'));
838
- console.log(chalk.cyan(V) + chalk.white.bold(centerTitle('Session Summary', W)) + chalk.cyan(V));
839
- console.log(chalk.cyan(TOP.replace('\u2554', '\u2560').replace('\u2557', '\u2563')));
860
+ console.log(chalk.cyan(SUMMARY_TOP));
861
+ console.log(chalk.cyan(summaryV) + chalk.white.bold(centerSummaryTitle('Session Summary', summaryW)) + chalk.cyan(summaryV));
862
+ console.log(chalk.cyan(SUMMARY_GRID_TOP));
840
863
 
841
864
  // Row 1: Target | Risk | P&L | Win Rate
842
- const r1c1 = cell('Target', chalk.green('$' + dailyTarget.toFixed(2)), cw);
843
- const r1c2 = cell('Risk', chalk.red('$' + maxRisk.toFixed(2)), cw);
844
- const r1c3 = cell('P&L', pnlValue, cw);
845
- const r1c4 = cell('Win Rate', chalk.yellow(stats.winRate + '%'), cw);
846
- console.log(chalk.cyan(V) + r1c1 + chalk.cyan(VS) + r1c2 + chalk.cyan(VS) + r1c3 + chalk.cyan(VS) + r1c4 + chalk.cyan(V));
865
+ const r1c1 = summaryCell('Target', chalk.green('$' + dailyTarget.toFixed(2)), sc1);
866
+ const r1c2 = summaryCell('Risk', chalk.red('$' + maxRisk.toFixed(2)), sc2);
867
+ const r1c3 = summaryCell('P&L', pnlValue, sc3);
868
+ const r1c4 = summaryCell('Win Rate', chalk.yellow(stats.winRate + '%'), sc4);
869
+ console.log(chalk.cyan(summaryV) + r1c1 + chalk.cyan(summaryVS) + r1c2 + chalk.cyan(summaryVS) + r1c3 + chalk.cyan(summaryVS) + r1c4 + chalk.cyan(summaryV));
847
870
 
848
- console.log(chalk.cyan(MID));
871
+ console.log(chalk.cyan(SUMMARY_GRID_MID));
849
872
 
850
873
  // Row 2: Trades | Wins | Losses | Duration
851
- const r2c1 = cell('Trades', chalk.cyan(stats.trades.toString()), cw);
852
- const r2c2 = cell('Wins', chalk.green(stats.wins.toString()), cw);
853
- const r2c3 = cell('Losses', chalk.red(stats.losses.toString()), cw);
854
- const r2c4 = cell('Duration', chalk.white(durationStr), cw);
855
- console.log(chalk.cyan(V) + r2c1 + chalk.cyan(VS) + r2c2 + chalk.cyan(VS) + r2c3 + chalk.cyan(VS) + r2c4 + chalk.cyan(V));
874
+ const r2c1 = summaryCell('Trades', chalk.cyan(stats.trades.toString()), sc1);
875
+ const r2c2 = summaryCell('Wins', chalk.green(stats.wins.toString()), sc2);
876
+ const r2c3 = summaryCell('Losses', chalk.red(stats.losses.toString()), sc3);
877
+ const r2c4 = summaryCell('Duration', chalk.white(durationStr), sc4);
878
+ console.log(chalk.cyan(summaryV) + r2c1 + chalk.cyan(summaryVS) + r2c2 + chalk.cyan(summaryVS) + r2c3 + chalk.cyan(summaryVS) + r2c4 + chalk.cyan(summaryV));
856
879
 
857
- console.log(chalk.cyan(BOT));
880
+ console.log(chalk.cyan(SUMMARY_BOT));
858
881
  console.log();
859
882
 
860
883
  await inquirer.prompt([{ type: 'input', name: 'continue', message: 'Press Enter to continue...' }]);