hedgequantx 2.6.131 → 2.6.133

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.6.131",
3
+ "version": "2.6.133",
4
4
  "description": "HedgeQuantX - Prop Futures Trading CLI",
5
5
  "main": "src/app.js",
6
6
  "bin": {
@@ -10,7 +10,7 @@ const ora = require('ora');
10
10
  const readline = require('readline');
11
11
 
12
12
  const { connections } = require('../../services');
13
- const { AlgoUI, renderSessionSummary } = require('./ui');
13
+ const { AlgoUI, renderSessionSummary, renderMultiSymbolSummary } = require('./ui');
14
14
  const { prompts } = require('../../utils');
15
15
  const { checkMarketHours } = require('../../services/projectx/market');
16
16
  const { FAST_SCALPING } = require('../../config/settings');
@@ -1974,32 +1974,14 @@ const launchMultiSymbolRithmic = async (service, account, contracts, config) =>
1974
1974
  const hours = Math.floor(durationMs / 3600000);
1975
1975
  const minutes = Math.floor((durationMs % 3600000) / 60000);
1976
1976
  const seconds = Math.floor((durationMs % 60000) / 1000);
1977
- const duration = hours > 0
1977
+ stats.duration = hours > 0
1978
1978
  ? `${hours}h ${minutes}m ${seconds}s`
1979
1979
  : minutes > 0
1980
1980
  ? `${minutes}m ${seconds}s`
1981
1981
  : `${seconds}s`;
1982
1982
 
1983
- console.log();
1984
- console.log(chalk.cyan('═══════════════════════════════════════════════════════════════'));
1985
- console.log(chalk.cyan(' MULTI-SYMBOL SESSION SUMMARY'));
1986
- console.log(chalk.cyan('═══════════════════════════════════════════════════════════════'));
1987
- console.log();
1988
-
1989
- for (const [symbol, symStats] of Object.entries(stats.symbolStats)) {
1990
- const winRate = symStats.trades > 0 ? ((symStats.wins / symStats.trades) * 100).toFixed(0) : 0;
1991
- const pnlColor = symStats.pnl >= 0 ? chalk.green : chalk.red;
1992
- console.log(chalk.white(` ${symbol}:`));
1993
- console.log(` Trades: ${symStats.trades} | WR: ${winRate}% | P&L: ${pnlColor('$' + symStats.pnl.toFixed(2))}`);
1994
- }
1995
-
1996
- console.log();
1997
- const totalPnlColor = stats.sessionPnl >= 0 ? chalk.green : chalk.red;
1998
- console.log(chalk.white(` TOTAL: ${stats.trades} trades | ${stats.wins}W/${stats.losses}L`));
1999
- console.log(chalk.white(` Session P&L: ${totalPnlColor('$' + stats.sessionPnl.toFixed(2))}`));
2000
- console.log(chalk.white(` Duration: ${duration}`));
2001
- console.log();
2002
- console.log(chalk.cyan('═══════════════════════════════════════════════════════════════'));
1983
+ // Render multi-symbol summary with same style as single-symbol
1984
+ renderMultiSymbolSummary(stats, stopReason, stats.symbolStats);
2003
1985
 
2004
1986
  await prompts.waitForEnter();
2005
1987
  };
@@ -547,4 +547,138 @@ const renderSessionSummary = (stats, stopReason) => {
547
547
  console.log();
548
548
  };
549
549
 
