hedgequantx 2.4.38 → 2.4.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.
- package/package.json +1 -1
- package/src/app.js +1 -1
- package/src/config/constants.js +27 -27
- package/src/menus/dashboard.js +1 -1
- package/src/pages/accounts.js +10 -10
- package/src/pages/algo/ui.js +2 -2
- package/src/pages/stats.js +21 -21
- package/src/ui/box.js +1 -1
- package/src/ui/index.js +1 -1
- package/src/ui/menu.js +1 -1
- package/src/utils/prompts.js +1 -0
package/package.json
CHANGED
package/src/app.js
CHANGED
|
@@ -140,7 +140,7 @@ const banner = async () => {
|
|
|
140
140
|
|
|
141
141
|
console.log(chalk.cyan('╠' + '═'.repeat(innerWidth) + '╣'));
|
|
142
142
|
|
|
143
|
-
const tagline = isMobile ? `HQX v${version}` : `
|
|
143
|
+
const tagline = isMobile ? `HQX v${version}` : `PROP FUTURES ALGO TRADING v${version}`;
|
|
144
144
|
console.log(chalk.cyan('║') + chalk.white(centerText(tagline, innerWidth)) + chalk.cyan('║'));
|
|
145
145
|
};
|
|
146
146
|
|
package/src/config/constants.js
CHANGED
|
@@ -4,49 +4,49 @@
|
|
|
4
4
|
|
|
5
5
|
// Account Status Codes (ProjectX UserAPI)
|
|
6
6
|
const ACCOUNT_STATUS = {
|
|
7
|
-
0: { text: '
|
|
8
|
-
1: { text: '
|
|
9
|
-
2: { text: '
|
|
10
|
-
3: { text: '
|
|
11
|
-
4: { text: '
|
|
12
|
-
5: { text: '
|
|
13
|
-
6: { text: '
|
|
14
|
-
7: { text: '
|
|
15
|
-
8: { text: '
|
|
16
|
-
9: { text: '
|
|
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: '
|
|
22
|
-
1: { text: '
|
|
23
|
-
2: { text: '
|
|
24
|
-
3: { text: '
|
|
25
|
-
4: { text: '
|
|
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: '
|
|
31
|
-
1: { text: '
|
|
32
|
-
2: { text: '
|
|
33
|
-
3: { text: '
|
|
34
|
-
4: { text: '
|
|
35
|
-
5: { text: '
|
|
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: '
|
|
41
|
-
2: '
|
|
42
|
-
3: '
|
|
43
|
-
4: '
|
|
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: '
|
|
49
|
-
1: { text: '
|
|
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
|
package/src/menus/dashboard.js
CHANGED
|
@@ -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 || '
|
|
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
|
}
|
package/src/pages/accounts.js
CHANGED
|
@@ -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 || '
|
|
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 || '
|
|
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 || '
|
|
98
|
-
const pf2 = acc2 ? chalk.magenta(acc2.propfirm || '
|
|
99
|
-
console.log(chalk.cyan('║') + fmtRow('
|
|
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: '
|
|
121
|
-
const status2 = acc2 ? (ACCOUNT_STATUS[acc2.status] || { text: '
|
|
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: '
|
|
126
|
-
const type2 = acc2 ? (ACCOUNT_TYPE[acc2.type] || { text: '
|
|
127
|
-
console.log(chalk.cyan('║') + fmtRow('
|
|
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('╣'));
|
package/src/pages/algo/ui.js
CHANGED
|
@@ -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(`
|
|
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(`
|
|
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
|
|
package/src/pages/stats.js
CHANGED
|
@@ -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 + '
|
|
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
|
-
? '
|
|
425
|
-
: '
|
|
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
|
-
' ' + '
|
|
471
|
-
'
|
|
472
|
-
'
|
|
470
|
+
' ' + 'TIME'.padEnd(colTime),
|
|
471
|
+
'SYMBOL'.padEnd(colSymbol),
|
|
472
|
+
'SIDE'.padEnd(colSide),
|
|
473
473
|
'P&L'.padEnd(colPnl),
|
|
474
|
-
'
|
|
475
|
-
'
|
|
476
|
-
'
|
|
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 = '
|
|
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
|
-
? '
|
|
549
|
-
: '
|
|
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: '
|
|
585
|
-
{ name: '
|
|
586
|
-
{ name: '
|
|
587
|
-
{ name: '
|
|
588
|
-
{ name: '
|
|
589
|
-
{ name: '
|
|
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 [
|
|
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('
|
|
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('
|
|
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('
|
|
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}` : `
|
|
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(`
|
|
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) {
|