hedgequantx 2.5.13 → 2.5.14

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.
@@ -1,10 +1,13 @@
1
1
  /**
2
- * Algo Trading - Main Menu
2
+ * Algo Trading - Main Menu with AI Supervision
3
3
  */
4
4
 
5
5
  const chalk = require('chalk');
6
- const { getSeparator } = require('../../ui');
6
+ const ora = require('ora');
7
+ const { getLogoWidth, drawBoxHeaderContinue, drawBoxFooter, displayBanner } = require('../../ui');
7
8
  const { logger, prompts } = require('../../utils');
9
+ const aiService = require('../../services/ai');
10
+ const AISupervisor = require('../../services/ai/supervisor');
8
11
 
9
12
  const log = logger.scope('AlgoMenu');
10
13
 
@@ -12,48 +15,240 @@ const { oneAccountMenu } = require('./one-account');
12
15
  const { copyTradingMenu } = require('./copy-trading');
13
16
 
14
17
  /**
15
- * Algo Trading Menu
18
+ * Algo Trading Menu with AI status
16
19
  */
17
20
  const algoTradingMenu = async (service) => {
21
+ const boxWidth = getLogoWidth();
22
+ const W = boxWidth - 2;
23
+
24
+ const makeLine = (content, align = 'left') => {
25
+ const plainLen = content.replace(/\x1b\[[0-9;]*m/g, '').length;
26
+ const padding = W - plainLen;
27
+ if (align === 'center') {
28
+ const leftPad = Math.floor(padding / 2);
29
+ return chalk.cyan('║') + ' '.repeat(leftPad) + content + ' '.repeat(padding - leftPad) + chalk.cyan('║');
30
+ }
31
+ return chalk.cyan('║') + ' ' + content + ' '.repeat(Math.max(0, padding - 1)) + chalk.cyan('║');
32
+ };
33
+
18
34
  log.info('Algo Trading menu opened');
19
35
 
20
- try {
21
- console.log();
22
- console.log(chalk.gray(getSeparator()));
23
- console.log(chalk.yellow.bold(' ALGO-TRADING'));
24
- console.log(chalk.gray(getSeparator()));
25
- console.log();
26
-
27
- const action = await prompts.selectOption(chalk.yellow('SELECT MODE:'), [
28
- { value: 'one_account', label: 'ONE ACCOUNT' },
29
- { value: 'copy_trading', label: 'COPY TRADING' },
30
- { value: 'back', label: '< BACK' }
31
- ]);
36
+ console.clear();
37
+ displayBanner();
38
+ drawBoxHeaderContinue('ALGO TRADING', boxWidth);
39
+
40
+ // Get AI status
41
+ const aiAgents = aiService.getAgents();
42
+ const aiConnected = aiAgents.length > 0;
43
+ const activeAgent = aiService.getActiveAgent();
44
+ const supervisionStatus = AISupervisor.getAllStatus();
45
+
46
+ // Show AI supervision status
47
+ if (aiConnected && activeAgent) {
48
+ console.log(makeLine(chalk.green(`AI SUPERVISION: ACTIVE`), 'center'));
49
+ console.log(makeLine(chalk.magenta(`AGENT: ${activeAgent.name}`), 'center'));
50
+
51
+ if (supervisionStatus.length > 0) {
52
+ const supervisor = supervisionStatus[0];
53
+ const duration = Math.floor(supervisor.duration / 1000);
54
+ console.log(makeLine(chalk.gray(`SESSION: ${duration}s | DECISIONS: ${supervisor.metrics.totalDecisions}`), 'center'));
55
+
56
+ if (supervisor.lastDecision) {
57
+ console.log(makeLine(chalk.yellow(`LAST: ${supervisor.lastDecision.reason.substring(0, 50)}...`), 'center'));
58
+ }
59
+ }
60
+ } else {
61
+ console.log(makeLine(chalk.gray('AI SUPERVISION: INACTIVE'), 'center'));
62
+ }
63
+
64
+ console.log(chalk.cyan('╠' + '═'.repeat(W) + '╣'));
65
+
66
+ // Menu options
67
+ const options = [];
68
+
69
+ if (aiConnected && activeAgent) {
70
+ options.push({ label: chalk.cyan('[1] HQX ULTRA SCALPING (AI SUPERVISED)'), value: 'ai_supervised' });
71
+ options.push({ label: chalk.white('[2] HQX ULTRA SCALPING (MANUAL MODE)'), value: 'one_account' });
72
+ options.push({ label: chalk.magenta('[3] AI SUPERVISION DASHBOARD'), value: 'ai_dashboard' });
73
+ } else {
74
+ options.push({ label: chalk.cyan('[1] HQX ULTRA SCALPING (MANUAL MODE)'), value: 'one_account' });
75
+ options.push({ label: chalk.gray('[2] HQX ULTRA SCALPING (AI SUPERVISED) - NO AI AGENT'), value: 'no_agent' });
76
+ }
77
+
78
+ options.push({ label: chalk.white('[C] COPY TRADING'), value: 'copy_trading' });
79
+ options.push({ label: chalk.gray('[<] BACK'), value: 'back' });
80
+
81
+ for (const opt of options) {
82
+ console.log(makeLine(opt.label));
83
+ }
84
+
85
+ drawBoxFooter(boxWidth);
86
+
87
+ const choice = await prompts.textInput(chalk.cyan('SELECT:'));
88
+
89
+ switch (choice?.toLowerCase()) {
90
+ case '1':
91
+ if (aiConnected && activeAgent) {
92
+ return await startAISupervised(service, activeAgent);
93
+ } else {
94
+ await oneAccountMenu(service);
95
+ }
96
+ break;
97
+
98
+ case '2':
99
+ if (aiConnected && activeAgent) {
100
+ await oneAccountMenu(service);
101
+ } else {
102
+ console.log(chalk.yellow('\n NO AI AGENT CONNECTED'));
103
+ console.log(chalk.gray(' Connect an AI agent first from [I] AI AGENTS menu'));
104
+ await prompts.waitForEnter();
105
+ }
106
+ break;
107
+
108
+ case '3':
109
+ if (aiConnected && activeAgent) {
110
+ await showAIDashboard(activeAgent);
111
+ }
112
+ break;
113
+
114
+ case 'c':
115
+ await copyTradingMenu();
116
+ break;
117
+
118
+ case '<':
119
+ case 'b':
120
+ return 'back';
121
+
122
+ default:
123
+ // Handle direct number input
124
+ const num = parseInt(choice);
125
+ if (num === 1) {
126
+ if (aiConnected && activeAgent) {
127
+ return await startAISupervised(service, activeAgent);
128
+ } else {
129
+ await oneAccountMenu(service);
130
+ }
131
+ } else if (num === 2) {
132
+ if (aiConnected && activeAgent) {
133
+ await oneAccountMenu(service);
134
+ } else {
135
+ console.log(chalk.yellow('\n NO AI AGENT CONNECTED'));
136
+ await prompts.waitForEnter();
137
+ }
138
+ } else if (num === 3 && aiConnected && activeAgent) {
139
+ await showAIDashboard(activeAgent);
140
+ }
141
+ break;
142
+ }
143
+
144
+ return algoTradingMenu(service);
145
+ };
32
146
 
33
- log.debug('Algo mode selected', { action });
147
+ /**
148
+ * Start AI supervised trading
149
+ */
150
+ const startAISupervised = async (service, agent) => {
151
+ const boxWidth = getLogoWidth();
152
+ const W = boxWidth - 2;
153
+
154
+ const makeLine = (content) => {
155
+ const plainLen = content.replace(/\x1b\[[0-9;]*m/g, '').length;
156
+ const padding = W - plainLen;
157
+ return chalk.cyan('║') + ' ' + content + ' '.repeat(Math.max(0, padding - 1)) + chalk.cyan('║');
158
+ };
159
+
160
+ console.clear();
161
+ displayBanner();
162
+ drawBoxHeaderContinue('AI SUPERVISED TRADING', boxWidth);
163
+
164
+ console.log(makeLine(chalk.magenta(`AGENT: ${agent.name}`)));
165
+ console.log(makeLine(chalk.green('STATUS: STARTING SUPERVISION...')));
166
+
167
+ drawBoxFooter(boxWidth);
168
+
169
+ // Start AI supervision
170
+ const success = AISupervisor.start(agent.id, { /* algo target */ });
171
+
172
+ if (success) {
173
+ const spinner = ora({ text: 'INITIALIZING AI SUPERVISION...', color: 'cyan' }).start();
174
+
175
+ // Simulate initialization
176
+ await new Promise(resolve => setTimeout(resolve, 2000));
177
+
178
+ spinner.succeed('AI SUPERVISION ACTIVE');
179
+ console.log(chalk.green('\n ✓ Agent is now monitoring HQX Ultra Scalping'));
180
+ console.log(chalk.gray(' ✓ AI will optimize parameters and manage risk'));
181
+ console.log(chalk.gray(' ✓ Supervision continues until agent is disconnected'));
182
+
183
+ await prompts.waitForEnter();
184
+
185
+ // Start the algo (placeholder for real implementation)
186
+ return await oneAccountMenu(service);
187
+
188
+ } else {
189
+ console.log(chalk.red('\n ✗ Failed to start AI supervision'));
190
+ await prompts.waitForEnter();
191
+ }
192
+ };
34
193
 
35
- if (!action || action === 'back') {
36
- return 'back';
194
+ /**
195
+ * Show AI Dashboard
196
+ */
197
+ const showAIDashboard = async (agent) => {
198
+ const boxWidth = getLogoWidth();
199
+ const W = boxWidth - 2;
200
+
201
+ const makeLine = (content) => {
202
+ const plainLen = content.replace(/\x1b\[[0-9;]*m/g, '').length;
203
+ const padding = W - plainLen;
204
+ return chalk.cyan('║') + ' ' + content + ' '.repeat(Math.max(0, padding - 1)) + chalk.cyan('║');
205
+ };
206
+
207
+ const supervisionStatus = AISupervisor.getStatus(agent.id);
208
+
209
+ while (true) {
210
+ console.clear();
211
+ displayBanner();
212
+ drawBoxHeaderContinue('AI SUPERVISION DASHBOARD', boxWidth);
213
+
214
+ console.log(makeLine(chalk.magenta(`AGENT: ${agent.name}`)));
215
+ console.log(makeLine(chalk.green(`STATUS: ${supervisionStatus.active ? 'ACTIVE' : 'INACTIVE'}`)));
216
+
217
+ if (supervisionStatus.active) {
218
+ const duration = Math.floor(supervisionStatus.duration / 1000);
219
+ console.log(makeLine(chalk.gray(`SESSION: ${duration}s`)));
220
+ console.log(makeLine(chalk.gray(`DECISIONS: ${supervisionStatus.decisions}`)));
221
+ console.log(makeLine(chalk.yellow(`INTERVENTIONS: ${supervisionStatus.interventions}`)));
222
+ console.log(makeLine(chalk.cyan(`OPTIMIZATIONS: ${supervisionStatus.optimizations}`)));
223
+
224
+ console.log(chalk.cyan('╠' + '═'.repeat(W) + '╣'));
225
+
226
+ if (supervisionStatus.lastDecision) {
227
+ const decision = supervisionStatus.lastDecision;
228
+ console.log(makeLine(chalk.white('LAST DECISION:')));
229
+ console.log(makeLine(chalk.gray(` Type: ${decision.type}`)));
230
+ console.log(makeLine(chalk.gray(` Reason: ${decision.reason}`)));
231
+ console.log(makeLine(chalk.gray(` Confidence: ${decision.confidence}%`)));
232
+ } else {
233
+ console.log(makeLine(chalk.gray('No decisions yet...')));
234
+ }
37
235
  }
38
-
39
- switch (action) {
40
- case 'one_account':
41
- log.info('Starting One Account mode');
42
- await oneAccountMenu(service);
43
- break;
44
- case 'copy_trading':
45
- log.info('Starting Copy Trading mode');
46
- await copyTradingMenu();
47
- break;
236
+
237
+ console.log(chalk.cyan('╠' + '═'.repeat(W) + '╣'));
238
+ console.log(makeLine(chalk.gray('[<] BACK')));
239
+
240
+ drawBoxFooter(boxWidth);
241
+
242
+ const choice = await prompts.textInput(chalk.cyan('PRESS < TO GO BACK:'));
243
+
244
+ if (choice === '<' || choice?.toLowerCase() === 'b') {
245
+ break;
48
246
  }
49
247
 
50
- return action;
51
- } catch (err) {
52
- log.error('Algo menu error:', err.message);
53
- console.log(chalk.red(` ERROR: ${err.message}`));
54
- await prompts.waitForEnter();
55
- return 'back';
248
+ // Refresh data
249
+ const freshStatus = AISupervisor.getStatus(agent.id);
250
+ Object.assign(supervisionStatus, freshStatus);
56
251
  }
57
252
  };
58
253
 
59
- module.exports = { algoTradingMenu };
254
+ module.exports = { algoTradingMenu };