hedgequantx 2.5.37 → 2.5.39
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/pages/stats.js +136 -0
- package/src/services/ai/strategy-supervisor.js +111 -3
package/package.json
CHANGED
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,141 @@ const showStats = async (service) => {
|
|
|
479
480
|
}
|
|
480
481
|
|
|
481
482
|
drawBoxFooter(boxWidth);
|
|
483
|
+
|
|
484
|
+
// ========== AI BEHAVIOR DIAGRAM ==========
|
|
485
|
+
const behaviorData = StrategySupervisor.getBehaviorHistory(100);
|
|
486
|
+
const learningStats = StrategySupervisor.getLearningStats();
|
|
487
|
+
|
|
488
|
+
console.log();
|
|
489
|
+
drawBoxHeader('AI AGENTS BEHAVIOR', boxWidth);
|
|
490
|
+
|
|
491
|
+
const behaviorInnerWidth = boxWidth - 2;
|
|
492
|
+
|
|
493
|
+
// Count behavior occurrences
|
|
494
|
+
const behaviorCounts = { AGGRESSIVE: 0, NORMAL: 0, CAUTIOUS: 0, PAUSE: 0 };
|
|
495
|
+
const valueToAction = { 3: 'AGGRESSIVE', 2: 'NORMAL', 1: 'CAUTIOUS', 0: 'PAUSE' };
|
|
496
|
+
|
|
497
|
+
if (behaviorData.values.length > 0) {
|
|
498
|
+
for (const val of behaviorData.values) {
|
|
499
|
+
const action = valueToAction[Math.round(val)] || 'NORMAL';
|
|
500
|
+
behaviorCounts[action]++;
|
|
501
|
+
}
|
|
502
|
+
} else {
|
|
503
|
+
behaviorCounts.NORMAL = 1; // Default
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
const total = Object.values(behaviorCounts).reduce((a, b) => a + b, 0) || 1;
|
|
507
|
+
const percentages = {
|
|
508
|
+
AGGRESSIVE: Math.round((behaviorCounts.AGGRESSIVE / total) * 100),
|
|
509
|
+
NORMAL: Math.round((behaviorCounts.NORMAL / total) * 100),
|
|
510
|
+
CAUTIOUS: Math.round((behaviorCounts.CAUTIOUS / total) * 100),
|
|
511
|
+
PAUSE: Math.round((behaviorCounts.PAUSE / total) * 100)
|
|
512
|
+
};
|
|
513
|
+
|
|
514
|
+
// Bar chart configuration
|
|
515
|
+
const labelWidth = 12;
|
|
516
|
+
const percentWidth = 6;
|
|
517
|
+
const barMaxWidth = behaviorInnerWidth - labelWidth - percentWidth - 6;
|
|
518
|
+
|
|
519
|
+
// Get current behavior
|
|
520
|
+
const currentValue = behaviorData.values.length > 0 ? behaviorData.values[behaviorData.values.length - 1] : 2;
|
|
521
|
+
const currentAction = valueToAction[Math.round(currentValue)] || 'NORMAL';
|
|
522
|
+
|
|
523
|
+
// Draw vertical bar chart (bars going up)
|
|
524
|
+
const chartHeight = 8;
|
|
525
|
+
const barWidth = Math.floor((barMaxWidth - 12) / 4); // 4 bars with spacing
|
|
526
|
+
|
|
527
|
+
// Calculate bar heights (max height = chartHeight)
|
|
528
|
+
const maxPercent = Math.max(...Object.values(percentages), 1);
|
|
529
|
+
const barHeights = {
|
|
530
|
+
AGGRESSIVE: Math.round((percentages.AGGRESSIVE / 100) * chartHeight),
|
|
531
|
+
NORMAL: Math.round((percentages.NORMAL / 100) * chartHeight),
|
|
532
|
+
CAUTIOUS: Math.round((percentages.CAUTIOUS / 100) * chartHeight),
|
|
533
|
+
PAUSE: Math.round((percentages.PAUSE / 100) * chartHeight)
|
|
534
|
+
};
|
|
535
|
+
|
|
536
|
+
// Colors for each behavior
|
|
537
|
+
const barColors = {
|
|
538
|
+
AGGRESSIVE: chalk.green,
|
|
539
|
+
NORMAL: chalk.cyan,
|
|
540
|
+
CAUTIOUS: chalk.yellow,
|
|
541
|
+
PAUSE: chalk.red
|
|
542
|
+
};
|
|
543
|
+
|
|
544
|
+
// Draw bars from top to bottom
|
|
545
|
+
const barLabels = ['AGGRESSIVE', 'NORMAL', 'CAUTIOUS', 'PAUSE'];
|
|
546
|
+
const shortLabels = ['AGR', 'NOR', 'CAU', 'PAU'];
|
|
547
|
+
|
|
548
|
+
// Calculate left padding to center the chart
|
|
549
|
+
const totalBarWidth = (barWidth * 4) + 9; // 4 bars + 3 spaces of 3 chars
|
|
550
|
+
const leftPad = Math.floor((behaviorInnerWidth - totalBarWidth - 4) / 2);
|
|
551
|
+
|
|
552
|
+
for (let row = chartHeight; row >= 1; row--) {
|
|
553
|
+
let line = ' '.repeat(leftPad);
|
|
554
|
+
|
|
555
|
+
for (let i = 0; i < 4; i++) {
|
|
556
|
+
const label = barLabels[i];
|
|
557
|
+
const height = barHeights[label];
|
|
558
|
+
const color = barColors[label];
|
|
559
|
+
const isCurrent = label === currentAction;
|
|
560
|
+
|
|
561
|
+
if (row <= height) {
|
|
562
|
+
// Draw filled bar
|
|
563
|
+
const block = isCurrent ? '█' : '▓';
|
|
564
|
+
line += color(block.repeat(barWidth));
|
|
565
|
+
} else {
|
|
566
|
+
// Empty space
|
|
567
|
+
line += ' '.repeat(barWidth);
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
if (i < 3) line += ' '; // Space between bars
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
const lineLen = line.replace(/\x1b\[[0-9;]*m/g, '').length;
|
|
574
|
+
line += ' '.repeat(Math.max(0, behaviorInnerWidth - lineLen));
|
|
575
|
+
console.log(chalk.cyan('\u2551') + line + chalk.cyan('\u2551'));
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
// Draw baseline
|
|
579
|
+
let baseLine = ' '.repeat(leftPad) + '─'.repeat(totalBarWidth);
|
|
580
|
+
const baseLen = baseLine.length;
|
|
581
|
+
baseLine += ' '.repeat(Math.max(0, behaviorInnerWidth - baseLen));
|
|
582
|
+
console.log(chalk.cyan('\u2551') + chalk.white(baseLine) + chalk.cyan('\u2551'));
|
|
583
|
+
|
|
584
|
+
// Draw labels
|
|
585
|
+
let labelLine = ' '.repeat(leftPad);
|
|
586
|
+
for (let i = 0; i < 4; i++) {
|
|
587
|
+
const lbl = shortLabels[i];
|
|
588
|
+
const pad = Math.floor((barWidth - lbl.length) / 2);
|
|
589
|
+
labelLine += ' '.repeat(pad) + barColors[barLabels[i]](lbl) + ' '.repeat(barWidth - pad - lbl.length);
|
|
590
|
+
if (i < 3) labelLine += ' ';
|
|
591
|
+
}
|
|
592
|
+
const lblLen = labelLine.replace(/\x1b\[[0-9;]*m/g, '').length;
|
|
593
|
+
labelLine += ' '.repeat(Math.max(0, behaviorInnerWidth - lblLen));
|
|
594
|
+
console.log(chalk.cyan('\u2551') + labelLine + chalk.cyan('\u2551'));
|
|
595
|
+
|
|
596
|
+
// Draw percentages
|
|
597
|
+
let pctLine = ' '.repeat(leftPad);
|
|
598
|
+
for (let i = 0; i < 4; i++) {
|
|
599
|
+
const pct = percentages[barLabels[i]] + '%';
|
|
600
|
+
const pad = Math.floor((barWidth - pct.length) / 2);
|
|
601
|
+
pctLine += ' '.repeat(pad) + chalk.white(pct) + ' '.repeat(barWidth - pad - pct.length);
|
|
602
|
+
if (i < 3) pctLine += ' ';
|
|
603
|
+
}
|
|
604
|
+
const pctLen = pctLine.replace(/\x1b\[[0-9;]*m/g, '').length;
|
|
605
|
+
pctLine += ' '.repeat(Math.max(0, behaviorInnerWidth - pctLen));
|
|
606
|
+
console.log(chalk.cyan('\u2551') + pctLine + chalk.cyan('\u2551'));
|
|
607
|
+
|
|
608
|
+
// Empty line
|
|
609
|
+
console.log(chalk.cyan('\u2551') + ' '.repeat(behaviorInnerWidth) + chalk.cyan('\u2551'));
|
|
610
|
+
|
|
611
|
+
// Stats line
|
|
612
|
+
const durationMin = behaviorData.duration ? Math.floor(behaviorData.duration / 60000) : 0;
|
|
613
|
+
const statsLine = ` CURRENT: ${barColors[currentAction](currentAction)} | PATTERNS: ${learningStats.patternsLearned.total} (${learningStats.patternsLearned.winning}W/${learningStats.patternsLearned.losing}L) | OPTIMIZATIONS: ${learningStats.optimizations}`;
|
|
614
|
+
const statsLen = statsLine.replace(/\x1b\[[0-9;]*m/g, '').length;
|
|
615
|
+
console.log(chalk.cyan('\u2551') + statsLine + ' '.repeat(Math.max(0, behaviorInnerWidth - statsLen)) + chalk.cyan('\u2551'));
|
|
616
|
+
|
|
617
|
+
drawBoxFooter(boxWidth);
|
|
482
618
|
}
|
|
483
619
|
|
|
484
620
|
// ========== EQUITY CURVE ==========
|
|
@@ -56,7 +56,12 @@ let supervisorState = {
|
|
|
56
56
|
action: 'NORMAL',
|
|
57
57
|
sizeMultiplier: 1.0,
|
|
58
58
|
reason: 'Starting'
|
|
59
|
-
}
|
|
59
|
+
},
|
|
60
|
+
|
|
61
|
+
// Behavior history for graph (action over time)
|
|
62
|
+
// Values: 0=PAUSE, 1=CAUTIOUS, 2=NORMAL, 3=AGGRESSIVE
|
|
63
|
+
behaviorHistory: [],
|
|
64
|
+
behaviorStartTime: null
|
|
60
65
|
};
|
|
61
66
|
|
|
62
67
|
// Analysis interval
|
|
@@ -66,6 +71,8 @@ let analysisInterval = null;
|
|
|
66
71
|
* Initialize supervisor with strategy and agents
|
|
67
72
|
*/
|
|
68
73
|
const initialize = (strategy, agents, service, accountId) => {
|
|
74
|
+
const now = Date.now();
|
|
75
|
+
|
|
69
76
|
supervisorState = {
|
|
70
77
|
...supervisorState,
|
|
71
78
|
active: true,
|
|
@@ -92,13 +99,23 @@ const initialize = (strategy, agents, service, accountId) => {
|
|
|
92
99
|
maxLossStreak: 0
|
|
93
100
|
},
|
|
94
101
|
optimizations: [],
|
|
95
|
-
lastOptimizationTime:
|
|
102
|
+
lastOptimizationTime: now,
|
|
103
|
+
behaviorHistory: [{ timestamp: now, value: 2, action: 'NORMAL' }], // Start with NORMAL
|
|
104
|
+
behaviorStartTime: now,
|
|
105
|
+
currentAdvice: { action: 'NORMAL', sizeMultiplier: 1.0, reason: 'Starting' }
|
|
96
106
|
};
|
|
97
107
|
|
|
98
108
|
// Start continuous analysis loop
|
|
99
109
|
if (analysisInterval) clearInterval(analysisInterval);
|
|
100
110
|
analysisInterval = setInterval(analyzeAndOptimize, supervisorState.optimizationInterval);
|
|
101
111
|
|
|
112
|
+
// Also record behavior every 10 seconds to have smooth graph
|
|
113
|
+
setInterval(() => {
|
|
114
|
+
if (supervisorState.active) {
|
|
115
|
+
recordBehavior(supervisorState.currentAdvice.action);
|
|
116
|
+
}
|
|
117
|
+
}, 10000);
|
|
118
|
+
|
|
102
119
|
return {
|
|
103
120
|
success: true,
|
|
104
121
|
agents: agents.length,
|
|
@@ -410,6 +427,7 @@ const analyzeAndOptimize = async () => {
|
|
|
410
427
|
sizeMultiplier: consensusResult.sizeMultiplier || 1.0,
|
|
411
428
|
reason: consensusResult.reason || 'Consensus recommendation'
|
|
412
429
|
};
|
|
430
|
+
recordBehavior(consensusResult.action);
|
|
413
431
|
}
|
|
414
432
|
} else {
|
|
415
433
|
// INDIVIDUAL MODE: Apply single agent's suggestions
|
|
@@ -427,12 +445,40 @@ const analyzeAndOptimize = async () => {
|
|
|
427
445
|
sizeMultiplier: suggestion.sizeMultiplier || 1.0,
|
|
428
446
|
reason: suggestion.reason || 'Agent recommendation'
|
|
429
447
|
};
|
|
448
|
+
recordBehavior(suggestion.action);
|
|
430
449
|
}
|
|
431
450
|
}
|
|
432
451
|
|
|
433
452
|
supervisorState.lastOptimizationTime = Date.now();
|
|
434
453
|
};
|
|
435
454
|
|
|
455
|
+
/**
|
|
456
|
+
* Record behavior for graph visualization
|
|
457
|
+
* Converts action to numeric value: PAUSE=0, CAUTIOUS=1, NORMAL=2, AGGRESSIVE=3
|
|
458
|
+
*/
|
|
459
|
+
const recordBehavior = (action) => {
|
|
460
|
+
const actionToValue = {
|
|
461
|
+
'PAUSE': 0,
|
|
462
|
+
'CAUTIOUS': 1,
|
|
463
|
+
'NORMAL': 2,
|
|
464
|
+
'AGGRESSIVE': 3
|
|
465
|
+
};
|
|
466
|
+
|
|
467
|
+
const value = actionToValue[action] ?? 2; // Default to NORMAL
|
|
468
|
+
const now = Date.now();
|
|
469
|
+
|
|
470
|
+
supervisorState.behaviorHistory.push({
|
|
471
|
+
timestamp: now,
|
|
472
|
+
value,
|
|
473
|
+
action
|
|
474
|
+
});
|
|
475
|
+
|
|
476
|
+
// Keep last 200 data points
|
|
477
|
+
if (supervisorState.behaviorHistory.length > 200) {
|
|
478
|
+
supervisorState.behaviorHistory = supervisorState.behaviorHistory.slice(-200);
|
|
479
|
+
}
|
|
480
|
+
};
|
|
481
|
+
|
|
436
482
|
/**
|
|
437
483
|
* Analyze patterns in losing trades
|
|
438
484
|
*/
|
|
@@ -662,6 +708,66 @@ const shouldTrade = () => {
|
|
|
662
708
|
};
|
|
663
709
|
};
|
|
664
710
|
|
|
711
|
+
/**
|
|
712
|
+
* Get behavior history for graph visualization
|
|
713
|
+
* Returns array of numeric values (0-3) representing agent behavior over time
|
|
714
|
+
*
|
|
715
|
+
* @param {number} maxPoints - Maximum data points to return
|
|
716
|
+
* @returns {Object} { values: number[], labels: string[], startTime: number }
|
|
717
|
+
*/
|
|
718
|
+
const getBehaviorHistory = (maxPoints = 50) => {
|
|
719
|
+
if (!supervisorState.active || supervisorState.behaviorHistory.length === 0) {
|
|
720
|
+
return { values: [], labels: [], startTime: null };
|
|
721
|
+
}
|
|
722
|
+
|
|
723
|
+
let history = [...supervisorState.behaviorHistory];
|
|
724
|
+
|
|
725
|
+
// Downsample if too many points
|
|
726
|
+
if (history.length > maxPoints) {
|
|
727
|
+
const step = Math.ceil(history.length / maxPoints);
|
|
728
|
+
history = history.filter((_, i) => i % step === 0);
|
|
729
|
+
}
|
|
730
|
+
|
|
731
|
+
// If too few points, interpolate to make smooth curve
|
|
732
|
+
if (history.length < 10 && history.length > 1) {
|
|
733
|
+
const interpolated = [];
|
|
734
|
+
for (let i = 0; i < history.length - 1; i++) {
|
|
735
|
+
interpolated.push(history[i]);
|
|
736
|
+
// Add intermediate points
|
|
737
|
+
const curr = history[i].value;
|
|
738
|
+
const next = history[i + 1].value;
|
|
739
|
+
const mid = (curr + next) / 2;
|
|
740
|
+
interpolated.push({ value: mid, action: 'interpolated' });
|
|
741
|
+
}
|
|
742
|
+
interpolated.push(history[history.length - 1]);
|
|
743
|
+
history = interpolated;
|
|
744
|
+
}
|
|
745
|
+
|
|
746
|
+
return {
|
|
747
|
+
values: history.map(h => h.value),
|
|
748
|
+
actions: history.map(h => h.action),
|
|
749
|
+
startTime: supervisorState.behaviorStartTime,
|
|
750
|
+
duration: Date.now() - supervisorState.behaviorStartTime
|
|
751
|
+
};
|
|
752
|
+
};
|
|
753
|
+
|
|
754
|
+
/**
|
|
755
|
+
* Get learning statistics for display
|
|
756
|
+
*/
|
|
757
|
+
const getLearningStats = () => {
|
|
758
|
+
return {
|
|
759
|
+
patternsLearned: {
|
|
760
|
+
winning: supervisorState.winningPatterns.length,
|
|
761
|
+
losing: supervisorState.losingPatterns.length,
|
|
762
|
+
total: supervisorState.winningPatterns.length + supervisorState.losingPatterns.length
|
|
763
|
+
},
|
|
764
|
+
optimizations: supervisorState.optimizations.length,
|
|
765
|
+
tradesAnalyzed: supervisorState.trades.length,
|
|
766
|
+
ticksProcessed: supervisorState.ticks.length,
|
|
767
|
+
signalsObserved: supervisorState.signals.length
|
|
768
|
+
};
|
|
769
|
+
};
|
|
770
|
+
|
|
665
771
|
module.exports = {
|
|
666
772
|
initialize,
|
|
667
773
|
stop,
|
|
@@ -671,5 +777,7 @@ module.exports = {
|
|
|
671
777
|
getCurrentAdvice,
|
|
672
778
|
shouldTrade,
|
|
673
779
|
getStatus,
|
|
674
|
-
analyzeAndOptimize
|
|
780
|
+
analyzeAndOptimize,
|
|
781
|
+
getBehaviorHistory,
|
|
782
|
+
getLearningStats
|
|
675
783
|
};
|