hedgequantx 2.6.131 → 2.6.132

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.132",
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,123 @@ 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
+ */
553
+ const renderMultiSymbolSummary = (stats, stopReason, symbolStats) => {
554
+ const W = 96;
555
+ const version = require('../../../package.json').version;
556
+
557
+ console.clear();
558
+ console.log();
559
+
560
+ // Top border
561
+ console.log(chalk.cyan(BOX.TOP + BOX.H.repeat(W) + BOX.TR));
562
+
563
+ // Logo
564
+ console.log(chalk.cyan(BOX.V) + chalk.cyan(' ██╗ ██╗███████╗██████╗ ██████╗ ███████╗ ██████╗ ██╗ ██╗ █████╗ ███╗ ██╗████████╗') + chalk.yellow('██╗ ██╗') + ' ' + chalk.cyan(BOX.V));
565
+ console.log(chalk.cyan(BOX.V) + chalk.cyan(' ██║ ██║██╔════╝██╔══██╗██╔════╝ ██╔════╝██╔═══██╗██║ ██║██╔══██╗████╗ ██║╚══██╔══╝') + chalk.yellow('╚██╗██╔╝') + ' ' + chalk.cyan(BOX.V));
566
+ console.log(chalk.cyan(BOX.V) + chalk.cyan(' ███████║█████╗ ██║ ██║██║ ███╗█████╗ ██║ ██║██║ ██║███████║██╔██╗ ██║ ██║ ') + chalk.yellow(' ╚███╔╝ ') + ' ' + chalk.cyan(BOX.V));
567
+ console.log(chalk.cyan(BOX.V) + chalk.cyan(' ██╔══██║██╔══╝ ██║ ██║██║ ██║██╔══╝ ██║▄▄ ██║██║ ██║██╔══██║██║╚██╗██║ ██║ ') + chalk.yellow(' ██╔██╗ ') + ' ' + chalk.cyan(BOX.V));
568
+ console.log(chalk.cyan(BOX.V) + chalk.cyan(' ██║ ██║███████╗██████╔╝╚██████╔╝███████╗╚██████╔╝╚██████╔╝██║ ██║██║ ╚████║ ██║ ') + chalk.yellow('██╔╝ ██╗') + ' ' + chalk.cyan(BOX.V));
569
+ console.log(chalk.cyan(BOX.V) + chalk.cyan(' ╚═╝ ╚═╝╚══════╝╚═════╝ ╚═════╝ ╚══════╝ ╚══▀▀═╝ ╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═══╝ ╚═╝ ') + chalk.yellow('╚═╝ ╚═╝') + ' ' + chalk.cyan(BOX.V));
570
+
571
+ // Separator + title
572
+ console.log(chalk.cyan(BOX.ML + BOX.H.repeat(W) + BOX.MR));
573
+ console.log(chalk.cyan(BOX.V) + chalk.white(center(`PROP FUTURES ALGO TRADING v${version}`, W)) + chalk.cyan(BOX.V));
574
+ console.log(chalk.cyan(BOX.ML + BOX.H.repeat(W) + BOX.MR));
575
+ console.log(chalk.cyan(BOX.V) + chalk.yellow.bold(center('MULTI-SYMBOL SESSION SUMMARY', W)) + chalk.cyan(BOX.V));
576
+ console.log(chalk.cyan(BOX.ML + BOX.H.repeat(W) + BOX.MR));
577
+
578
+ // Per-symbol stats header
579
+ const colSymbol = 12;
580
+ const colTrades = 10;
581
+ const colWR = 10;
582
+ const colWins = 8;
583
+ const colLosses = 8;
584
+ const colPnL = 14;
585
+ const remaining = W - colSymbol - colTrades - colWR - colWins - colLosses - colPnL - 5; // 5 separators
586
+
587
+ // Header row
588
+ const headerSymbol = ' SYMBOL'.padEnd(colSymbol);
589
+ const headerTrades = 'TRADES'.padEnd(colTrades);
590
+ const headerWR = 'WIN RATE'.padEnd(colWR);
591
+ const headerWins = 'WINS'.padEnd(colWins);
592
+ const headerLosses = 'LOSSES'.padEnd(colLosses);
593
+ const headerPnL = 'P&L'.padEnd(colPnL + remaining);
594
+
595
+ console.log(chalk.cyan(BOX.V) + chalk.bold.white(headerSymbol) + chalk.cyan(BOX.VS) +
596
+ chalk.bold.white(headerTrades) + chalk.cyan(BOX.VS) +
597
+ chalk.bold.white(headerWR) + chalk.cyan(BOX.VS) +
598
+ chalk.bold.white(headerWins) + chalk.cyan(BOX.VS) +
599
+ chalk.bold.white(headerLosses) + chalk.cyan(BOX.VS) +
600
+ chalk.bold.white(headerPnL) + chalk.cyan(BOX.V));
601
+
602
+ console.log(chalk.cyan(BOX.ML + BOX.H.repeat(W) + BOX.MR));
603
+
604
+ // Per-symbol rows
605
+ for (const [symbol, symStats] of Object.entries(symbolStats)) {
606
+ const winRate = symStats.trades > 0 ? ((symStats.wins / symStats.trades) * 100).toFixed(0) + '%' : '0%';
607
+ const pnl = symStats.pnl || 0;
608
+ const pnlStr = (pnl >= 0 ? '+$' : '-$') + Math.abs(pnl).toFixed(2);
609
+ const pnlColor = pnl >= 0 ? chalk.green : chalk.red;
610
+ const wrColor = symStats.wins >= symStats.losses ? chalk.green : chalk.red;
611
+
612
+ const cellSymbol = (' ' + symbol).padEnd(colSymbol);
613
+ const cellTrades = String(symStats.trades || 0).padEnd(colTrades);
614
+ const cellWR = winRate.padEnd(colWR);
615
+ const cellWins = String(symStats.wins || 0).padEnd(colWins);
616
+ const cellLosses = String(symStats.losses || 0).padEnd(colLosses);
617
+ const cellPnL = pnlStr.padEnd(colPnL + remaining);
618
+
619
+ console.log(chalk.cyan(BOX.V) + chalk.yellow(cellSymbol) + chalk.cyan(BOX.VS) +
620
+ chalk.white(cellTrades) + chalk.cyan(BOX.VS) +
621
+ wrColor(cellWR) + chalk.cyan(BOX.VS) +
622
+ chalk.green(cellWins) + chalk.cyan(BOX.VS) +
623
+ chalk.red(cellLosses) + chalk.cyan(BOX.VS) +
624
+ pnlColor.bold(cellPnL) + chalk.cyan(BOX.V));
625
+ }
626
+
627
+ // Separator before totals
628
+ console.log(chalk.cyan(BOX.ML + BOX.H.repeat(W) + BOX.MR));
629
+
630
+ // Total row
631
+ const totalWinRate = stats.trades > 0 ? ((stats.wins / stats.trades) * 100).toFixed(0) + '%' : '0%';
632
+ const totalPnl = stats.sessionPnl || 0;
633
+ const totalPnlStr = (totalPnl >= 0 ? '+$' : '-$') + Math.abs(totalPnl).toFixed(2);
634
+ const totalPnlColor = totalPnl >= 0 ? chalk.green : chalk.red;
635
+ const totalWrColor = stats.wins >= stats.losses ? chalk.green : chalk.red;
636
+
637
+ const totalCellSymbol = ' TOTAL'.padEnd(colSymbol);
638
+ const totalCellTrades = String(stats.trades || 0).padEnd(colTrades);
639
+ const totalCellWR = totalWinRate.padEnd(colWR);
640
+ const totalCellWins = String(stats.wins || 0).padEnd(colWins);
641
+ const totalCellLosses = String(stats.losses || 0).padEnd(colLosses);
642
+ const totalCellPnL = totalPnlStr.padEnd(colPnL + remaining);
643
+
644
+ console.log(chalk.cyan(BOX.V) + chalk.bold.white(totalCellSymbol) + chalk.cyan(BOX.VS) +
645
+ chalk.bold.white(totalCellTrades) + chalk.cyan(BOX.VS) +
646
+ totalWrColor.bold(totalCellWR) + chalk.cyan(BOX.VS) +
647
+ chalk.bold.green(totalCellWins) + chalk.cyan(BOX.VS) +
648
+ chalk.bold.red(totalCellLosses) + chalk.cyan(BOX.VS) +
649
+ totalPnlColor.bold(totalCellPnL) + chalk.cyan(BOX.V));
650
+
651
+ // Separator
652
+ console.log(chalk.cyan(BOX.ML + BOX.H.repeat(W) + BOX.MR));
653
+
654
+ // Stop Reason & Duration row
655
+ const duration = stats.duration || '--';
656
+ const reasonColor = stopReason === 'target' ? chalk.green : stopReason === 'risk' ? chalk.red : chalk.yellow;
657
+ const reasonStr = (stopReason || 'manual').toUpperCase();
658
+ const infoText = ` STOP: ${reasonStr} | DURATION: ${duration} | TARGET: $${(stats.target || 0).toFixed(2)} | RISK: $${(stats.risk || 0).toFixed(2)}`;
659
+ const infoPlain = ` STOP: ${reasonStr} | DURATION: ${duration} | TARGET: $${(stats.target || 0).toFixed(2)} | RISK: $${(stats.risk || 0).toFixed(2)}`;
660
+ const infoColored = ` ${chalk.bold('STOP')}: ${reasonColor.bold(reasonStr)} | ${chalk.bold('DURATION')}: ${chalk.white(duration)} | ${chalk.bold('TARGET')}: ${chalk.cyan('$' + (stats.target || 0).toFixed(2))} | ${chalk.bold('RISK')}: ${chalk.red('$' + (stats.risk || 0).toFixed(2))}`;
661
+
662
+ console.log(chalk.cyan(BOX.V) + infoColored + ' '.repeat(Math.max(0, W - infoPlain.length)) + chalk.cyan(BOX.V));
663
+
664
+ // Bottom border
665
+ console.log(chalk.cyan(BOX.BOT + BOX.H.repeat(W) + BOX.BR));
666
+ console.log();
667
+ };
668
+
669
+ module.exports = { AlgoUI, checkMarketStatus, renderSessionSummary, renderMultiSymbolSummary, LOG_COLORS, LOG_ICONS, stripAnsi, center, fitToWidth };