hedgequantx 1.1.1 → 1.2.32

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.
@@ -1,56 +1,368 @@
1
1
  /**
2
- * PropFirm API Configurations
3
- * UserAPI: Authentication, accounts, user info
4
- * GatewayAPI: Trading (orders, positions, trades)
2
+ * @fileoverview PropFirm API Configurations - Synced with Admin Dashboard
3
+ * @module config/propfirms
5
4
  */
6
5
 
6
+ /**
7
+ * PropFirm configurations
8
+ * Synced with: /root/HQX-Dev/hqx_tg/src/propfirms/config.ts
9
+ */
7
10
  const PROPFIRMS = {
11
+ // ==================== ProjectX Platform ====================
8
12
  topstep: {
9
- name: 'Topstep',
13
+ id: 'topstepx',
14
+ name: 'TopStep',
15
+ displayName: 'TopStep',
16
+ platform: 'ProjectX',
10
17
  userApi: 'userapi.topstepx.com',
11
18
  gatewayApi: 'api.topstepx.com'
12
19
  },
13
20
  alpha_futures: {
21
+ id: 'alphafutures',
14
22
  name: 'Alpha Futures',
23
+ displayName: 'Alpha Futures',
24
+ platform: 'ProjectX',
15
25
  userApi: 'userapi.alphafutures.projectx.com',
16
26
  gatewayApi: 'api.alphafutures.projectx.com'
17
27
  },
18
28
  tickticktrader: {
29
+ id: 'tickticktrader',
19
30
  name: 'TickTickTrader',
31
+ displayName: 'TickTickTrader',
32
+ platform: 'ProjectX',
20
33
  userApi: 'userapi.tickticktrader.projectx.com',
21
34
  gatewayApi: 'api.tickticktrader.projectx.com'
22
35
  },
23
36
  bulenox: {
37
+ id: 'bulenox',
24
38
  name: 'Bulenox',
39
+ displayName: 'Bulenox',
40
+ platform: 'ProjectX',
25
41
  userApi: 'userapi.bulenox.projectx.com',
26
42
  gatewayApi: 'api.bulenox.projectx.com'
27
43
  },
28
44
  tradeday: {
45
+ id: 'tradeday',
29
46
  name: 'TradeDay',
47
+ displayName: 'TradeDay',
48
+ platform: 'ProjectX',
30
49
  userApi: 'userapi.tradeday.projectx.com',
31
50
  gatewayApi: 'api.tradeday.projectx.com'
32
51
  },
33
52
  blusky: {
53
+ id: 'blusky',
34
54
  name: 'Blusky',
55
+ displayName: 'Blusky',
56
+ platform: 'ProjectX',
35
57
  userApi: 'userapi.blusky.projectx.com',
36
58
  gatewayApi: 'api.blusky.projectx.com'
37
59
  },
38
60
  goat_futures: {
61
+ id: 'goatfutures',
39
62
  name: 'Goat Futures',
40
- userApi: 'userapi.goatfunded.projectx.com',
41
- gatewayApi: 'api.goatfunded.projectx.com'
63
+ displayName: 'Goat Futures',
64
+ platform: 'ProjectX',
65
+ userApi: 'userapi.goatfutures.projectx.com',
66
+ gatewayApi: 'api.goatfutures.projectx.com'
42
67
  },
43
68
  futures_desk: {
69
+ id: 'thefuturesdesk',
44
70
  name: 'The Futures Desk',
71
+ displayName: 'The Futures Desk',
72
+ platform: 'ProjectX',
45
73
  userApi: 'userapi.thefuturesdesk.projectx.com',
46
74
  gatewayApi: 'api.thefuturesdesk.projectx.com'
75
+ },
76
+ daytraders: {
77
+ id: 'daytraders',
78
+ name: 'DayTraders',
79
+ displayName: 'DayTraders',
80
+ platform: 'ProjectX',
81
+ userApi: 'userapi.daytraders.projectx.com',
82
+ gatewayApi: 'api.daytraders.projectx.com'
83
+ },
84
+ e8_futures: {
85
+ id: 'e8futures',
86
+ name: 'E8 Futures',
87
+ displayName: 'E8 Futures',
88
+ platform: 'ProjectX',
89
+ userApi: 'userapi.e8futures.projectx.com',
90
+ gatewayApi: 'api.e8futures.projectx.com'
91
+ },
92
+ blue_guardian: {
93
+ id: 'blueguardianfutures',
94
+ name: 'Blue Guardian Futures',
95
+ displayName: 'Blue Guardian Futures',
96
+ platform: 'ProjectX',
97
+ userApi: 'userapi.blueguardianfutures.projectx.com',
98
+ gatewayApi: 'api.blueguardianfutures.projectx.com'
99
+ },
100
+ futures_elite: {
101
+ id: 'futureselite',
102
+ name: 'FuturesElite',
103
+ displayName: 'FuturesElite',
104
+ platform: 'ProjectX',
105
+ userApi: 'userapi.futureselite.projectx.com',
106
+ gatewayApi: 'api.futureselite.projectx.com'
107
+ },
108
+ fxify: {
109
+ id: 'fxify',
110
+ name: 'FXIFY',
111
+ displayName: 'FXIFY',
112
+ platform: 'ProjectX',
113
+ userApi: 'userapi.fxify.projectx.com',
114
+ gatewayApi: 'api.fxify.projectx.com'
115
+ },
116
+ hola_prime: {
117
+ id: 'holaprime',
118
+ name: 'Hola Prime',
119
+ displayName: 'Hola Prime',
120
+ platform: 'ProjectX',
121
+ userApi: 'userapi.holaprime.projectx.com',
122
+ gatewayApi: 'api.holaprime.projectx.com'
123
+ },
124
+ top_one_futures: {
125
+ id: 'toponefutures',
126
+ name: 'Top One Futures',
127
+ displayName: 'Top One Futures',
128
+ platform: 'ProjectX',
129
+ userApi: 'userapi.toponefutures.projectx.com',
130
+ gatewayApi: 'api.toponefutures.projectx.com'
131
+ },
132
+ funding_futures: {
133
+ id: 'fundingfutures',
134
+ name: 'Funding Futures',
135
+ displayName: 'Funding Futures',
136
+ platform: 'ProjectX',
137
+ userApi: 'userapi.fundingfutures.projectx.com',
138
+ gatewayApi: 'api.fundingfutures.projectx.com'
139
+ },
140
+ tx3_funding: {
141
+ id: 'tx3funding',
142
+ name: 'TX3 Funding',
143
+ displayName: 'TX3 Funding',
144
+ platform: 'ProjectX',
145
+ userApi: 'userapi.tx3funding.projectx.com',
146
+ gatewayApi: 'api.tx3funding.projectx.com'
147
+ },
148
+ lucid_trading: {
149
+ id: 'lucidtrading',
150
+ name: 'Lucid Trading',
151
+ displayName: 'Lucid Trading',
152
+ platform: 'ProjectX',
153
+ userApi: 'userapi.lucidtrading.projectx.com',
154
+ gatewayApi: 'api.lucidtrading.projectx.com'
155
+ },
156
+ tradeify: {
157
+ id: 'tradeify',
158
+ name: 'Tradeify',
159
+ displayName: 'Tradeify',
160
+ platform: 'ProjectX',
161
+ userApi: 'userapi.tradeify.projectx.com',
162
+ gatewayApi: 'api.tradeify.projectx.com'
163
+ },
164
+
165
+ // ==================== Tradovate Platform ====================
166
+ apex_tradovate: {
167
+ id: 'apex',
168
+ name: 'Apex',
169
+ displayName: 'Apex (Tradovate)',
170
+ platform: 'Tradovate',
171
+ userApi: 'userapi.apex.tradovate.com',
172
+ gatewayApi: 'api.apex.tradovate.com'
173
+ },
174
+ takeprofittrader: {
175
+ id: 'takeprofittrader',
176
+ name: 'TakeProfitTrader',
177
+ displayName: 'TakeProfitTrader',
178
+ platform: 'Tradovate',
179
+ userApi: 'userapi.takeprofittrader.tradovate.com',
180
+ gatewayApi: 'api.takeprofittrader.tradovate.com'
181
+ },
182
+
183
+ // ==================== Rithmic Platform ====================
184
+ apex_rithmic: {
185
+ id: 'rithmic-apex',
186
+ name: 'Apex',
187
+ displayName: 'Apex (Rithmic)',
188
+ platform: 'Rithmic',
189
+ rithmicSystem: 'Apex',
190
+ wsEndpoint: 'wss://ritpa11120.11.rithmic.com:443',
191
+ defaultStartingBalance: 300000
192
+ },
193
+ topsteptrader: {
194
+ id: 'topsteptrader',
195
+ name: 'TopstepTrader',
196
+ displayName: 'TopstepTrader',
197
+ platform: 'Rithmic',
198
+ rithmicSystem: 'TopstepTrader',
199
+ wsEndpoint: 'wss://ritpa11120.11.rithmic.com:443'
200
+ },
201
+ mes_capital: {
202
+ id: 'mes-capital',
203
+ name: 'MES Capital',
204
+ displayName: 'MES Capital',
205
+ platform: 'Rithmic',
206
+ rithmicSystem: 'MES Capital',
207
+ wsEndpoint: 'wss://ritpa11120.11.rithmic.com:443'
208
+ },
209
+ bulenox_rithmic: {
210
+ id: 'rithmic-bulenox',
211
+ name: 'Bulenox',
212
+ displayName: 'Bulenox (Rithmic)',
213
+ platform: 'Rithmic',
214
+ rithmicSystem: 'Bulenox',
215
+ wsEndpoint: 'wss://ritpa11120.11.rithmic.com:443'
216
+ },
217
+ tradefundrr: {
218
+ id: 'tradefundrr',
219
+ name: 'TradeFundrr',
220
+ displayName: 'TradeFundrr',
221
+ platform: 'Rithmic',
222
+ rithmicSystem: 'TradeFundrr',
223
+ wsEndpoint: 'wss://ritpa11120.11.rithmic.com:443'
224
+ },
225
+ thetradingpit: {
226
+ id: 'thetradingpit',
227
+ name: 'TheTradingPit',
228
+ displayName: 'TheTradingPit',
229
+ platform: 'Rithmic',
230
+ rithmicSystem: 'TheTradingPit',
231
+ wsEndpoint: 'wss://ritpa11120.11.rithmic.com:443'
232
+ },
233
+ fundedfuturesnetwork: {
234
+ id: 'fundedfuturesnetwork',
235
+ name: 'FundedFuturesNetwork',
236
+ displayName: 'FundedFuturesNetwork',
237
+ platform: 'Rithmic',
238
+ rithmicSystem: 'FundedFuturesNetwork',
239
+ wsEndpoint: 'wss://ritpa11120.11.rithmic.com:443'
240
+ },
241
+ propshoptrader: {
242
+ id: 'propshoptrader',
243
+ name: 'PropShopTrader',
244
+ displayName: 'PropShopTrader',
245
+ platform: 'Rithmic',
246
+ rithmicSystem: 'PropShopTrader',
247
+ wsEndpoint: 'wss://ritpa11120.11.rithmic.com:443'
248
+ },
249
+ fourproptrader: {
250
+ id: '4proptrader',
251
+ name: '4PropTrader',
252
+ displayName: '4PropTrader',
253
+ platform: 'Rithmic',
254
+ rithmicSystem: '4PropTrader',
255
+ wsEndpoint: 'wss://ritpa11120.11.rithmic.com:443'
256
+ },
257
+ daytraders_rithmic: {
258
+ id: 'rithmic-daytraders',
259
+ name: 'DayTraders.com',
260
+ displayName: 'DayTraders.com (Rithmic)',
261
+ platform: 'Rithmic',
262
+ rithmicSystem: 'DayTraders.com',
263
+ wsEndpoint: 'wss://ritpa11120.11.rithmic.com:443'
264
+ },
265
+ tenxfutures: {
266
+ id: '10xfutures',
267
+ name: '10XFutures',
268
+ displayName: '10XFutures',
269
+ platform: 'Rithmic',
270
+ rithmicSystem: '10XFutures',
271
+ wsEndpoint: 'wss://ritpa11120.11.rithmic.com:443'
272
+ },
273
+ lucidtrading_rithmic: {
274
+ id: 'rithmic-lucidtrading',
275
+ name: 'LucidTrading',
276
+ displayName: 'LucidTrading (Rithmic)',
277
+ platform: 'Rithmic',
278
+ rithmicSystem: 'LucidTrading',
279
+ wsEndpoint: 'wss://ritpa11120.11.rithmic.com:443'
280
+ },
281
+ thrivetrading: {
282
+ id: 'thrivetrading',
283
+ name: 'ThriveTrading',
284
+ displayName: 'ThriveTrading',
285
+ platform: 'Rithmic',
286
+ rithmicSystem: 'ThriveTrading',
287
+ wsEndpoint: 'wss://ritpa11120.11.rithmic.com:443'
288
+ },
289
+ legendstrading: {
290
+ id: 'legendstrading',
291
+ name: 'LegendsTrading',
292
+ displayName: 'LegendsTrading',
293
+ platform: 'Rithmic',
294
+ rithmicSystem: 'LegendsTrading',
295
+ wsEndpoint: 'wss://ritpa11120.11.rithmic.com:443'
296
+ },
297
+ earn2trade: {
298
+ id: 'earn2trade',
299
+ name: 'Earn2Trade',
300
+ displayName: 'Earn2Trade',
301
+ platform: 'Rithmic',
302
+ rithmicSystem: 'Earn2Trade',
303
+ wsEndpoint: 'wss://ritpa11120.11.rithmic.com:443'
304
+ },
305
+ tradesea: {
306
+ id: 'tradesea',
307
+ name: 'Tradesea',
308
+ displayName: 'Tradesea',
309
+ platform: 'Rithmic',
310
+ rithmicSystem: 'tradesea',
311
+ wsEndpoint: 'wss://ritpa11120.11.rithmic.com:443'
47
312
  }
48
313
  };
