hedgequantx 1.2.142 → 1.2.144

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.142",
3
+ "version": "1.2.144",
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
@@ -46,6 +46,27 @@ const restoreTerminal = () => {
46
46
  }
47
47
  };
48
48
 
49
+ /**
50
+ * Ensure stdin is ready for inquirer prompts
51
+ * This fixes input leaking to bash after session restore
52
+ */
53
+ const prepareStdin = () => {
54
+ try {
55
+ // Remove any raw mode that might be left from previous operations
56
+ if (process.stdin.isTTY && process.stdin.isRaw) {
57
+ process.stdin.setRawMode(false);
58
+ }
59
+ // Remove any lingering keypress listeners
60
+ process.stdin.removeAllListeners('keypress');
61
+ process.stdin.removeAllListeners('data');
62
+ // Pause stdin so inquirer can take control
63
+ process.stdin.pause();
64
+ // Small delay to let event loop settle
65
+ } catch (e) {
66
+ // Ignore errors
67
+ }
68
+ };
69
+
49
70
  // Register global handlers to restore terminal on exit/crash
50
71
  process.on('exit', restoreTerminal);
51
72
  process.on('SIGINT', () => { restoreTerminal(); process.exit(0); });
@@ -802,89 +823,102 @@ const handleUpdate = async () => {
802
823
  * Main application loop
803
824
  */
804
825
  const run = async () => {
805
- await banner();
806
-
807
- // Try to restore session
808
- const spinner = ora('Restoring session...').start();
809
- const restored = await connections.restoreFromStorage();
810
-
811
- if (restored) {
812
- spinner.succeed('Session restored');
813
- currentService = connections.getAll()[0].service;
814
- } else {
815
- spinner.info('No active session');
816
- }
817
-
818
- // Main loop
819
- while (true) {
820
- // Refresh banner with stats
826
+ try {
821
827
  await banner();
822
828
 
823
- if (!connections.isConnected()) {
824
- const choice = await mainMenu();
825
-
826
- if (choice === 'exit') {
827
- console.log(chalk.gray('Goodbye!'));
828
- process.exit(0);
829
- }
830
-
831
- if (choice === 'projectx') {
832
- const service = await projectXMenu();
833
- if (service) currentService = service;
834
- }
835
-
836
- if (choice === 'rithmic') {
837
- const service = await rithmicMenu();
838
- if (service) currentService = service;
839
- }
840
-
841
- if (choice === 'tradovate') {
842
- const service = await tradovateMenu();
843
- if (service) currentService = service;
844
- }
829
+ // Try to restore session
830
+ const spinner = ora('Restoring session...').start();
831
+ const restored = await connections.restoreFromStorage();
832
+
833
+ if (restored) {
834
+ spinner.succeed('Session restored');
835
+ currentService = connections.getAll()[0].service;
845
836
  } else {
846
- const action = await dashboardMenu(currentService);
847
-
848
- switch (action) {
849
- case 'accounts':
850
- await showAccounts(currentService);
851
- break;
852
-
853
- case 'stats':
854
- await showStats(currentService);
855
- break;
856
- case 'add_prop_account':
857
- // Show platform selection menu
858
- const platformChoice = await addPropAccountMenu();
859
- if (platformChoice === 'projectx') {
860
- const newService = await projectXMenu();
861
- if (newService) currentService = newService;
862
- } else if (platformChoice === 'rithmic') {
863
- const newService = await rithmicMenu();
864
- if (newService) currentService = newService;
865
- } else if (platformChoice === 'tradovate') {
866
- const newService = await tradovateMenu();
867
- if (newService) currentService = newService;
837
+ spinner.info('No active session');
838
+ }
839
+
840
+ // Main loop
841
+ while (true) {
842
+ try {
843
+ // Ensure stdin is ready for prompts (fixes input leaking to bash)
844
+ prepareStdin();
845
+
846
+ // Refresh banner with stats
847
+ await banner();
848
+
849
+ if (!connections.isConnected()) {
850
+ const choice = await mainMenu();
851
+
852
+ if (choice === 'exit') {
853
+ console.log(chalk.gray('Goodbye!'));
854
+ process.exit(0);
855
+ }
856
+
857
+ if (choice === 'projectx') {
858
+ const service = await projectXMenu();
859
+ if (service) currentService = service;
860
+ }
861
+
862
+ if (choice === 'rithmic') {
863
+ const service = await rithmicMenu();
864
+ if (service) currentService = service;
868
865
  }
869
- break;
870
- case 'algotrading':
871
- await algoTradingMenu(currentService);
872
- break;
873
- case 'update':
874
- const updateResult = await handleUpdate();
875
- if (updateResult === 'restart') return; // Stop loop, new process spawned
876
- break;
877
- case 'disconnect':
878
- const connCount = connections.count();
879
- connections.disconnectAll();
880
- currentService = null;
881
- console.log(chalk.yellow(`Disconnected ${connCount} connection${connCount > 1 ? 's' : ''}`));
882
- break;
883
- case 'exit':
884
- console.log(chalk.gray('Goodbye!'));
885
- process.exit(0);
866
+
867
+ if (choice === 'tradovate') {
868
+ const service = await tradovateMenu();
869
+ if (service) currentService = service;
870
+ }
871
+ } else {
872
+ const action = await dashboardMenu(currentService);
873
+
874
+ switch (action) {
875
+ case 'accounts':
876
+ await showAccounts(currentService);
877
+ break;
878
+
879
+ case 'stats':
880
+ await showStats(currentService);
881
+ break;
882
+ case 'add_prop_account':
883
+ // Show platform selection menu
884
+ const platformChoice = await addPropAccountMenu();
885
+ if (platformChoice === 'projectx') {
886
+ const newService = await projectXMenu();
887
+ if (newService) currentService = newService;
888
+ } else if (platformChoice === 'rithmic') {
889
+ const newService = await rithmicMenu();
890
+ if (newService) currentService = newService;
891
+ } else if (platformChoice === 'tradovate') {
892
+ const newService = await tradovateMenu();
893
+ if (newService) currentService = newService;
894
+ }
895
+ break;
896
+ case 'algotrading':
897
+ await algoTradingMenu(currentService);
898
+ break;
899
+ case 'update':
900
+ const updateResult = await handleUpdate();
901
+ if (updateResult === 'restart') return; // Stop loop, new process spawned
902
+ break;
903
+ case 'disconnect':
904
+ const connCount = connections.count();
905
+ connections.disconnectAll();
906
+ currentService = null;
907
+ console.log(chalk.yellow(`Disconnected ${connCount} connection${connCount > 1 ? 's' : ''}`));
908
+ break;
909
+ case 'exit':
910
+ console.log(chalk.gray('Goodbye!'));
911
+ process.exit(0);
912
+ }
913
+ }
914
+ } catch (loopError) {
915
+ console.error(chalk.red('Error in main loop:'), loopError.message);
916
+ // Continue the loop
886
917
  }
887
918
  }
919
+ } catch (error) {
920
+ console.error(chalk.red('Fatal error:'), error.message);
921
+ process.exit(1);
888
922
  }
889
923
  };
890
924
 
package/src/pages/algo.js CHANGED
@@ -1382,6 +1382,27 @@ const copyTradingMenu = async () => {
1382
1382
  }
1383
1383
  ]);
1384
1384
 
1385
+ // Privacy option - show or hide account names
1386
+ console.log();
1387
+ console.log(chalk.cyan.bold(' Step 6: Privacy Settings'));
1388
+ console.log();
1389
+
1390
+ const { showAccountNames } = await inquirer.prompt([
1391
+ {
1392
+ type: 'list',
1393
+ name: 'showAccountNames',
1394
+ message: chalk.white.bold('Account names visibility:'),
1395
+ choices: [
1396
+ { name: chalk.cyan('[>] Show account names'), value: true },
1397
+ { name: chalk.gray('[.] Hide account names'), value: false }
1398
+ ],
1399
+ loop: false
1400
+ }
1401
+ ]);
1402
+
1403
+ const displayLeadName = showAccountNames ? (leadAccount.accountName || leadAccount.name || 'N/A') : 'HQX Lead *****';
1404
+ const displayFollowerName = showAccountNames ? (followerAccount.accountName || followerAccount.name || 'N/A') : 'HQX Follower *****';
1405
+
1385
1406
  // Configuration Summary
1386
1407
  console.log();
1387
1408
  console.log(chalk.gray(getSeparator()));
@@ -1393,13 +1414,13 @@ const copyTradingMenu = async () => {
1393
1414
  console.log(chalk.white(` Max Risk: ${chalk.red('$' + maxRisk.toFixed(2))}`));
1394
1415
  console.log();
1395
1416
  console.log(chalk.white(' LEAD ACCOUNT'));
1396
- console.log(chalk.white(` Account: ${chalk.cyan(leadAccount.accountName || leadAccount.name || 'N/A')}`));
1417
+ console.log(chalk.white(` Account: ${chalk.cyan(displayLeadName)}`));
1397
1418
  console.log(chalk.white(` PropFirm: ${chalk.magenta(leadAccount.propfirm || 'N/A')}`));
1398
1419
  console.log(chalk.white(` Symbol: ${chalk.cyan(leadSymbol.name || 'N/A')}`));
1399
1420
  console.log(chalk.white(` Contracts: ${chalk.cyan(leadContracts)}`));
1400
1421
  console.log();
1401
1422
  console.log(chalk.white(' FOLLOWER ACCOUNT'));
1402
- console.log(chalk.white(` Account: ${chalk.cyan(followerAccount.accountName || followerAccount.name || 'N/A')}`));
1423
+ console.log(chalk.white(` Account: ${chalk.cyan(displayFollowerName)}`));
1403
1424
  console.log(chalk.white(` PropFirm: ${chalk.magenta(followerAccount.propfirm || 'N/A')}`));
1404
1425
  console.log(chalk.white(` Symbol: ${chalk.cyan(followerSymbol.name || 'N/A')}`));
1405
1426
  console.log(chalk.white(` Contracts: ${chalk.cyan(followerContracts)}`));
@@ -1430,13 +1451,15 @@ const copyTradingMenu = async () => {
1430
1451
  account: leadAccount,
1431
1452
  symbol: leadSymbol,
1432
1453
  contracts: leadContracts,
1433
- service: leadAccount.service
1454
+ service: leadAccount.service,
1455
+ displayName: displayLeadName
1434
1456
  },
1435
1457
  follower: {
1436
1458
  account: followerAccount,
1437
1459
  symbol: followerSymbol,
1438
1460
  contracts: followerContracts,
1439
- service: followerAccount.service
1461
+ service: followerAccount.service,
1462
+ displayName: displayFollowerName
1440
1463
  }
1441
1464
  });
1442
1465
  };
@@ -1592,7 +1615,7 @@ const launchCopyTrading = async (config) => {
1592
1615
  const colL = 48, colR = 47;
1593
1616
 
1594
1617
  // Row 1: Lead Account | Lead Symbol
1595
- const leadName = (lead.account.accountName || '').substring(0, 30);
1618
+ const leadName = (lead.displayName || lead.account.accountName || '').substring(0, 30);
1596
1619
  const leadSym = lead.symbol.value || lead.symbol.name || '';
1597
1620
  const r1c1 = buildCell('Lead', leadName, chalk.cyan, colL);
1598
1621
  const r1c2text = ` Symbol: ${chalk.yellow(leadSym)} Qty: ${chalk.cyan(lead.contracts)}`;
@@ -1600,7 +1623,7 @@ const launchCopyTrading = async (config) => {
1600
1623
  const r1c2 = r1c2text + safePad(colR - r1c2plain.length);
1601
1624
 
1602
1625
  // Row 2: Follower Account | Follower Symbol
1603
- const followerName = (follower.account.accountName || '').substring(0, 30);
1626
+ const followerName = (follower.displayName || follower.account.accountName || '').substring(0, 30);
1604
1627
  const followerSym = follower.symbol.value || follower.symbol.name || '';
1605
1628
  const r2c1 = buildCell('Follower', followerName, chalk.magenta, colL);
1606
1629
  const r2c2text = ` Symbol: ${chalk.yellow(followerSym)} Qty: ${chalk.cyan(follower.contracts)}`;