550
- module.exports = { AlgoUI, checkMarketStatus, renderSessionSummary, LOG_COLORS, LOG_ICONS, stripAnsi, center, fitToWidth };
550
+ /**
551
+ * Render Multi-Symbol Session Summary - Same style as single-symbol
552
+ * All columns centered
553
+ */
554
+ const renderMultiSymbolSummary = (stats, stopReason, symbolStats) => {
555
+ const W = 96;
556
+ const version = require('../../../package.json').version;
557
+
558
+ // Helper: center text in column width
559
+ const centerCol = (text, width) => {
560
+ const pad = Math.floor((width - text.length) / 2);
561
+ return ' '.repeat(pad) + text + ' '.repeat(width - pad - text.length);
562
+ };
563
+
564
+ console.clear();
565
+ console.log();
566
+
567
+ // Top border
568
+ console.log(chalk.cyan(BOX.TOP + BOX.H.repeat(W) + BOX.TR));
569
+
570
+ // Logo
571
+ console.log(chalk.cyan(BOX.V) + chalk.cyan(' ██╗ ██╗███████╗██████╗ ██████╗ ███████╗ ██████╗ ██╗ ██╗ █████╗ ███╗ ██╗████████╗') + chalk.yellow('██╗ ██╗') + ' ' + chalk.cyan(BOX.V));
572
+ console.log(chalk.cyan(BOX.V) + chalk.cyan(' ██║ ██║██╔════╝██╔══██╗██╔════╝ ██╔════╝██╔═══██╗██║ ██║██╔══██╗████╗ ██║╚══██╔══╝') + chalk.yellow('╚██╗██╔╝') + ' ' + chalk.cyan(BOX.V));
573
+ console.log(chalk.cyan(BOX.V) + chalk.cyan(' ███████║█████╗ ██║ ██║██║ ███╗█████╗ ██║ ██║██║ ██║███████║██╔██╗ ██║ ██║ ') + chalk.yellow(' ╚███╔╝ ') + ' ' + chalk.cyan(BOX.V));
574
+ console.log(chalk.cyan(BOX.V) + chalk.cyan(' ██╔══██║██╔══╝ ██║ ██║██║ ██║██╔══╝ ██║▄▄ ██║██║ ██║██╔══██║██║╚██╗██║ ██║ ') + chalk.yellow(' ██╔██╗ ') + ' ' + chalk.cyan(BOX.V));
575
+ console.log(chalk.cyan(BOX.V) + chalk.cyan(' ██║ ██║███████╗██████╔╝╚██████╔╝███████╗╚██████╔╝╚██████╔╝██║ ██║██║ ╚████║ ██║ ') + chalk.yellow('██╔╝ ██╗') + ' ' + chalk.cyan(BOX.V));
576
+ console.log(chalk.cyan(BOX.V) + chalk.cyan(' ╚═╝ ╚═╝╚══════╝╚═════╝ ╚═════╝ ╚══════╝ ╚══▀▀═╝ ╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═══╝ ╚═╝ ') + chalk.yellow('╚═╝ ╚═╝') + ' ' + chalk.cyan(BOX.V));
577
+
578
+ // Separator + title
579
+ console.log(chalk.cyan(BOX.ML + BOX.H.repeat(W) + BOX.MR));
580
+ console.log(chalk.cyan(BOX.V) + chalk.white(center(`PROP FUTURES ALGO TRADING v${version}`, W)) + chalk.cyan(BOX.V));
581
+ console.log(chalk.cyan(BOX.ML + BOX.H.repeat(W) + BOX.MR));
582
+ console.log(chalk.cyan(BOX.V) + chalk.yellow.bold(center('MULTI-SYMBOL SESSION SUMMARY', W)) + chalk.cyan(BOX.V));
583
+ console.log(chalk.cyan(BOX.ML + BOX.H.repeat(W) + BOX.MR));
584
+
585
+ // Column widths (total = 96 - 5 separators = 91)
586
+ const colSymbol = 14;
587
+ const colTrades = 12;
588
+ const colWR = 14;
589
+ const colWins = 12;
590
+ const colLosses = 12;
591
+ const colPnL = W - colSymbol - colTrades - colWR - colWins - colLosses - 5; // remaining
592
+
593
+ // Header row - centered
594
+ const headerSymbol = centerCol('SYMBOL', colSymbol);
595
+ const headerTrades = centerCol('TRADES', colTrades);
596
+ const headerWR = centerCol('WIN RATE', colWR);
597
+ const headerWins = centerCol('WINS', colWins);
598
+ const headerLosses = centerCol('LOSSES', colLosses);
599
+ const headerPnL = centerCol('P&L', colPnL);
600
+
601
+ console.log(chalk.cyan(BOX.V) + chalk.bold.white(headerSymbol) + chalk.cyan(BOX.VS) +
602
+ chalk.bold.white(headerTrades) + chalk.cyan(BOX.VS) +
603
+ chalk.bold.white(headerWR) + chalk.cyan(BOX.VS) +
604
+ chalk.bold.white(headerWins) + chalk.cyan(BOX.VS) +
605
+ chalk.bold.white(headerLosses) + chalk.cyan(BOX.VS) +
606
+ chalk.bold.white(headerPnL) + chalk.cyan(BOX.V));
607
+
608
+ console.log(chalk.cyan(BOX.ML + BOX.H.repeat(W) + BOX.MR));
609
+
610
+ // Per-symbol rows - centered
611
+ for (const [symbol, symStats] of Object.entries(symbolStats)) {
612
+ const winRate = symStats.trades > 0 ? ((symStats.wins / symStats.trades) * 100).toFixed(0) + '%' : '0%';
613
+ const pnl = symStats.pnl || 0;
614
+ const pnlStr = (pnl >= 0 ? '+$' : '-$') + Math.abs(pnl).toFixed(2);
615
+ const pnlColor = pnl >= 0 ? chalk.green : chalk.red;
616
+ const wrColor = symStats.wins >= symStats.losses ? chalk.green : chalk.red;
617
+
618
+ const cellSymbol = centerCol(symbol, colSymbol);
619
+ const cellTrades = centerCol(String(symStats.trades || 0), colTrades);
620
+ const cellWR = centerCol(winRate, colWR);
621
+ const cellWins = centerCol(String(symStats.wins || 0), colWins);
622
+ const cellLosses = centerCol(String(symStats.losses || 0), colLosses);
623
+ const cellPnL = centerCol(pnlStr, colPnL);
624
+
625
+ console.log(chalk.cyan(BOX.V) + chalk.yellow(cellSymbol) + chalk.cyan(BOX.VS) +
626
+ chalk.white(cellTrades) + chalk.cyan(BOX.VS) +
627
+ wrColor(cellWR) + chalk.cyan(BOX.VS) +
628
+ chalk.green(cellWins) + chalk.cyan(BOX.VS) +
629
+ chalk.red(cellLosses) + chalk.cyan(BOX.VS) +
630
+ pnlColor.bold(cellPnL) + chalk.cyan(BOX.V));
631
+ }
632
+
633
+ // Separator before totals
634
+ console.log(chalk.cyan(BOX.ML + BOX.H.repeat(W) + BOX.MR));
635
+
636
+ // Total row - centered
637
+ const totalWinRate = stats.trades > 0 ? ((stats.wins / stats.trades) * 100).toFixed(0) + '%' : '0%';
638
+ const totalPnl = stats.sessionPnl || 0;
639
+ const totalPnlStr = (totalPnl >= 0 ? '+$' : '-$') + Math.abs(totalPnl).toFixed(2);
640
+ const totalPnlColor = totalPnl >= 0 ? chalk.green : chalk.red;
641
+ const totalWrColor = stats.wins >= stats.losses ? chalk.green : chalk.red;
642
+
643
+ const totalCellSymbol = centerCol('TOTAL', colSymbol);
644
+ const totalCellTrades = centerCol(String(stats.trades || 0), colTrades);
645
+ const totalCellWR = centerCol(totalWinRate, colWR);
646
+ const totalCellWins = centerCol(String(stats.wins || 0), colWins);
647
+ const totalCellLosses = centerCol(String(stats.losses || 0), colLosses);
648
+ const totalCellPnL = centerCol(totalPnlStr, colPnL);
649
+
650
+ console.log(chalk.cyan(BOX.V) + chalk.bold.cyan(totalCellSymbol) + chalk.cyan(BOX.VS) +
651
+ chalk.bold.white(totalCellTrades) + chalk.cyan(BOX.VS) +
652
+ totalWrColor.bold(totalCellWR) + chalk.cyan(BOX.VS) +
653
+ chalk.bold.green(totalCellWins) + chalk.cyan(BOX.VS) +
654
+ chalk.bold.red(totalCellLosses) + chalk.cyan(BOX.VS) +
655
+ totalPnlColor.bold(totalCellPnL) + chalk.cyan(BOX.V));
656
+
657
+ // Separator
658
+ console.log(chalk.cyan(BOX.ML + BOX.H.repeat(W) + BOX.MR));
659
+
660
+ // Stop Reason & Duration row - centered
661
+ const duration = stats.duration || '--';
662
+ const reasonColor = stopReason === 'target' ? chalk.green : stopReason === 'risk' ? chalk.red : chalk.yellow;
663
+ const reasonStr = (stopReason || 'manual').toUpperCase();
664
+ const infoPlain = `STOP: ${reasonStr} | DURATION: ${duration} | TARGET: $${(stats.target || 0).toFixed(2)} | RISK: $${(stats.risk || 0).toFixed(2)}`;
665
+ const infoPadded = center(infoPlain, W);
666
+
667
+ // Build colored version with same centering
668
+ const padLeft = Math.floor((W - infoPlain.length) / 2);
669
+ const padRight = W - infoPlain.length - padLeft;
670
+ const infoColored = ' '.repeat(padLeft) +
671
+ chalk.bold('STOP') + ': ' + reasonColor.bold(reasonStr) + ' | ' +
672
+ chalk.bold('DURATION') + ': ' + chalk.white(duration) + ' | ' +
673
+ chalk.bold('TARGET') + ': ' + chalk.cyan('$' + (stats.target || 0).toFixed(2)) + ' | ' +
674
+ chalk.bold('RISK') + ': ' + chalk.red('$' + (stats.risk || 0).toFixed(2)) +
675
+ ' '.repeat(padRight);
676
+
677
+ console.log(chalk.cyan(BOX.V) + infoColored + chalk.cyan(BOX.V));
678
+
679
+ // Bottom border
680
+ console.log(chalk.cyan(BOX.BOT + BOX.H.repeat(W) + BOX.BR));
681
+ console.log();
682
+ };
683
+
684
+ module.exports = { AlgoUI, checkMarketStatus, renderSessionSummary, renderMultiSymbolSummary, LOG_COLORS, LOG_ICONS, stripAnsi, center, fitToWidth };