49
314
 
50
- // PropFirm display list for menus
51
- const PROPFIRM_CHOICES = Object.entries(PROPFIRMS).map(([key, val]) => ({
52
- name: val.name,
53
- value: key
54
- }));
315
+ /**
316
+ * PropFirm choices for menus (grouped by platform)
317
+ */
318
+ const PROPFIRM_CHOICES = {
319
+ projectx: Object.entries(PROPFIRMS)
320
+ .filter(([_, v]) => v.platform === 'ProjectX')
321
+ .map(([key, val]) => ({ name: val.displayName, value: key })),
322
+
323
+ tradovate: Object.entries(PROPFIRMS)
324
+ .filter(([_, v]) => v.platform === 'Tradovate')
325
+ .map(([key, val]) => ({ name: val.displayName, value: key })),
326
+
327
+ rithmic: Object.entries(PROPFIRMS)
328
+ .filter(([_, v]) => v.platform === 'Rithmic')
329
+ .map(([key, val]) => ({ name: val.displayName, value: key })),
330
+
331
+ all: Object.entries(PROPFIRMS)
332
+ .map(([key, val]) => ({ name: `${val.displayName} (${val.platform})`, value: key }))
333
+ };
334
+
335
+ /**
336
+ * Gets a PropFirm by key
337
+ * @param {string} key - PropFirm key
338
+ * @returns {Object|undefined} PropFirm config
339
+ */
340
+ const getPropFirm = (key) => PROPFIRMS[key];
341
+
342
+ /**
343
+ * Gets PropFirm by ID (synced with dashboard)
344
+ * @param {string} id - PropFirm ID
345
+ * @returns {Object|undefined} PropFirm config
346
+ */
347
+ const getPropFirmById = (id) => {
348
+ return Object.values(PROPFIRMS).find(pf => pf.id === id);
349
+ };
350
+
351
+ /**
352
+ * Gets all PropFirms for a platform
353
+ * @param {string} platform - Platform name (ProjectX, Tradovate, Rithmic)
354
+ * @returns {Array} PropFirm configs
355
+ */
356
+ const getPropFirmsByPlatform = (platform) => {
357
+ return Object.entries(PROPFIRMS)
358
+ .filter(([_, v]) => v.platform === platform)
359
+ .map(([key, val]) => ({ key, ...val }));
360
+ };
55
361
 
