hedgequantx 2.6.163 → 2.7.1

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 (146) hide show
  1. package/README.md +15 -88
  2. package/bin/cli.js +0 -11
  3. package/dist/lib/api.jsc +0 -0
  4. package/dist/lib/api2.jsc +0 -0
  5. package/dist/lib/core.jsc +0 -0
  6. package/dist/lib/core2.jsc +0 -0
  7. package/dist/lib/data.js +1 -1
  8. package/dist/lib/data.jsc +0 -0
  9. package/dist/lib/data2.jsc +0 -0
  10. package/dist/lib/decoder.jsc +0 -0
  11. package/dist/lib/m/mod1.jsc +0 -0
  12. package/dist/lib/m/mod2.jsc +0 -0
  13. package/dist/lib/n/r1.jsc +0 -0
  14. package/dist/lib/n/r2.jsc +0 -0
  15. package/dist/lib/n/r3.jsc +0 -0
  16. package/dist/lib/n/r4.jsc +0 -0
  17. package/dist/lib/n/r5.jsc +0 -0
  18. package/dist/lib/n/r6.jsc +0 -0
  19. package/dist/lib/n/r7.jsc +0 -0
  20. package/dist/lib/o/util1.jsc +0 -0
  21. package/dist/lib/o/util2.jsc +0 -0
  22. package/package.json +8 -5
  23. package/src/app.js +40 -162
  24. package/src/config/constants.js +31 -33
  25. package/src/config/propfirms.js +13 -217
  26. package/src/config/settings.js +0 -43
  27. package/src/lib/api.js +198 -0
  28. package/src/lib/api2.js +353 -0
  29. package/src/lib/core.js +539 -0
  30. package/src/lib/core2.js +341 -0
  31. package/src/lib/data.js +555 -0
  32. package/src/lib/data2.js +492 -0
  33. package/src/lib/decoder.js +599 -0
  34. package/src/lib/m/s1.js +804 -0
  35. package/src/lib/m/s2.js +34 -0
  36. package/src/lib/n/r1.js +454 -0
  37. package/src/lib/n/r2.js +514 -0
  38. package/src/lib/n/r3.js +631 -0
  39. package/src/lib/n/r4.js +401 -0
  40. package/src/lib/n/r5.js +335 -0
  41. package/src/lib/n/r6.js +425 -0
  42. package/src/lib/n/r7.js +530 -0
  43. package/src/lib/o/l1.js +44 -0
  44. package/src/lib/o/l2.js +427 -0
  45. package/src/lib/python-bridge.js +206 -0
  46. package/src/menus/connect.js +14 -176
  47. package/src/menus/dashboard.js +65 -110
  48. package/src/pages/accounts.js +18 -18
  49. package/src/pages/algo/copy-trading.js +210 -240
  50. package/src/pages/algo/index.js +41 -104
  51. package/src/pages/algo/one-account.js +386 -33
  52. package/src/pages/algo/ui.js +312 -151
  53. package/src/pages/orders.js +3 -3
  54. package/src/pages/positions.js +3 -3
  55. package/src/pages/stats/chart.js +74 -0
  56. package/src/pages/stats/display.js +228 -0
  57. package/src/pages/stats/index.js +236 -0
  58. package/src/pages/stats/metrics.js +213 -0
  59. package/src/pages/user.js +6 -6
  60. package/src/services/hqx-server/constants.js +55 -0
  61. package/src/services/hqx-server/index.js +401 -0
  62. package/src/services/hqx-server/latency.js +81 -0
  63. package/src/services/index.js +12 -3
  64. package/src/services/rithmic/accounts.js +7 -32
  65. package/src/services/rithmic/connection.js +1 -204
  66. package/src/services/rithmic/contracts.js +116 -99
  67. package/src/services/rithmic/handlers.js +21 -196
  68. package/src/services/rithmic/index.js +63 -120
  69. package/src/services/rithmic/market.js +31 -0
  70. package/src/services/rithmic/orders.js +5 -111
  71. package/src/services/rithmic/protobuf.js +384 -138
  72. package/src/services/session.js +22 -173
  73. package/src/ui/box.js +10 -18
  74. package/src/ui/index.js +1 -3
  75. package/src/ui/menu.js +1 -1
  76. package/src/utils/prompts.js +2 -2
  77. package/dist/lib/m/s1.js +0 -1
  78. package/src/menus/ai-agent-connect.js +0 -181
  79. package/src/menus/ai-agent-models.js +0 -219
  80. package/src/menus/ai-agent-oauth.js +0 -292
  81. package/src/menus/ai-agent-ui.js +0 -141
  82. package/src/menus/ai-agent.js +0 -484
  83. package/src/pages/algo/algo-config.js +0 -195
  84. package/src/pages/algo/algo-multi.js +0 -801
  85. package/src/pages/algo/algo-utils.js +0 -58
  86. package/src/pages/algo/copy-engine.js +0 -449
  87. package/src/pages/algo/custom-strategy.js +0 -459
  88. package/src/pages/algo/logger.js +0 -245
  89. package/src/pages/algo/smart-logs-data.js +0 -218
  90. package/src/pages/algo/smart-logs.js +0 -387
  91. package/src/pages/algo/ui-constants.js +0 -144
  92. package/src/pages/algo/ui-summary.js +0 -184
  93. package/src/pages/stats-calculations.js +0 -191
  94. package/src/pages/stats-ui.js +0 -381
  95. package/src/pages/stats.js +0 -339
  96. package/src/services/ai/client-analysis.js +0 -194
  97. package/src/services/ai/client-models.js +0 -333
  98. package/src/services/ai/client.js +0 -343
  99. package/src/services/ai/index.js +0 -384
  100. package/src/services/ai/oauth-anthropic.js +0 -265
  101. package/src/services/ai/oauth-gemini.js +0 -223
  102. package/src/services/ai/oauth-iflow.js +0 -269
  103. package/src/services/ai/oauth-openai.js +0 -233
  104. package/src/services/ai/oauth-qwen.js +0 -279
  105. package/src/services/ai/providers/direct-providers.js +0 -323
  106. package/src/services/ai/providers/index.js +0 -62
  107. package/src/services/ai/providers/other-providers.js +0 -104
  108. package/src/services/ai/proxy-install.js +0 -249
  109. package/src/services/ai/proxy-manager.js +0 -494
  110. package/src/services/ai/proxy-remote.js +0 -161
  111. package/src/services/ai/strategy-supervisor.js +0 -1312
  112. package/src/services/ai/supervisor-data.js +0 -195
  113. package/src/services/ai/supervisor-optimize.js +0 -215
  114. package/src/services/ai/supervisor-sync.js +0 -178
  115. package/src/services/ai/supervisor-utils.js +0 -158
  116. package/src/services/ai/supervisor.js +0 -484
  117. package/src/services/ai/validation.js +0 -250
  118. package/src/services/hqx-server-events.js +0 -110
  119. package/src/services/hqx-server-handlers.js +0 -217
  120. package/src/services/hqx-server-latency.js +0 -136
  121. package/src/services/hqx-server.js +0 -403
  122. package/src/services/position-constants.js +0 -28
  123. package/src/services/position-exit-logic.js +0 -174
  124. package/src/services/position-manager.js +0 -438
  125. package/src/services/position-momentum.js +0 -206
  126. package/src/services/projectx/accounts.js +0 -142
  127. package/src/services/projectx/index.js +0 -443
  128. package/src/services/projectx/market.js +0 -172
  129. package/src/services/projectx/stats.js +0 -110
  130. package/src/services/projectx/trading.js +0 -180
  131. package/src/services/rithmic/latency-tracker.js +0 -182
  132. package/src/services/rithmic/market-data-decoders.js +0 -229
  133. package/src/services/rithmic/market-data.js +0 -272
  134. package/src/services/rithmic/orders-fast.js +0 -246
  135. package/src/services/rithmic/proto-decoders.js +0 -403
  136. package/src/services/rithmic/specs.js +0 -146
  137. package/src/services/rithmic/trade-history.js +0 -254
  138. package/src/services/session-history.js +0 -475
  139. package/src/services/strategy/hft-signal-calc.js +0 -147
  140. package/src/services/strategy/hft-tick.js +0 -407
  141. package/src/services/strategy/recovery-math.js +0 -402
  142. package/src/services/tradovate/constants.js +0 -109
  143. package/src/services/tradovate/index.js +0 -392
  144. package/src/services/tradovate/market.js +0 -47
  145. package/src/services/tradovate/orders.js +0 -145
  146. package/src/services/tradovate/websocket.js +0 -97
