hedgequantx 2.5.37 → 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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hedgequantx",
3
- "version": "2.5.37",
3
+ "version": "2.5.38",
4
4
  "description": "HedgeQuantX - Prop Futures Trading CLI",
5
5
  "main": "src/app.js",
6
6
  "bin": {
@@ -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 ==========
@@ -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: Date.now()
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
  };