hedgequantx 2.5.38 → 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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/src/pages/stats.js +126 -70
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hedgequantx",
3
- "version": "2.5.38",
3
+ "version": "2.5.39",
4
4
  "description": "HedgeQuantX - Prop Futures Trading CLI",
5
5
  "main": "src/app.js",
6
6
  "bin": {
@@ -481,84 +481,140 @@ const showStats = async (service) => {
481
481
 
482
482
  drawBoxFooter(boxWidth);
483
483
 
484
- // ========== AI BEHAVIOR GRAPH ==========
485
- const behaviorData = StrategySupervisor.getBehaviorHistory(boxWidth - 20);
484
+ // ========== AI BEHAVIOR DIAGRAM ==========
485
+ const behaviorData = StrategySupervisor.getBehaviorHistory(100);
486
486
  const learningStats = StrategySupervisor.getLearningStats();
487
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);
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]++;
517
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);
518
554
 
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);
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);
537
568
  }
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'));
569
+
570
+ if (i < 3) line += ' '; // Space between bars
552
571
  }
553
572
 
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);
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 += ' ';
561
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);
562
618
  }
563
619
 
564
620
  // ========== EQUITY CURVE ==========