hedgequantx 1.2.98 → 1.2.100

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": "1.2.98",
3
+ "version": "1.2.100",
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/app.js CHANGED
@@ -580,47 +580,57 @@ const mainMenu = async () => {
580
580
  const dashboardMenu = async (service) => {
581
581
  const user = service.user;
582
582
  const boxWidth = getLogoWidth();
583
- const innerWidth = boxWidth - 2;
583
+ const W = boxWidth - 2; // Same width as logo (inner width)
584
+
585
+ // Helper to center text
586
+ const centerLine = (text, width) => {
587
+ const pad = Math.floor((width - text.length) / 2);
588
+ return ' '.repeat(Math.max(0, pad)) + text + ' '.repeat(Math.max(0, width - pad - text.length));
589
+ };
590
+
591
+ // Helper to pad text left
592
+ const padLine = (text, width) => {
593
+ return ' ' + text + ' '.repeat(Math.max(0, width - text.length - 1));
594
+ };
584
595
 
585
596
  // Dashboard box header
586
597
  console.log();
587
- console.log(chalk.cyan('╔' + '═'.repeat(innerWidth) + '╗'));
588
- console.log(chalk.cyan('║') + chalk.white.bold(centerText('DASHBOARD', innerWidth)) + chalk.cyan('║'));
589
- console.log(chalk.cyan('╠' + '═'.repeat(innerWidth) + '╣'));
598
+ console.log(chalk.cyan('╔' + '═'.repeat(W) + '╗'));
599
+ console.log(chalk.cyan('║') + chalk.white.bold(centerLine('DASHBOARD', W)) + chalk.cyan('║'));
600
+ console.log(chalk.cyan('╠' + '═'.repeat(W) + '╣'));
590
601
 
591
602
  // Connection info - show all active connections
592
603
  const allConns = connections.getAll();
593
604
  if (allConns.length > 0) {
594
605
  const connNames = allConns.map(c => c.propfirm || c.type).join(', ');
595
606
  const connText = `Connected to ${connNames}`;
596
- const connInfo = chalk.green(connText);
597
- console.log(chalk.cyan('║') + ' ' + connInfo + ' '.repeat(Math.max(0, innerWidth - connText.length - 2)) + chalk.cyan('║'));
607
+ console.log(chalk.cyan('║') + chalk.green(padLine(connText, W)) + chalk.cyan('║'));
598
608
  }
599
609
 
600
610
  if (user) {
601
- const userInfo = 'Welcome, ' + user.userName.toUpperCase() + '!';
602
- console.log(chalk.cyan('║') + ' ' + chalk.white(userInfo) + ' '.repeat(innerWidth - userInfo.length - 2) + chalk.cyan('║'));
611
+ const userText = 'Welcome, ' + user.userName.toUpperCase() + '!';
612
+ console.log(chalk.cyan('║') + chalk.white(padLine(userText, W)) + chalk.cyan('║'));
603
613
  }
604
614
 
605
- console.log(chalk.cyan('╠' + '═'.repeat(innerWidth) + '╣'));
615
+ console.log(chalk.cyan('╠' + '═'.repeat(W) + '╣'));
606
616
 
607
617
  // Menu options in 2 columns
608
- const col1Width = Math.floor(innerWidth / 2);
609
- const col2Width = innerWidth - col1Width;
618
+ const col1Width = Math.floor(W / 2);
619
+ const col2Width = W - col1Width;
610
620
 
611
621
  const menuRow = (left, right) => {
612
- const leftText = ' ' + left;
613
- const rightText = right ? ' ' + right : '';
614
- const leftPad = col1Width - leftText.replace(/\x1b\[[0-9;]*m/g, '').length;
615
- const rightPad = col2Width - rightText.replace(/\x1b\[[0-9;]*m/g, '').length;
616
- console.log(chalk.cyan('║') + leftText + ' '.repeat(Math.max(0, leftPad)) + rightText + ' '.repeat(Math.max(0, rightPad)) + chalk.cyan('║'));
622
+ const leftPlain = left.replace(/\x1b\[[0-9;]*m/g, '');
623
+ const rightPlain = right ? right.replace(/\x1b\[[0-9;]*m/g, '') : '';
624
+ const leftPad = ' '.repeat(Math.max(0, col1Width - leftPlain.length - 2));
625
+ const rightPad = ' '.repeat(Math.max(0, col2Width - rightPlain.length - 2));
626
+ console.log(chalk.cyan('║') + ' ' + left + leftPad + ' ' + (right || '') + rightPad + chalk.cyan('║'));
617
627
  };
618
628
 
619
629
  menuRow(chalk.cyan('[1] View Accounts'), chalk.cyan('[2] View Stats'));
620
630
  menuRow(chalk.cyan('[+] Add Prop-Account'), chalk.cyan('[A] Algo-Trading'));
621
631
  menuRow(chalk.yellow('[U] Update HQX'), chalk.red('[X] Disconnect'));
622
632
 
623
- console.log(chalk.cyan('╚' + '═'.repeat(innerWidth) + '╝'));
633
+ console.log(chalk.cyan('╚' + '═'.repeat(W) + '╝'));
624
634
  console.log();
625
635
 
626
636
  const { action } = await inquirer.prompt([
package/src/pages/algo.js CHANGED
@@ -241,8 +241,11 @@ const selectSymbolMenu = async (service, account) => {
241
241
  'ZW': 'Wheat'
242
242
  };
243
243
 
244
- // Format symbols for display
245
- const symbolChoices = availableSymbols.map(symbol => {
244
+ // Format symbols for display - deduplicate by base symbol + month
245
+ const seenSymbols = new Set();
246
+ const symbolChoices = [];
247
+
248
+ for (const symbol of availableSymbols) {
246
249
  const symbolCode = symbol.symbol || symbol.id || '';
247
250
 
248
251
  // Extract base symbol (e.g., NQ from NQH6) and month code
@@ -258,15 +261,20 @@ const selectSymbolMenu = async (service, account) => {
258
261
  monthYear = (monthCodes[monthCode] || monthCode) + year;
259
262
  }
260
263
 
264
+ // Create unique key to deduplicate
265
+ const uniqueKey = `${baseSymbol}-${monthYear}`;
266
+ if (seenSymbols.has(uniqueKey)) continue;
267
+ seenSymbols.add(uniqueKey);
268
+
261
269
  // Get descriptive name from mapping
262
270
  const description = symbolDescriptions[baseSymbol] || symbol.name || baseSymbol;
263
271
 
264
272
  // Format: "NQ Mar26 E-mini NASDAQ-100"
265
- return {
273
+ symbolChoices.push({
266
274
  name: chalk.yellow(baseSymbol.padEnd(5)) + chalk.cyan(monthYear.padEnd(7)) + chalk.white(description),
267
275
  value: symbol
268
- };
269
- });
276
+ });
277
+ }
270
278
 
271
279
  symbolChoices.push(new inquirer.Separator());
272
280
  symbolChoices.push({ name: chalk.yellow('< Back'), value: 'back' });
@@ -506,9 +514,10 @@ const launchAlgo = async (service, account, contract, numContracts, dailyTarget,
506
514
  // Use ANSI escape codes to avoid flickering
507
515
  let firstDraw = true;
508
516
  const displayUI = () => {
509
- // First time: clear screen, after: just move cursor to top
517
+ // First time: clear screen and hide cursor, after: just move cursor to top
510
518
  if (firstDraw) {
511
519
  console.clear();
520
+ process.stdout.write('\x1B[?25l'); // Hide cursor
512
521
  firstDraw = false;
513
522
  } else {
514
523
  // Move cursor to top-left without clearing (avoids flicker)
@@ -871,6 +880,9 @@ const launchAlgo = async (service, account, contract, numContracts, dailyTarget,
871
880
  // Clear spinner interval
872
881
  clearInterval(spinnerInterval);
873
882
 
883
+ // Show cursor again
884
+ process.stdout.write('\x1B[?25h');
885
+
874
886
  // Stop algo
875
887
  console.log();
876
888
  if (!stopReason) {