hedgequantx 1.2.70 → 1.2.72

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/algo.js +125 -27
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hedgequantx",
3
- "version": "1.2.70",
3
+ "version": "1.2.72",
4
4
  "description": "Prop Futures Algo Trading CLI - Connect to Topstep, Alpha Futures, and other prop firms",
5
5
  "main": "src/app.js",
6
6
  "bin": {
package/src/pages/algo.js CHANGED
@@ -379,14 +379,14 @@ const launchAlgo = async (service, account, contract, numContracts, dailyTarget,
379
379
  // Display full UI with logs (newest first)
380
380
  const displayUI = () => {
381
381
  console.clear();
382
- const marketStatus = checkMarketStatus();
383
382
 
384
383
  // Stats
385
384
  const pnlColor = stats.pnl >= 0 ? chalk.green : chalk.red;
386
385
  const pnlStr = (stats.pnl >= 0 ? '+$' : '-$') + Math.abs(stats.pnl).toFixed(2);
387
386
  const latencyStr = hqxConnected ? (latency > 0 ? `${latency}ms` : '---') : '---';
388
387
  const latencyColor = latency < 100 ? chalk.green : (latency < 300 ? chalk.yellow : chalk.red);
389
- const serverStatus = hqxConnected ? chalk.green('ON') : chalk.red('OFF');
388
+ const serverStatus = hqxConnected ? 'ON' : 'OFF';
389
+ const serverColor = hqxConnected ? chalk.green : chalk.red;
390
390
 
391
391
  // Current date
392
392
  const now = new Date();
@@ -395,40 +395,138 @@ const launchAlgo = async (service, account, contract, numContracts, dailyTarget,
395
395
  // Get package version
396
396
  const version = require('../../package.json').version;
397
397
 
398
- // Full header with logo inside box
398
+ // Fixed width = 96 inner chars
399
+ const W = 96;
400
+ const TOP = '\u2554' + '\u2550'.repeat(W) + '\u2557';
401
+ const MID = '\u2560' + '\u2550'.repeat(W) + '\u2563';
402
+ const BOT = '\u255A' + '\u2550'.repeat(W) + '\u255D';
403
+ const V = '\u2551';
404
+
405
+ // Center text helper
406
+ const center = (text, width) => {
407
+ const pad = Math.floor((width - text.length) / 2);
408
+ return ' '.repeat(pad) + text + ' '.repeat(width - pad - text.length);
409
+ };
410
+
411
+ // Pad text to exact width
412
+ const padRight = (text, width) => {
413
+ if (text.length >= width) return text.substring(0, width);
414
+ return text + ' '.repeat(width - text.length);
415
+ };
416
+
399
417
  console.log();
400
- console.log(chalk.cyan('\u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557'));
401
- console.log(chalk.cyan('\u2551') + chalk.cyan(' \u2588\u2588\u2557 \u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2557 \u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2557 \u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2557 \u2588\u2588\u2557 ') + chalk.cyan('\u2551'));
402
- console.log(chalk.cyan('\u2551') + chalk.cyan(' \u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D \u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D\u2588\u2588\u2554\u2550\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2551\u255A\u2550\u2550\u2588\u2588\u2554\u2550\u2550\u255D\u255A\u2588\u2588\u2557\u2588\u2588\u2554\u255D ') + chalk.cyan('\u2551'));
403
- console.log(chalk.cyan('\u2551') + chalk.cyan(' \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2551\u2588\u2588\u2554\u2588\u2588\u2557 \u2588\u2588\u2551 \u2588\u2588\u2551 \u255A\u2588\u2588\u2588\u2554\u255D ') + chalk.cyan('\u2551'));
404
- console.log(chalk.cyan('\u2551') + chalk.cyan(' \u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u255D \u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u255D \u2588\u2588\u2551\u2584\u2584 \u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2551\u2588\u2588\u2551\u255A\u2588\u2588\u2557\u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2554\u2588\u2588\u2557 ') + chalk.cyan('\u2551'));
405
- console.log(chalk.cyan('\u2551') + chalk.cyan(' \u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551 \u255A\u2588\u2588\u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2554\u255D \u2588\u2588\u2557 ') + chalk.cyan('\u2551'));
406
- console.log(chalk.cyan('\u2551') + chalk.cyan(' \u255A\u2550\u255D \u255A\u2550\u255D\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u255D\u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u255D\u255A\u2550\u255D \u255A\u2550\u2550\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u255D ') + chalk.cyan('\u2551'));
407
- console.log(chalk.cyan('\u2560\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2563'));
408
- console.log(chalk.cyan('\u2551') + chalk.white(` Prop Futures Algo Trading v${version} `) + chalk.cyan('\u2551'));
409
- console.log(chalk.cyan('\u2560\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2563'));
410
- console.log(chalk.cyan('\u2551') + chalk.white(' HQX Ultra-Scalping Algorithm ') + chalk.cyan('\u2551'));
411
- console.log(chalk.cyan('\u2560\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2563'));
412
- console.log(chalk.cyan('\u2551') + chalk.white(` Account: ${chalk.cyan(accountName.padEnd(28))} Symbol: ${chalk.yellow(symbolName.padEnd(12))} Qty: ${chalk.cyan(numContracts.toString().padEnd(4))} Server: ${serverStatus} ${latencyColor(latencyStr.padEnd(6))}`) + chalk.cyan('\u2551'));
413
- console.log(chalk.cyan('\u2551') + chalk.white(` Target: ${chalk.green(('$' + dailyTarget.toFixed(2)).padEnd(12))} Risk: ${chalk.red(('$' + maxRisk.toFixed(2)).padEnd(12))} P&L: ${pnlColor(pnlStr.padEnd(12))} Trades: ${chalk.cyan(stats.trades.toString())} W:${chalk.green(stats.wins.toString())} L:${chalk.red(stats.losses.toString())} `) + chalk.cyan('\u2551'));
414
- console.log(chalk.cyan('\u2560\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2563'));
415
- console.log(chalk.cyan('\u2551') + chalk.white(` Activity Log - ${chalk.gray(dateStr)} `) + chalk.yellow('Press X to stop') + chalk.cyan(' \u2551'));
416
- console.log(chalk.cyan('\u2560\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2563'));
418
+ console.log(chalk.cyan(TOP));
419
+ console.log(chalk.cyan(V) + chalk.cyan(' \u2588\u2588\u2557 \u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2557 \u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2557 \u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2557 \u2588\u2588\u2557 ') + chalk.cyan(V));
420
+ console.log(chalk.cyan(V) + chalk.cyan(' \u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D \u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D\u2588\u2588\u2554\u2550\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2551\u255A\u2550\u2550\u2588\u2588\u2554\u2550\u2550\u255D\u255A\u2588\u2588\u2557\u2588\u2588\u2554\u255D ') + chalk.cyan(V));
421
+ console.log(chalk.cyan(V) + chalk.cyan(' \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2551\u2588\u2588\u2554\u2588\u2588\u2557 \u2588\u2588\u2551 \u2588\u2588\u2551 \u255A\u2588\u2588\u2588\u2554\u255D ') + chalk.cyan(V));
422
+ console.log(chalk.cyan(V) + chalk.cyan(' \u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u255D \u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u255D \u2588\u2588\u2551\u2584\u2584 \u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2551\u2588\u2588\u2551\u255A\u2588\u2588\u2557\u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2554\u2588\u2588\u2557 ') + chalk.cyan(V));
423
+ console.log(chalk.cyan(V) + chalk.cyan(' \u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551 \u255A\u2588\u2588\u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2554\u255D \u2588\u2588\u2557 ') + chalk.cyan(V));
424
+ console.log(chalk.cyan(V) + chalk.cyan(' \u255A\u2550\u255D \u255A\u2550\u255D\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u255D\u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u255D\u255A\u2550\u255D \u255A\u2550\u2550\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u255D ') + chalk.cyan(V));
425
+ console.log(chalk.cyan(MID));
426
+
427
+ // Centered title
428
+ const title1 = `Prop Futures Algo Trading v${version}`;
429
+ console.log(chalk.cyan(V) + chalk.white(center(title1, W)) + chalk.cyan(V));
430
+ console.log(chalk.cyan(MID));
431
+
432
+ // Centered subtitle
433
+ const title2 = 'HQX Ultra-Scalping Algorithm';
434
+ console.log(chalk.cyan(V) + chalk.white(center(title2, W)) + chalk.cyan(V));
435
+ console.log(chalk.cyan(MID));
436
+
437
+ // Grid layout for metrics - each in its own cell
438
+ // Row 1: Account | Symbol | Qty | Server | Latency
439
+ // Row 2: Target | Risk | P&L | Trades | W/L
440
+ const VS = '\u2502'; // Vertical separator (thin)
441
+
442
+ // Prepare values with fixed widths
443
+ const accLabel = 'Account';
444
+ const accVal = accountName.length > 26 ? accountName.substring(0, 26) : accountName;
445
+ const symLabel = 'Symbol';
446
+ const symVal = symbolName.length > 10 ? symbolName.substring(0, 10) : symbolName;
447
+ const qtyLabel = 'Qty';
448
+ const qtyVal = numContracts.toString();
449
+ const srvLabel = 'Server';
450
+ const srvVal = serverStatus;
451
+ const latLabel = 'Latency';
452
+ const latVal = latencyStr;
453
+
454
+ // Row 1 cells: widths = 36 + 18 + 10 + 14 + 14 = 92 + 4 separators = 96
455
+ const c1w = 36, c2w = 18, c3w = 10, c4w = 14, c5w = 14;
456
+
457
+ const cell1 = ` ${accLabel}: ${chalk.cyan(accVal)}`;
458
+ const cell1plain = ` ${accLabel}: ${accVal}`;
459
+ const cell2 = ` ${symLabel}: ${chalk.yellow(symVal)}`;
460
+ const cell2plain = ` ${symLabel}: ${symVal}`;
461
+ const cell3 = ` ${qtyLabel}: ${chalk.cyan(qtyVal)}`;
462
+ const cell3plain = ` ${qtyLabel}: ${qtyVal}`;
463
+ const cell4 = ` ${srvLabel}: ${serverColor(srvVal)}`;
464
+ const cell4plain = ` ${srvLabel}: ${srvVal}`;
465
+ const cell5 = ` ${latLabel}: ${latencyColor(latVal)}`;
466
+ const cell5plain = ` ${latLabel}: ${latVal}`;
417
467
 
418
- // Logs (without date, just time)
468
+ const row1 = cell1 + ' '.repeat(c1w - cell1plain.length) + chalk.cyan(VS) +
469
+ cell2 + ' '.repeat(c2w - cell2plain.length) + chalk.cyan(VS) +
470
+ cell3 + ' '.repeat(c3w - cell3plain.length) + chalk.cyan(VS) +
471
+ cell4 + ' '.repeat(c4w - cell4plain.length) + chalk.cyan(VS) +
472
+ cell5 + ' '.repeat(c5w - cell5plain.length);
473
+
474
+ console.log(chalk.cyan(V) + row1 + chalk.cyan(V));
475
+
476
+ // Separator with intersections
477
+ const SEP = '\u2560' + '\u2550'.repeat(c1w) + '\u256A' + '\u2550'.repeat(c2w) + '\u256A' + '\u2550'.repeat(c3w) + '\u256A' + '\u2550'.repeat(c4w) + '\u256A' + '\u2550'.repeat(c5w) + '\u2563';
478
+ console.log(chalk.cyan(SEP));
479
+
480
+ // Row 2: Target | Risk | P&L | Trades | W/L
481
+ const tgtLabel = 'Target';
482
+ const tgtVal = '$' + dailyTarget.toFixed(2);
483
+ const rskLabel = 'Risk';
484
+ const rskVal = '$' + maxRisk.toFixed(2);
485
+ const pnlLabel = 'P&L';
486
+ const pnlVal = pnlStr;
487
+ const trdLabel = 'Trades';
488
+ const trdVal = stats.trades.toString();
489
+ const wlLabel = 'W/L';
490
+ const wlVal = `${stats.wins}/${stats.losses}`;
491
+
492
+ const cell6 = ` ${tgtLabel}: ${chalk.green(tgtVal)}`;
493
+ const cell6plain = ` ${tgtLabel}: ${tgtVal}`;
494
+ const cell7 = ` ${rskLabel}: ${chalk.red(rskVal)}`;
495
+ const cell7plain = ` ${rskLabel}: ${rskVal}`;
496
+ const cell8 = ` ${pnlLabel}: ${pnlColor(pnlVal)}`;
497
+ const cell8plain = ` ${pnlLabel}: ${pnlVal}`;
498
+ const cell9 = ` ${trdLabel}: ${chalk.cyan(trdVal)}`;
499
+ const cell9plain = ` ${trdLabel}: ${trdVal}`;
500
+ const cell10 = ` ${wlLabel}: ${chalk.green(stats.wins.toString())}/${chalk.red(stats.losses.toString())}`;
501
+ const cell10plain = ` ${wlLabel}: ${wlVal}`;
502
+
503
+ const row2 = cell6 + ' '.repeat(c1w - cell6plain.length) + chalk.cyan(VS) +
504
+ cell7 + ' '.repeat(c2w - cell7plain.length) + chalk.cyan(VS) +
505
+ cell8 + ' '.repeat(c3w - cell8plain.length) + chalk.cyan(VS) +
506
+ cell9 + ' '.repeat(c4w - cell9plain.length) + chalk.cyan(VS) +
507
+ cell10 + ' '.repeat(c5w - cell10plain.length);
508
+
509
+ console.log(chalk.cyan(V) + row2 + chalk.cyan(V));
510
+ console.log(chalk.cyan(MID));
511
+
512
+ // Activity log header
513
+ const actLeft = ` Activity Log - ${dateStr}`;
514
+ const actRight = 'Press X to stop ';
515
+ const actMid = W - actLeft.length - actRight.length;
516
+ console.log(chalk.cyan(V) + chalk.white(actLeft) + ' '.repeat(actMid) + chalk.yellow(actRight) + chalk.cyan(V));
517
+ console.log(chalk.cyan(BOT));
518
+
519
+ // Logs (without borders)
520
+ console.log();
419
521
  if (logs.length === 0) {
420
- console.log(chalk.cyan('\u2551') + chalk.gray(' Waiting for activity...'.padEnd(95)) + chalk.cyan('\u2551'));
522
+ console.log(chalk.gray(' Waiting for activity...'));
421
523
  } else {
422
524
  logs.forEach(log => {
423
525
  const color = typeColors[log.type] || chalk.white;
424
526
  const icon = getIcon(log.type);
425
- const logLine = `[${log.timestamp}] ${icon} ${log.message}`;
426
- const truncated = logLine.length > 93 ? logLine.substring(0, 90) + '...' : logLine;
427
- console.log(chalk.cyan('\u2551') + ' ' + color(truncated.padEnd(94)) + chalk.cyan('\u2551'));
527
+ console.log(color(` [${log.timestamp}] ${icon} ${log.message}`));
428
528
  });
429
529
  }
430
-
431
- console.log(chalk.cyan('\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D'));
432
530
  };
433
531
 
434
532
  // Connect to HQX Server