hedgequantx 2.4.38 → 2.4.40

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.4.38",
3
+ "version": "2.4.40",
4
4
  "description": "HedgeQuantX - Prop Futures Trading CLI",
5
5
  "main": "src/app.js",
6
6
  "bin": {
package/src/app.js CHANGED
@@ -115,9 +115,10 @@ const refreshStats = async () => {
115
115
 
116
116
  /**
117
117
  * Display application banner
118
+ * @param {boolean} [clear=true] - Whether to clear screen first
118
119
  */
119
- const banner = async () => {
120
- console.clear();
120
+ const banner = async (clear = true) => {
121
+ if (clear) console.clear();
121
122
 
122
123
  const termWidth = process.stdout.columns || 100;
123
124
  const isMobile = termWidth < 60;
@@ -140,7 +141,7 @@ const banner = async () => {
140
141
 
141
142
  console.log(chalk.cyan('╠' + '═'.repeat(innerWidth) + '╣'));
142
143
 
143
- const tagline = isMobile ? `HQX v${version}` : `Prop Futures Algo Trading v${version}`;
144
+ const tagline = isMobile ? `HQX v${version}` : `PROP FUTURES ALGO TRADING v${version}`;
144
145
  console.log(chalk.cyan('║') + chalk.white(centerText(tagline, innerWidth)) + chalk.cyan('║'));
145
146
  };
146
147
 
@@ -240,7 +241,8 @@ const run = async () => {
240
241
  while (true) {
241
242
  try {
242
243
  prepareStdin();
243
- await banner();
244
+ console.clear();
245
+ await banner(false);
244
246
 
245
247
  if (!connections.isConnected()) {
246
248
  const choice = await mainMenu();
@@ -4,49 +4,49 @@
4
4
 
5
5
  // Account Status Codes (ProjectX UserAPI)
6
6
  const ACCOUNT_STATUS = {
7
- 0: { text: 'Active', color: 'green' },
8
- 1: { text: 'End Of Day', color: 'cyan' },
9
- 2: { text: 'Halted', color: 'red' },
10
- 3: { text: 'Paused', color: 'yellow' },
11
- 4: { text: 'Holiday', color: 'blue' },
12
- 5: { text: 'Expired', color: 'gray' },
13
- 6: { text: 'Terminated', color: 'red' },
14
- 7: { text: 'Cancelled', color: 'red' },
15
- 8: { text: 'Failed', color: 'red' },
16
- 9: { text: 'Passed', color: 'green' }
7
+ 0: { text: 'ACTIVE', color: 'green' },
8
+ 1: { text: 'END OF DAY', color: 'cyan' },
9
+ 2: { text: 'HALTED', color: 'red' },
10
+ 3: { text: 'PAUSED', color: 'yellow' },
11
+ 4: { text: 'HOLIDAY', color: 'blue' },
12
+ 5: { text: 'EXPIRED', color: 'gray' },
13
+ 6: { text: 'TERMINATED', color: 'red' },
14
+ 7: { text: 'CANCELLED', color: 'red' },
15
+ 8: { text: 'FAILED', color: 'red' },
16
+ 9: { text: 'PASSED', color: 'green' }
17
17
  };
18
18
 
19
19
  // Account Types (ProjectX UserAPI)
20
20
  const ACCOUNT_TYPE = {
21
- 0: { text: 'Practice', color: 'blue' },
22
- 1: { text: 'Evaluation', color: 'yellow' },
23
- 2: { text: 'Live', color: 'green' },
24
- 3: { text: 'Express', color: 'magenta' },
25
- 4: { text: 'Sim', color: 'gray' }
21
+ 0: { text: 'PRACTICE', color: 'blue' },
22
+ 1: { text: 'EVALUATION', color: 'yellow' },
23
+ 2: { text: 'LIVE', color: 'green' },
24
+ 3: { text: 'EXPRESS', color: 'magenta' },
25
+ 4: { text: 'SIM', color: 'gray' }
26
26
  };
27
27
 
28
28
  // Order Status
29
29
  const ORDER_STATUS = {
30
- 0: { text: 'Pending', color: 'yellow', icon: '[~]' },
31
- 1: { text: 'Working', color: 'cyan', icon: '[>]' },
32
- 2: { text: 'Filled', color: 'green', icon: '[OK]' },
33
- 3: { text: 'Cancelled', color: 'gray', icon: '[X]' },
34
- 4: { text: 'Rejected', color: 'red', icon: '[!]' },
35
- 5: { text: 'Expired', color: 'gray', icon: '[-]' }
30
+ 0: { text: 'PENDING', color: 'yellow', icon: '[~]' },
31
+ 1: { text: 'WORKING', color: 'cyan', icon: '[>]' },
32
+ 2: { text: 'FILLED', color: 'green', icon: '[OK]' },
33
+ 3: { text: 'CANCELLED', color: 'gray', icon: '[X]' },
34
+ 4: { text: 'REJECTED', color: 'red', icon: '[!]' },
35
+ 5: { text: 'EXPIRED', color: 'gray', icon: '[-]' }
36
36
  };
37
37
 
38
38
  // Order Types
39
39
  const ORDER_TYPE = {
40
- 1: 'Market',
41
- 2: 'Limit',
42
- 3: 'Stop',
43
- 4: 'Stop Limit'
40
+ 1: 'MARKET',
41
+ 2: 'LIMIT',
42
+ 3: 'STOP',
43
+ 4: 'STOP LIMIT'
44
44
  };
45
45
 
46
46
  // Order Side
47
47
  const ORDER_SIDE = {
48
- 0: { text: 'Buy', color: 'green' },
49
- 1: { text: 'Sell', color: 'red' }
48
+ 0: { text: 'BUY', color: 'green' },
49
+ 1: { text: 'SELL', color: 'red' }
50
50
  };
51
51
 
52
52
  // NO STATIC CONTRACT DATA - All symbols/contracts come from API
@@ -38,7 +38,7 @@ const dashboardMenu = async (service) => {
38
38
  // Show connected propfirms
39
39
  const allConns = connections.getAll();
40
40
  if (allConns.length > 0) {
41
- const propfirms = allConns.slice(0, 3).map(c => c.propfirm || c.type || 'Connected');
41
+ const propfirms = allConns.slice(0, 3).map(c => (c.propfirm || c.type || 'CONNECTED').toUpperCase());
42
42
  const propfirmText = propfirms.map(p => chalk.green('● ') + chalk.white(p)).join(' ');
43
43
  console.log(makeLine(propfirmText, 'center'));
44
44
  }
@@ -31,7 +31,7 @@ const showAccounts = async (service) => {
31
31
  // Single spinner for loading (appears below the dashboard header)
32
32
  spinner = ora({ text: 'LOADING ACCOUNTS...', color: 'yellow' }).start();
33
33
 
34
- const allConns = connections.count() > 0 ? connections.getAll() : (service ? [{ service, propfirm: service.propfirm?.name || 'Unknown', type: 'single' }] : []);
34
+ const allConns = connections.count() > 0 ? connections.getAll() : (service ? [{ service, propfirm: service.propfirm?.name || 'UNKNOWN', type: 'single' }] : []);
35
35
 
36
36
  if (allConns.length === 0) {
37
37
  spinner.fail('NO CONNECTIONS FOUND');
@@ -41,7 +41,7 @@ const showAccounts = async (service) => {
41
41
 
42
42
  // Fetch accounts from each connection
43
43
  for (const conn of allConns) {
44
- const propfirmName = conn.propfirm || conn.type || 'Unknown';
44
+ const propfirmName = conn.propfirm || conn.type || 'UNKNOWN';
45
45
 
46
46
  try {
47
47
  const result = await conn.service.getTradingAccounts();
@@ -94,9 +94,9 @@ const showAccounts = async (service) => {
94
94
  draw2ColHeader(name1.substring(0, col1 - 4), name2 ? name2.substring(0, col2 - 4) : '', boxWidth);
95
95
 
96
96
  // PropFirm
97
- const pf1 = chalk.magenta(acc1.propfirm || 'Unknown');
98
- const pf2 = acc2 ? chalk.magenta(acc2.propfirm || 'Unknown') : '';
99
- console.log(chalk.cyan('║') + fmtRow('PropFirm:', pf1, col1) + chalk.cyan('│') + (acc2 ? fmtRow('PropFirm:', pf2, col2) : ' '.repeat(col2)) + chalk.cyan('║'));
97
+ const pf1 = chalk.magenta(acc1.propfirm || 'UNKNOWN');
98
+ const pf2 = acc2 ? chalk.magenta(acc2.propfirm || 'UNKNOWN') : '';
99
+ console.log(chalk.cyan('║') + fmtRow('PROPFIRM:', pf1, col1) + chalk.cyan('│') + (acc2 ? fmtRow('PROPFIRM:', pf2, col2) : ' '.repeat(col2)) + chalk.cyan('║'));
100
100
 
101
101
  // Balance
102
102
  const bal1 = acc1.balance;
@@ -117,14 +117,14 @@ const showAccounts = async (service) => {
117
117
  console.log(chalk.cyan('║') + fmtRow('P&L:', pnlColor1(pnlStr1), col1) + chalk.cyan('│') + (acc2 ? fmtRow('P&L:', pnlColor2(pnlStr2), col2) : ' '.repeat(col2)) + chalk.cyan('║'));
118
118
 
119
119
  // Status
120
- const status1 = ACCOUNT_STATUS[acc1.status] || { text: 'Unknown', color: 'gray' };
121
- const status2 = acc2 ? (ACCOUNT_STATUS[acc2.status] || { text: 'Unknown', color: 'gray' }) : null;
120
+ const status1 = ACCOUNT_STATUS[acc1.status] || { text: 'UNKNOWN', color: 'gray' };
121
+ const status2 = acc2 ? (ACCOUNT_STATUS[acc2.status] || { text: 'UNKNOWN', color: 'gray' }) : null;
122
122
  console.log(chalk.cyan('║') + fmtRow('STATUS:', chalk[status1.color](status1.text), col1) + chalk.cyan('│') + (acc2 ? fmtRow('STATUS:', chalk[status2.color](status2.text), col2) : ' '.repeat(col2)) + chalk.cyan('║'));
123
123
 
124
124
  // Type
125
- const type1 = ACCOUNT_TYPE[acc1.type] || { text: 'Unknown', color: 'white' };
126
- const type2 = acc2 ? (ACCOUNT_TYPE[acc2.type] || { text: 'Unknown', color: 'white' }) : null;
127
- console.log(chalk.cyan('║') + fmtRow('Type:', chalk[type1.color](type1.text), col1) + chalk.cyan('│') + (acc2 ? fmtRow('Type:', chalk[type2.color](type2.text), col2) : ' '.repeat(col2)) + chalk.cyan('║'));
125
+ const type1 = ACCOUNT_TYPE[acc1.type] || { text: 'UNKNOWN', color: 'white' };
126
+ const type2 = acc2 ? (ACCOUNT_TYPE[acc2.type] || { text: 'UNKNOWN', color: 'white' }) : null;
127
+ console.log(chalk.cyan('║') + fmtRow('TYPE:', chalk[type1.color](type1.text), col1) + chalk.cyan('│') + (acc2 ? fmtRow('TYPE:', chalk[type2.color](type2.text), col2) : ' '.repeat(col2)) + chalk.cyan('║'));
128
128
 
129
129
  if (i + 2 < allAccounts.length) {
130
130
  console.log(chalk.cyan('╠') + chalk.cyan('═'.repeat(col1)) + chalk.cyan('╪') + chalk.cyan('═'.repeat(col2)) + chalk.cyan('╣'));
@@ -136,7 +136,7 @@ class AlgoUI {
136
136
 
137
137
  // Separator + title
138
138
  this._line(chalk.cyan(BOX.ML + BOX.H.repeat(W) + BOX.MR));
139
- this._line(chalk.cyan(BOX.V) + chalk.white(center(`Prop Futures Algo Trading v${version}`, W)) + chalk.cyan(BOX.V));
139
+ this._line(chalk.cyan(BOX.V) + chalk.white(center(`PROP FUTURES ALGO TRADING v${version}`, W)) + chalk.cyan(BOX.V));
140
140
  this._line(chalk.cyan(BOX.ML + BOX.H.repeat(W) + BOX.MR));
141
141
  this._line(chalk.cyan(BOX.V) + chalk.yellow.bold(center((this.config.subtitle || 'HQX ALGO TRADING').toUpperCase(), W)) + chalk.cyan(BOX.V));
142
142
  }
@@ -396,7 +396,7 @@ const renderSessionSummary = (stats, stopReason) => {
396
396
 
397
397
  // Separator + title
398
398
  console.log(chalk.cyan(BOX.ML + BOX.H.repeat(W) + BOX.MR));
399
- console.log(chalk.cyan(BOX.V) + chalk.white(center(`Prop Futures Algo Trading v${version}`, W)) + chalk.cyan(BOX.V));
399
+ console.log(chalk.cyan(BOX.V) + chalk.white(center(`PROP FUTURES ALGO TRADING v${version}`, W)) + chalk.cyan(BOX.V));
400
400
  console.log(chalk.cyan(BOX.ML + BOX.H.repeat(W) + BOX.MR));
401
401
  console.log(chalk.cyan(BOX.V) + chalk.yellow.bold(center('SESSION SUMMARY', W)) + chalk.cyan(BOX.V));
402
402
 
@@ -343,7 +343,7 @@ const showStats = async (service) => {
343
343
  console.log(chalk.cyan('\u2551') + fmtRow('STARTING BALANCE:', chalk.white(startBalStr), col1) + chalk.cyan('\u2502') + fmtRow('WIN RATE:', winRate !== 'N/A' ? (parseFloat(winRate) >= 50 ? chalk.green(winRate + '%') : chalk.yellow(winRate + '%')) : chalk.gray('N/A'), col2) + chalk.cyan('\u2551'));
344
344
  console.log(chalk.cyan('\u2551') + fmtRow('TOTAL P&L:', pnlColor(pnlStr), col1) + chalk.cyan('\u2502') + fmtRow('LONG TRADES:', hasTradeData ? chalk.white(stats.longTrades + (longWinRate !== 'N/A' ? ' (' + longWinRate + '%)' : '')) : chalk.gray('N/A'), col2) + chalk.cyan('\u2551'));
345
345
  console.log(chalk.cyan('\u2551') + fmtRow('OPEN POSITIONS:', chalk.white(String(totalOpenPositions)), col1) + chalk.cyan('\u2502') + fmtRow('SHORT TRADES:', hasTradeData ? chalk.white(stats.shortTrades + (shortWinRate !== 'N/A' ? ' (' + shortWinRate + '%)' : '')) : chalk.gray('N/A'), col2) + chalk.cyan('\u2551'));
346
- console.log(chalk.cyan('\u2551') + fmtRow('OPEN ORDERS:', chalk.white(String(totalOpenOrders)), col1) + chalk.cyan('\u2502') + fmtRow('VOLUME:', hasTradeData ? chalk.white(stats.totalVolume + ' contracts') : chalk.gray('N/A'), col2) + chalk.cyan('\u2551'));
346
+ console.log(chalk.cyan('\u2551') + fmtRow('OPEN ORDERS:', chalk.white(String(totalOpenOrders)), col1) + chalk.cyan('\u2502') + fmtRow('VOLUME:', hasTradeData ? chalk.white(stats.totalVolume + ' CONTRACTS') : chalk.gray('N/A'), col2) + chalk.cyan('\u2551'));
347
347
 
348
348
  // ========== P&L METRICS ==========
349
349
  draw2ColSeparator(boxWidth);
@@ -421,8 +421,8 @@ const showStats = async (service) => {
421
421
  });
422
422
  } else {
423
423
  const msg = connectionTypes.rithmic > 0
424
- ? ' No trade history (Rithmic does not provide trade history API)'
425
- : ' No trade data available';
424
+ ? ' NO TRADE HISTORY (RITHMIC DOES NOT PROVIDE TRADE HISTORY API)'
425
+ : ' NO TRADE DATA AVAILABLE';
426
426
  console.log(chalk.cyan('\u2551') + chalk.gray(msg) + ' '.repeat(Math.max(0, chartInnerWidth - msg.length)) + chalk.cyan('\u2551'));
427
427
  }
428
428
 
@@ -467,13 +467,13 @@ const showStats = async (service) => {
467
467
 
468
468
  // Header - build with exact spacing
469
469
  const headerParts = [
470
- ' ' + 'Time'.padEnd(colTime),
471
- 'Symbol'.padEnd(colSymbol),
472
- 'Side'.padEnd(colSide),
470
+ ' ' + 'TIME'.padEnd(colTime),
471
+ 'SYMBOL'.padEnd(colSymbol),
472
+ 'SIDE'.padEnd(colSide),
473
473
  'P&L'.padEnd(colPnl),
474
- 'Fees'.padEnd(colFees),
475
- 'Net'.padEnd(colNet),
476
- 'Account'.padEnd(colAccount)
474
+ 'FEES'.padEnd(colFees),
475
+ 'NET'.padEnd(colNet),
476
+ 'ACCOUNT'.padEnd(colAccount)
477
477
  ];
478
478
  const header = headerParts.join('| ');
479
479
  console.log(chalk.cyan('\u2551') + chalk.white(header) + chalk.cyan('\u2551'));
@@ -540,13 +540,13 @@ const showStats = async (service) => {
540
540
  }
541
541
 
542
542
  if (sortedTrades.length === 0) {
543
- const msg = ' No completed trades yet';
543
+ const msg = ' NO COMPLETED TRADES YET';
544
544
  console.log(chalk.cyan('\u2551') + chalk.gray(msg.padEnd(innerWidth)) + chalk.cyan('\u2551'));
545
545
  }
546
546
  } else {
547
547
  const msg = connectionTypes.rithmic > 0
548
- ? ' No trade history (Rithmic API limitation)'
549
- : ' No trade history available';
548
+ ? ' NO TRADE HISTORY (RITHMIC API LIMITATION)'
549
+ : ' NO TRADE HISTORY AVAILABLE';
550
550
  console.log(chalk.cyan('\u2551') + chalk.gray(msg.padEnd(innerWidth)) + chalk.cyan('\u2551'));
551
551
  }
552
552
 
@@ -581,18 +581,18 @@ const showStats = async (service) => {
581
581
  };
582
582
 
583
583
  const metricsDisplay = [
584
- { name: 'Win Rate', score: winRateScore },
585
- { name: 'Profit Factor', score: profitFactorScore },
586
- { name: 'Consistency', score: consistencyScore },
587
- { name: 'Risk Management', score: riskScore },
588
- { name: 'Volume', score: volumeScore },
589
- { name: 'Returns', score: returnScore }
584
+ { name: 'WIN RATE', score: winRateScore },
585
+ { name: 'PROFIT FACTOR', score: profitFactorScore },
586
+ { name: 'CONSISTENCY', score: consistencyScore },
587
+ { name: 'RISK MANAGEMENT', score: riskScore },
588
+ { name: 'VOLUME', score: volumeScore },
589
+ { name: 'RETURNS', score: returnScore }
590
590
  ];
591
591
 
592
592
  const barWidth = 30;
593
593
  const labelWidth = 18;
594
594
 
595
- const overallLine = ` OVERALL SCORE: ${scoreColor(String(hqxScore))} / 100 [Grade: ${scoreColor(scoreGrade)}]`;
595
+ const overallLine = ` OVERALL SCORE: ${scoreColor(String(hqxScore))} / 100 [GRADE: ${scoreColor(scoreGrade)}]`;
596
596
  const overallVisLen = overallLine.replace(/\x1b\[[0-9;]*m/g, '').length;
597
597
  console.log(chalk.cyan('\u2551') + overallLine + ' '.repeat(innerWidth - overallVisLen) + chalk.cyan('\u2551'));
598
598
  console.log(chalk.cyan('\u2551') + chalk.gray('\u2500'.repeat(innerWidth)) + chalk.cyan('\u2551'));
@@ -613,9 +613,9 @@ const showStats = async (service) => {
613
613
 
614
614
  // Show data source notice
615
615
  if (connectionTypes.rithmic > 0 && connectionTypes.projectx === 0) {
616
- console.log(chalk.gray(' Note: Rithmic API provides balance/P&L only. Trade history not available.'));
616
+ console.log(chalk.gray(' NOTE: RITHMIC API PROVIDES BALANCE/P&L ONLY. TRADE HISTORY NOT AVAILABLE.'));
617
617
  } else if (connectionTypes.rithmic > 0 && connectionTypes.projectx > 0) {
618
- console.log(chalk.gray(' Note: Trade history shown from ProjectX accounts only.'));
618
+ console.log(chalk.gray(' NOTE: TRADE HISTORY SHOWN FROM PROJECTX ACCOUNTS ONLY.'));
619
619
  }
620
620
 
621
621
  } catch (error) {
package/src/ui/box.js CHANGED
@@ -97,7 +97,7 @@ const drawBoxSeparator = (width) => {
97
97
  const printLogo = () => {
98
98
  const logoText = figlet.textSync('HEDGEQUANTX', { font: 'ANSI Shadow' });
99
99
  console.log(chalk.cyan(logoText));
100
- console.log(chalk.gray.italic(' Prop Futures Algo Trading CLI'));
100
+ console.log(chalk.gray.italic(' PROP FUTURES ALGO TRADING CLI'));
101
101
  console.log();
102
102
  };
103
103
 
package/src/ui/index.js CHANGED
@@ -70,7 +70,7 @@ const displayBanner = () => {
70
70
  }
71
71
 
72
72
  console.log(chalk.cyan('╠' + '═'.repeat(innerWidth) + '╣'));
73
- const tagline = isMobile ? `HQX v${version}` : `Prop Futures Algo Trading v${version}`;
73
+ const tagline = isMobile ? `HQX v${version}` : `PROP FUTURES ALGO TRADING v${version}`;
74
74
  console.log(chalk.cyan('║') + chalk.white(centerText(tagline, innerWidth)) + chalk.cyan('║'));
75
75
  };
76
76
 
package/src/ui/menu.js CHANGED
@@ -48,7 +48,7 @@ const createBoxMenu = async (title, items, options = {}) => {
48
48
  });
49
49
 
50
50
  console.log(chalk.cyan('╠' + '═'.repeat(innerWidth) + '╣'));
51
- console.log(chalk.cyan('║') + chalk.white(centerText(`Prop Futures Algo Trading v${version}`, innerWidth)) + chalk.cyan('║'));
51
+ console.log(chalk.cyan('║') + chalk.white(centerText(`PROP FUTURES ALGO TRADING v${version}`, innerWidth)) + chalk.cyan('║'));
52
52
 
53
53
  // Stats bar if provided
54
54
  if (options.statsLine) {