hedgequantx 2.5.36 → 2.5.38
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
CHANGED
|
@@ -16,6 +16,10 @@ const { M1 } = require('../../../dist/lib/m/s1');
|
|
|
16
16
|
const { MarketDataFeed } = require('../../../dist/lib/data');
|
|
17
17
|
const { algoLogger } = require('./logger');
|
|
18
18
|
|
|
19
|
+
// AI Strategy Supervisor - observes, learns, and optimizes the strategy
|
|
20
|
+
const aiService = require('../../services/ai');
|
|
21
|
+
const StrategySupervisor = require('../../services/ai/strategy-supervisor');
|
|
22
|
+
|
|
19
23
|
|
|
20
24
|
|
|
21
25
|
/**
|
|
@@ -167,6 +171,7 @@ const configureAlgo = async (account, contract) => {
|
|
|
167
171
|
/**
|
|
168
172
|
* Launch algo trading - HQX Ultra Scalping Strategy
|
|
169
173
|
* Real-time market data + Strategy signals + Auto order execution
|
|
174
|
+
* AI Supervision: All connected agents monitor and supervise trading
|
|
170
175
|
*/
|
|
171
176
|
const launchAlgo = async (service, account, contract, config) => {
|
|
172
177
|
const { contracts, dailyTarget, maxRisk, showName } = config;
|
|
@@ -197,7 +202,9 @@ const launchAlgo = async (service, account, contract, config) => {
|
|
|
197
202
|
losses: 0,
|
|
198
203
|
latency: 0,
|
|
199
204
|
connected: false,
|
|
200
|
-
startTime: Date.now()
|
|
205
|
+
startTime: Date.now(),
|
|
206
|
+
aiSupervision: false,
|
|
207
|
+
aiMode: null
|
|
201
208
|
};
|
|
202
209
|
|
|
203
210
|
let running = true;
|
|
@@ -213,6 +220,14 @@ const launchAlgo = async (service, account, contract, config) => {
|
|
|
213
220
|
const strategy = M1;
|
|
214
221
|
strategy.initialize(contractId, tickSize, tickValue);
|
|
215
222
|
|
|
223
|
+
// Initialize AI Strategy Supervisor - agents observe, learn & optimize
|
|
224
|
+
const aiAgents = aiService.getAgents();
|
|
225
|
+
if (aiAgents.length > 0) {
|
|
226
|
+
const supervisorResult = StrategySupervisor.initialize(strategy, aiAgents, service, account.accountId);
|
|
227
|
+
stats.aiSupervision = supervisorResult.success;
|
|
228
|
+
stats.aiMode = supervisorResult.mode;
|
|
229
|
+
}
|
|
230
|
+
|
|
216
231
|
// Initialize Market Data Feed
|
|
217
232
|
const marketFeed = new MarketDataFeed({ propfirm: account.propfirm });
|
|
218
233
|
|
|
@@ -225,17 +240,44 @@ const launchAlgo = async (service, account, contract, config) => {
|
|
|
225
240
|
algoLogger.engineStarting(ui, connectionType, dailyTarget, maxRisk);
|
|
226
241
|
algoLogger.marketOpen(ui, sessionName.toUpperCase(), etTime);
|
|
227
242
|
|
|
243
|
+
// Log AI supervision status
|
|
244
|
+
if (stats.aiSupervision) {
|
|
245
|
+
algoLogger.info(ui, 'AI SUPERVISION', `${aiAgents.length} agent(s) - ${stats.aiMode} mode - LEARNING ACTIVE`);
|
|
246
|
+
}
|
|
247
|
+
|
|
228
248
|
// Handle strategy signals
|
|
229
249
|
strategy.on('signal', async (signal) => {
|
|
230
250
|
if (!running || pendingOrder || currentPosition !== 0) return;
|
|
231
251
|
|
|
232
252
|
const { side, direction, entry, stopLoss, takeProfit, confidence } = signal;
|
|
233
253
|
|
|
254
|
+
// Feed signal to AI supervisor (agents observe the signal)
|
|
255
|
+
if (stats.aiSupervision) {
|
|
256
|
+
StrategySupervisor.feedSignal({ direction, entry, stopLoss, takeProfit, confidence });
|
|
257
|
+
|
|
258
|
+
// Check AI advice - agents may recommend caution based on learned patterns
|
|
259
|
+
const advice = StrategySupervisor.shouldTrade();
|
|
260
|
+
if (!advice.proceed) {
|
|
261
|
+
algoLogger.info(ui, 'AI HOLD', advice.reason);
|
|
262
|
+
return; // Skip - agents learned this pattern leads to losses
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
|
|
234
266
|
// Calculate position size with kelly
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
const riskPct = Math.round((riskAmount / maxRisk) * 100);
|
|
267
|
+
let kelly = Math.min(0.25, confidence);
|
|
268
|
+
let riskAmount = Math.round(maxRisk * kelly);
|
|
238
269
|
|
|
270
|
+
// AI may adjust size based on learning
|
|
271
|
+
if (stats.aiSupervision) {
|
|
272
|
+
const advice = StrategySupervisor.getCurrentAdvice();
|
|
273
|
+
if (advice.sizeMultiplier && advice.sizeMultiplier !== 1.0) {
|
|
274
|
+
kelly = kelly * advice.sizeMultiplier;
|
|
275
|
+
riskAmount = Math.round(riskAmount * advice.sizeMultiplier);
|
|
276
|
+
algoLogger.info(ui, 'AI ADJUST', `Size x${advice.sizeMultiplier.toFixed(2)} - ${advice.reason}`);
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
const riskPct = Math.round((riskAmount / maxRisk) * 100);
|
|
239
281
|
algoLogger.positionSized(ui, contracts, kelly, riskAmount, riskPct);
|
|
240
282
|
|
|
241
283
|
// Place order via API
|
|
@@ -319,6 +361,11 @@ const launchAlgo = async (service, account, contract, config) => {
|
|
|
319
361
|
timestamp: tick.timestamp || Date.now()
|
|
320
362
|
};
|
|
321
363
|
|
|
364
|
+
// Feed tick to AI supervisor (agents observe same data as strategy)
|
|
365
|
+
if (stats.aiSupervision) {
|
|
366
|
+
StrategySupervisor.feedTick(tickData);
|
|
367
|
+
}
|
|
368
|
+
|
|
322
369
|
strategy.processTick(tickData);
|
|
323
370
|
|
|
324
371
|
stats.latency = Date.now() - latencyStart;
|
|
@@ -443,6 +490,25 @@ const launchAlgo = async (service, account, contract, config) => {
|
|
|
443
490
|
|
|
444
491
|
// Record in strategy for adaptation
|
|
445
492
|
strategy.recordTradeResult(pnl);
|
|
493
|
+
|
|
494
|
+
// Feed trade result to AI supervisor - THIS IS WHERE AGENTS LEARN
|
|
495
|
+
if (stats.aiSupervision) {
|
|
496
|
+
StrategySupervisor.feedTradeResult({
|
|
497
|
+
side,
|
|
498
|
+
qty: contracts,
|
|
499
|
+
price: exitPrice,
|
|
500
|
+
pnl,
|
|
501
|
+
symbol: symbolName,
|
|
502
|
+
direction: side
|
|
503
|
+
});
|
|
504
|
+
|
|
505
|
+
// Log if AI learned something
|
|
506
|
+
const status = StrategySupervisor.getStatus();
|
|
507
|
+
if (status.patternsLearned.winning + status.patternsLearned.losing > 0) {
|
|
508
|
+
algoLogger.info(ui, 'AI LEARNING',
|
|
509
|
+
`${status.patternsLearned.winning}W/${status.patternsLearned.losing}L patterns`);
|
|
510
|
+
}
|
|
511
|
+
}
|
|
446
512
|
}
|
|
447
513
|
}
|
|
448
514
|
} catch (e) {
|
|
@@ -510,6 +576,15 @@ const launchAlgo = async (service, account, contract, config) => {
|
|
|
510
576
|
clearInterval(refreshInterval);
|
|
511
577
|
clearInterval(pnlInterval);
|
|
512
578
|
|
|
579
|
+
// Stop AI Supervisor and get learning summary
|
|
580
|
+
if (stats.aiSupervision) {
|
|
581
|
+
const aiSummary = StrategySupervisor.stop();
|
|
582
|
+
stats.aiLearning = {
|
|
583
|
+
optimizations: aiSummary.optimizationsApplied || 0,
|
|
584
|
+
patternsLearned: (aiSummary.winningPatterns || 0) + (aiSummary.losingPatterns || 0)
|
|
585
|
+
};
|
|
586
|
+
}
|
|
587
|
+
|
|
513
588
|
// Disconnect market feed with timeout
|
|
514
589
|
try {
|
|
515
590
|
await Promise.race([
|
package/src/pages/stats.js
CHANGED
|
@@ -16,6 +16,7 @@ const { getLogoWidth, visibleLength, drawBoxHeader, drawBoxFooter, getColWidths,
|
|
|
16
16
|
const { prompts } = require('../utils');
|
|
17
17
|
const aiService = require('../services/ai');
|
|
18
18
|
const AISupervisor = require('../services/ai/supervisor');
|
|
19
|
+
const StrategySupervisor = require('../services/ai/strategy-supervisor');
|
|
19
20
|
|
|
20
21
|
/**
|
|
21
22
|
* Show Stats Page
|
|
@@ -479,6 +480,85 @@ const showStats = async (service) => {
|
|
|
479
480
|
}
|
|
480
481
|
|
|
481
482
|
drawBoxFooter(boxWidth);
|
|
483
|
+
|
|
484
|
+
// ========== AI BEHAVIOR GRAPH ==========
|
|
485
|
+
const behaviorData = StrategySupervisor.getBehaviorHistory(boxWidth - 20);
|
|
486
|
+
const learningStats = StrategySupervisor.getLearningStats();
|
|
487
|
+
|
|
488
|
+
if (behaviorData.values.length > 2) {
|
|
489
|
+
console.log();
|
|
490
|
+
drawBoxHeader('AI AGENTS BEHAVIOR', boxWidth);
|
|
491
|
+
|
|
492
|
+
const behaviorInnerWidth = boxWidth - 2;
|
|
493
|
+
const yAxisWidth = 12;
|
|
494
|
+
const chartWidth = behaviorInnerWidth - yAxisWidth - 4;
|
|
495
|
+
|
|
496
|
+
// Scale values for better visualization (0-3 -> 0-100 with some padding)
|
|
497
|
+
let scaledValues = behaviorData.values.map(v => (v + 0.5) * 25); // 0->12.5, 1->37.5, 2->62.5, 3->87.5
|
|
498
|
+
|
|
499
|
+
// Ensure we have enough points for a nice curve
|
|
500
|
+
if (scaledValues.length < 10) {
|
|
501
|
+
const newValues = [];
|
|
502
|
+
for (let i = 0; i < scaledValues.length - 1; i++) {
|
|
503
|
+
newValues.push(scaledValues[i]);
|
|
504
|
+
// Smooth interpolation
|
|
505
|
+
const diff = scaledValues[i + 1] - scaledValues[i];
|
|
506
|
+
newValues.push(scaledValues[i] + diff * 0.33);
|
|
507
|
+
newValues.push(scaledValues[i] + diff * 0.66);
|
|
508
|
+
}
|
|
509
|
+
newValues.push(scaledValues[scaledValues.length - 1]);
|
|
510
|
+
scaledValues = newValues;
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
// Limit data points to chart width
|
|
514
|
+
if (scaledValues.length > chartWidth) {
|
|
515
|
+
const step = Math.ceil(scaledValues.length / chartWidth);
|
|
516
|
+
scaledValues = scaledValues.filter((_, i) => i % step === 0);
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
// Determine color based on current behavior
|
|
520
|
+
const currentValue = behaviorData.values[behaviorData.values.length - 1];
|
|
521
|
+
let chartColor = asciichart.white;
|
|
522
|
+
if (currentValue >= 2.5) chartColor = asciichart.green; // AGGRESSIVE
|
|
523
|
+
else if (currentValue >= 1.5) chartColor = asciichart.cyan; // NORMAL
|
|
524
|
+
else if (currentValue >= 0.5) chartColor = asciichart.yellow; // CAUTIOUS
|
|
525
|
+
else chartColor = asciichart.red; // PAUSE
|
|
526
|
+
|
|
527
|
+
const behaviorConfig = {
|
|
528
|
+
height: 6,
|
|
529
|
+
min: 0,
|
|
530
|
+
max: 100,
|
|
531
|
+
colors: [chartColor],
|
|
532
|
+
format: (x) => {
|
|
533
|
+
if (x >= 75) return 'AGGRESSIVE'.padStart(yAxisWidth);
|
|
534
|
+
if (x >= 50) return ' NORMAL'.padStart(yAxisWidth);
|
|
535
|
+
if (x >= 25) return ' CAUTIOUS'.padStart(yAxisWidth);
|
|
536
|
+
return ' PAUSE'.padStart(yAxisWidth);
|
|
537
|
+
}
|
|
538
|
+
};
|
|
539
|
+
|
|
540
|
+
try {
|
|
541
|
+
const behaviorChart = asciichart.plot(scaledValues, behaviorConfig);
|
|
542
|
+
behaviorChart.split('\n').forEach(line => {
|
|
543
|
+
let chartLine = ' ' + line;
|
|
544
|
+
const len = chartLine.replace(/\x1b\[[0-9;]*m/g, '').length;
|
|
545
|
+
if (len < behaviorInnerWidth) chartLine += ' '.repeat(behaviorInnerWidth - len);
|
|
546
|
+
console.log(chalk.cyan('\u2551') + chartLine + chalk.cyan('\u2551'));
|
|
547
|
+
});
|
|
548
|
+
} catch (e) {
|
|
549
|
+
// Fallback if chart fails
|
|
550
|
+
const msg = ' BEHAVIOR DATA INSUFFICIENT';
|
|
551
|
+
console.log(chalk.cyan('\u2551') + chalk.white(msg) + ' '.repeat(Math.max(0, behaviorInnerWidth - msg.length)) + chalk.cyan('\u2551'));
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
// Add learning stats line
|
|
555
|
+
const durationMin = Math.floor(behaviorData.duration / 60000);
|
|
556
|
+
const statsLine = ` SESSION: ${durationMin}m | PATTERNS: ${learningStats.patternsLearned.total} (${learningStats.patternsLearned.winning}W/${learningStats.patternsLearned.losing}L) | OPTIMIZATIONS: ${learningStats.optimizations} | SIGNALS: ${learningStats.signalsObserved}`;
|
|
557
|
+
const statsLen = statsLine.length;
|
|
558
|
+
console.log(chalk.cyan('\u2551') + chalk.white(statsLine) + ' '.repeat(Math.max(0, behaviorInnerWidth - statsLen)) + chalk.cyan('\u2551'));
|
|
559
|
+
|
|
560
|
+
drawBoxFooter(boxWidth);
|
|
561
|
+
}
|
|
482
562
|
}
|
|
483
563
|
|
|
484
564
|
// ========== EQUITY CURVE ==========
|
|
@@ -308,6 +308,145 @@ Analyze and provide recommendation.`;
|
|
|
308
308
|
}
|
|
309
309
|
};
|
|
310
310
|
|
|
311
|
+
/**
|
|
312
|
+
* Analyze strategy performance and suggest optimizations
|
|
313
|
+
* Called periodically to help the strategy improve
|
|
314
|
+
*
|
|
315
|
+
* @param {Object} agent - AI agent
|
|
316
|
+
* @param {Object} performanceData - Strategy performance data
|
|
317
|
+
* @returns {Promise<Object|null>} Optimization suggestions
|
|
318
|
+
*/
|
|
319
|
+
const analyzePerformance = async (agent, performanceData) => {
|
|
320
|
+
if (!agent || !performanceData) return null;
|
|
321
|
+
|
|
322
|
+
const systemPrompt = `You are an AI supervisor for HQX Ultra Scalping, a professional prop firm futures trading strategy.
|
|
323
|
+
|
|
324
|
+
The strategy uses advanced mathematical models:
|
|
325
|
+
- Order flow analysis (delta, cumulative delta, absorption)
|
|
326
|
+
- Market microstructure (bid/ask imbalance, volume profile)
|
|
327
|
+
- Statistical edge detection (z-score, standard deviation bands)
|
|
328
|
+
- Dynamic risk management (Kelly criterion, volatility-adjusted sizing)
|
|
329
|
+
|
|
330
|
+
Your job is to analyze performance data and suggest parameter optimizations.
|
|
331
|
+
Be precise and actionable. Focus on improving win rate, reducing drawdown, and optimizing risk/reward.
|
|
332
|
+
|
|
333
|
+
Respond ONLY in valid JSON format:
|
|
334
|
+
{
|
|
335
|
+
"assessment": "brief performance assessment",
|
|
336
|
+
"winRateAnalysis": "analysis of win/loss patterns",
|
|
337
|
+
"riskAnalysis": "analysis of risk management",
|
|
338
|
+
"optimizations": [
|
|
339
|
+
{ "param": "parameter_name", "current": "current_value", "suggested": "new_value", "reason": "why" }
|
|
340
|
+
],
|
|
341
|
+
"marketCondition": "trending|ranging|volatile|calm",
|
|
342
|
+
"confidence": 0-100
|
|
343
|
+
}`;
|
|
344
|
+
|
|
345
|
+
const prompt = `STRATEGY PERFORMANCE DATA - ANALYZE AND OPTIMIZE
|
|
346
|
+
|
|
347
|
+
Session Stats:
|
|
348
|
+
- Trades: ${performanceData.trades || 0}
|
|
349
|
+
- Wins: ${performanceData.wins || 0}
|
|
350
|
+
- Losses: ${performanceData.losses || 0}
|
|
351
|
+
- Win Rate: ${performanceData.winRate ? (performanceData.winRate * 100).toFixed(1) + '%' : 'N/A'}
|
|
352
|
+
- Total P&L: $${performanceData.pnl?.toFixed(2) || '0.00'}
|
|
353
|
+
- Avg Win: $${performanceData.avgWin?.toFixed(2) || 'N/A'}
|
|
354
|
+
- Avg Loss: $${performanceData.avgLoss?.toFixed(2) || 'N/A'}
|
|
355
|
+
- Largest Win: $${performanceData.largestWin?.toFixed(2) || 'N/A'}
|
|
356
|
+
- Largest Loss: $${performanceData.largestLoss?.toFixed(2) || 'N/A'}
|
|
357
|
+
- Max Drawdown: $${performanceData.maxDrawdown?.toFixed(2) || 'N/A'}
|
|
358
|
+
- Profit Factor: ${performanceData.profitFactor?.toFixed(2) || 'N/A'}
|
|
359
|
+
|
|
360
|
+
Current Parameters:
|
|
361
|
+
- Position Size: ${performanceData.positionSize || 'N/A'} contracts
|
|
362
|
+
- Daily Target: $${performanceData.dailyTarget || 'N/A'}
|
|
363
|
+
- Max Risk: $${performanceData.maxRisk || 'N/A'}
|
|
364
|
+
- Symbol: ${performanceData.symbol || 'N/A'}
|
|
365
|
+
|
|
366
|
+
Recent Trades:
|
|
367
|
+
${performanceData.recentTrades?.map(t =>
|
|
368
|
+
`- ${t.side} ${t.qty}x @ ${t.price} → P&L: $${t.pnl?.toFixed(2) || 'N/A'}`
|
|
369
|
+
).join('\n') || 'No recent trades'}
|
|
370
|
+
|
|
371
|
+
Market Context:
|
|
372
|
+
- Volatility: ${performanceData.volatility || 'N/A'}
|
|
373
|
+
- Trend: ${performanceData.trend || 'N/A'}
|
|
374
|
+
- Session: ${performanceData.session || 'N/A'}
|
|
375
|
+
|
|
376
|
+
Analyze and suggest optimizations to improve performance.`;
|
|
377
|
+
|
|
378
|
+
try {
|
|
379
|
+
const response = await callAI(agent, prompt, systemPrompt);
|
|
380
|
+
if (!response) return null;
|
|
381
|
+
|
|
382
|
+
// Parse JSON from response
|
|
383
|
+
const jsonMatch = response.match(/\{[\s\S]*\}/);
|
|
384
|
+
if (jsonMatch) {
|
|
385
|
+
return JSON.parse(jsonMatch[0]);
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
return null;
|
|
389
|
+
} catch (error) {
|
|
390
|
+
return null;
|
|
391
|
+
}
|
|
392
|
+
};
|
|
393
|
+
|
|
394
|
+
/**
|
|
395
|
+
* Get real-time trading advice based on current market conditions
|
|
396
|
+
*
|
|
397
|
+
* @param {Object} agent - AI agent
|
|
398
|
+
* @param {Object} marketData - Current market data
|
|
399
|
+
* @returns {Promise<Object|null>} Trading advice
|
|
400
|
+
*/
|
|
401
|
+
const getMarketAdvice = async (agent, marketData) => {
|
|
402
|
+
if (!agent || !marketData) return null;
|
|
403
|
+
|
|
404
|
+
const systemPrompt = `You are an AI supervisor for HQX Ultra Scalping futures strategy.
|
|
405
|
+
Analyze real-time market data and provide actionable advice.
|
|
406
|
+
Be concise and precise. The strategy will use your recommendations.
|
|
407
|
+
|
|
408
|
+
Respond ONLY in valid JSON:
|
|
409
|
+
{
|
|
410
|
+
"action": "AGGRESSIVE|NORMAL|CAUTIOUS|PAUSE",
|
|
411
|
+
"sizeMultiplier": 0.5-1.5,
|
|
412
|
+
"reason": "brief reason",
|
|
413
|
+
"confidence": 0-100
|
|
414
|
+
}`;
|
|
415
|
+
|
|
416
|
+
const prompt = `REAL-TIME MARKET ANALYSIS
|
|
417
|
+
|
|
418
|
+
Current Price: ${marketData.price || 'N/A'}
|
|
419
|
+
Bid: ${marketData.bid || 'N/A'} | Ask: ${marketData.ask || 'N/A'}
|
|
420
|
+
Spread: ${marketData.spread || 'N/A'}
|
|
421
|
+
Volume: ${marketData.volume || 'N/A'}
|
|
422
|
+
Delta: ${marketData.delta || 'N/A'}
|
|
423
|
+
Volatility: ${marketData.volatility || 'N/A'}
|
|
424
|
+
|
|
425
|
+
Recent Price Action:
|
|
426
|
+
- High: ${marketData.high || 'N/A'}
|
|
427
|
+
- Low: ${marketData.low || 'N/A'}
|
|
428
|
+
- Range: ${marketData.range || 'N/A'}
|
|
429
|
+
|
|
430
|
+
Current Position: ${marketData.position || 'FLAT'}
|
|
431
|
+
Session P&L: $${marketData.pnl?.toFixed(2) || '0.00'}
|
|
432
|
+
|
|
433
|
+
What should the strategy do?`;
|
|
434
|
+
|
|
435
|
+
try {
|
|
436
|
+
const response = await callAI(agent, prompt, systemPrompt);
|
|
437
|
+
if (!response) return null;
|
|
438
|
+
|
|
439
|
+
const jsonMatch = response.match(/\{[\s\S]*\}/);
|
|
440
|
+
if (jsonMatch) {
|
|
441
|
+
return JSON.parse(jsonMatch[0]);
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
return null;
|
|
445
|
+
} catch (error) {
|
|
446
|
+
return null;
|
|
447
|
+
}
|
|
448
|
+
};
|
|
449
|
+
|
|
311
450
|
/**
|
|
312
451
|
* Fetch available models from Anthropic API (API Key auth)
|
|
313
452
|
* @param {string} apiKey - API key
|
|
@@ -429,6 +568,8 @@ const fetchOpenAIModels = async (endpoint, apiKey) => {
|
|
|
429
568
|
module.exports = {
|
|
430
569
|
callAI,
|
|
431
570
|
analyzeTrading,
|
|
571
|
+
analyzePerformance,
|
|
572
|
+
getMarketAdvice,
|
|
432
573
|
callOpenAICompatible,
|
|
433
574
|
callAnthropic,
|
|
434
575
|
callGemini,
|