hedgequantx 2.5.13 ā 2.5.15
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 +9 -3
- package/src/menus/ai-agent.js +297 -50
- package/src/menus/dashboard.js +9 -13
- package/src/pages/algo/index.js +230 -35
- package/src/services/ai/index.js +294 -51
- package/src/services/ai/supervisor.js +713 -0
- package/src/services/ai/token-scanner.js +2 -1
|
@@ -0,0 +1,713 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AI Supervisor
|
|
3
|
+
* Manages AI supervision of algo trading
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
let aiService = null;
|
|
7
|
+
|
|
8
|
+
// Lazy load to avoid circular dependency
|
|
9
|
+
const getAIService = () => {
|
|
10
|
+
if (!aiService) {
|
|
11
|
+
aiService = require('./index');
|
|
12
|
+
}
|
|
13
|
+
return aiService;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
// In-memory supervision sessions
|
|
17
|
+
const supervisionSessions = new Map();
|
|
18
|
+
|
|
19
|
+
// Consensus supervision interval
|
|
20
|
+
let consensusInterval = null;
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* AI Supervisor Class
|
|
24
|
+
*/
|
|
25
|
+
class AISupervisor {
|
|
26
|
+
/**
|
|
27
|
+
* Start supervision for an agent
|
|
28
|
+
*/
|
|
29
|
+
static start(agentId, targetAlgo) {
|
|
30
|
+
if (supervisionSessions.has(agentId)) {
|
|
31
|
+
console.log(`Supervision already active for agent ${agentId}`);
|
|
32
|
+
return false;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const agentInfo = getAIService().getAgent(agentId);
|
|
36
|
+
if (!agentInfo) {
|
|
37
|
+
console.log(`Agent ${agentId} not found`);
|
|
38
|
+
return false;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const session = {
|
|
42
|
+
agentId,
|
|
43
|
+
agent: agentInfo,
|
|
44
|
+
algo: targetAlgo,
|
|
45
|
+
startTime: Date.now(),
|
|
46
|
+
lastCheck: Date.now(),
|
|
47
|
+
decisions: [],
|
|
48
|
+
metrics: {
|
|
49
|
+
totalDecisions: 0,
|
|
50
|
+
interventions: 0,
|
|
51
|
+
optimizations: 0,
|
|
52
|
+
riskWarnings: 0
|
|
53
|
+
},
|
|
54
|
+
interval: null
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
// Check if this is the first agent or if we need consensus mode
|
|
58
|
+
const currentSessionCount = supervisionSessions.size;
|
|
59
|
+
|
|
60
|
+
if (currentSessionCount === 0) {
|
|
61
|
+
// First agent - start individual supervision
|
|
62
|
+
session.interval = setInterval(() => {
|
|
63
|
+
this.supervise(agentId);
|
|
64
|
+
}, 5000);
|
|
65
|
+
|
|
66
|
+
supervisionSessions.set(agentId, session);
|
|
67
|
+
console.log(`AI supervision started: ${agentInfo.name} monitoring HQX algo`);
|
|
68
|
+
console.log(` Mode: Single agent supervision`);
|
|
69
|
+
|
|
70
|
+
} else {
|
|
71
|
+
// Additional agent - switch to consensus mode
|
|
72
|
+
console.log(`Adding ${agentInfo.name} to supervision`);
|
|
73
|
+
console.log(` Total agents: ${currentSessionCount + 1}`);
|
|
74
|
+
|
|
75
|
+
// Stop individual loops and start consensus loop
|
|
76
|
+
this.switchToConsensusMode();
|
|
77
|
+
|
|
78
|
+
session.interval = null; // Will use consensus loop
|
|
79
|
+
supervisionSessions.set(agentId, session);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
return true;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Switch to consensus mode when multiple agents
|
|
87
|
+
*/
|
|
88
|
+
static switchToConsensusMode() {
|
|
89
|
+
console.log(`\nš¤ SWITCHING TO MULTI-AGENT CONSENSUS MODE`);
|
|
90
|
+
|
|
91
|
+
// Clear all individual intervals
|
|
92
|
+
for (const [agentId, session] of supervisionSessions.entries()) {
|
|
93
|
+
if (session.interval) {
|
|
94
|
+
clearInterval(session.interval);
|
|
95
|
+
session.interval = null;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// Start single consensus loop
|
|
100
|
+
if (!this.consensusInterval) {
|
|
101
|
+
this.consensusInterval = setInterval(() => {
|
|
102
|
+
this.superviseConsensus();
|
|
103
|
+
}, 5000);
|
|
104
|
+
|
|
105
|
+
console.log(` Consensus loop started - all agents will vote on decisions`);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Start supervision for an agent
|
|
111
|
+
*/
|
|
112
|
+
static start(agentId, targetAlgo) {
|
|
113
|
+
if (supervisionSessions.has(agentId)) {
|
|
114
|
+
console.log(`Supervision already active for agent ${agentId}`);
|
|
115
|
+
return false;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
const agent = getAIService().getAgent(agentId);
|
|
119
|
+
if (!agent) {
|
|
120
|
+
console.log(`Agent ${agentId} not found`);
|
|
121
|
+
return false;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
const session = {
|
|
125
|
+
agentId,
|
|
126
|
+
agent: agent,
|
|
127
|
+
algo: targetAlgo,
|
|
128
|
+
startTime: Date.now(),
|
|
129
|
+
lastCheck: Date.now(),
|
|
130
|
+
decisions: [],
|
|
131
|
+
metrics: {
|
|
132
|
+
totalDecisions: 0,
|
|
133
|
+
interventions: 0,
|
|
134
|
+
optimizations: 0,
|
|
135
|
+
riskWarnings: 0
|
|
136
|
+
},
|
|
137
|
+
interval: null
|
|
138
|
+
};
|
|
139
|
+
|
|
140
|
+
// Start supervision loop (every 5 seconds)
|
|
141
|
+
session.interval = setInterval(() => {
|
|
142
|
+
this.supervise(agentId);
|
|
143
|
+
}, 5000);
|
|
144
|
+
|
|
145
|
+
supervisionSessions.set(agentId, session);
|
|
146
|
+
console.log(`AI supervision started: ${agent.name} monitoring HQX algo`);
|
|
147
|
+
|
|
148
|
+
return true;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Stop supervision for an agent
|
|
153
|
+
*/
|
|
154
|
+
static stop(agentId) {
|
|
155
|
+
const session = supervisionSessions.get(agentId);
|
|
156
|
+
if (!session) {
|
|
157
|
+
return false;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
if (session.interval) {
|
|
161
|
+
clearInterval(session.interval);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
const duration = Date.now() - session.startTime;
|
|
165
|
+
supervisionSessions.delete(agentId);
|
|
166
|
+
|
|
167
|
+
console.log(`AI supervision stopped for ${session.agent.name}`);
|
|
168
|
+
console.log(`Session duration: ${Math.round(duration / 1000)}s`);
|
|
169
|
+
console.log(`Decisions: ${session.metrics.totalDecisions}, Interventions: ${session.metrics.interventions}`);
|
|
170
|
+
|
|
171
|
+
// Check if we need to switch back to single agent mode
|
|
172
|
+
const remainingSessions = supervisionSessions.size;
|
|
173
|
+
if (remainingSessions === 1 && consensusInterval) {
|
|
174
|
+
// Last agent - switch back to single mode
|
|
175
|
+
clearInterval(consensusInterval);
|
|
176
|
+
consensusInterval = null;
|
|
177
|
+
|
|
178
|
+
const remainingSession = supervisionSessions.values().next().value;
|
|
179
|
+
if (remainingSession && !remainingSession.interval) {
|
|
180
|
+
const remainingAgentId = remainingSession.agentId;
|
|
181
|
+
remainingSession.interval = setInterval(() => {
|
|
182
|
+
this.supervise(remainingAgentId);
|
|
183
|
+
}, 5000);
|
|
184
|
+
|
|
185
|
+
console.log(`Switched back to single agent supervision for ${remainingSession.agent.name}`);
|
|
186
|
+
}
|
|
187
|
+
} else if (remainingSessions === 0 && consensusInterval) {
|
|
188
|
+
// No agents left
|
|
189
|
+
clearInterval(consensusInterval);
|
|
190
|
+
consensusInterval = null;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
return true;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* Main supervision loop - single agent
|
|
198
|
+
*/
|
|
199
|
+
static async supervise(agentId) {
|
|
200
|
+
const session = supervisionSessions.get(agentId);
|
|
201
|
+
if (!session) return;
|
|
202
|
+
|
|
203
|
+
try {
|
|
204
|
+
session.lastCheck = Date.now();
|
|
205
|
+
|
|
206
|
+
// Get algo status
|
|
207
|
+
const algoStatus = this.getAlgoStatus(session.algo);
|
|
208
|
+
const marketData = this.getMarketData();
|
|
209
|
+
const riskMetrics = this.getRiskMetrics(session.algo);
|
|
210
|
+
|
|
211
|
+
// Make AI decision
|
|
212
|
+
const decision = await this.makeAIDecision(session.agent, algoStatus, marketData, riskMetrics);
|
|
213
|
+
|
|
214
|
+
if (decision) {
|
|
215
|
+
session.decisions.push(decision);
|
|
216
|
+
session.metrics.totalDecisions++;
|
|
217
|
+
|
|
218
|
+
// Execute decision if confidence is high enough
|
|
219
|
+
if (decision.confidence > 75) {
|
|
220
|
+
await this.executeDecision(session, decision);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
} catch (error) {
|
|
225
|
+
console.log(`Supervision error for agent ${agentId}: ${error.message}`);
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* Multi-agent consensus supervision loop
|
|
231
|
+
*/
|
|
232
|
+
static async superviseConsensus() {
|
|
233
|
+
const allSessions = Array.from(supervisionSessions.entries());
|
|
234
|
+
if (allSessions.length === 0) return;
|
|
235
|
+
|
|
236
|
+
try {
|
|
237
|
+
// Get all active agents
|
|
238
|
+
const allAgents = allSessions.map(([id, session]) => session.agent).filter(Boolean);
|
|
239
|
+
|
|
240
|
+
if (allAgents.length === 0) return;
|
|
241
|
+
|
|
242
|
+
console.log(`š¤ MULTI-AGENT CONSENSUS: ${allAgents.length} agents participating`);
|
|
243
|
+
|
|
244
|
+
// Get algo status (use same algo for all agents)
|
|
245
|
+
const mockAlgo = { name: 'HQX Ultra Scalping' }; // Would be real algo
|
|
246
|
+
const algoStatus = this.getAlgoStatus(mockAlgo);
|
|
247
|
+
const marketData = this.getMarketData();
|
|
248
|
+
const riskMetrics = this.getRiskMetrics(mockAlgo);
|
|
249
|
+
|
|
250
|
+
// Make consensus decision
|
|
251
|
+
const consensusDecision = await this.makeConsensusDecision(allAgents, algoStatus, marketData, riskMetrics);
|
|
252
|
+
|
|
253
|
+
if (consensusDecision) {
|
|
254
|
+
// Update all sessions with the consensus decision
|
|
255
|
+
for (const [agentId, session] of allSessions) {
|
|
256
|
+
session.decisions.push({
|
|
257
|
+
...consensusDecision,
|
|
258
|
+
timestamp: Date.now(),
|
|
259
|
+
isConsensus: true,
|
|
260
|
+
participantAgents: consensusDecision.agentNames
|
|
261
|
+
});
|
|
262
|
+
|
|
263
|
+
session.metrics.totalDecisions++;
|
|
264
|
+
|
|
265
|
+
// Execute decision if confidence is high enough (lower threshold for consensus)
|
|
266
|
+
if (consensusDecision.confidence > 70) {
|
|
267
|
+
await this.executeConsensusDecision(session, consensusDecision);
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
} catch (error) {
|
|
273
|
+
console.log(`Consensus supervision error: ${error.message}`);
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
/**
|
|
278
|
+
* Execute multi-agent consensus decision
|
|
279
|
+
*/
|
|
280
|
+
static async executeConsensusDecision(session, decision) {
|
|
281
|
+
const { agent, metrics } = session;
|
|
282
|
+
|
|
283
|
+
console.log(`\nšÆ MULTI-AGENT CONSENSUS ACTION:`);
|
|
284
|
+
console.log(` Agents: ${decision.agentNames.join(', ')}`);
|
|
285
|
+
console.log(` Type: ${decision.type}`);
|
|
286
|
+
console.log(` Confidence: ${decision.confidence}%`);
|
|
287
|
+
console.log(` Reason: ${decision.reason}`);
|
|
288
|
+
|
|
289
|
+
// Update metrics
|
|
290
|
+
switch (decision.type) {
|
|
291
|
+
case 'ADJUST_SIZE':
|
|
292
|
+
case 'ADJUST_PARAMETERS':
|
|
293
|
+
case 'ADJUST_STRATEGY':
|
|
294
|
+
metrics.optimizations++;
|
|
295
|
+
console.log(` Action: Consensus optimization - ${decision.agentNames.length} agents agree`);
|
|
296
|
+
break;
|
|
297
|
+
case 'PAUSE_TRADING':
|
|
298
|
+
case 'RISK_ADJUSTMENT':
|
|
299
|
+
metrics.interventions++;
|
|
300
|
+
console.log(` Action: Consensus risk intervention - ${decision.agentNames.length} agents agree`);
|
|
301
|
+
break;
|
|
302
|
+
case 'ADJUST_FREQUENCY':
|
|
303
|
+
metrics.interventions++;
|
|
304
|
+
console.log(` Action: Consensus frequency adjustment - ${decision.agentNames.length} agents agree`);
|
|
305
|
+
break;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
// In real implementation, this would actually modify the algo
|
|
309
|
+
console.log(` Status: Consensus decision executed across all agents\n`);
|
|
310
|
+
|
|
311
|
+
return decision;
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
/**
|
|
315
|
+
* Get algo status (placeholder for real implementation)
|
|
316
|
+
*/
|
|
317
|
+
static getAlgoStatus(algo) {
|
|
318
|
+
// This would interface with HQX Ultra Scalping
|
|
319
|
+
// For now, return mock data
|
|
320
|
+
return {
|
|
321
|
+
active: true,
|
|
322
|
+
positions: 1,
|
|
323
|
+
currentPnL: 145.50,
|
|
324
|
+
dayTrades: 8,
|
|
325
|
+
winRate: 0.75,
|
|
326
|
+
avgWin: 25.30,
|
|
327
|
+
avgLoss: 8.20,
|
|
328
|
+
lastTradeTime: Date.now() - 120000, // 2 minutes ago
|
|
329
|
+
currentStrategy: 'momentum_scalping',
|
|
330
|
+
parameters: {
|
|
331
|
+
tradeSize: 2,
|
|
332
|
+
stopLoss: 3,
|
|
333
|
+
takeProfit: 6,
|
|
334
|
+
maxPositions: 3
|
|
335
|
+
}
|
|
336
|
+
};
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
/**
|
|
340
|
+
* Get market data (placeholder)
|
|
341
|
+
*/
|
|
342
|
+
static getMarketData() {
|
|
343
|
+
// This would get real market data
|
|
344
|
+
return {
|
|
345
|
+
symbol: 'ES',
|
|
346
|
+
price: 4502.25,
|
|
347
|
+
change: 12.50,
|
|
348
|
+
volume: 1250000,
|
|
349
|
+
volatility: 0.018,
|
|
350
|
+
trend: 'bullish',
|
|
351
|
+
momentum: 'strong',
|
|
352
|
+
timeframe: '1m'
|
|
353
|
+
};
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
/**
|
|
357
|
+
* Get risk metrics (placeholder)
|
|
358
|
+
*/
|
|
359
|
+
static getRiskMetrics(algo) {
|
|
360
|
+
return {
|
|
361
|
+
maxDrawdown: 0.025, // 2.5%
|
|
362
|
+
currentDrawdown: 0.008, // 0.8%
|
|
363
|
+
exposure: 0.65, // 65% of max
|
|
364
|
+
dailyLoss: -45.30,
|
|
365
|
+
sharpeRatio: 1.8,
|
|
366
|
+
var95: 125.50 // Value at Risk
|
|
367
|
+
};
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
/**
|
|
371
|
+
* Make AI decision for single agent
|
|
372
|
+
*/
|
|
373
|
+
static async makeAIDecision(agent, algoStatus, marketData, riskMetrics) {
|
|
374
|
+
// Simulate AI decision making based on provider
|
|
375
|
+
const decisions = [];
|
|
376
|
+
|
|
377
|
+
switch (agent.providerId) {
|
|
378
|
+
case 'anthropic':
|
|
379
|
+
// Claude: Technical analysis expert
|
|
380
|
+
if (marketData.volatility > 0.025 && algoStatus.parameters.tradeSize > 1) {
|
|
381
|
+
decisions.push({
|
|
382
|
+
type: 'ADJUST_SIZE',
|
|
383
|
+
action: 'REDUCE',
|
|
384
|
+
currentSize: algoStatus.parameters.tradeSize,
|
|
385
|
+
suggestedSize: Math.max(1, Math.floor(algoStatus.parameters.tradeSize * 0.7)),
|
|
386
|
+
reason: 'High volatility detected - reducing position size',
|
|
387
|
+
confidence: 85,
|
|
388
|
+
agentType: 'technical',
|
|
389
|
+
urgency: 'medium'
|
|
390
|
+
});
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
if (riskMetrics.currentDrawdown > 0.02) {
|
|
394
|
+
decisions.push({
|
|
395
|
+
type: 'PAUSE_TRADING',
|
|
396
|
+
reason: 'Drawdown exceeding 2% - pausing to preserve capital',
|
|
397
|
+
confidence: 92,
|
|
398
|
+
agentType: 'technical',
|
|
399
|
+
urgency: 'high'
|
|
400
|
+
});
|
|
401
|
+
}
|
|
402
|
+
break;
|
|
403
|
+
|
|
404
|
+
case 'openai':
|
|
405
|
+
// OpenAI: Parameter optimization expert
|
|
406
|
+
if (marketData.trend === 'bullish' && marketData.momentum === 'strong') {
|
|
407
|
+
decisions.push({
|
|
408
|
+
type: 'ADJUST_PARAMETERS',
|
|
409
|
+
parameter: 'takeProfit',
|
|
410
|
+
current: algoStatus.parameters.takeProfit,
|
|
411
|
+
suggested: algoStatus.parameters.takeProfit * 1.25,
|
|
412
|
+
reason: 'Strong bullish trend - increasing take profit target',
|
|
413
|
+
confidence: 78,
|
|
414
|
+
agentType: 'optimization',
|
|
415
|
+
urgency: 'low'
|
|
416
|
+
});
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
// OpenAI suggests scaling in consolidation
|
|
420
|
+
if (marketData.volatility < 0.015) {
|
|
421
|
+
decisions.push({
|
|
422
|
+
type: 'ADJUST_STRATEGY',
|
|
423
|
+
suggestedStrategy: 'scaling',
|
|
424
|
+
reason: 'Low volatility - switching to scaling strategy',
|
|
425
|
+
confidence: 72,
|
|
426
|
+
agentType: 'optimization',
|
|
427
|
+
urgency: 'medium'
|
|
428
|
+
});
|
|
429
|
+
}
|
|
430
|
+
break;
|
|
431
|
+
|
|
432
|
+
case 'deepseek':
|
|
433
|
+
// DeepSeek: Trading and prop firm expert
|
|
434
|
+
if (algoStatus.dayTrades > 8) {
|
|
435
|
+
decisions.push({
|
|
436
|
+
type: 'ADJUST_FREQUENCY',
|
|
437
|
+
action: 'REDUCE',
|
|
438
|
+
reason: 'Overtrading detected - reducing trade frequency',
|
|
439
|
+
confidence: 88,
|
|
440
|
+
agentType: 'trading',
|
|
441
|
+
urgency: 'high'
|
|
442
|
+
});
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
// DeepSeek focuses on prop firm rules
|
|
446
|
+
if (riskMetrics.dailyLoss < -100) {
|
|
447
|
+
decisions.push({
|
|
448
|
+
type: 'RISK_ADJUSTMENT',
|
|
449
|
+
adjustment: 'HALF_SIZE',
|
|
450
|
+
reason: 'Daily loss approaching limit - halving position size',
|
|
451
|
+
confidence: 95,
|
|
452
|
+
agentType: 'trading',
|
|
453
|
+
urgency: 'critical'
|
|
454
|
+
});
|
|
455
|
+
}
|
|
456
|
+
break;
|
|
457
|
+
|
|
458
|
+
default:
|
|
459
|
+
// Generic decision for other providers
|
|
460
|
+
if (marketData.volatility > 0.03) {
|
|
461
|
+
decisions.push({
|
|
462
|
+
type: 'ADJUST_SIZE',
|
|
463
|
+
action: 'REDUCE',
|
|
464
|
+
suggestedSize: Math.max(1, Math.floor(algoStatus.parameters.tradeSize * 0.6)),
|
|
465
|
+
reason: 'Very high volatility - significant size reduction',
|
|
466
|
+
confidence: 80,
|
|
467
|
+
agentType: 'generic',
|
|
468
|
+
urgency: 'medium'
|
|
469
|
+
});
|
|
470
|
+
}
|
|
471
|
+
break;
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
return decisions.length > 0 ? decisions[0] : null;
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
/**
|
|
478
|
+
* Make multi-agent consensus decision
|
|
479
|
+
*/
|
|
480
|
+
static async makeConsensusDecision(allAgents, algoStatus, marketData, riskMetrics) {
|
|
481
|
+
if (!allAgents || allAgents.length === 0) return null;
|
|
482
|
+
|
|
483
|
+
if (allAgents.length === 1) {
|
|
484
|
+
// Single agent - use normal decision
|
|
485
|
+
return await this.makeAIDecision(allAgents[0], algoStatus, marketData, riskMetrics);
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
console.log(`š¤ CONSENSUS: Getting decisions from ${allAgents.length} agents...`);
|
|
489
|
+
|
|
490
|
+
// Get decision from each agent
|
|
491
|
+
const agentDecisions = [];
|
|
492
|
+
|
|
493
|
+
for (const agent of allAgents) {
|
|
494
|
+
const decision = await this.makeAIDecision(agent, algoStatus, marketData, riskMetrics);
|
|
495
|
+
|
|
496
|
+
if (decision) {
|
|
497
|
+
agentDecisions.push({
|
|
498
|
+
agentId: agent.id,
|
|
499
|
+
agentName: agent.name,
|
|
500
|
+
providerId: agent.providerId,
|
|
501
|
+
agentType: decision.agentType,
|
|
502
|
+
...decision
|
|
503
|
+
});
|
|
504
|
+
|
|
505
|
+
console.log(` ${agent.name} (${agent.providerId}): ${decision.type} (${decision.confidence}% confidence)`);
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
if (agentDecisions.length === 0) {
|
|
510
|
+
console.log(' No consensus - all agents agree current parameters are optimal');
|
|
511
|
+
return null;
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
// Group decisions by type
|
|
515
|
+
const decisionGroups = {};
|
|
516
|
+
for (const decision of agentDecisions) {
|
|
517
|
+
const key = `${decision.type}_${decision.action || ''}_${decision.parameter || ''}`;
|
|
518
|
+
if (!decisionGroups[key]) {
|
|
519
|
+
decisionGroups[key] = [];
|
|
520
|
+
}
|
|
521
|
+
decisionGroups[key].push(decision);
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
// Weight agents by their expertise
|
|
525
|
+
const agentWeights = {
|
|
526
|
+
'anthropic': { technical: 1.2, optimization: 1.0, trading: 1.0, generic: 1.1 },
|
|
527
|
+
'openai': { technical: 1.0, optimization: 1.3, trading: 0.9, generic: 1.2 },
|
|
528
|
+
'deepseek': { technical: 0.9, optimization: 1.0, trading: 1.4, generic: 1.1 },
|
|
529
|
+
'groq': { technical: 1.1, optimization: 1.0, trading: 1.2, generic: 1.0 },
|
|
530
|
+
'gemini': { technical: 1.0, optimization: 1.1, trading: 1.0, generic: 1.2 }
|
|
531
|
+
};
|
|
532
|
+
|
|
533
|
+
// Calculate weighted consensus for each decision type
|
|
534
|
+
const consensusResults = [];
|
|
535
|
+
|
|
536
|
+
for (const [decisionKey, group] of Object.entries(decisionGroups)) {
|
|
537
|
+
let totalWeight = 0;
|
|
538
|
+
let weightedConfidence = 0;
|
|
539
|
+
let agentNames = [];
|
|
540
|
+
|
|
541
|
+
for (const decision of group) {
|
|
542
|
+
const weight = agentWeights[decision.providerId]?.[decision.agentType] || 1.0;
|
|
543
|
+
totalWeight += weight;
|
|
544
|
+
weightedConfidence += decision.confidence * weight;
|
|
545
|
+
agentNames.push(decision.agentName);
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
const consensusConfidence = weightedConfidence / totalWeight;
|
|
549
|
+
|
|
550
|
+
consensusResults.push({
|
|
551
|
+
type: group[0].type,
|
|
552
|
+
action: group[0].action,
|
|
553
|
+
parameter: group[0].parameter,
|
|
554
|
+
currentSize: group[0].currentSize,
|
|
555
|
+
suggestedSize: group[0].suggestedSize,
|
|
556
|
+
current: group[0].current,
|
|
557
|
+
suggested: group[0].suggested,
|
|
558
|
+
adjustment: group[0].adjustment,
|
|
559
|
+
suggestedStrategy: group[0].suggestedStrategy,
|
|
560
|
+
reason: this.buildConsensusReason(group, decisionKey),
|
|
561
|
+
confidence: Math.round(consensusConfidence),
|
|
562
|
+
agentCount: group.length,
|
|
563
|
+
agentNames: [...new Set(agentNames)], // Unique names
|
|
564
|
+
agentTypes: [...new Set(group.map(d => d.agentType))],
|
|
565
|
+
urgency: this.calculateUrgency(group),
|
|
566
|
+
consensusStrength: totalWeight
|
|
567
|
+
});
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
// Return highest confidence consensus decision
|
|
571
|
+
if (consensusResults.length > 0) {
|
|
572
|
+
const bestDecision = consensusResults.sort((a, b) => b.confidence - a.confidence)[0];
|
|
573
|
+
|
|
574
|
+
console.log(`šÆ CONSENSUS DECISION:`);
|
|
575
|
+
console.log(` Type: ${bestDecision.type}`);
|
|
576
|
+
console.log(` Confidence: ${bestDecision.confidence}%`);
|
|
577
|
+
console.log(` Agents: ${bestDecision.agentNames.join(', ')}`);
|
|
578
|
+
console.log(` Reason: ${bestDecision.reason}`);
|
|
579
|
+
|
|
580
|
+
return bestDecision;
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
return null;
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
/**
|
|
587
|
+
* Build consensus reason
|
|
588
|
+
*/
|
|
589
|
+
static buildConsensusReason(group, decisionKey) {
|
|
590
|
+
const agentNames = group.map(d => d.agentName);
|
|
591
|
+
const agentTypes = [...new Set(group.map(d => d.agentType))];
|
|
592
|
+
|
|
593
|
+
let expertise = '';
|
|
594
|
+
if (agentTypes.length === 1) {
|
|
595
|
+
const typeMap = {
|
|
596
|
+
'technical': 'technical analysis',
|
|
597
|
+
'optimization': 'parameter optimization',
|
|
598
|
+
'trading': 'trading strategy',
|
|
599
|
+
'generic': 'general analysis'
|
|
600
|
+
};
|
|
601
|
+
expertise = `based on ${typeMap[agentTypes[0]]}`;
|
|
602
|
+
} else {
|
|
603
|
+
expertise = `based on multiple expertises (${agentTypes.join(', ')})`;
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
return `Consensus from ${agentNames.join(', ')} - ${expertise}`;
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
/**
|
|
610
|
+
* Calculate urgency from consensus
|
|
611
|
+
*/
|
|
612
|
+
static calculateUrgency(group) {
|
|
613
|
+
const urgencyLevels = { 'low': 1, 'medium': 2, 'high': 3, 'critical': 4 };
|
|
614
|
+
const maxUrgency = Math.max(...group.map(d => urgencyLevels[d.urgency] || 1));
|
|
615
|
+
|
|
616
|
+
const urgencyMap = { 1: 'low', 2: 'medium', 3: 'high', 4: 'critical' };
|
|
617
|
+
return urgencyMap[maxUrgency];
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
/**
|
|
621
|
+
* Execute AI decision
|
|
622
|
+
*/
|
|
623
|
+
static async executeDecision(session, decision) {
|
|
624
|
+
const { agent, algo, metrics } = session;
|
|
625
|
+
|
|
626
|
+
console.log(`\nš¤ ${agent.name} Decision:`);
|
|
627
|
+
console.log(` Type: ${decision.type}`);
|
|
628
|
+
console.log(` Reason: ${decision.reason}`);
|
|
629
|
+
console.log(` Confidence: ${decision.confidence}%`);
|
|
630
|
+
|
|
631
|
+
// Update metrics
|
|
632
|
+
switch (decision.type) {
|
|
633
|
+
case 'ADJUST_SIZE':
|
|
634
|
+
case 'ADJUST_PARAMETERS':
|
|
635
|
+
metrics.optimizations++;
|
|
636
|
+
console.log(` Action: Optimizing algo parameters`);
|
|
637
|
+
break;
|
|
638
|
+
case 'PAUSE_TRADING':
|
|
639
|
+
case 'REDUCE_EXPOSURE':
|
|
640
|
+
metrics.interventions++;
|
|
641
|
+
console.log(` Action: Risk intervention - ${decision.reason.toLowerCase()}`);
|
|
642
|
+
break;
|
|
643
|
+
case 'RISK_WARNING':
|
|
644
|
+
metrics.riskWarnings++;
|
|
645
|
+
console.log(` Action: Risk warning issued`);
|
|
646
|
+
break;
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
// In real implementation, this would actually modify the algo
|
|
650
|
+
// For now, just log the decision
|
|
651
|
+
console.log(` Status: Decision logged for manual review\n`);
|
|
652
|
+
|
|
653
|
+
return decision;
|
|
654
|
+
}
|
|
655
|
+
|
|
656
|
+
/**
|
|
657
|
+
* Get supervision status for an agent
|
|
658
|
+
*/
|
|
659
|
+
static getStatus(agentId) {
|
|
660
|
+
const session = supervisionSessions.get(agentId);
|
|
661
|
+
if (!session) {
|
|
662
|
+
return { active: false };
|
|
663
|
+
}
|
|
664
|
+
|
|
665
|
+
const duration = Date.now() - session.startTime;
|
|
666
|
+
return {
|
|
667
|
+
active: true,
|
|
668
|
+
agentName: session.agent.name,
|
|
669
|
+
duration: Math.round(duration / 1000),
|
|
670
|
+
decisions: session.metrics.totalDecisions,
|
|
671
|
+
interventions: session.metrics.interventions,
|
|
672
|
+
optimizations: session.metrics.optimizations,
|
|
673
|
+
lastDecision: session.decisions.length > 0 ? session.decisions[session.decisions.length - 1] : null
|
|
674
|
+
};
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
/**
|
|
678
|
+
* Get all active supervision sessions
|
|
679
|
+
*/
|
|
680
|
+
static getAllStatus() {
|
|
681
|
+
const result = [];
|
|
682
|
+
const isConsensusMode = supervisionSessions.size > 1 && consensusInterval;
|
|
683
|
+
|
|
684
|
+
for (const [agentId, session] of supervisionSessions.entries()) {
|
|
685
|
+
result.push({
|
|
686
|
+
agentId,
|
|
687
|
+
agentName: session.agent.name,
|
|
688
|
+
duration: Date.now() - session.startTime,
|
|
689
|
+
metrics: session.metrics,
|
|
690
|
+
lastDecision: session.decisions.length > 0 ? session.decisions[session.decisions.length - 1] : null,
|
|
691
|
+
mode: isConsensusMode ? 'consensus' : 'single'
|
|
692
|
+
});
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
return {
|
|
696
|
+
sessions: result,
|
|
697
|
+
mode: isConsensusMode ? 'consensus' : 'single',
|
|
698
|
+
totalAgents: supervisionSessions.size
|
|
699
|
+
};
|
|
700
|
+
}
|
|
701
|
+
|
|
702
|
+
/**
|
|
703
|
+
* Stop all supervision sessions
|
|
704
|
+
*/
|
|
705
|
+
static stopAll() {
|
|
706
|
+
const agentIds = Array.from(supervisionSessions.keys());
|
|
707
|
+
for (const agentId of agentIds) {
|
|
708
|
+
this.stop(agentId);
|
|
709
|
+
}
|
|
710
|
+
}
|
|
711
|
+
}
|
|
712
|
+
|
|
713
|
+
module.exports = AISupervisor;
|