hedgequantx 2.6.161 → 2.6.163
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/ai-agent-connect.js +181 -0
- package/src/menus/ai-agent-models.js +219 -0
- package/src/menus/ai-agent-oauth.js +292 -0
- package/src/menus/ai-agent-ui.js +141 -0
- package/src/menus/ai-agent.js +88 -1489
- package/src/pages/algo/copy-engine.js +449 -0
- package/src/pages/algo/copy-trading.js +11 -543
- package/src/pages/algo/smart-logs-data.js +218 -0
- package/src/pages/algo/smart-logs.js +9 -214
- package/src/pages/algo/ui-constants.js +144 -0
- package/src/pages/algo/ui-summary.js +184 -0
- package/src/pages/algo/ui.js +42 -526
- package/src/pages/stats-calculations.js +191 -0
- package/src/pages/stats-ui.js +381 -0
- package/src/pages/stats.js +14 -507
- package/src/services/ai/client-analysis.js +194 -0
- package/src/services/ai/client-models.js +333 -0
- package/src/services/ai/client.js +6 -489
- package/src/services/ai/index.js +2 -257
- package/src/services/ai/providers/direct-providers.js +323 -0
- package/src/services/ai/providers/index.js +8 -472
- package/src/services/ai/providers/other-providers.js +104 -0
- package/src/services/ai/proxy-install.js +249 -0
- package/src/services/ai/proxy-manager.js +29 -411
- package/src/services/ai/proxy-remote.js +161 -0
- package/src/services/ai/supervisor-optimize.js +215 -0
- package/src/services/ai/supervisor-sync.js +178 -0
- package/src/services/ai/supervisor.js +50 -515
- package/src/services/ai/validation.js +250 -0
- package/src/services/hqx-server-events.js +110 -0
- package/src/services/hqx-server-handlers.js +217 -0
- package/src/services/hqx-server-latency.js +136 -0
- package/src/services/hqx-server.js +51 -403
- package/src/services/position-constants.js +28 -0
- package/src/services/position-exit-logic.js +174 -0
- package/src/services/position-manager.js +90 -629
- package/src/services/position-momentum.js +206 -0
- package/src/services/projectx/accounts.js +142 -0
- package/src/services/projectx/index.js +40 -289
- package/src/services/projectx/trading.js +180 -0
- package/src/services/rithmic/contracts.js +218 -0
- package/src/services/rithmic/handlers.js +2 -208
- package/src/services/rithmic/index.js +28 -712
- package/src/services/rithmic/latency-tracker.js +182 -0
- package/src/services/rithmic/market-data-decoders.js +229 -0
- package/src/services/rithmic/market-data.js +1 -278
- package/src/services/rithmic/orders-fast.js +246 -0
- package/src/services/rithmic/orders.js +1 -251
- package/src/services/rithmic/proto-decoders.js +403 -0
- package/src/services/rithmic/protobuf.js +7 -443
- package/src/services/rithmic/specs.js +146 -0
- package/src/services/rithmic/trade-history.js +254 -0
- package/src/services/strategy/hft-signal-calc.js +147 -0
- package/src/services/strategy/hft-tick.js +33 -133
- package/src/services/tradovate/index.js +6 -119
- package/src/services/tradovate/orders.js +145 -0
|
@@ -7,7 +7,12 @@
|
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
const { connections } = require('../session');
|
|
10
|
-
const { analyzeTrading, analyzePerformance, getMarketAdvice } = require('./client');
|
|
10
|
+
const { analyzeTrading, analyzePerformance, getMarketAdvice: getMarketAdviceClient } = require('./client');
|
|
11
|
+
const { feedTick: feedTickImpl, feedSignal: feedSignalImpl, feedTrade: feedTradeImpl,
|
|
12
|
+
updatePosition: updatePositionImpl, updatePnL: updatePnLImpl,
|
|
13
|
+
checkIntervention: checkInterventionImpl, getSyncStatus: getSyncStatusImpl } = require('./supervisor-sync');
|
|
14
|
+
const { requestOptimization: requestOptimizationImpl, getMarketAdvice: getMarketAdviceImpl,
|
|
15
|
+
applyOptimization: applyOptimizationImpl } = require('./supervisor-optimize');
|
|
11
16
|
|
|
12
17
|
let aiService = null;
|
|
13
18
|
|
|
@@ -68,10 +73,9 @@ class AISupervisor {
|
|
|
68
73
|
const currentSessionCount = supervisionSessions.size;
|
|
69
74
|
|
|
70
75
|
if (currentSessionCount === 0) {
|
|
71
|
-
// First agent - start individual supervision
|
|
72
76
|
session.interval = setInterval(() => {
|
|
73
77
|
this.supervise(agentId);
|
|
74
|
-
}, 10000);
|
|
78
|
+
}, 10000);
|
|
75
79
|
|
|
76
80
|
supervisionSessions.set(agentId, session);
|
|
77
81
|
|
|
@@ -82,7 +86,6 @@ class AISupervisor {
|
|
|
82
86
|
};
|
|
83
87
|
|
|
84
88
|
} else {
|
|
85
|
-
// Additional agent - switch to consensus mode
|
|
86
89
|
this.switchToConsensusMode();
|
|
87
90
|
session.interval = null;
|
|
88
91
|
supervisionSessions.set(agentId, session);
|
|
@@ -100,7 +103,6 @@ class AISupervisor {
|
|
|
100
103
|
* Switch to consensus mode when multiple agents
|
|
101
104
|
*/
|
|
102
105
|
static switchToConsensusMode() {
|
|
103
|
-
// Clear all individual intervals
|
|
104
106
|
for (const [agentId, session] of supervisionSessions.entries()) {
|
|
105
107
|
if (session.interval) {
|
|
106
108
|
clearInterval(session.interval);
|
|
@@ -108,7 +110,6 @@ class AISupervisor {
|
|
|
108
110
|
}
|
|
109
111
|
}
|
|
110
112
|
|
|
111
|
-
// Start single consensus loop
|
|
112
113
|
if (!consensusInterval) {
|
|
113
114
|
consensusInterval = setInterval(() => {
|
|
114
115
|
this.superviseConsensus();
|
|
@@ -132,7 +133,6 @@ class AISupervisor {
|
|
|
132
133
|
const duration = Date.now() - session.startTime;
|
|
133
134
|
supervisionSessions.delete(agentId);
|
|
134
135
|
|
|
135
|
-
// Check if we need to switch back to single agent mode
|
|
136
136
|
const remainingSessions = supervisionSessions.size;
|
|
137
137
|
if (remainingSessions === 1 && consensusInterval) {
|
|
138
138
|
clearInterval(consensusInterval);
|
|
@@ -158,155 +158,71 @@ class AISupervisor {
|
|
|
158
158
|
}
|
|
159
159
|
|
|
160
160
|
/**
|
|
161
|
-
*
|
|
162
|
-
* Fetches REAL data from APIs and analyzes with AI
|
|
163
|
-
*
|
|
164
|
-
* Data source: Trading APIs (ProjectX, Rithmic, Tradovate)
|
|
165
|
-
* AI source: Configured AI provider (real API call)
|
|
161
|
+
* Process AI decision and update session metrics
|
|
166
162
|
*/
|
|
163
|
+
static processDecision(session, aiDecision, data, agentId = null) {
|
|
164
|
+
const decision = {
|
|
165
|
+
timestamp: Date.now(),
|
|
166
|
+
action: aiDecision.action || null,
|
|
167
|
+
confidence: aiDecision.confidence || null,
|
|
168
|
+
reason: aiDecision.reason || null,
|
|
169
|
+
dataSnapshot: {
|
|
170
|
+
balance: data.account?.balance ?? null,
|
|
171
|
+
pnl: data.account?.profitAndLoss ?? null,
|
|
172
|
+
positions: data.positions?.length ?? 0,
|
|
173
|
+
orders: data.orders?.length ?? 0
|
|
174
|
+
}
|
|
175
|
+
};
|
|
176
|
+
if (agentId) { decision.agentId = agentId; decision.agentName = session.agent.name; }
|
|
177
|
+
session.decisions.push(decision);
|
|
178
|
+
session.metrics.totalDecisions++;
|
|
179
|
+
if (aiDecision.action === 'REDUCE_SIZE' || aiDecision.action === 'PAUSE') session.metrics.interventions++;
|
|
180
|
+
else if (aiDecision.action === 'CONTINUE') session.metrics.optimizations++;
|
|
181
|
+
if (aiDecision.confidence !== null && aiDecision.confidence < 50) session.metrics.riskWarnings++;
|
|
182
|
+
if (session.decisions.length > 100) session.decisions = session.decisions.slice(-100);
|
|
183
|
+
return decision;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/** Main supervision loop - single agent */
|
|
167
187
|
static async supervise(agentId) {
|
|
168
188
|
const session = supervisionSessions.get(agentId);
|
|
169
189
|
if (!session) return;
|
|
170
|
-
|
|
171
190
|
try {
|
|
172
191
|
session.lastCheck = Date.now();
|
|
173
|
-
|
|
174
|
-
// Get REAL data from API
|
|
175
192
|
const data = await this.fetchRealData(session.service, session.accountId);
|
|
176
193
|
if (!data) return;
|
|
177
|
-
|
|
178
194
|
session.lastData = data;
|
|
179
195
|
session.metrics.lastFetch = Date.now();
|
|
180
|
-
|
|
181
|
-
// Call AI for analysis (real API call, returns null if fails)
|
|
182
196
|
const aiDecision = await analyzeTrading(session.agent, data);
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
// Store decision with timestamp
|
|
186
|
-
const decision = {
|
|
187
|
-
timestamp: Date.now(),
|
|
188
|
-
action: aiDecision.action || null,
|
|
189
|
-
confidence: aiDecision.confidence || null,
|
|
190
|
-
reason: aiDecision.reason || null,
|
|
191
|
-
dataSnapshot: {
|
|
192
|
-
balance: data.account?.balance ?? null,
|
|
193
|
-
pnl: data.account?.profitAndLoss ?? null,
|
|
194
|
-
positions: data.positions?.length ?? 0,
|
|
195
|
-
orders: data.orders?.length ?? 0
|
|
196
|
-
}
|
|
197
|
-
};
|
|
198
|
-
|
|
199
|
-
session.decisions.push(decision);
|
|
200
|
-
session.metrics.totalDecisions++;
|
|
201
|
-
|
|
202
|
-
// Track decision types
|
|
203
|
-
if (aiDecision.action === 'REDUCE_SIZE' || aiDecision.action === 'PAUSE') {
|
|
204
|
-
session.metrics.interventions++;
|
|
205
|
-
} else if (aiDecision.action === 'CONTINUE') {
|
|
206
|
-
session.metrics.optimizations++;
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
// Check for risk warnings
|
|
210
|
-
if (aiDecision.confidence !== null && aiDecision.confidence < 50) {
|
|
211
|
-
session.metrics.riskWarnings++;
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
// Keep only last 100 decisions to prevent memory bloat
|
|
215
|
-
if (session.decisions.length > 100) {
|
|
216
|
-
session.decisions = session.decisions.slice(-100);
|
|
217
|
-
}
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
} catch (error) {
|
|
221
|
-
// Silent fail - don't spam logs
|
|
222
|
-
}
|
|
197
|
+
if (aiDecision) this.processDecision(session, aiDecision, data);
|
|
198
|
+
} catch (error) { /* Silent fail */ }
|
|
223
199
|
}
|
|
224
200
|
|
|
225
|
-
/**
|
|
226
|
-
* Multi-agent consensus supervision loop
|
|
227
|
-
* Each agent analyzes data independently, then consensus is calculated
|
|
228
|
-
*
|
|
229
|
-
* Data source: Trading APIs (ProjectX, Rithmic, Tradovate)
|
|
230
|
-
* AI source: Each agent's configured AI provider (real API calls)
|
|
231
|
-
*/
|
|
201
|
+
/** Multi-agent consensus supervision loop */
|
|
232
202
|
static async superviseConsensus() {
|
|
233
203
|
const allSessions = Array.from(supervisionSessions.entries());
|
|
234
204
|
if (allSessions.length === 0) return;
|
|
235
|
-
|
|
236
205
|
try {
|
|
237
206
|
const decisions = [];
|
|
238
|
-
|
|
239
|
-
// Fetch data and get AI analysis for each session
|
|
240
207
|
for (const [agentId, session] of allSessions) {
|
|
241
208
|
const data = await this.fetchRealData(session.service, session.accountId);
|
|
242
209
|
if (!data) continue;
|
|
243
|
-
|
|
244
210
|
session.lastData = data;
|
|
245
211
|
session.lastCheck = Date.now();
|
|
246
212
|
session.metrics.lastFetch = Date.now();
|
|
247
|
-
|
|
248
|
-
// Call AI for analysis (real API call)
|
|
249
213
|
const aiDecision = await analyzeTrading(session.agent, data);
|
|
250
|
-
|
|
251
|
-
if (aiDecision) {
|
|
252
|
-
const decision = {
|
|
253
|
-
timestamp: Date.now(),
|
|
254
|
-
agentId,
|
|
255
|
-
agentName: session.agent.name,
|
|
256
|
-
action: aiDecision.action || null,
|
|
257
|
-
confidence: aiDecision.confidence || null,
|
|
258
|
-
reason: aiDecision.reason || null,
|
|
259
|
-
dataSnapshot: {
|
|
260
|
-
balance: data.account?.balance ?? null,
|
|
261
|
-
pnl: data.account?.profitAndLoss ?? null,
|
|
262
|
-
positions: data.positions?.length ?? 0,
|
|
263
|
-
orders: data.orders?.length ?? 0
|
|
264
|
-
}
|
|
265
|
-
};
|
|
266
|
-
|
|
267
|
-
session.decisions.push(decision);
|
|
268
|
-
session.metrics.totalDecisions++;
|
|
269
|
-
decisions.push(decision);
|
|
270
|
-
|
|
271
|
-
// Track decision types
|
|
272
|
-
if (aiDecision.action === 'REDUCE_SIZE' || aiDecision.action === 'PAUSE') {
|
|
273
|
-
session.metrics.interventions++;
|
|
274
|
-
} else if (aiDecision.action === 'CONTINUE') {
|
|
275
|
-
session.metrics.optimizations++;
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
if (aiDecision.confidence !== null && aiDecision.confidence < 50) {
|
|
279
|
-
session.metrics.riskWarnings++;
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
// Keep only last 100 decisions
|
|
283
|
-
if (session.decisions.length > 100) {
|
|
284
|
-
session.decisions = session.decisions.slice(-100);
|
|
285
|
-
}
|
|
286
|
-
}
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
// Calculate consensus if multiple decisions
|
|
290
|
-
if (decisions.length > 1) {
|
|
291
|
-
this.calculateConsensus(decisions);
|
|
214
|
+
if (aiDecision) decisions.push(this.processDecision(session, aiDecision, data, agentId));
|
|
292
215
|
}
|
|
293
|
-
|
|
294
|
-
} catch (error) {
|
|
295
|
-
// Silent fail
|
|
296
|
-
}
|
|
216
|
+
if (decisions.length > 1) this.calculateConsensus(decisions);
|
|
217
|
+
} catch (error) { /* Silent fail */ }
|
|
297
218
|
}
|
|
298
219
|
|
|
299
220
|
/**
|
|
300
221
|
* Calculate consensus from multiple agent decisions
|
|
301
|
-
* RULE: ALL agents must agree (100% unanimity) before taking action
|
|
302
|
-
*
|
|
303
|
-
* @param {Array} decisions - Array of agent decisions
|
|
304
|
-
* @returns {Object|null} Consensus result
|
|
305
222
|
*/
|
|
306
223
|
static calculateConsensus(decisions) {
|
|
307
224
|
if (!decisions || decisions.length === 0) return null;
|
|
308
225
|
|
|
309
|
-
// Count votes for each action
|
|
310
226
|
const votes = {};
|
|
311
227
|
let totalConfidence = 0;
|
|
312
228
|
let validConfidenceCount = 0;
|
|
@@ -321,26 +237,21 @@ class AISupervisor {
|
|
|
321
237
|
}
|
|
322
238
|
}
|
|
323
239
|
|
|
324
|
-
// Check for UNANIMITY - ALL agents must agree
|
|
325
240
|
let unanimousAction = null;
|
|
326
241
|
let isUnanimous = false;
|
|
327
242
|
|
|
328
243
|
for (const [action, count] of Object.entries(votes)) {
|
|
329
244
|
if (count === decisions.length) {
|
|
330
|
-
// All agents voted for this action
|
|
331
245
|
unanimousAction = action;
|
|
332
246
|
isUnanimous = true;
|
|
333
247
|
break;
|
|
334
248
|
}
|
|
335
249
|
}
|
|
336
250
|
|
|
337
|
-
// Calculate average confidence
|
|
338
251
|
const avgConfidence = validConfidenceCount > 0
|
|
339
252
|
? Math.round(totalConfidence / validConfidenceCount)
|
|
340
253
|
: null;
|
|
341
254
|
|
|
342
|
-
// Store consensus result
|
|
343
|
-
// If not unanimous, action is HOLD (no action taken)
|
|
344
255
|
const consensus = {
|
|
345
256
|
timestamp: Date.now(),
|
|
346
257
|
action: isUnanimous ? unanimousAction : 'HOLD',
|
|
@@ -351,7 +262,6 @@ class AISupervisor {
|
|
|
351
262
|
agreement: isUnanimous ? 1.0 : 0
|
|
352
263
|
};
|
|
353
264
|
|
|
354
|
-
// Store consensus in first session for retrieval
|
|
355
265
|
const firstSession = supervisionSessions.values().next().value;
|
|
356
266
|
if (firstSession) {
|
|
357
267
|
firstSession.lastConsensus = consensus;
|
|
@@ -362,7 +272,6 @@ class AISupervisor {
|
|
|
362
272
|
|
|
363
273
|
/**
|
|
364
274
|
* Fetch REAL data from trading API
|
|
365
|
-
* NO MOCK, NO SIMULATION
|
|
366
275
|
*/
|
|
367
276
|
static async fetchRealData(service, accountId) {
|
|
368
277
|
if (!service || !accountId) return null;
|
|
@@ -376,7 +285,6 @@ class AISupervisor {
|
|
|
376
285
|
};
|
|
377
286
|
|
|
378
287
|
try {
|
|
379
|
-
// Get account with P&L
|
|
380
288
|
const accountResult = await service.getTradingAccounts();
|
|
381
289
|
if (accountResult.success && accountResult.accounts) {
|
|
382
290
|
data.account = accountResult.accounts.find(a =>
|
|
@@ -386,19 +294,16 @@ class AISupervisor {
|
|
|
386
294
|
);
|
|
387
295
|
}
|
|
388
296
|
|
|
389
|
-
// Get open positions
|
|
390
297
|
const posResult = await service.getPositions(accountId);
|
|
391
298
|
if (posResult.success && posResult.positions) {
|
|
392
299
|
data.positions = posResult.positions;
|
|
393
300
|
}
|
|
394
301
|
|
|
395
|
-
// Get open orders
|
|
396
302
|
const orderResult = await service.getOrders(accountId);
|
|
397
303
|
if (orderResult.success && orderResult.orders) {
|
|
398
304
|
data.orders = orderResult.orders;
|
|
399
305
|
}
|
|
400
306
|
|
|
401
|
-
// Get today's trades (if available)
|
|
402
307
|
if (typeof service.getTrades === 'function') {
|
|
403
308
|
const tradesResult = await service.getTrades(accountId);
|
|
404
309
|
if (tradesResult.success && tradesResult.trades) {
|
|
@@ -461,7 +366,6 @@ class AISupervisor {
|
|
|
461
366
|
|
|
462
367
|
/**
|
|
463
368
|
* Get aggregated data from all supervised accounts
|
|
464
|
-
* Returns REAL data only
|
|
465
369
|
*/
|
|
466
370
|
static getAggregatedData() {
|
|
467
371
|
const result = {
|
|
@@ -502,8 +406,6 @@ class AISupervisor {
|
|
|
502
406
|
|
|
503
407
|
/**
|
|
504
408
|
* Get latest AI decision for an agent
|
|
505
|
-
* @param {string} agentId - Agent ID
|
|
506
|
-
* @returns {Object|null} Latest decision or null
|
|
507
409
|
*/
|
|
508
410
|
static getLatestDecision(agentId) {
|
|
509
411
|
const session = supervisionSessions.get(agentId);
|
|
@@ -515,9 +417,6 @@ class AISupervisor {
|
|
|
515
417
|
|
|
516
418
|
/**
|
|
517
419
|
* Get all decisions for an agent
|
|
518
|
-
* @param {string} agentId - Agent ID
|
|
519
|
-
* @param {number} limit - Max decisions to return (default 10)
|
|
520
|
-
* @returns {Array} Array of decisions
|
|
521
420
|
*/
|
|
522
421
|
static getDecisions(agentId, limit = 10) {
|
|
523
422
|
const session = supervisionSessions.get(agentId);
|
|
@@ -529,7 +428,6 @@ class AISupervisor {
|
|
|
529
428
|
|
|
530
429
|
/**
|
|
531
430
|
* Get latest consensus (multi-agent mode only)
|
|
532
|
-
* @returns {Object|null} Latest consensus or null
|
|
533
431
|
*/
|
|
534
432
|
static getConsensus() {
|
|
535
433
|
if (supervisionSessions.size <= 1) {
|
|
@@ -568,382 +466,19 @@ class AISupervisor {
|
|
|
568
466
|
return supervisionSessions.size;
|
|
569
467
|
}
|
|
570
468
|
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
static
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
// Store latest tick in all sessions
|
|
581
|
-
for (const [agentId, session] of supervisionSessions.entries()) {
|
|
582
|
-
if (!session.marketData) {
|
|
583
|
-
session.marketData = { ticks: [], lastTick: null };
|
|
584
|
-
}
|
|
585
|
-
session.marketData.lastTick = tick;
|
|
586
|
-
session.marketData.ticks.push(tick);
|
|
587
|
-
|
|
588
|
-
// Keep only last 1000 ticks to prevent memory bloat
|
|
589
|
-
if (session.marketData.ticks.length > 1000) {
|
|
590
|
-
session.marketData.ticks = session.marketData.ticks.slice(-1000);
|
|
591
|
-
}
|
|
592
|
-
}
|
|
593
|
-
}
|
|
594
|
-
|
|
595
|
-
/**
|
|
596
|
-
* Feed strategy signal to all agents (sync with strategy)
|
|
597
|
-
* Agents see every signal the strategy generates
|
|
598
|
-
*
|
|
599
|
-
* @param {Object} signal - Strategy signal { direction, entry, stopLoss, takeProfit, confidence }
|
|
600
|
-
*/
|
|
601
|
-
static feedSignal(signal) {
|
|
602
|
-
if (supervisionSessions.size === 0) return;
|
|
603
|
-
|
|
604
|
-
const signalData = {
|
|
605
|
-
timestamp: Date.now(),
|
|
606
|
-
direction: signal.direction,
|
|
607
|
-
entry: signal.entry,
|
|
608
|
-
stopLoss: signal.stopLoss,
|
|
609
|
-
takeProfit: signal.takeProfit,
|
|
610
|
-
confidence: signal.confidence
|
|
611
|
-
};
|
|
612
|
-
|
|
613
|
-
// Store signal in all sessions
|
|
614
|
-
for (const [agentId, session] of supervisionSessions.entries()) {
|
|
615
|
-
if (!session.signals) {
|
|
616
|
-
session.signals = [];
|
|
617
|
-
}
|
|
618
|
-
session.signals.push(signalData);
|
|
619
|
-
|
|
620
|
-
// Keep only last 100 signals
|
|
621
|
-
if (session.signals.length > 100) {
|
|
622
|
-
session.signals = session.signals.slice(-100);
|
|
623
|
-
}
|
|
624
|
-
}
|
|
625
|
-
}
|
|
626
|
-
|
|
627
|
-
/**
|
|
628
|
-
* Feed trade execution to all agents (sync with strategy)
|
|
629
|
-
* Agents see every trade executed
|
|
630
|
-
*
|
|
631
|
-
* @param {Object} trade - Trade data { side, qty, price, pnl, symbol }
|
|
632
|
-
*/
|
|
633
|
-
static feedTrade(trade) {
|
|
634
|
-
if (supervisionSessions.size === 0) return;
|
|
635
|
-
|
|
636
|
-
const tradeData = {
|
|
637
|
-
timestamp: Date.now(),
|
|
638
|
-
side: trade.side,
|
|
639
|
-
qty: trade.qty,
|
|
640
|
-
price: trade.price,
|
|
641
|
-
pnl: trade.pnl,
|
|
642
|
-
symbol: trade.symbol
|
|
643
|
-
};
|
|
644
|
-
|
|
645
|
-
// Store trade in all sessions
|
|
646
|
-
for (const [agentId, session] of supervisionSessions.entries()) {
|
|
647
|
-
if (!session.trades) {
|
|
648
|
-
session.trades = [];
|
|
649
|
-
}
|
|
650
|
-
session.trades.push(tradeData);
|
|
651
|
-
}
|
|
652
|
-
}
|
|
653
|
-
|
|
654
|
-
/**
|
|
655
|
-
* Update current position for all agents
|
|
656
|
-
*
|
|
657
|
-
* @param {Object} position - Position data { qty, side, entryPrice, pnl }
|
|
658
|
-
*/
|
|
659
|
-
static updatePosition(position) {
|
|
660
|
-
if (supervisionSessions.size === 0) return;
|
|
661
|
-
|
|
662
|
-
for (const [agentId, session] of supervisionSessions.entries()) {
|
|
663
|
-
session.currentPosition = {
|
|
664
|
-
timestamp: Date.now(),
|
|
665
|
-
qty: position.qty,
|
|
666
|
-
side: position.side,
|
|
667
|
-
entryPrice: position.entryPrice,
|
|
668
|
-
pnl: position.pnl
|
|
669
|
-
};
|
|
670
|
-
}
|
|
671
|
-
}
|
|
672
|
-
|
|
673
|
-
/**
|
|
674
|
-
* Update P&L for all agents
|
|
675
|
-
*
|
|
676
|
-
* @param {number} pnl - Current session P&L
|
|
677
|
-
* @param {number} balance - Account balance
|
|
678
|
-
*/
|
|
679
|
-
static updatePnL(pnl, balance) {
|
|
680
|
-
if (supervisionSessions.size === 0) return;
|
|
681
|
-
|
|
682
|
-
for (const [agentId, session] of supervisionSessions.entries()) {
|
|
683
|
-
session.currentPnL = pnl;
|
|
684
|
-
session.currentBalance = balance;
|
|
685
|
-
}
|
|
686
|
-
}
|
|
469
|
+
// Strategy sync methods (delegated to supervisor-sync.js)
|
|
470
|
+
static feedTick(tick) { feedTickImpl(supervisionSessions, tick); }
|
|
471
|
+
static feedSignal(signal) { feedSignalImpl(supervisionSessions, signal); }
|
|
472
|
+
static feedTrade(trade) { feedTradeImpl(supervisionSessions, trade); }
|
|
473
|
+
static updatePosition(position) { updatePositionImpl(supervisionSessions, position); }
|
|
474
|
+
static updatePnL(pnl, balance) { updatePnLImpl(supervisionSessions, pnl, balance); }
|
|
475
|
+
static checkIntervention() { return checkInterventionImpl(supervisionSessions, () => this.getConsensus()); }
|
|
476
|
+
static getSyncStatus() { return getSyncStatusImpl(supervisionSessions); }
|
|
687
477
|
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
* @returns {Object} { shouldContinue: boolean, action: string, reason: string }
|
|
693
|
-
*/
|
|
694
|
-
static checkIntervention() {
|
|
695
|
-
if (supervisionSessions.size === 0) {
|
|
696
|
-
return { shouldContinue: true, action: 'CONTINUE', reason: 'No AI supervision active' };
|
|
697
|
-
}
|
|
698
|
-
|
|
699
|
-
// Get last consensus or individual decision
|
|
700
|
-
const consensus = this.getConsensus();
|
|
701
|
-
|
|
702
|
-
if (consensus && consensus.isUnanimous) {
|
|
703
|
-
if (consensus.action === 'PAUSE' || consensus.action === 'STOP') {
|
|
704
|
-
return { shouldContinue: false, action: consensus.action, reason: 'AI agents recommend pause' };
|
|
705
|
-
}
|
|
706
|
-
if (consensus.action === 'REDUCE_SIZE') {
|
|
707
|
-
return { shouldContinue: true, action: 'REDUCE_SIZE', reason: 'AI agents recommend reducing size' };
|
|
708
|
-
}
|
|
709
|
-
} else if (consensus && !consensus.isUnanimous) {
|
|
710
|
-
// Agents disagree - be conservative, don't take new trades
|
|
711
|
-
return { shouldContinue: false, action: 'HOLD', reason: 'AI agents disagree - waiting for consensus' };
|
|
712
|
-
}
|
|
713
|
-
|
|
714
|
-
return { shouldContinue: true, action: 'CONTINUE', reason: 'AI supervision active' };
|
|
715
|
-
}
|
|
716
|
-
|
|
717
|
-
/**
|
|
718
|
-
* Get real-time sync status for display
|
|
719
|
-
* Shows what data the agents are receiving
|
|
720
|
-
*
|
|
721
|
-
* @returns {Object} Sync status
|
|
722
|
-
*/
|
|
723
|
-
static getSyncStatus() {
|
|
724
|
-
if (supervisionSessions.size === 0) {
|
|
725
|
-
return { synced: false, agents: 0 };
|
|
726
|
-
}
|
|
727
|
-
|
|
728
|
-
const firstSession = supervisionSessions.values().next().value;
|
|
729
|
-
|
|
730
|
-
return {
|
|
731
|
-
synced: true,
|
|
732
|
-
agents: supervisionSessions.size,
|
|
733
|
-
lastTick: firstSession?.marketData?.lastTick?.timestamp || null,
|
|
734
|
-
tickCount: firstSession?.marketData?.ticks?.length || 0,
|
|
735
|
-
signalCount: firstSession?.signals?.length || 0,
|
|
736
|
-
tradeCount: firstSession?.trades?.length || 0,
|
|
737
|
-
currentPnL: firstSession?.currentPnL || 0,
|
|
738
|
-
currentPosition: firstSession?.currentPosition || null
|
|
739
|
-
};
|
|
740
|
-
}
|
|
741
|
-
|
|
742
|
-
/**
|
|
743
|
-
* Request strategy optimization from all agents
|
|
744
|
-
* Agents analyze performance data and suggest improvements
|
|
745
|
-
* In CONSENSUS mode, only unanimous suggestions are applied
|
|
746
|
-
*
|
|
747
|
-
* @param {Object} performanceData - Strategy performance data
|
|
748
|
-
* @returns {Promise<Object|null>} Optimization suggestions (consensus)
|
|
749
|
-
*/
|
|
750
|
-
static async requestOptimization(performanceData) {
|
|
751
|
-
if (supervisionSessions.size === 0) return null;
|
|
752
|
-
|
|
753
|
-
const allSessions = Array.from(supervisionSessions.values());
|
|
754
|
-
const suggestions = [];
|
|
755
|
-
|
|
756
|
-
// Get optimization suggestions from each agent
|
|
757
|
-
for (const session of allSessions) {
|
|
758
|
-
try {
|
|
759
|
-
const suggestion = await analyzePerformance(session.agent, performanceData);
|
|
760
|
-
if (suggestion) {
|
|
761
|
-
suggestions.push({
|
|
762
|
-
agentId: session.agentId,
|
|
763
|
-
agentName: session.agent.name,
|
|
764
|
-
...suggestion
|
|
765
|
-
});
|
|
766
|
-
}
|
|
767
|
-
} catch (e) {
|
|
768
|
-
// Silent fail for individual agent
|
|
769
|
-
}
|
|
770
|
-
}
|
|
771
|
-
|
|
772
|
-
if (suggestions.length === 0) return null;
|
|
773
|
-
|
|
774
|
-
// If single agent, return its suggestion
|
|
775
|
-
if (suggestions.length === 1) {
|
|
776
|
-
return {
|
|
777
|
-
mode: 'INDIVIDUAL',
|
|
778
|
-
...suggestions[0]
|
|
779
|
-
};
|
|
780
|
-
}
|
|
781
|
-
|
|
782
|
-
// CONSENSUS MODE: Find common optimizations
|
|
783
|
-
const consensusOptimizations = [];
|
|
784
|
-
const allOptimizations = suggestions.flatMap(s => s.optimizations || []);
|
|
785
|
-
|
|
786
|
-
// Group by parameter name
|
|
787
|
-
const paramGroups = {};
|
|
788
|
-
for (const opt of allOptimizations) {
|
|
789
|
-
if (!opt.param) continue;
|
|
790
|
-
if (!paramGroups[opt.param]) {
|
|
791
|
-
paramGroups[opt.param] = [];
|
|
792
|
-
}
|
|
793
|
-
paramGroups[opt.param].push(opt);
|
|
794
|
-
}
|
|
795
|
-
|
|
796
|
-
// Find unanimous suggestions (all agents agree on direction)
|
|
797
|
-
for (const [param, opts] of Object.entries(paramGroups)) {
|
|
798
|
-
if (opts.length === suggestions.length) {
|
|
799
|
-
// All agents suggested this param - check if they agree on direction
|
|
800
|
-
const directions = opts.map(o => {
|
|
801
|
-
const current = parseFloat(o.current) || 0;
|
|
802
|
-
const suggested = parseFloat(o.suggested) || 0;
|
|
803
|
-
return suggested > current ? 'increase' : suggested < current ? 'decrease' : 'same';
|
|
804
|
-
});
|
|
805
|
-
|
|
806
|
-
const allSame = directions.every(d => d === directions[0]);
|
|
807
|
-
if (allSame && directions[0] !== 'same') {
|
|
808
|
-
// Unanimous - use average of suggested values
|
|
809
|
-
const avgSuggested = opts.reduce((sum, o) => sum + (parseFloat(o.suggested) || 0), 0) / opts.length;
|
|
810
|
-
consensusOptimizations.push({
|
|
811
|
-
param,
|
|
812
|
-
current: opts[0].current,
|
|
813
|
-
suggested: avgSuggested.toFixed(2),
|
|
814
|
-
reason: `Unanimous (${suggestions.length} agents agree)`,
|
|
815
|
-
direction: directions[0]
|
|
816
|
-
});
|
|
817
|
-
}
|
|
818
|
-
}
|
|
819
|
-
}
|
|
820
|
-
|
|
821
|
-
// Calculate average confidence
|
|
822
|
-
const avgConfidence = Math.round(
|
|
823
|
-
suggestions.reduce((sum, s) => sum + (s.confidence || 0), 0) / suggestions.length
|
|
824
|
-
);
|
|
825
|
-
|
|
826
|
-
// Determine consensus market condition
|
|
827
|
-
const conditions = suggestions.map(s => s.marketCondition).filter(Boolean);
|
|
828
|
-
const conditionCounts = {};
|
|
829
|
-
for (const c of conditions) {
|
|
830
|
-
conditionCounts[c] = (conditionCounts[c] || 0) + 1;
|
|
831
|
-
}
|
|
832
|
-
const consensusCondition = Object.entries(conditionCounts)
|
|
833
|
-
.sort((a, b) => b[1] - a[1])[0]?.[0] || 'unknown';
|
|
834
|
-
|
|
835
|
-
return {
|
|
836
|
-
mode: 'CONSENSUS',
|
|
837
|
-
agentCount: suggestions.length,
|
|
838
|
-
isUnanimous: consensusOptimizations.length > 0,
|
|
839
|
-
optimizations: consensusOptimizations,
|
|
840
|
-
marketCondition: consensusCondition,
|
|
841
|
-
confidence: avgConfidence,
|
|
842
|
-
individualSuggestions: suggestions
|
|
843
|
-
};
|
|
844
|
-
}
|
|
845
|
-
|
|
846
|
-
/**
|
|
847
|
-
* Get real-time market advice from all agents
|
|
848
|
-
* Used for dynamic position sizing and risk adjustment
|
|
849
|
-
*
|
|
850
|
-
* @param {Object} marketData - Current market data
|
|
851
|
-
* @returns {Promise<Object|null>} Market advice (consensus)
|
|
852
|
-
*/
|
|
853
|
-
static async getMarketAdvice(marketData) {
|
|
854
|
-
if (supervisionSessions.size === 0) return null;
|
|
855
|
-
|
|
856
|
-
const allSessions = Array.from(supervisionSessions.values());
|
|
857
|
-
const advices = [];
|
|
858
|
-
|
|
859
|
-
// Get advice from each agent
|
|
860
|
-
for (const session of allSessions) {
|
|
861
|
-
try {
|
|
862
|
-
const advice = await getMarketAdvice(session.agent, marketData);
|
|
863
|
-
if (advice) {
|
|
864
|
-
advices.push({
|
|
865
|
-
agentId: session.agentId,
|
|
866
|
-
agentName: session.agent.name,
|
|
867
|
-
...advice
|
|
868
|
-
});
|
|
869
|
-
}
|
|
870
|
-
} catch (e) {
|
|
871
|
-
// Silent fail
|
|
872
|
-
}
|
|
873
|
-
}
|
|
874
|
-
|
|
875
|
-
if (advices.length === 0) return null;
|
|
876
|
-
|
|
877
|
-
// Single agent
|
|
878
|
-
if (advices.length === 1) {
|
|
879
|
-
return {
|
|
880
|
-
mode: 'INDIVIDUAL',
|
|
881
|
-
...advices[0]
|
|
882
|
-
};
|
|
883
|
-
}
|
|
884
|
-
|
|
885
|
-
// CONSENSUS: All agents must agree on action
|
|
886
|
-
const actions = advices.map(a => a.action);
|
|
887
|
-
const allSameAction = actions.every(a => a === actions[0]);
|
|
888
|
-
|
|
889
|
-
if (allSameAction) {
|
|
890
|
-
// Unanimous action - average the size multiplier
|
|
891
|
-
const avgMultiplier = advices.reduce((sum, a) => sum + (a.sizeMultiplier || 1), 0) / advices.length;
|
|
892
|
-
const avgConfidence = Math.round(advices.reduce((sum, a) => sum + (a.confidence || 0), 0) / advices.length);
|
|
893
|
-
|
|
894
|
-
return {
|
|
895
|
-
mode: 'CONSENSUS',
|
|
896
|
-
isUnanimous: true,
|
|
897
|
-
action: actions[0],
|
|
898
|
-
sizeMultiplier: Math.round(avgMultiplier * 100) / 100,
|
|
899
|
-
confidence: avgConfidence,
|
|
900
|
-
reason: `${advices.length} agents unanimous`,
|
|
901
|
-
agentCount: advices.length
|
|
902
|
-
};
|
|
903
|
-
} else {
|
|
904
|
-
// Agents disagree - be conservative
|
|
905
|
-
return {
|
|
906
|
-
mode: 'CONSENSUS',
|
|
907
|
-
isUnanimous: false,
|
|
908
|
-
action: 'CAUTIOUS',
|
|
909
|
-
sizeMultiplier: 0.5,
|
|
910
|
-
confidence: 0,
|
|
911
|
-
reason: 'Agents disagree - reducing exposure',
|
|
912
|
-
agentCount: advices.length,
|
|
913
|
-
votes: actions.reduce((acc, a) => { acc[a] = (acc[a] || 0) + 1; return acc; }, {})
|
|
914
|
-
};
|
|
915
|
-
}
|
|
916
|
-
}
|
|
917
|
-
|
|
918
|
-
/**
|
|
919
|
-
* Apply optimization to strategy
|
|
920
|
-
* Called when agents have consensus on improvements
|
|
921
|
-
*
|
|
922
|
-
* @param {Object} strategy - Strategy instance (M1)
|
|
923
|
-
* @param {Object} optimization - Optimization to apply
|
|
924
|
-
* @returns {boolean} Success
|
|
925
|
-
*/
|
|
926
|
-
static applyOptimization(strategy, optimization) {
|
|
927
|
-
if (!strategy || !optimization) return false;
|
|
928
|
-
|
|
929
|
-
try {
|
|
930
|
-
// Check if strategy has optimization method
|
|
931
|
-
if (typeof strategy.applyOptimization === 'function') {
|
|
932
|
-
strategy.applyOptimization(optimization);
|
|
933
|
-
return true;
|
|
934
|
-
}
|
|
935
|
-
|
|
936
|
-
// Fallback: try to set individual parameters
|
|
937
|
-
if (typeof strategy.setParameter === 'function' && optimization.param) {
|
|
938
|
-
strategy.setParameter(optimization.param, optimization.suggested);
|
|
939
|
-
return true;
|
|
940
|
-
}
|
|
941
|
-
|
|
942
|
-
return false;
|
|
943
|
-
} catch (e) {
|
|
944
|
-
return false;
|
|
945
|
-
}
|
|
946
|
-
}
|
|
478
|
+
// Optimization methods (delegated to supervisor-optimize.js)
|
|
479
|
+
static async requestOptimization(performanceData) { return requestOptimizationImpl(supervisionSessions, performanceData); }
|
|
480
|
+
static async getMarketAdvice(marketData) { return getMarketAdviceImpl(supervisionSessions, marketData); }
|
|
481
|
+
static applyOptimization(strategy, optimization) { return applyOptimizationImpl(strategy, optimization); }
|
|
947
482
|
}
|
|
948
483
|
|
|
949
484
|
module.exports = AISupervisor;
|