hedgequantx 2.7.99 → 2.8.1
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/menus/dashboard.js +4 -12
- package/src/pages/ai-agents-ui.js +46 -1
- package/src/pages/ai-agents.js +84 -54
- package/src/pages/algo/algo-executor.js +61 -19
- package/src/pages/algo/copy-executor.js +331 -0
- package/src/pages/algo/copy-trading.js +44 -263
- package/src/pages/algo/custom-strategy.js +27 -2
- package/src/pages/algo/one-account.js +48 -1
- package/src/services/ai-supervision/consensus.js +284 -0
- package/src/services/ai-supervision/context.js +275 -0
- package/src/services/ai-supervision/directive.js +167 -0
- package/src/services/ai-supervision/health.js +288 -0
- package/src/services/ai-supervision/index.js +309 -0
- package/src/services/ai-supervision/parser.js +278 -0
- package/src/services/ai-supervision/symbols.js +259 -0
- package/src/services/cliproxy/index.js +32 -1
- package/src/services/index.js +5 -1
package/package.json
CHANGED
package/src/menus/dashboard.js
CHANGED
|
@@ -242,18 +242,10 @@ const handleUpdate = async () => {
|
|
|
242
242
|
|
|
243
243
|
spinner.succeed(`UPDATED TO V${latestVersion}!`);
|
|
244
244
|
console.log(chalk.green('\n ✓ UPDATE SUCCESSFUL!'));
|
|
245
|
-
console.log(chalk.
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
const child = spawn('hqx', [], {
|
|
250
|
-
detached: true,
|
|
251
|
-
stdio: 'inherit',
|
|
252
|
-
shell: true
|
|
253
|
-
});
|
|
254
|
-
child.unref();
|
|
255
|
-
|
|
256
|
-
// Exit current process to let new one take over
|
|
245
|
+
console.log(chalk.yellow('\n Please restart HQX to use the new version.'));
|
|
246
|
+
console.log(chalk.cyan(' Run: hqx'));
|
|
247
|
+
console.log();
|
|
248
|
+
await prompts.waitForEnter();
|
|
257
249
|
process.exit(0);
|
|
258
250
|
|
|
259
251
|
} catch (error) {
|
|
@@ -5,8 +5,10 @@
|
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
const chalk = require('chalk');
|
|
8
|
+
const ora = require('ora');
|
|
8
9
|
const { centerText, visibleLength } = require('../ui');
|
|
9
10
|
const cliproxy = require('../services/cliproxy');
|
|
11
|
+
const { runPreflightCheck, formatPreflightResults, getPreflightSummary } = require('../services/ai-supervision');
|
|
10
12
|
|
|
11
13
|
/**
|
|
12
14
|
* Draw a 2-column row with perfect alignment
|
|
@@ -294,10 +296,53 @@ const drawProviderWindow = (provider, config, boxWidth) => {
|
|
|
294
296
|
console.log(chalk.cyan('╚' + '═'.repeat(W) + '╝'));
|
|
295
297
|
};
|
|
296
298
|
|
|
299
|
+
/**
|
|
300
|
+
* Draw and run connection test for all agents
|
|
301
|
+
* @param {Array} agents - Array of agent configs
|
|
302
|
+
* @param {number} boxWidth - Box width
|
|
303
|
+
* @param {Function} clearWithBanner - Function to clear and show banner
|
|
304
|
+
* @returns {Promise<Object>} Test results
|
|
305
|
+
*/
|
|
306
|
+
const drawConnectionTest = async (agents, boxWidth, clearWithBanner) => {
|
|
307
|
+
if (agents.length === 0) {
|
|
308
|
+
console.log(chalk.yellow('\n No agents configured. Connect an agent first.'));
|
|
309
|
+
return { success: false, error: 'No agents' };
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
clearWithBanner();
|
|
313
|
+
const W = boxWidth - 2;
|
|
314
|
+
|
|
315
|
+
console.log(chalk.cyan('╔' + '═'.repeat(W) + '╗'));
|
|
316
|
+
console.log(chalk.cyan('║') + chalk.yellow.bold(centerText('AI AGENTS CONNECTION TEST', W)) + chalk.cyan('║'));
|
|
317
|
+
console.log(chalk.cyan('╠' + '═'.repeat(W) + '╣'));
|
|
318
|
+
console.log(chalk.cyan('║') + ' '.repeat(W) + chalk.cyan('║'));
|
|
319
|
+
|
|
320
|
+
// Run pre-flight check
|
|
321
|
+
const spinner = ora({ text: 'Testing connections...', color: 'yellow' }).start();
|
|
322
|
+
const results = await runPreflightCheck(agents);
|
|
323
|
+
spinner.stop();
|
|
324
|
+
|
|
325
|
+
// Display results
|
|
326
|
+
const lines = formatPreflightResults(results, boxWidth);
|
|
327
|
+
for (const line of lines) {
|
|
328
|
+
const paddedLine = line.length < W - 1 ? line + ' '.repeat(W - 1 - visibleLength(line)) : line;
|
|
329
|
+
console.log(chalk.cyan('║') + ' ' + paddedLine + chalk.cyan('║'));
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
// Summary
|
|
333
|
+
console.log(chalk.cyan('╠' + '═'.repeat(W) + '╣'));
|
|
334
|
+
const summary = getPreflightSummary(results);
|
|
335
|
+
console.log(chalk.cyan('║') + centerText(summary.text, W) + chalk.cyan('║'));
|
|
336
|
+
console.log(chalk.cyan('╚' + '═'.repeat(W) + '╝'));
|
|
337
|
+
|
|
338
|
+
return results;
|
|
339
|
+
};
|
|
340
|
+
|
|
297
341
|
module.exports = {
|
|
298
342
|
draw2ColRow,
|
|
299
343
|
draw2ColTable,
|
|
300
344
|
drawProvidersTable,
|
|
301
345
|
drawModelsTable,
|
|
302
|
-
drawProviderWindow
|
|
346
|
+
drawProviderWindow,
|
|
347
|
+
drawConnectionTest
|
|
303
348
|
};
|
package/src/pages/ai-agents.js
CHANGED
|
@@ -14,7 +14,7 @@ const ora = require('ora');
|
|
|
14
14
|
const { getLogoWidth, displayBanner } = require('../ui');
|
|
15
15
|
const { prompts } = require('../utils');
|
|
16
16
|
const { fetchModelsFromApi } = require('./ai-models');
|
|
17
|
-
const { drawProvidersTable, drawModelsTable, drawProviderWindow } = require('./ai-agents-ui');
|
|
17
|
+
const { drawProvidersTable, drawModelsTable, drawProviderWindow, drawConnectionTest } = require('./ai-agents-ui');
|
|
18
18
|
const cliproxy = require('../services/cliproxy');
|
|
19
19
|
|
|
20
20
|
/** Clear screen and show banner (always closed) */
|
|
@@ -102,70 +102,46 @@ const activateProvider = (config, providerId, data) => {
|
|
|
102
102
|
};
|
|
103
103
|
|
|
104
104
|
/** Wait for child process to exit */
|
|
105
|
-
const waitForProcessExit = (
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
});
|
|
118
|
-
};
|
|
105
|
+
const waitForProcessExit = (cp, timeoutMs = 15000, intervalMs = 500) => new Promise((resolve) => {
|
|
106
|
+
if (!cp) return resolve();
|
|
107
|
+
let elapsed = 0;
|
|
108
|
+
const check = setInterval(() => {
|
|
109
|
+
elapsed += intervalMs;
|
|
110
|
+
if (cp.exitCode !== null || cp.killed || elapsed >= timeoutMs) {
|
|
111
|
+
clearInterval(check);
|
|
112
|
+
if (elapsed >= timeoutMs) try { cp.kill(); } catch (e) {}
|
|
113
|
+
resolve();
|
|
114
|
+
}
|
|
115
|
+
}, intervalMs);
|
|
116
|
+
});
|
|
119
117
|
|
|
120
118
|
/** Handle CLIProxy connection (with auto-install) */
|
|
121
119
|
const handleCliProxyConnection = async (provider, config, boxWidth) => {
|
|
122
120
|
console.log();
|
|
123
|
-
|
|
124
|
-
// Check if CLIProxyAPI is installed
|
|
121
|
+
// Check/install CLIProxyAPI
|
|
125
122
|
if (!cliproxy.isInstalled()) {
|
|
126
123
|
console.log(chalk.yellow(' CLIPROXYAPI NOT INSTALLED. INSTALLING...'));
|
|
127
|
-
const spinner = ora({ text: 'DOWNLOADING
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
spinner.text = `${msg.toUpperCase()} ${percent}%`;
|
|
131
|
-
});
|
|
132
|
-
|
|
133
|
-
if (!installResult.success) {
|
|
134
|
-
spinner.fail(`INSTALLATION FAILED: ${installResult.error.toUpperCase()}`);
|
|
135
|
-
await prompts.waitForEnter();
|
|
136
|
-
return false;
|
|
137
|
-
}
|
|
124
|
+
const spinner = ora({ text: 'DOWNLOADING...', color: 'yellow' }).start();
|
|
125
|
+
const installResult = await cliproxy.install((msg, percent) => { spinner.text = `${msg.toUpperCase()} ${percent}%`; });
|
|
126
|
+
if (!installResult.success) { spinner.fail(`INSTALL FAILED: ${installResult.error}`); await prompts.waitForEnter(); return false; }
|
|
138
127
|
spinner.succeed('CLIPROXYAPI INSTALLED');
|
|
139
128
|
}
|
|
140
|
-
|
|
141
|
-
// Check if running, start if not (or restart if config missing)
|
|
129
|
+
// Check/start CLIProxy
|
|
142
130
|
let status = await cliproxy.isRunning();
|
|
143
131
|
if (!status.running) {
|
|
144
132
|
const spinner = ora({ text: 'STARTING CLIPROXYAPI...', color: 'yellow' }).start();
|
|
145
133
|
const startResult = await cliproxy.start();
|
|
146
|
-
|
|
147
|
-
if (!startResult.success) {
|
|
148
|
-
spinner.fail(`FAILED TO START: ${startResult.error.toUpperCase()}`);
|
|
149
|
-
await prompts.waitForEnter();
|
|
150
|
-
return false;
|
|
151
|
-
}
|
|
134
|
+
if (!startResult.success) { spinner.fail(`START FAILED: ${startResult.error}`); await prompts.waitForEnter(); return false; }
|
|
152
135
|
spinner.succeed('CLIPROXYAPI STARTED');
|
|
153
136
|
} else {
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
console.log(chalk.yellow(' RESTARTING CLIPROXYAPI WITH PROPER CONFIG...'));
|
|
137
|
+
const cfgPath = path.join(os.homedir(), '.hqx', 'cliproxy', 'config.yaml');
|
|
138
|
+
if (!fs.existsSync(cfgPath)) {
|
|
139
|
+
console.log(chalk.yellow(' RESTARTING CLIPROXYAPI...'));
|
|
158
140
|
await cliproxy.stop();
|
|
159
|
-
const
|
|
160
|
-
if (!
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
return false;
|
|
164
|
-
}
|
|
165
|
-
console.log(chalk.green(' ✓ CLIPROXYAPI RESTARTED'));
|
|
166
|
-
} else {
|
|
167
|
-
console.log(chalk.green(' ✓ CLIPROXYAPI IS RUNNING'));
|
|
168
|
-
}
|
|
141
|
+
const res = await cliproxy.start();
|
|
142
|
+
if (!res.success) { console.log(chalk.red(` RESTART FAILED: ${res.error}`)); await prompts.waitForEnter(); return false; }
|
|
143
|
+
console.log(chalk.green(' ✓ RESTARTED'));
|
|
144
|
+
} else console.log(chalk.green(' ✓ CLIPROXYAPI RUNNING'));
|
|
169
145
|
}
|
|
170
146
|
|
|
171
147
|
// First, check if models are already available (existing auth)
|
|
@@ -397,7 +373,7 @@ const handleProviderConfig = async (provider, config) => {
|
|
|
397
373
|
return config;
|
|
398
374
|
};
|
|
399
375
|
|
|
400
|
-
/** Get active AI provider config */
|
|
376
|
+
/** Get active AI provider config (legacy - single provider) */
|
|
401
377
|
const getActiveProvider = () => {
|
|
402
378
|
const config = loadConfig();
|
|
403
379
|
for (const provider of AI_PROVIDERS) {
|
|
@@ -409,15 +385,52 @@ const getActiveProvider = () => {
|
|
|
409
385
|
connectionType: pc.connectionType,
|
|
410
386
|
apiKey: pc.apiKey || null,
|
|
411
387
|
modelId: pc.modelId || null,
|
|
412
|
-
modelName: pc.modelName || null
|
|
388
|
+
modelName: pc.modelName || null,
|
|
389
|
+
weight: pc.weight || 100
|
|
413
390
|
};
|
|
414
391
|
}
|
|
415
392
|
}
|
|
416
393
|
return null;
|
|
417
394
|
};
|
|
418
395
|
|
|
396
|
+
/** Get ALL active AI agents for multi-agent supervision */
|
|
397
|
+
const getActiveAgents = () => {
|
|
398
|
+
const config = loadConfig();
|
|
399
|
+
const agents = [];
|
|
400
|
+
|
|
401
|
+
for (const provider of AI_PROVIDERS) {
|
|
402
|
+
const pc = config.providers[provider.id];
|
|
403
|
+
if (pc && pc.active) {
|
|
404
|
+
agents.push({
|
|
405
|
+
id: `agent-${provider.id}`,
|
|
406
|
+
provider: provider.id,
|
|
407
|
+
name: provider.name,
|
|
408
|
+
connectionType: pc.connectionType,
|
|
409
|
+
apiKey: pc.apiKey || null,
|
|
410
|
+
modelId: pc.modelId || null,
|
|
411
|
+
modelName: pc.modelName || null,
|
|
412
|
+
weight: pc.weight || Math.floor(100 / AI_PROVIDERS.filter(p => config.providers[p.id]?.active).length),
|
|
413
|
+
active: true
|
|
414
|
+
});
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
return agents;
|
|
419
|
+
};
|
|
420
|
+
|
|
421
|
+
/** Get supervision config for SupervisionEngine */
|
|
422
|
+
const getSupervisionConfig = () => {
|
|
423
|
+
const agents = getActiveAgents();
|
|
424
|
+
return {
|
|
425
|
+
supervisionEnabled: agents.length > 0,
|
|
426
|
+
agents,
|
|
427
|
+
minAgents: 1,
|
|
428
|
+
timeout: 30000
|
|
429
|
+
};
|
|
430
|
+
};
|
|
431
|
+
|
|
419
432
|
/** Count active AI agents */
|
|
420
|
-
const getActiveAgentCount = () =>
|
|
433
|
+
const getActiveAgentCount = () => getActiveAgents().length;
|
|
421
434
|
|
|
422
435
|
/** Main AI Agents menu */
|
|
423
436
|
const aiAgentsMenu = async () => {
|
|
@@ -428,11 +441,26 @@ const aiAgentsMenu = async () => {
|
|
|
428
441
|
clearWithBanner();
|
|
429
442
|
drawProvidersTable(AI_PROVIDERS, config, boxWidth);
|
|
430
443
|
|
|
431
|
-
|
|
444
|
+
// Show [T] TEST option if agents are configured
|
|
445
|
+
const agentCount = getActiveAgentCount();
|
|
446
|
+
if (agentCount > 0) {
|
|
447
|
+
console.log(chalk.cyan(' [T] TEST ALL CONNECTIONS'));
|
|
448
|
+
}
|
|
449
|
+
console.log();
|
|
450
|
+
|
|
451
|
+
const promptText = agentCount > 0 ? 'SELECT (1-8/T/B): ' : 'SELECT (1-8/B): ';
|
|
452
|
+
const input = await prompts.textInput(chalk.cyan(promptText));
|
|
432
453
|
const choice = (input || '').toLowerCase().trim();
|
|
433
454
|
|
|
434
455
|
if (choice === 'b' || choice === '') break;
|
|
435
456
|
|
|
457
|
+
if (choice === 't' && agentCount > 0) {
|
|
458
|
+
const agents = getActiveAgents();
|
|
459
|
+
await drawConnectionTest(agents, boxWidth, clearWithBanner);
|
|
460
|
+
await prompts.waitForEnter();
|
|
461
|
+
continue;
|
|
462
|
+
}
|
|
463
|
+
|
|
436
464
|
const num = parseInt(choice);
|
|
437
465
|
if (!isNaN(num) && num >= 1 && num <= AI_PROVIDERS.length) {
|
|
438
466
|
config = await handleProviderConfig(AI_PROVIDERS[num - 1], config);
|
|
@@ -447,6 +475,8 @@ const aiAgentsMenu = async () => {
|
|
|
447
475
|
module.exports = {
|
|
448
476
|
aiAgentsMenu,
|
|
449
477
|
getActiveProvider,
|
|
478
|
+
getActiveAgents,
|
|
479
|
+
getSupervisionConfig,
|
|
450
480
|
getActiveAgentCount,
|
|
451
481
|
loadConfig,
|
|
452
482
|
saveConfig,
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Algo Executor - Shared execution engine for all algo modes
|
|
3
3
|
* Handles market data, signals, orders, and P&L tracking
|
|
4
|
+
* Supports multi-agent AI supervision for signal optimization
|
|
4
5
|
*/
|
|
5
6
|
|
|
6
7
|
const readline = require('readline');
|
|
7
8
|
const { AlgoUI, renderSessionSummary } = require('./ui');
|
|
8
9
|
const { M1 } = require('../../lib/m/s1');
|
|
9
10
|
const { MarketDataFeed } = require('../../lib/data');
|
|
11
|
+
const { SupervisionEngine } = require('../../services/ai-supervision');
|
|
10
12
|
|
|
11
13
|
/**
|
|
12
14
|
* Execute algo strategy with market data
|
|
@@ -15,11 +17,15 @@ const { MarketDataFeed } = require('../../lib/data');
|
|
|
15
17
|
* @param {Object} params.account - Account object
|
|
16
18
|
* @param {Object} params.contract - Contract object
|
|
17
19
|
* @param {Object} params.config - Algo config (contracts, target, risk, showName)
|
|
18
|
-
* @param {Object} params.options - Optional:
|
|
20
|
+
* @param {Object} params.options - Optional: supervisionConfig for multi-agent AI
|
|
19
21
|
*/
|
|
20
22
|
const executeAlgo = async ({ service, account, contract, config, options = {} }) => {
|
|
21
23
|
const { contracts, dailyTarget, maxRisk, showName } = config;
|
|
22
|
-
const {
|
|
24
|
+
const { supervisionConfig, subtitle } = options;
|
|
25
|
+
|
|
26
|
+
// Initialize AI Supervision Engine if configured
|
|
27
|
+
const supervisionEnabled = supervisionConfig?.supervisionEnabled && supervisionConfig?.agents?.length > 0;
|
|
28
|
+
const supervisionEngine = supervisionEnabled ? new SupervisionEngine(supervisionConfig) : null;
|
|
23
29
|
|
|
24
30
|
const accountName = showName
|
|
25
31
|
? (account.accountName || account.rithmicAccountId || account.accountId)
|
|
@@ -29,7 +35,7 @@ const executeAlgo = async ({ service, account, contract, config, options = {} })
|
|
|
29
35
|
const tickSize = contract.tickSize || 0.25;
|
|
30
36
|
|
|
31
37
|
const ui = new AlgoUI({
|
|
32
|
-
subtitle: subtitle || (
|
|
38
|
+
subtitle: subtitle || (supervisionEnabled ? 'HQX + AI SUPERVISION' : 'HQX Ultra Scalping'),
|
|
33
39
|
mode: 'one-account'
|
|
34
40
|
});
|
|
35
41
|
|
|
@@ -57,8 +63,8 @@ const executeAlgo = async ({ service, account, contract, config, options = {} })
|
|
|
57
63
|
let pendingOrder = false;
|
|
58
64
|
let tickCount = 0;
|
|
59
65
|
|
|
60
|
-
//
|
|
61
|
-
const aiContext = { recentTicks: [], recentSignals: [], maxTicks: 100 };
|
|
66
|
+
// Context for AI supervision
|
|
67
|
+
const aiContext = { recentTicks: [], recentSignals: [], recentTrades: [], maxTicks: 100 };
|
|
62
68
|
|
|
63
69
|
// Initialize Strategy
|
|
64
70
|
const strategy = new M1({ tickSize });
|
|
@@ -68,32 +74,68 @@ const executeAlgo = async ({ service, account, contract, config, options = {} })
|
|
|
68
74
|
const marketFeed = new MarketDataFeed({ propfirm: account.propfirm });
|
|
69
75
|
|
|
70
76
|
// Log startup
|
|
71
|
-
ui.addLog('info', `Strategy: ${
|
|
77
|
+
ui.addLog('info', `Strategy: ${supervisionEnabled ? 'HQX + AI Supervision' : 'HQX Ultra Scalping'}`);
|
|
72
78
|
ui.addLog('info', `Account: ${accountName}`);
|
|
73
79
|
ui.addLog('info', `Symbol: ${symbolName} | Qty: ${contracts}`);
|
|
74
80
|
ui.addLog('info', `Target: $${dailyTarget} | Risk: $${maxRisk}`);
|
|
75
|
-
if (
|
|
81
|
+
if (supervisionEnabled) {
|
|
82
|
+
const agentCount = supervisionEngine.getActiveCount();
|
|
83
|
+
ui.addLog('info', `AI Agents: ${agentCount} active`);
|
|
84
|
+
}
|
|
76
85
|
ui.addLog('info', 'Connecting to market data...');
|
|
77
86
|
|
|
78
87
|
// Handle strategy signals
|
|
79
88
|
strategy.on('signal', async (signal) => {
|
|
80
89
|
if (!running || pendingOrder || currentPosition !== 0) return;
|
|
81
90
|
|
|
82
|
-
|
|
91
|
+
let { direction, entry, stopLoss, takeProfit, confidence } = signal;
|
|
92
|
+
let orderSize = contracts;
|
|
83
93
|
|
|
84
94
|
aiContext.recentSignals.push({ ...signal, timestamp: Date.now() });
|
|
85
95
|
if (aiContext.recentSignals.length > 10) aiContext.recentSignals.shift();
|
|
86
96
|
|
|
87
97
|
ui.addLog('info', `Signal: ${direction.toUpperCase()} @ ${entry.toFixed(2)} (${(confidence * 100).toFixed(0)}%)`);
|
|
88
98
|
|
|
89
|
-
// AI Supervision
|
|
90
|
-
if (
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
99
|
+
// Multi-Agent AI Supervision
|
|
100
|
+
if (supervisionEnabled && supervisionEngine) {
|
|
101
|
+
ui.addLog('info', 'AI analyzing signal...');
|
|
102
|
+
|
|
103
|
+
const supervisionResult = await supervisionEngine.supervise({
|
|
104
|
+
symbolId: symbolName,
|
|
105
|
+
signal: { direction, entry, stopLoss, takeProfit, confidence, size: contracts },
|
|
106
|
+
recentTicks: aiContext.recentTicks,
|
|
107
|
+
recentSignals: aiContext.recentSignals,
|
|
108
|
+
recentTrades: aiContext.recentTrades,
|
|
109
|
+
stats,
|
|
110
|
+
config: { dailyTarget, maxRisk }
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
if (!supervisionResult.success) {
|
|
114
|
+
ui.addLog('info', `AI: ${supervisionResult.reason || 'Error'}`);
|
|
115
|
+
} else if (supervisionResult.decision === 'reject') {
|
|
116
|
+
ui.addLog('info', `AI rejected (${supervisionResult.confidence}%): ${supervisionResult.reason}`);
|
|
94
117
|
return;
|
|
118
|
+
} else {
|
|
119
|
+
// Apply optimizations
|
|
120
|
+
const opt = supervisionResult.optimizedSignal;
|
|
121
|
+
if (opt.aiOptimized) {
|
|
122
|
+
if (opt.entry !== entry) entry = opt.entry;
|
|
123
|
+
if (opt.stopLoss !== stopLoss) stopLoss = opt.stopLoss;
|
|
124
|
+
if (opt.takeProfit !== takeProfit) takeProfit = opt.takeProfit;
|
|
125
|
+
if (opt.size && opt.size !== contracts) orderSize = opt.size;
|
|
126
|
+
}
|
|
127
|
+
const action = supervisionResult.decision === 'modify' ? 'optimized' : 'approved';
|
|
128
|
+
ui.addLog('info', `AI ${action} (${supervisionResult.confidence}%): ${supervisionResult.reason}`);
|
|
129
|
+
|
|
130
|
+
// Check timing
|
|
131
|
+
if (opt.aiTiming === 'wait') {
|
|
132
|
+
ui.addLog('info', 'AI: Wait for better entry');
|
|
133
|
+
return;
|
|
134
|
+
} else if (opt.aiTiming === 'cancel') {
|
|
135
|
+
ui.addLog('info', 'AI: Signal cancelled');
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
95
138
|
}
|
|
96
|
-
ui.addLog('info', `AI approved: ${aiDecision.reason || 'OK'}`);
|
|
97
139
|
}
|
|
98
140
|
|
|
99
141
|
// Place order
|
|
@@ -105,24 +147,24 @@ const executeAlgo = async ({ service, account, contract, config, options = {} })
|
|
|
105
147
|
contractId: contractId,
|
|
106
148
|
type: 2,
|
|
107
149
|
side: orderSide,
|
|
108
|
-
size:
|
|
150
|
+
size: orderSize
|
|
109
151
|
});
|
|
110
152
|
|
|
111
153
|
if (orderResult.success) {
|
|
112
|
-
currentPosition = direction === 'long' ?
|
|
154
|
+
currentPosition = direction === 'long' ? orderSize : -orderSize;
|
|
113
155
|
stats.trades++;
|
|
114
156
|
ui.addLog('fill_' + (direction === 'long' ? 'buy' : 'sell'),
|
|
115
|
-
`OPENED ${direction.toUpperCase()} ${
|
|
157
|
+
`OPENED ${direction.toUpperCase()} ${orderSize}x @ market`);
|
|
116
158
|
|
|
117
159
|
// Bracket orders
|
|
118
160
|
if (stopLoss && takeProfit) {
|
|
119
161
|
await service.placeOrder({
|
|
120
162
|
accountId: account.accountId, contractId, type: 4,
|
|
121
|
-
side: direction === 'long' ? 1 : 0, size:
|
|
163
|
+
side: direction === 'long' ? 1 : 0, size: orderSize, stopPrice: stopLoss
|
|
122
164
|
});
|
|
123
165
|
await service.placeOrder({
|
|
124
166
|
accountId: account.accountId, contractId, type: 1,
|
|
125
|
-
side: direction === 'long' ? 1 : 0, size:
|
|
167
|
+
side: direction === 'long' ? 1 : 0, size: orderSize, limitPrice: takeProfit
|
|
126
168
|
});
|
|
127
169
|
ui.addLog('info', `SL: ${stopLoss.toFixed(2)} | TP: ${takeProfit.toFixed(2)}`);
|
|
128
170
|
}
|