56
- module.exports = { PROPFIRMS, PROPFIRM_CHOICES };
362
+ module.exports = {
363
+ PROPFIRMS,
364
+ PROPFIRM_CHOICES,
365
+ getPropFirm,
366
+ getPropFirmById,
367
+ getPropFirmsByPlatform
368
+ };
@@ -0,0 +1,115 @@
1
+ /**
2
+ * @fileoverview Accounts page
3
+ * @module pages/accounts
4
+ */
5
+
6
+ const chalk = require('chalk');
7
+ const ora = require('ora');
8
+ const inquirer = require('inquirer');
9
+
10
+ const { connections } = require('../services');
11
+ const { ACCOUNT_STATUS, ACCOUNT_TYPE } = require('../config');
12
+ const { getLogoWidth, getColWidths, drawBoxHeader, drawBoxFooter, draw2ColHeader, visibleLength, padText } = require('../ui');
13
+
14
+ /**
15
+ * Shows all accounts from all connections
16
+ * @param {Object} service - Current service
17
+ */
18
+ const showAccounts = async (service) => {
19
+ const spinner = ora('Fetching accounts...').start();
20
+ const boxWidth = getLogoWidth();
21
+ const { col1, col2 } = getColWidths(boxWidth);
22
+
23
+ // Helper for row formatting
24
+ const fmtRow = (label, value, colW) => {
25
+ const labelStr = ' ' + label.padEnd(12);
26
+ const valueVisible = visibleLength(value || '');
27
+ const totalVisible = labelStr.length + valueVisible;
28
+ const padding = Math.max(0, colW - totalVisible);
29
+ return chalk.white(labelStr) + value + ' '.repeat(padding);
30
+ };
31
+
32
+ // Get accounts from all connections
33
+ let allAccounts = [];
34
+
35
+ if (connections.count() > 0) {
36
+ for (const conn of connections.getAll()) {
37
+ try {
38
+ const result = await conn.service.getTradingAccounts();
39
+ if (result.success && result.accounts) {
40
+ result.accounts.forEach(account => {
41
+ allAccounts.push({
42
+ ...account,
43
+ propfirm: conn.propfirm || conn.type,
44
+ service: conn.service
45
+ });
46
+ });
47
+ }
48
+ } catch (e) { /* ignore */ }
49
+ }
50
+ } else if (service) {
51
+ const result = await service.getTradingAccounts();
52
+ if (result.success && result.accounts) {
53
+ allAccounts = result.accounts.map(a => ({ ...a, service, propfirm: service.propfirm.name }));
54
+ }
55
+ }
56
+
57
+ if (allAccounts.length === 0) {
58
+ spinner.fail('No accounts found');
59
+ await inquirer.prompt([{ type: 'input', name: 'c', message: 'Press Enter to continue...' }]);
60
+ return;
61
+ }
62
+
63
+ spinner.succeed(`Found ${allAccounts.length} account(s)`);
64
+ console.log();
65
+
66
+ drawBoxHeader('TRADING ACCOUNTS', boxWidth);
67
+
68
+ // Display accounts 2 per row
69
+ for (let i = 0; i < allAccounts.length; i += 2) {
70
+ const acc1 = allAccounts[i];
71
+ const acc2 = allAccounts[i + 1];
72
+
73
+ const name1 = acc1.accountName || acc1.name || `Account #${acc1.accountId}`;
74
+ const name2 = acc2 ? (acc2.accountName || acc2.name || `Account #${acc2.accountId}`) : '';
75
+
76
+ draw2ColHeader(name1.substring(0, col1 - 4), name2.substring(0, col2 - 4), boxWidth);
77
+
78
+ // PropFirm
79
+ const pf1 = chalk.magenta(acc1.propfirm || 'Unknown');
80
+ const pf2 = acc2 ? chalk.magenta(acc2.propfirm || 'Unknown') : '';
81
+ console.log(chalk.cyan('║') + fmtRow('PropFirm:', pf1, col1) + chalk.cyan('│') + (acc2 ? fmtRow('PropFirm:', pf2, col2) : ' '.repeat(col2)) + chalk.cyan('║'));
82
+
83
+ // Balance
84
+ const bal1 = acc1.balance || 0;
85
+ const bal2 = acc2 ? (acc2.balance || 0) : 0;
86
+ const balColor1 = bal1 >= 0 ? chalk.green : chalk.red;
87
+ const balColor2 = bal2 >= 0 ? chalk.green : chalk.red;
88
+ console.log(chalk.cyan('║') + fmtRow('Balance:', balColor1('$' + bal1.toLocaleString()), col1) + chalk.cyan('│') + (acc2 ? fmtRow('Balance:', balColor2('$' + bal2.toLocaleString()), col2) : ' '.repeat(col2)) + chalk.cyan('║'));
89
+
90
+ // Status
91
+ const status1 = ACCOUNT_STATUS[acc1.status] || { text: 'Unknown', color: 'gray' };
92
+ const status2 = acc2 ? (ACCOUNT_STATUS[acc2.status] || { text: 'Unknown', color: 'gray' }) : null;
93
+ 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('║'));
94
+
95
+ // Type
96
+ const type1 = ACCOUNT_TYPE[acc1.type] || { text: 'Unknown', color: 'white' };
97
+ const type2 = acc2 ? (ACCOUNT_TYPE[acc2.type] || { text: 'Unknown', color: 'white' }) : null;
98
+ 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('║'));
99
+
100
+ // Account ID
101
+ console.log(chalk.cyan('║') + fmtRow('ID:', chalk.gray(acc1.accountId), col1) + chalk.cyan('│') + (acc2 ? fmtRow('ID:', chalk.gray(acc2.accountId), col2) : ' '.repeat(col2)) + chalk.cyan('║'));
102
+
103
+ // Separator between pairs
104
+ if (i + 2 < allAccounts.length) {
105
+ console.log(chalk.cyan('╠') + chalk.cyan('═'.repeat(col1)) + chalk.cyan('╪') + chalk.cyan('═'.repeat(col2)) + chalk.cyan('╣'));
106
+ }
107
+ }
108
+
109
+ drawBoxFooter(boxWidth);
110
+ console.log();
111
+
112
+ await inquirer.prompt([{ type: 'input', name: 'c', message: 'Press Enter to continue...' }]);
113
+ };
114
+
115
+ module.exports = { showAccounts };