@@ -1,339 +0,0 @@
1
- /**
2
- * Stats Page
3
- *
4
- * STRICT RULE: Display ONLY values returned by API
5
- * - ProjectX: Uses /api/Trade/search, /Position, /TradingAccount APIs
6
- * - Rithmic: Uses PNL_PLANT for balance/P&L, ORDER_PLANT for accounts
7
- * - NO estimation, NO simulation, NO mock data
8
- */
9
-
10
- const chalk = require('chalk');
11
- const ora = require('ora');
12
-
13
- const { connections } = require('../services');
14
- const { getLogoWidth, drawBoxHeader, drawBoxFooter, getColWidths, draw2ColHeader, draw2ColSeparator, fmtRow } = require('../ui');
15
- const { prompts } = require('../utils');
16
- const aiService = require('../services/ai');
17
- const AISupervisor = require('../services/ai/supervisor');
18
- const StrategySupervisor = require('../services/ai/strategy-supervisor');
19
- const { calculateTradeStats, calculateQuantMetrics, calculateHQXScore, extractSymbol } = require('./stats-calculations');
20
- const { renderAISupervision, renderAIBehavior, renderEquityCurve, renderTradesHistory, renderHQXScore } = require('./stats-ui');
21
-
22
- /**
23
- * Show Stats Page
24
- * Aggregates data from all connections (ProjectX, Rithmic, Tradovate)
25
- */
26
- const showStats = async (service) => {
27
- let spinner;
28
-
29
- try {
30
- spinner = ora({ text: 'LOADING STATS...', color: 'yellow' }).start();
31
-
32
- // Get all connections
33
- const allConns = connections.count() > 0
34
- ? connections.getAll()
35
- : (service ? [{ service, propfirm: service.propfirm?.name || 'Unknown', type: 'single' }] : []);
36
-
37
- if (allConns.length === 0) {
38
- spinner.fail('NO CONNECTIONS FOUND');
39
- await prompts.waitForEnter();
40
- return;
41
- }
42
-
43
- // Track connection types for display
44
- const connectionTypes = {
45
- projectx: 0,
46
- rithmic: 0,
47
- tradovate: 0
48
- };
49
-
50
- // Fetch accounts from each connection with type detection
51
- let allAccountsData = [];
52
-
53
- for (const conn of allConns) {
54
- const connType = conn.type || 'projectx';
55
- const propfirmName = conn.propfirm || conn.type || 'Unknown';
56
-
57
- // Count connection types
58
- if (connType === 'projectx') connectionTypes.projectx++;
59
- else if (connType === 'rithmic') connectionTypes.rithmic++;
60
- else if (connType === 'tradovate') connectionTypes.tradovate++;
61
-
62
- try {
63
- const result = await conn.service.getTradingAccounts();
64
- if (result.success && result.accounts && result.accounts.length > 0) {
65
- result.accounts.forEach(account => {
66
- allAccountsData.push({
67
- ...account,
68
- propfirm: propfirmName,
69
- connectionType: connType,
70
- service: conn.service
71
- });
72
- });
73
- }
74
- } catch (e) {
75
- // Silently skip failed connections
76
- }
77
- }
78
-
79
- if (allAccountsData.length === 0) {
80
- spinner.fail('NO ACCOUNTS FOUND');
81
- await prompts.waitForEnter();
82
- return;
83
- }
84
-
85
- // Remove duplicates by accountId
86
- const seen = new Set();
87
- allAccountsData = allAccountsData.filter(acc => {
88
- const id = String(acc.accountId);
89
- if (seen.has(id)) return false;
90
- seen.add(id);
91
- return true;
92
- });
93
-
94
- // Filter only active accounts (status === 0)
95
- const activeAccounts = allAccountsData.filter(acc => acc.status === 0);
96
-
97
- if (activeAccounts.length === 0) {
98
- spinner.fail('NO ACTIVE ACCOUNTS FOUND');
99
- await prompts.waitForEnter();
100
- return;
101
- }
102
-
103
- // ========== AGGREGATE DATA FROM APIs ==========
104
- // All values come from APIs - NO local calculation for P&L
105
-
106
- let totalBalance = 0;
107
- let totalPnL = 0;
108
- let totalStartingBalance = 0;
109
- let allTrades = [];
110
- let totalOpenPositions = 0;
111
- let totalOpenOrders = 0;
112
-
113
- // Track data availability (null means no data from API)
114
- let hasBalanceData = false;
115
- let hasPnLData = false;
116
- let hasTradeData = false;
117
-
118
- for (let i = 0; i < activeAccounts.length; i++) {
119
- const account = activeAccounts[i];
120
- const svc = account.service;
121
- const connType = account.connectionType || 'projectx';
122
-
123
- try {
124
- // ===== BALANCE (from API) =====
125
- if (account.balance !== null && account.balance !== undefined) {
126
- totalBalance += account.balance;
127
- hasBalanceData = true;
128
- }
129
-
130
- // ===== P&L (from API - NEVER calculated locally) =====
131
- // ProjectX: profitAndLoss comes from /Position API (unrealized) + /Trade API (realized)
132
- // Rithmic: profitAndLoss comes from PNL_PLANT (dayPnl or openPnl + closedPnl)
133
- if (account.profitAndLoss !== null && account.profitAndLoss !== undefined) {
134
- totalPnL += account.profitAndLoss;
135
- hasPnLData = true;
136
- }
137
-
138
- // ===== STARTING BALANCE =====
139
- // Derived: startingBalance from API or calculated as balance - P&L
140
- if (account.startingBalance !== null && account.startingBalance !== undefined) {
141
- totalStartingBalance += account.startingBalance;
142
- } else if (account.balance !== null && account.balance !== undefined) {
143
- const pnl = account.profitAndLoss || 0;
144
- totalStartingBalance += (account.balance - pnl);
145
- }
146
-
147
- // ===== POSITIONS (from API) =====
148
- try {
149
- const posResult = await svc.getPositions(account.accountId);
150
- if (posResult.success && posResult.positions) {
151
- totalOpenPositions += posResult.positions.length;
152
- }
153
- } catch (e) {}
154
-
155
- // ===== ORDERS (from API) =====
156
- try {
157
- const ordResult = await svc.getOrders(account.accountId);
158
- if (ordResult.success && ordResult.orders) {
159
- totalOpenOrders += ordResult.orders.filter(o => o.status === 1 || o.status === 'Working').length;
160
- }
161
- } catch (e) {}
162
-
163
- // ===== LIFETIME STATS (from API - ProjectX only) =====
164
- // Rithmic doesn't have getLifetimeStats - returns null
165
- if (typeof svc.getLifetimeStats === 'function') {
166
- try {
167
- const lifetimeResult = await svc.getLifetimeStats(account.accountId);
168
- if (lifetimeResult.success && lifetimeResult.stats) {
169
- account.lifetimeStats = lifetimeResult.stats;
170
- }
171
- } catch (e) {}
172
- }
173
-
174
- // ===== TRADE HISTORY (from API) =====
175
- // ProjectX: Historical trades from API
176
- // Rithmic: Session trades tracked locally (entry/exit matching)
177
- if (typeof svc.getTradeHistory === 'function') {
178
- try {
179
- const tradesResult = await svc.getTradeHistory(account.accountId, 30);
180
- if (tradesResult.success && tradesResult.trades && tradesResult.trades.length > 0) {
181
- hasTradeData = true;
182
- allTrades = allTrades.concat(tradesResult.trades.map(t => ({
183
- ...t,
184
- accountName: account.accountName,
185
- propfirm: account.propfirm,
186
- connectionType: connType
187
- })));
188
- }
189
- } catch (e) {}
190
- }
191
- } catch (e) {}
192
- }
193
-
194
- // ========== AGGREGATE STATS FROM TRADE HISTORY (API DATA) ==========
195
- // Filter to completed trades only (P&L != 0, not null)
196
- const completedTrades = allTrades.filter(t => {
197
- const pnl = t.profitAndLoss || t.pnl;
198
- return pnl !== null && pnl !== undefined && pnl !== 0;
199
- });
200
-
201
- // Calculate stats from completed trades (uses stats-calculations.js)
202
- const stats = calculateTradeStats(completedTrades);
203
-
204
- spinner.succeed('STATS LOADED');
205
- console.log();
206
-
207
- // ========== DISPLAY ==========
208
- const boxWidth = getLogoWidth();
209
- const { col1, col2 } = getColWidths(boxWidth);
210
-
211
- // Calculate metrics (using API data only)
212
- const winRate = stats.totalTrades > 0 ? ((stats.winningTrades / stats.totalTrades) * 100).toFixed(1) : 'N/A';
213
- const avgWin = stats.winningTrades > 0 ? (stats.totalWinAmount / stats.winningTrades).toFixed(2) : '0.00';
214
- const avgLoss = stats.losingTrades > 0 ? (stats.totalLossAmount / stats.losingTrades).toFixed(2) : '0.00';
215
- const profitFactor = stats.totalLossAmount > 0
216
- ? (stats.totalWinAmount / stats.totalLossAmount).toFixed(2)
217
- : (stats.totalWinAmount > 0 ? '∞' : 'N/A');
218
- const netPnL = stats.totalWinAmount - stats.totalLossAmount;
219
- const returnPercent = totalStartingBalance > 0 ? ((totalPnL / totalStartingBalance) * 100).toFixed(2) : 'N/A';
220
- const longWinRate = stats.longTrades > 0 ? ((stats.longWins / stats.longTrades) * 100).toFixed(1) : 'N/A';
221
- const shortWinRate = stats.shortTrades > 0 ? ((stats.shortWins / stats.shortTrades) * 100).toFixed(1) : 'N/A';
222
-
223
- // Quantitative metrics (uses stats-calculations.js)
224
- const quantMetrics = calculateQuantMetrics(completedTrades, totalStartingBalance);
225
- const { avgReturn, stdDev, sharpeRatio, sortinoRatio, maxDrawdown, tradePnLs } = quantMetrics;
226
-
227
- const expectancy = stats.totalTrades > 0 ? netPnL / stats.totalTrades : 0;
228
- const riskRewardRatio = parseFloat(avgLoss) > 0 ? (parseFloat(avgWin) / parseFloat(avgLoss)).toFixed(2) : 'N/A';
229
- const calmarRatio = maxDrawdown > 0 && returnPercent !== 'N/A' ? (parseFloat(returnPercent) / maxDrawdown).toFixed(2) : 'N/A';
230
-
231
- // Colors
232
- const totalBalanceColor = hasBalanceData ? (totalBalance >= 0 ? chalk.green : chalk.red) : chalk.gray;
233
- const pnlColor = hasPnLData ? (totalPnL >= 0 ? chalk.green : chalk.red) : chalk.gray;
234
-
235
- // Connection type string
236
- const connTypeStr = [];
237
- if (connectionTypes.projectx > 0) connTypeStr.push(`ProjectX(${connectionTypes.projectx})`);
238
- if (connectionTypes.rithmic > 0) connTypeStr.push(`Rithmic(${connectionTypes.rithmic})`);
239
- if (connectionTypes.tradovate > 0) connTypeStr.push(`Tradovate(${connectionTypes.tradovate})`);
240
-
241
- // ========== MAIN SUMMARY ==========
242
- drawBoxHeader('HQX STATS', boxWidth);
243
- draw2ColHeader('ACCOUNT OVERVIEW', 'TRADING PERFORMANCE', boxWidth);
244
-
245
- // Format balance/P&L - show "N/A" if no data from API
246
- const balanceStr = hasBalanceData ? '$' + totalBalance.toLocaleString(undefined, {minimumFractionDigits: 2}) : 'N/A';
247
- const pnlStr = hasPnLData
248
- ? (totalPnL >= 0 ? '+' : '') + '$' + totalPnL.toLocaleString(undefined, {minimumFractionDigits: 2}) + (returnPercent !== 'N/A' ? ' (' + returnPercent + '%)' : '')
249
- : 'N/A';
250
- const startBalStr = totalStartingBalance > 0 ? '$' + totalStartingBalance.toLocaleString(undefined, {minimumFractionDigits: 2}) : 'N/A';
251
-
252
- console.log(chalk.cyan('\u2551') + fmtRow('CONNECTIONS:', chalk.cyan(connTypeStr.join(', ') || String(connections.count() || 1)), col1) + chalk.cyan('\u2502') + fmtRow('TOTAL TRADES:', hasTradeData || stats.totalTrades > 0 ? chalk.white(String(stats.totalTrades)) : chalk.gray('N/A'), col2) + chalk.cyan('\u2551'));
253
- console.log(chalk.cyan('\u2551') + fmtRow('TOTAL ACCOUNTS:', chalk.cyan(String(activeAccounts.length)), col1) + chalk.cyan('\u2502') + fmtRow('WINNING TRADES:', hasTradeData || stats.winningTrades > 0 ? chalk.green(String(stats.winningTrades)) : chalk.gray('N/A'), col2) + chalk.cyan('\u2551'));
254
- console.log(chalk.cyan('\u2551') + fmtRow('TOTAL BALANCE:', totalBalanceColor(balanceStr), col1) + chalk.cyan('\u2502') + fmtRow('LOSING TRADES:', hasTradeData || stats.losingTrades > 0 ? chalk.red(String(stats.losingTrades)) : chalk.gray('N/A'), col2) + chalk.cyan('\u2551'));
255
- 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'));
256
- 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'));
257
- 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'));
258
- 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'));
259
-
260
- // ========== P&L METRICS ==========
261
- draw2ColSeparator(boxWidth);
262
- draw2ColHeader('P&L METRICS', 'RISK METRICS', boxWidth);
263
-
264
- // Profit Factor coloring
265
- const pfColor = profitFactor === '∞' ? chalk.green(profitFactor)
266
- : profitFactor === 'N/A' ? chalk.gray(profitFactor)
267
- : parseFloat(profitFactor) >= 1.5 ? chalk.green(profitFactor)
268
- : parseFloat(profitFactor) >= 1 ? chalk.yellow(profitFactor)
269
- : chalk.red(profitFactor);
270
-
271
- // Worst trade display
272
- const worstTradeStr = stats.worstTrade < 0 ? '-$' + Math.abs(stats.worstTrade).toFixed(2) : '$' + stats.worstTrade.toFixed(2);
273
-
274
- const netPnLStr = hasTradeData ? (netPnL >= 0 ? chalk.green('$' + netPnL.toFixed(2)) : chalk.red('-$' + Math.abs(netPnL).toFixed(2))) : chalk.gray('N/A');
275
-
276
- console.log(chalk.cyan('\u2551') + fmtRow('NET P&L:', netPnLStr, col1) + chalk.cyan('\u2502') + fmtRow('PROFIT FACTOR:', pfColor, col2) + chalk.cyan('\u2551'));
277
- console.log(chalk.cyan('\u2551') + fmtRow('GROSS PROFIT:', hasTradeData ? chalk.green('$' + stats.totalWinAmount.toFixed(2)) : chalk.gray('N/A'), col1) + chalk.cyan('\u2502') + fmtRow('MAX CONSEC. WINS:', hasTradeData ? chalk.green(String(stats.maxConsecutiveWins)) : chalk.gray('N/A'), col2) + chalk.cyan('\u2551'));
278
- console.log(chalk.cyan('\u2551') + fmtRow('GROSS LOSS:', hasTradeData ? chalk.red('-$' + stats.totalLossAmount.toFixed(2)) : chalk.gray('N/A'), col1) + chalk.cyan('\u2502') + fmtRow('MAX CONSEC. LOSS:', hasTradeData ? (stats.maxConsecutiveLosses > 0 ? chalk.red(String(stats.maxConsecutiveLosses)) : chalk.green('0')) : chalk.gray('N/A'), col2) + chalk.cyan('\u2551'));
279
- console.log(chalk.cyan('\u2551') + fmtRow('AVG WIN:', hasTradeData ? chalk.green('$' + avgWin) : chalk.gray('N/A'), col1) + chalk.cyan('\u2502') + fmtRow('BEST TRADE:', hasTradeData ? chalk.green('$' + stats.bestTrade.toFixed(2)) : chalk.gray('N/A'), col2) + chalk.cyan('\u2551'));
280
- console.log(chalk.cyan('\u2551') + fmtRow('AVG LOSS:', hasTradeData ? (stats.losingTrades > 0 ? chalk.red('-$' + avgLoss) : chalk.green('$0.00')) : chalk.gray('N/A'), col1) + chalk.cyan('\u2502') + fmtRow('WORST TRADE:', hasTradeData ? (stats.worstTrade < 0 ? chalk.red(worstTradeStr) : chalk.green(worstTradeStr)) : chalk.gray('N/A'), col2) + chalk.cyan('\u2551'));
281
-
282
- // ========== QUANTITATIVE METRICS ==========
283
- draw2ColSeparator(boxWidth);
284
- draw2ColHeader('QUANTITATIVE METRICS', 'ADVANCED RATIOS', boxWidth);
285
-
286
- const sharpeColor = sharpeRatio === 'N/A' ? chalk.gray : parseFloat(sharpeRatio) >= 1 ? chalk.green : parseFloat(sharpeRatio) >= 0.5 ? chalk.yellow : chalk.red;
287
- const sortinoColor = sortinoRatio === 'N/A' ? chalk.gray : parseFloat(sortinoRatio) >= 1.5 ? chalk.green : parseFloat(sortinoRatio) >= 0.5 ? chalk.yellow : chalk.red;
288
- const ddColor = maxDrawdown === 0 ? chalk.gray : maxDrawdown <= 5 ? chalk.green : maxDrawdown <= 15 ? chalk.yellow : chalk.red;
289
- const rrColor = riskRewardRatio === 'N/A' ? chalk.gray : parseFloat(riskRewardRatio) >= 2 ? chalk.green : parseFloat(riskRewardRatio) >= 1 ? chalk.yellow : chalk.red;
290
-
291
- console.log(chalk.cyan('\u2551') + fmtRow('SHARPE RATIO:', sharpeColor(sharpeRatio), col1) + chalk.cyan('\u2502') + fmtRow('RISK/REWARD:', rrColor(riskRewardRatio), col2) + chalk.cyan('\u2551'));
292
- console.log(chalk.cyan('\u2551') + fmtRow('SORTINO RATIO:', sortinoColor(sortinoRatio), col1) + chalk.cyan('\u2502') + fmtRow('CALMAR RATIO:', calmarRatio === 'N/A' ? chalk.gray(calmarRatio) : chalk.white(calmarRatio), col2) + chalk.cyan('\u2551'));
293
- console.log(chalk.cyan('\u2551') + fmtRow('MAX DRAWDOWN:', hasTradeData && maxDrawdown > 0 ? ddColor(maxDrawdown.toFixed(2) + '%') : chalk.gray('N/A'), col1) + chalk.cyan('\u2502') + fmtRow('EXPECTANCY:', hasTradeData ? (expectancy >= 0 ? chalk.green('$' + expectancy.toFixed(2)) : chalk.red('$' + expectancy.toFixed(2))) : chalk.gray('N/A'), col2) + chalk.cyan('\u2551'));
294
- console.log(chalk.cyan('\u2551') + fmtRow('STD DEVIATION:', hasTradeData ? chalk.white('$' + stdDev.toFixed(2)) : chalk.gray('N/A'), col1) + chalk.cyan('\u2502') + fmtRow('AVG TRADE:', hasTradeData ? (avgReturn >= 0 ? chalk.green('$' + avgReturn.toFixed(2)) : chalk.red('$' + avgReturn.toFixed(2))) : chalk.gray('N/A'), col2) + chalk.cyan('\u2551'));
295
-
296
- drawBoxFooter(boxWidth);
297
-
298
- // ========== AI SUPERVISION ==========
299
- const aiAgents = aiService.getAgents();
300
- const supervisionStatus = AISupervisor.getAllStatus();
301
-
302
- if (aiAgents.length > 0) {
303
- console.log();
304
- renderAISupervision(aiAgents, supervisionStatus, AISupervisor, boxWidth, col1, col2);
305
- renderAIBehavior(StrategySupervisor, boxWidth);
306
- }
307
-
308
- // ========== EQUITY CURVE ==========
309
- console.log();
310
- renderEquityCurve(allTrades, totalStartingBalance, connectionTypes, boxWidth);
311
-
312
- // ========== TRADES HISTORY ==========
313
- console.log();
314
- renderTradesHistory(completedTrades, connectionTypes, extractSymbol, boxWidth);
315
-
316
- // ========== HQX SCORE ==========
317
- if (hasTradeData || stats.totalTrades > 0) {
318
- console.log();
319
- const hqxData = calculateHQXScore(stats, totalStartingBalance, returnPercent, profitFactor, winRate);
320
- renderHQXScore(hqxData, boxWidth);
321
- }
322
-
323
- console.log();
324
-
325
- // Show data source notice
326
- if (connectionTypes.rithmic > 0 && connectionTypes.projectx === 0) {
327
- console.log(chalk.gray(' NOTE: RITHMIC API PROVIDES BALANCE/P&L ONLY. TRADE HISTORY NOT AVAILABLE.'));
328
- } else if (connectionTypes.rithmic > 0 && connectionTypes.projectx > 0) {
329
- console.log(chalk.gray(' NOTE: TRADE HISTORY SHOWN FROM PROJECTX ACCOUNTS ONLY.'));
330
- }
331
-
332
- } catch (error) {
333
- if (spinner) spinner.fail('Error: ' + error.message);
334
- }
335
-
336
- await prompts.waitForEnter();
337
- };
338
-
339
- module.exports = { showStats };
@@ -1,194 +0,0 @@
1
- /**
2
- * @fileoverview AI Client - Trading Analysis Functions
3
- *
4
- * Functions to analyze trading data with AI
5
- * Uses callAI from client.js core
6
- */
7
-
8
- /**
9
- * Analyze trading data with AI
10
- * @param {Function} callAI - The callAI function from client.js
11
- * @param {Object} agent - AI agent
12
- * @param {Object} data - Trading data from APIs
13
- * @returns {Promise<Object|null>} Analysis result or null
14
- */
15
- const analyzeTrading = async (callAI, agent, data) => {
16
- if (!agent || !data) return null;
17
-
18
- const systemPrompt = `You are a professional trading analyst for prop firm futures trading.
19
- Analyze the provided real-time trading data and provide actionable insights.
20
- Be concise. Focus on risk management and optimization.
21
- Respond in JSON format with: { "action": "HOLD|REDUCE_SIZE|PAUSE|CONTINUE", "confidence": 0-100, "reason": "brief reason" }`;
22
-
23
- const prompt = `Current trading session data:
24
- - Account Balance: ${data.account?.balance ?? 'N/A'}
25
- - Today P&L: ${data.account?.profitAndLoss ?? 'N/A'}
26
- - Open Positions: ${data.positions?.length ?? 0}
27
- - Open Orders: ${data.orders?.length ?? 0}
28
- - Today Trades: ${data.trades?.length ?? 0}
29
-
30
- ${data.positions?.length > 0 ? `Positions: ${JSON.stringify(data.positions.map(p => ({
31
- symbol: p.symbol || p.contractId,
32
- qty: p.quantity,
33
- pnl: p.profitAndLoss
34
- })))}` : ''}
35
-
36
- Analyze and provide recommendation.`;
37
-
38
- try {
39
- const response = await callAI(agent, prompt, systemPrompt);
40
- if (!response) return null;
41
-
42
- const jsonMatch = response.match(/\{[\s\S]*\}/);
43
- if (jsonMatch) {
44
- return JSON.parse(jsonMatch[0]);
45
- }
46
-
47
- return null;
48
- } catch (error) {
49
- return null;
50
- }
51
- };
52
-
53
- /**
54
- * Analyze strategy performance and suggest optimizations
55
- * @param {Function} callAI - The callAI function from client.js
56
- * @param {Object} agent - AI agent
57
- * @param {Object} performanceData - Strategy performance data
58
- * @returns {Promise<Object|null>} Optimization suggestions
59
- */
60
- const analyzePerformance = async (callAI, agent, performanceData) => {
61
- if (!agent || !performanceData) return null;
62
-
63
- const systemPrompt = `You are an AI supervisor for HQX Ultra Scalping, a professional prop firm futures trading strategy.
64
-
65
- The strategy uses advanced mathematical models:
66
- - Order flow analysis (delta, cumulative delta, absorption)
67
- - Market microstructure (bid/ask imbalance, volume profile)
68
- - Statistical edge detection (z-score, standard deviation bands)
69
- - Dynamic risk management (Kelly criterion, volatility-adjusted sizing)
70
-
71
- Your job is to analyze performance data and suggest parameter optimizations.
72
- Be precise and actionable. Focus on improving win rate, reducing drawdown, and optimizing risk/reward.
73
-
74
- Respond ONLY in valid JSON format:
75
- {
76
- "assessment": "brief performance assessment",
77
- "winRateAnalysis": "analysis of win/loss patterns",
78
- "riskAnalysis": "analysis of risk management",
79
- "optimizations": [
80
- { "param": "parameter_name", "current": "current_value", "suggested": "new_value", "reason": "why" }
81
- ],
82
- "marketCondition": "trending|ranging|volatile|calm",
83
- "confidence": 0-100
84
- }`;
85
-
86
- const prompt = `STRATEGY PERFORMANCE DATA - ANALYZE AND OPTIMIZE
87
-
88
- Session Stats:
89
- - Trades: ${performanceData.trades || 0}
90
- - Wins: ${performanceData.wins || 0}
91
- - Losses: ${performanceData.losses || 0}
92
- - Win Rate: ${performanceData.winRate ? (performanceData.winRate * 100).toFixed(1) + '%' : 'N/A'}
93
- - Total P&L: $${performanceData.pnl?.toFixed(2) || '0.00'}
94
- - Avg Win: $${performanceData.avgWin?.toFixed(2) || 'N/A'}
95
- - Avg Loss: $${performanceData.avgLoss?.toFixed(2) || 'N/A'}
96
- - Largest Win: $${performanceData.largestWin?.toFixed(2) || 'N/A'}
97
- - Largest Loss: $${performanceData.largestLoss?.toFixed(2) || 'N/A'}
98
- - Max Drawdown: $${performanceData.maxDrawdown?.toFixed(2) || 'N/A'}
99
- - Profit Factor: ${performanceData.profitFactor?.toFixed(2) || 'N/A'}
100
-
101
- Current Parameters:
102
- - Position Size: ${performanceData.positionSize || 'N/A'} contracts
103
- - Daily Target: $${performanceData.dailyTarget || 'N/A'}
104
- - Max Risk: $${performanceData.maxRisk || 'N/A'}
105
- - Symbol: ${performanceData.symbol || 'N/A'}
106
-
107
- Recent Trades:
108
- ${performanceData.recentTrades?.map(t =>
109
- `- ${t.side} ${t.qty}x @ ${t.price} → P&L: $${t.pnl?.toFixed(2) || 'N/A'}`
110
- ).join('\n') || 'No recent trades'}
111
-
112
- Market Context:
113
- - Volatility: ${performanceData.volatility || 'N/A'}
114
- - Trend: ${performanceData.trend || 'N/A'}
115
- - Session: ${performanceData.session || 'N/A'}
116
-
117
- Analyze and suggest optimizations to improve performance.`;
118
-
119
- try {
120
- const response = await callAI(agent, prompt, systemPrompt);
121
- if (!response) return null;
122
-
123
- const jsonMatch = response.match(/\{[\s\S]*\}/);
124
- if (jsonMatch) {
125
- return JSON.parse(jsonMatch[0]);
126
- }
127
-
128
- return null;
129
- } catch (error) {
130
- return null;
131
- }
132
- };
133
-
134
- /**
135
- * Get real-time trading advice based on current market conditions
136
- * @param {Function} callAI - The callAI function from client.js
137
- * @param {Object} agent - AI agent
138
- * @param {Object} marketData - Current market data
139
- * @returns {Promise<Object|null>} Trading advice
140
- */
141
- const getMarketAdvice = async (callAI, agent, marketData) => {
142
- if (!agent || !marketData) return null;
143
-
144
- const systemPrompt = `You are an AI supervisor for HQX Ultra Scalping futures strategy.
145
- Analyze real-time market data and provide actionable advice.
146
- Be concise and precise. The strategy will use your recommendations.
147
-
148
- Respond ONLY in valid JSON:
149
- {
150
- "action": "AGGRESSIVE|NORMAL|CAUTIOUS|PAUSE",
151
- "sizeMultiplier": 0.5-1.5,
152
- "reason": "brief reason",
153
- "confidence": 0-100
154
- }`;
155
-
156
- const prompt = `REAL-TIME MARKET ANALYSIS
157
-
158
- Current Price: ${marketData.price || 'N/A'}
159
- Bid: ${marketData.bid || 'N/A'} | Ask: ${marketData.ask || 'N/A'}
160
- Spread: ${marketData.spread || 'N/A'}
161
- Volume: ${marketData.volume || 'N/A'}
162
- Delta: ${marketData.delta || 'N/A'}
163
- Volatility: ${marketData.volatility || 'N/A'}
164
-
165
- Recent Price Action:
166
- - High: ${marketData.high || 'N/A'}
167
- - Low: ${marketData.low || 'N/A'}
168
- - Range: ${marketData.range || 'N/A'}
169
-
170
- Current Position: ${marketData.position || 'FLAT'}
171
- Session P&L: $${marketData.pnl?.toFixed(2) || '0.00'}
172
-
173
- What should the strategy do?`;
174
-
175
- try {
176
- const response = await callAI(agent, prompt, systemPrompt);
177
- if (!response) return null;
178
-
179
- const jsonMatch = response.match(/\{[\s\S]*\}/);
180
- if (jsonMatch) {
181
- return JSON.parse(jsonMatch[0]);
182
- }
183
-
184
- return null;
185
- } catch (error) {
186
- return null;
187
- }
188
- };
189
-
190
- module.exports = {
191
- analyzeTrading,
192
- analyzePerformance,
193
- getMarketAdvice,
194
- };