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 +1 -1
- package/src/app.js +111 -77
- package/src/pages/algo.js +29 -6
package/package.json
CHANGED
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
|
-
|
|
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
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
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
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
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
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
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(
|
|
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(
|
|
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)}`;
|