hedgequantx 2.9.19 → 2.9.20
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 +42 -64
- package/src/lib/m/hqx-2b.js +7 -0
- package/src/lib/m/index.js +138 -0
- package/src/lib/m/ultra-scalping.js +7 -0
- package/src/menus/connect.js +14 -17
- package/src/menus/dashboard.js +58 -76
- package/src/pages/accounts.js +38 -49
- package/src/pages/algo/copy-trading.js +546 -178
- package/src/pages/algo/index.js +18 -75
- package/src/pages/algo/one-account.js +322 -57
- package/src/pages/algo/ui.js +15 -15
- package/src/pages/orders.js +19 -22
- package/src/pages/positions.js +19 -22
- package/src/pages/stats/index.js +15 -16
- package/src/pages/user.js +7 -11
- package/src/services/ai-supervision/health.js +35 -47
- package/src/services/index.js +1 -9
- package/src/services/rithmic/accounts.js +8 -6
- package/src/ui/box.js +9 -5
- package/src/ui/index.js +5 -18
- package/src/ui/menu.js +4 -4
- package/src/pages/ai-agents-ui.js +0 -388
- package/src/pages/ai-agents.js +0 -494
- package/src/pages/ai-models.js +0 -389
- package/src/pages/algo/algo-executor.js +0 -307
- package/src/pages/algo/copy-executor.js +0 -331
- package/src/pages/algo/custom-strategy.js +0 -313
- package/src/services/ai-supervision/consensus.js +0 -284
- package/src/services/ai-supervision/context.js +0 -275
- package/src/services/ai-supervision/directive.js +0 -167
- package/src/services/ai-supervision/index.js +0 -359
- package/src/services/ai-supervision/parser.js +0 -278
- package/src/services/ai-supervision/symbols.js +0 -259
- package/src/services/cliproxy/index.js +0 -256
- package/src/services/cliproxy/installer.js +0 -111
- package/src/services/cliproxy/manager.js +0 -387
- package/src/services/llmproxy/index.js +0 -166
- package/src/services/llmproxy/manager.js +0 -411
package/src/menus/dashboard.js
CHANGED
|
@@ -7,10 +7,9 @@ const ora = require('ora');
|
|
|
7
7
|
const { execSync, spawn } = require('child_process');
|
|
8
8
|
|
|
9
9
|
const { connections } = require('../services');
|
|
10
|
-
const { getLogoWidth, centerText, prepareStdin
|
|
10
|
+
const { getLogoWidth, centerText, prepareStdin } = require('../ui');
|
|
11
11
|
const { getCachedStats } = require('../services/stats-cache');
|
|
12
12
|
const { prompts } = require('../utils');
|
|
13
|
-
const { getActiveAgentCount } = require('../pages/ai-agents');
|
|
14
13
|
|
|
15
14
|
/**
|
|
16
15
|
* Dashboard menu after login
|
|
@@ -18,16 +17,6 @@ const { getActiveAgentCount } = require('../pages/ai-agents');
|
|
|
18
17
|
const dashboardMenu = async (service) => {
|
|
19
18
|
prepareStdin();
|
|
20
19
|
|
|
21
|
-
// Stop any global spinner before clearing
|
|
22
|
-
if (global.__hqxSpinner) {
|
|
23
|
-
global.__hqxSpinner.stop();
|
|
24
|
-
global.__hqxSpinner = null;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
// Clear screen and show banner (always closed)
|
|
28
|
-
clearScreen();
|
|
29
|
-
displayBanner();
|
|
30
|
-
|
|
31
20
|
const boxWidth = getLogoWidth();
|
|
32
21
|
const W = boxWidth - 2;
|
|
33
22
|
|
|
@@ -41,9 +30,9 @@ const dashboardMenu = async (service) => {
|
|
|
41
30
|
return chalk.cyan('║') + content + ' '.repeat(Math.max(0, padding)) + chalk.cyan('║');
|
|
42
31
|
};
|
|
43
32
|
|
|
44
|
-
//
|
|
45
|
-
console.log(chalk.cyan('
|
|
46
|
-
console.log(makeLine(chalk.yellow.bold('
|
|
33
|
+
// Continue from banner (use ╠ not ╔)
|
|
34
|
+
console.log(chalk.cyan('╠' + '═'.repeat(W) + '╣'));
|
|
35
|
+
console.log(makeLine(chalk.yellow.bold('Welcome, HQX Trader!'), 'center'));
|
|
47
36
|
console.log(chalk.cyan('╠' + '═'.repeat(W) + '╣'));
|
|
48
37
|
|
|
49
38
|
// Show connected propfirms
|
|
@@ -62,8 +51,8 @@ const dashboardMenu = async (service) => {
|
|
|
62
51
|
const balStr = statsInfo.balance !== null ? `$${statsInfo.balance.toLocaleString()}` : '--';
|
|
63
52
|
const balColor = statsInfo.balance !== null ? chalk.green : chalk.gray;
|
|
64
53
|
|
|
65
|
-
// AI Agents status
|
|
66
|
-
const agentCount =
|
|
54
|
+
// AI Agents status
|
|
55
|
+
const agentCount = statsInfo.agents || 0;
|
|
67
56
|
const agentDisplay = agentCount > 0 ? 'ON' : 'OFF';
|
|
68
57
|
const agentColor = agentCount > 0 ? chalk.green : chalk.red;
|
|
69
58
|
|
|
@@ -98,9 +87,9 @@ const dashboardMenu = async (service) => {
|
|
|
98
87
|
|
|
99
88
|
// Find max width for alignment
|
|
100
89
|
const menuItems = [
|
|
101
|
-
{ left: '[1]
|
|
102
|
-
{ left: '[+]
|
|
103
|
-
{ left: '[
|
|
90
|
+
{ left: '[1] View Accounts', right: '[2] View Stats' },
|
|
91
|
+
{ left: '[+] Add Prop-Account', right: '[A] Algo-Trading' },
|
|
92
|
+
{ left: '[U] Update HQX', right: '[X] Disconnect' },
|
|
104
93
|
];
|
|
105
94
|
|
|
106
95
|
const maxLeftLen = Math.max(...menuItems.map(m => m.left.length));
|
|
@@ -130,25 +119,20 @@ const dashboardMenu = async (service) => {
|
|
|
130
119
|
);
|
|
131
120
|
};
|
|
132
121
|
|
|
133
|
-
menuRow('[1]
|
|
134
|
-
menuRow('[+]
|
|
135
|
-
menuRow('[
|
|
136
|
-
|
|
137
|
-
// Separator and centered Disconnect button
|
|
138
|
-
console.log(chalk.cyan('╠' + '─'.repeat(W) + '╣'));
|
|
139
|
-
console.log(makeLine(chalk.red('[X] DISCONNECT'), 'center'));
|
|
122
|
+
menuRow('[1] View Accounts', '[2] View Stats', chalk.cyan, chalk.cyan);
|
|
123
|
+
menuRow('[+] Add Prop-Account', '[A] Algo-Trading', chalk.cyan, chalk.magenta);
|
|
124
|
+
menuRow('[U] Update HQX', '[X] Disconnect', chalk.yellow, chalk.red);
|
|
140
125
|
|
|
141
126
|
console.log(chalk.cyan('╚' + '═'.repeat(W) + '╝'));
|
|
142
127
|
|
|
143
128
|
// Simple input - no duplicate menu
|
|
144
|
-
const input = await prompts.textInput(chalk.cyan('
|
|
129
|
+
const input = await prompts.textInput(chalk.cyan('Select (1/2/+/A/U/X)'));
|
|
145
130
|
|
|
146
131
|
const actionMap = {
|
|
147
132
|
'1': 'accounts',
|
|
148
133
|
'2': 'stats',
|
|
149
134
|
'+': 'add_prop_account',
|
|
150
135
|
'a': 'algotrading',
|
|
151
|
-
'i': 'aiagents',
|
|
152
136
|
'u': 'update',
|
|
153
137
|
'x': 'disconnect'
|
|
154
138
|
};
|
|
@@ -160,95 +144,93 @@ const dashboardMenu = async (service) => {
|
|
|
160
144
|
* Handle update process
|
|
161
145
|
*/
|
|
162
146
|
const handleUpdate = async () => {
|
|
163
|
-
clearScreen();
|
|
164
|
-
displayBanner();
|
|
165
147
|
prepareStdin();
|
|
166
148
|
|
|
167
|
-
const boxWidth = getLogoWidth();
|
|
168
|
-
const W = boxWidth - 2;
|
|
169
|
-
|
|
170
|
-
console.log(chalk.cyan('╔' + '═'.repeat(W) + '╗'));
|
|
171
|
-
console.log(chalk.cyan('║') + chalk.yellow.bold(centerText('UPDATE HQX', W)) + chalk.cyan('║'));
|
|
172
|
-
console.log(chalk.cyan('╚' + '═'.repeat(W) + '╝'));
|
|
173
|
-
|
|
174
149
|
let spinner = null;
|
|
175
150
|
let currentVersion = 'unknown';
|
|
176
151
|
|
|
177
152
|
try {
|
|
178
|
-
// Get current version
|
|
179
153
|
try {
|
|
180
154
|
currentVersion = require('../../package.json').version || 'unknown';
|
|
181
155
|
} catch (e) {}
|
|
182
156
|
|
|
183
|
-
console.log(chalk.cyan(`\n
|
|
184
|
-
spinner = ora({ text: '
|
|
157
|
+
console.log(chalk.cyan(`\n Current version: v${currentVersion}`));
|
|
158
|
+
spinner = ora({ text: 'Checking for updates...', color: 'yellow' }).start();
|
|
185
159
|
|
|
186
|
-
// Check latest version from npm
|
|
187
160
|
let latestVersion;
|
|
188
161
|
try {
|
|
189
|
-
latestVersion = execSync('npm view hedgequantx version
|
|
162
|
+
latestVersion = execSync('npm view hedgequantx version', {
|
|
190
163
|
stdio: ['pipe', 'pipe', 'pipe'],
|
|
191
164
|
timeout: 30000,
|
|
192
165
|
encoding: 'utf8'
|
|
193
166
|
}).trim();
|
|
194
167
|
|
|
195
168
|
if (!latestVersion || !/^\d+\.\d+\.\d+/.test(latestVersion)) {
|
|
196
|
-
throw new Error('
|
|
169
|
+
throw new Error('Invalid version format');
|
|
197
170
|
}
|
|
198
171
|
} catch (e) {
|
|
199
|
-
spinner.fail('
|
|
200
|
-
console.log(chalk.
|
|
172
|
+
spinner.fail('Cannot reach npm registry');
|
|
173
|
+
console.log(chalk.gray(` Error: ${e.message}`));
|
|
174
|
+
console.log(chalk.yellow(' Try manually: npm install -g hedgequantx@latest'));
|
|
201
175
|
await prompts.waitForEnter();
|
|
202
176
|
return;
|
|
203
177
|
}
|
|
204
178
|
|
|
205
|
-
spinner.succeed(`
|
|
179
|
+
spinner.succeed(`Latest version: v${latestVersion}`);
|
|
206
180
|
|
|
207
|
-
// Already up to date
|
|
208
181
|
if (currentVersion === latestVersion) {
|
|
209
|
-
console.log(chalk.green('
|
|
182
|
+
console.log(chalk.green(' Already up to date!'));
|
|
210
183
|
await prompts.waitForEnter();
|
|
211
184
|
return;
|
|
212
185
|
}
|
|
213
186
|
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
spinner = ora({ text: 'INSTALLING UPDATE...', color: 'yellow' }).start();
|
|
187
|
+
console.log(chalk.yellow(` Update available: v${currentVersion} → v${latestVersion}`));
|
|
188
|
+
spinner = ora({ text: 'Installing update...', color: 'yellow' }).start();
|
|
217
189
|
|
|
218
|
-
// Try to install update
|
|
219
190
|
try {
|
|
220
|
-
|
|
191
|
+
// Try with sudo first on Unix systems
|
|
192
|
+
const isWindows = process.platform === 'win32';
|
|
193
|
+
const cmd = isWindows
|
|
194
|
+
? 'npm install -g hedgequantx@latest'
|
|
195
|
+
: 'npm install -g hedgequantx@latest';
|
|
196
|
+
|
|
197
|
+
execSync(cmd, {
|
|
221
198
|
stdio: ['pipe', 'pipe', 'pipe'],
|
|
222
199
|
timeout: 180000,
|
|
223
200
|
encoding: 'utf8'
|
|
224
201
|
});
|
|
225
202
|
} catch (e) {
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
});
|
|
233
|
-
} catch (e2) {
|
|
234
|
-
spinner.fail('UPDATE FAILED');
|
|
235
|
-
console.log(chalk.yellow('\n TRY MANUALLY:'));
|
|
236
|
-
console.log(chalk.white(' npm update -g hedgequantx'));
|
|
237
|
-
console.log(chalk.gray(' OR WITH SUDO:'));
|
|
238
|
-
console.log(chalk.white(' sudo npm update -g hedgequantx'));
|
|
239
|
-
await prompts.waitForEnter();
|
|
240
|
-
return;
|
|
241
|
-
}
|
|
203
|
+
spinner.fail('Update failed - permission denied?');
|
|
204
|
+
console.log(chalk.gray(` Error: ${e.message}`));
|
|
205
|
+
console.log(chalk.yellow(' Try manually with sudo:'));
|
|
206
|
+
console.log(chalk.white(' sudo npm install -g hedgequantx@latest'));
|
|
207
|
+
await prompts.waitForEnter();
|
|
208
|
+
return;
|
|
242
209
|
}
|
|
243
210
|
|
|
244
|
-
spinner.succeed(`
|
|
245
|
-
console.log(chalk.
|
|
246
|
-
|
|
247
|
-
|
|
211
|
+
spinner.succeed(`Updated to v${latestVersion}!`);
|
|
212
|
+
console.log(chalk.cyan(' Restarting HQX...'));
|
|
213
|
+
|
|
214
|
+
await new Promise(r => setTimeout(r, 1500));
|
|
215
|
+
|
|
216
|
+
try {
|
|
217
|
+
const child = spawn('hqx', [], {
|
|
218
|
+
stdio: 'inherit',
|
|
219
|
+
detached: true,
|
|
220
|
+
shell: true
|
|
221
|
+
});
|
|
222
|
+
child.unref();
|
|
223
|
+
process.exit(0);
|
|
224
|
+
} catch (e) {
|
|
225
|
+
console.log(chalk.yellow('\n Please restart HQX manually:'));
|
|
226
|
+
console.log(chalk.white(' hqx'));
|
|
227
|
+
await prompts.waitForEnter();
|
|
228
|
+
}
|
|
248
229
|
|
|
249
230
|
} catch (error) {
|
|
250
|
-
if (spinner) spinner.fail('
|
|
251
|
-
console.log(chalk.
|
|
231
|
+
if (spinner) spinner.fail('Update error');
|
|
232
|
+
console.log(chalk.gray(` Error: ${error.message}`));
|
|
233
|
+
console.log(chalk.yellow(' Try manually: npm install -g hedgequantx@latest'));
|
|
252
234
|
await prompts.waitForEnter();
|
|
253
235
|
}
|
|
254
236
|
};
|
package/src/pages/accounts.js
CHANGED
|
@@ -7,17 +7,13 @@ const ora = require('ora');
|
|
|
7
7
|
|
|
8
8
|
const { connections } = require('../services');
|
|
9
9
|
const { ACCOUNT_STATUS, ACCOUNT_TYPE } = require('../config');
|
|
10
|
-
const { getLogoWidth, getColWidths, drawBoxHeader, drawBoxFooter, draw2ColHeader, visibleLength, displayBanner
|
|
10
|
+
const { getLogoWidth, getColWidths, drawBoxHeader, drawBoxFooter, draw2ColHeader, visibleLength, displayBanner } = require('../ui');
|
|
11
11
|
const { prompts } = require('../utils');
|
|
12
12
|
|
|
13
13
|
/**
|
|
14
14
|
* Show all accounts
|
|
15
15
|
*/
|
|
16
16
|
const showAccounts = async (service) => {
|
|
17
|
-
// Clear screen and show banner
|
|
18
|
-
clearScreen();
|
|
19
|
-
displayBanner();
|
|
20
|
-
|
|
21
17
|
const boxWidth = getLogoWidth();
|
|
22
18
|
const { col1, col2 } = getColWidths(boxWidth);
|
|
23
19
|
|
|
@@ -32,12 +28,13 @@ const showAccounts = async (service) => {
|
|
|
32
28
|
let spinner;
|
|
33
29
|
|
|
34
30
|
try {
|
|
35
|
-
spinner
|
|
31
|
+
// Single spinner for loading (appears below the dashboard header)
|
|
32
|
+
spinner = ora({ text: 'Loading accounts...', color: 'yellow' }).start();
|
|
36
33
|
|
|
37
34
|
const allConns = connections.count() > 0 ? connections.getAll() : (service ? [{ service, propfirm: service.propfirm?.name || 'Unknown', type: 'single' }] : []);
|
|
38
35
|
|
|
39
36
|
if (allConns.length === 0) {
|
|
40
|
-
spinner.fail('
|
|
37
|
+
spinner.fail('No connections found');
|
|
41
38
|
await prompts.waitForEnter();
|
|
42
39
|
return;
|
|
43
40
|
}
|
|
@@ -63,7 +60,7 @@ const showAccounts = async (service) => {
|
|
|
63
60
|
}
|
|
64
61
|
|
|
65
62
|
if (allAccounts.length === 0) {
|
|
66
|
-
spinner.fail('
|
|
63
|
+
spinner.fail('No accounts found');
|
|
67
64
|
await prompts.waitForEnter();
|
|
68
65
|
return;
|
|
69
66
|
}
|
|
@@ -81,11 +78,8 @@ const showAccounts = async (service) => {
|
|
|
81
78
|
} catch (e) {}
|
|
82
79
|
}
|
|
83
80
|
|
|
84
|
-
spinner.
|
|
85
|
-
|
|
86
|
-
// Clear and show banner again before displaying accounts
|
|
87
|
-
clearScreen();
|
|
88
|
-
displayBanner();
|
|
81
|
+
spinner.succeed('Accounts loaded');
|
|
82
|
+
console.log();
|
|
89
83
|
|
|
90
84
|
// Display accounts
|
|
91
85
|
drawBoxHeader('TRADING ACCOUNTS', boxWidth);
|
|
@@ -97,20 +91,12 @@ const showAccounts = async (service) => {
|
|
|
97
91
|
const name1 = String(acc1.accountName || acc1.rithmicAccountId || acc1.accountId || `Account #${i + 1}`);
|
|
98
92
|
const name2 = acc2 ? String(acc2.accountName || acc2.rithmicAccountId || acc2.accountId || `Account #${i + 2}`) : '';
|
|
99
93
|
|
|
100
|
-
|
|
101
|
-
const sep = acc2 ? '│' : '║';
|
|
102
|
-
const rightCol = acc2 ? col2 : col2;
|
|
103
|
-
|
|
104
|
-
// Header row with account name(s)
|
|
105
|
-
const h1 = centerText(name1.substring(0, col1 - 4), col1);
|
|
106
|
-
const h2 = acc2 ? centerText(name2.substring(0, col2 - 4), col2) : ' '.repeat(col2);
|
|
107
|
-
console.log(chalk.cyan('║') + chalk.cyan.bold(h1) + chalk.cyan(sep) + chalk.cyan.bold(h2) + chalk.cyan('║'));
|
|
108
|
-
console.log(chalk.cyan('╠') + chalk.cyan('─'.repeat(col1)) + chalk.cyan(acc2 ? '┼' : '┼') + chalk.cyan('─'.repeat(col2)) + chalk.cyan('╣'));
|
|
94
|
+
draw2ColHeader(name1.substring(0, col1 - 4), name2 ? name2.substring(0, col2 - 4) : '', boxWidth);
|
|
109
95
|
|
|
110
96
|
// PropFirm
|
|
111
97
|
const pf1 = chalk.magenta(acc1.propfirm || 'Unknown');
|
|
112
98
|
const pf2 = acc2 ? chalk.magenta(acc2.propfirm || 'Unknown') : '';
|
|
113
|
-
console.log(chalk.cyan('║') + fmtRow('PropFirm:', pf1, col1) + chalk.cyan(
|
|
99
|
+
console.log(chalk.cyan('║') + fmtRow('PropFirm:', pf1, col1) + chalk.cyan('│') + (acc2 ? fmtRow('PropFirm:', pf2, col2) : ' '.repeat(col2)) + chalk.cyan('║'));
|
|
114
100
|
|
|
115
101
|
// Balance
|
|
116
102
|
const bal1 = acc1.balance;
|
|
@@ -119,7 +105,7 @@ const showAccounts = async (service) => {
|
|
|
119
105
|
const balStr2 = bal2 !== null && bal2 !== undefined ? '$' + Number(bal2).toLocaleString(undefined, {minimumFractionDigits: 2, maximumFractionDigits: 2}) : '--';
|
|
120
106
|
const balColor1 = bal1 === null || bal1 === undefined ? chalk.gray : (bal1 >= 0 ? chalk.green : chalk.red);
|
|
121
107
|
const balColor2 = bal2 === null || bal2 === undefined ? chalk.gray : (bal2 >= 0 ? chalk.green : chalk.red);
|
|
122
|
-
console.log(chalk.cyan('║') + fmtRow('Balance:', balColor1(balStr1), col1) + chalk.cyan(
|
|
108
|
+
console.log(chalk.cyan('║') + fmtRow('Balance:', balColor1(balStr1), col1) + chalk.cyan('│') + (acc2 ? fmtRow('Balance:', balColor2(balStr2), col2) : ' '.repeat(col2)) + chalk.cyan('║'));
|
|
123
109
|
|
|
124
110
|
// P&L
|
|
125
111
|
const pnl1 = acc1.profitAndLoss;
|
|
@@ -128,41 +114,44 @@ const showAccounts = async (service) => {
|
|
|
128
114
|
const pnlStr2 = pnl2 !== null && pnl2 !== undefined ? (pnl2 >= 0 ? '+' : '') + '$' + Number(pnl2).toLocaleString(undefined, {minimumFractionDigits: 2, maximumFractionDigits: 2}) : '--';
|
|
129
115
|
const pnlColor1 = pnl1 === null || pnl1 === undefined ? chalk.gray : (pnl1 >= 0 ? chalk.green : chalk.red);
|
|
130
116
|
const pnlColor2 = pnl2 === null || pnl2 === undefined ? chalk.gray : (pnl2 >= 0 ? chalk.green : chalk.red);
|
|
131
|
-
console.log(chalk.cyan('║') + fmtRow('P&L:', pnlColor1(pnlStr1), col1) + chalk.cyan(
|
|
117
|
+
console.log(chalk.cyan('║') + fmtRow('P&L:', pnlColor1(pnlStr1), col1) + chalk.cyan('│') + (acc2 ? fmtRow('P&L:', pnlColor2(pnlStr2), col2) : ' '.repeat(col2)) + chalk.cyan('║'));
|
|
132
118
|
|
|
133
|
-
// Status -
|
|
134
|
-
const getStatusDisplay = (
|
|
135
|
-
|
|
136
|
-
if (status === null || status === undefined) return { text: 'N/A', color: 'gray' };
|
|
119
|
+
// Status - handle both string from API and numeric lookup
|
|
120
|
+
const getStatusDisplay = (status) => {
|
|
121
|
+
if (!status && status !== 0) return { text: '--', color: 'gray' };
|
|
137
122
|
if (typeof status === 'string') {
|
|
123
|
+
// Direct string from Rithmic API (e.g., "Active", "Disabled")
|
|
138
124
|
const lowerStatus = status.toLowerCase();
|
|
139
125
|
if (lowerStatus.includes('active') || lowerStatus.includes('open')) return { text: status, color: 'green' };
|
|
140
126
|
if (lowerStatus.includes('disabled') || lowerStatus.includes('closed')) return { text: status, color: 'red' };
|
|
141
127
|
if (lowerStatus.includes('halt')) return { text: status, color: 'red' };
|
|
142
128
|
return { text: status, color: 'yellow' };
|
|
143
129
|
}
|
|
144
|
-
return { text:
|
|
130
|
+
return ACCOUNT_STATUS[status] || { text: 'Unknown', color: 'gray' };
|
|
145
131
|
};
|
|
146
|
-
const status1 = getStatusDisplay(acc1);
|
|
147
|
-
const status2 = acc2 ? getStatusDisplay(acc2) : null;
|
|
148
|
-
console.log(chalk.cyan('║') + fmtRow('Status:', chalk[status1.color](status1.text), col1) + chalk.cyan(
|
|
149
|
-
|
|
150
|
-
// Algorithm -
|
|
151
|
-
const
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
if (
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
if (
|
|
159
|
-
return { text:
|
|
132
|
+
const status1 = getStatusDisplay(acc1.status);
|
|
133
|
+
const status2 = acc2 ? getStatusDisplay(acc2.status) : null;
|
|
134
|
+
console.log(chalk.cyan('║') + fmtRow('Status:', chalk[status1.color](status1.text), col1) + chalk.cyan('│') + (acc2 ? fmtRow('Status:', chalk[status2.color](status2.text), col2) : ' '.repeat(col2)) + chalk.cyan('║'));
|
|
135
|
+
|
|
136
|
+
// Type/Algorithm - handle both string from API and numeric lookup
|
|
137
|
+
const getTypeDisplay = (type, algorithm) => {
|
|
138
|
+
// Prefer algorithm from RMS info if available
|
|
139
|
+
const value = algorithm || type;
|
|
140
|
+
if (!value && value !== 0) return { text: '--', color: 'gray' };
|
|
141
|
+
if (typeof value === 'string') {
|
|
142
|
+
// Direct string from Rithmic API
|
|
143
|
+
const lowerValue = value.toLowerCase();
|
|
144
|
+
if (lowerValue.includes('eval')) return { text: value, color: 'yellow' };
|
|
145
|
+
if (lowerValue.includes('live') || lowerValue.includes('funded')) return { text: value, color: 'green' };
|
|
146
|
+
if (lowerValue.includes('sim') || lowerValue.includes('demo')) return { text: value, color: 'gray' };
|
|
147
|
+
if (lowerValue.includes('express')) return { text: value, color: 'magenta' };
|
|
148
|
+
return { text: value, color: 'cyan' };
|
|
160
149
|
}
|
|
161
|
-
return { text:
|
|
150
|
+
return ACCOUNT_TYPE[value] || { text: 'Unknown', color: 'white' };
|
|
162
151
|
};
|
|
163
|
-
const
|
|
164
|
-
const
|
|
165
|
-
console.log(chalk.cyan('║') + fmtRow('
|
|
152
|
+
const type1 = getTypeDisplay(acc1.type, acc1.algorithm);
|
|
153
|
+
const type2 = acc2 ? getTypeDisplay(acc2.type, acc2.algorithm) : null;
|
|
154
|
+
console.log(chalk.cyan('║') + fmtRow('Type:', chalk[type1.color](type1.text), col1) + chalk.cyan('│') + (acc2 ? fmtRow('Type:', chalk[type2.color](type2.text), col2) : ' '.repeat(col2)) + chalk.cyan('║'));
|
|
166
155
|
|
|
167
156
|
if (i + 2 < allAccounts.length) {
|
|
168
157
|
console.log(chalk.cyan('╠') + chalk.cyan('═'.repeat(col1)) + chalk.cyan('╪') + chalk.cyan('═'.repeat(col2)) + chalk.cyan('╣'));
|
|
@@ -173,7 +162,7 @@ const showAccounts = async (service) => {
|
|
|
173
162
|
console.log();
|
|
174
163
|
|
|
175
164
|
} catch (error) {
|
|
176
|
-
if (spinner) spinner.fail('
|
|
165
|
+
if (spinner) spinner.fail('Error loading accounts: ' + error.message);
|
|
177
166
|
}
|
|
178
167
|
|
|
179
168
|
await prompts.waitForEnter();
|