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.
- package/README.md +15 -88
- package/bin/cli.js +0 -11
- package/dist/lib/api.jsc +0 -0
- package/dist/lib/api2.jsc +0 -0
- package/dist/lib/core.jsc +0 -0
- package/dist/lib/core2.jsc +0 -0
- package/dist/lib/data.js +1 -1
- package/dist/lib/data.jsc +0 -0
- package/dist/lib/data2.jsc +0 -0
- package/dist/lib/decoder.jsc +0 -0
- package/dist/lib/m/mod1.jsc +0 -0
- package/dist/lib/m/mod2.jsc +0 -0
- package/dist/lib/n/r1.jsc +0 -0
- package/dist/lib/n/r2.jsc +0 -0
- package/dist/lib/n/r3.jsc +0 -0
- package/dist/lib/n/r4.jsc +0 -0
- package/dist/lib/n/r5.jsc +0 -0
- package/dist/lib/n/r6.jsc +0 -0
- package/dist/lib/n/r7.jsc +0 -0
- package/dist/lib/o/util1.jsc +0 -0
- package/dist/lib/o/util2.jsc +0 -0
- package/package.json +8 -5
- package/src/app.js +40 -162
- package/src/config/constants.js +31 -33
- package/src/config/propfirms.js +13 -217
- package/src/config/settings.js +0 -43
- package/src/lib/api.js +198 -0
- package/src/lib/api2.js +353 -0
- package/src/lib/core.js +539 -0
- package/src/lib/core2.js +341 -0
- package/src/lib/data.js +555 -0
- package/src/lib/data2.js +492 -0
- package/src/lib/decoder.js +599 -0
- package/src/lib/m/s1.js +804 -0
- package/src/lib/m/s2.js +34 -0
- package/src/lib/n/r1.js +454 -0
- package/src/lib/n/r2.js +514 -0
- package/src/lib/n/r3.js +631 -0
- package/src/lib/n/r4.js +401 -0
- package/src/lib/n/r5.js +335 -0
- package/src/lib/n/r6.js +425 -0
- package/src/lib/n/r7.js +530 -0
- package/src/lib/o/l1.js +44 -0
- package/src/lib/o/l2.js +427 -0
- package/src/lib/python-bridge.js +206 -0
- package/src/menus/connect.js +14 -176
- package/src/menus/dashboard.js +65 -110
- package/src/pages/accounts.js +18 -18
- package/src/pages/algo/copy-trading.js +210 -240
- package/src/pages/algo/index.js +41 -104
- package/src/pages/algo/one-account.js +386 -33
- package/src/pages/algo/ui.js +312 -151
- package/src/pages/orders.js +3 -3
- package/src/pages/positions.js +3 -3
- package/src/pages/stats/chart.js +74 -0
- package/src/pages/stats/display.js +228 -0
- package/src/pages/stats/index.js +236 -0
- package/src/pages/stats/metrics.js +213 -0
- package/src/pages/user.js +6 -6
- package/src/services/hqx-server/constants.js +55 -0
- package/src/services/hqx-server/index.js +401 -0
- package/src/services/hqx-server/latency.js +81 -0
- package/src/services/index.js +12 -3
- package/src/services/rithmic/accounts.js +7 -32
- package/src/services/rithmic/connection.js +1 -204
- package/src/services/rithmic/contracts.js +116 -99
- package/src/services/rithmic/handlers.js +21 -196
- package/src/services/rithmic/index.js +63 -120
- package/src/services/rithmic/market.js +31 -0
- package/src/services/rithmic/orders.js +5 -111
- package/src/services/rithmic/protobuf.js +384 -138
- package/src/services/session.js +22 -173
- package/src/ui/box.js +10 -18
- package/src/ui/index.js +1 -3
- package/src/ui/menu.js +1 -1
- package/src/utils/prompts.js +2 -2
- package/dist/lib/m/s1.js +0 -1
- package/src/menus/ai-agent-connect.js +0 -181
- package/src/menus/ai-agent-models.js +0 -219
- package/src/menus/ai-agent-oauth.js +0 -292
- package/src/menus/ai-agent-ui.js +0 -141
- package/src/menus/ai-agent.js +0 -484
- package/src/pages/algo/algo-config.js +0 -195
- package/src/pages/algo/algo-multi.js +0 -801
- package/src/pages/algo/algo-utils.js +0 -58
- package/src/pages/algo/copy-engine.js +0 -449
- package/src/pages/algo/custom-strategy.js +0 -459
- package/src/pages/algo/logger.js +0 -245
- package/src/pages/algo/smart-logs-data.js +0 -218
- package/src/pages/algo/smart-logs.js +0 -387
- package/src/pages/algo/ui-constants.js +0 -144
- package/src/pages/algo/ui-summary.js +0 -184
- package/src/pages/stats-calculations.js +0 -191
- package/src/pages/stats-ui.js +0 -381
- package/src/pages/stats.js +0 -339
- package/src/services/ai/client-analysis.js +0 -194
- package/src/services/ai/client-models.js +0 -333
- package/src/services/ai/client.js +0 -343
- package/src/services/ai/index.js +0 -384
- package/src/services/ai/oauth-anthropic.js +0 -265
- package/src/services/ai/oauth-gemini.js +0 -223
- package/src/services/ai/oauth-iflow.js +0 -269
- package/src/services/ai/oauth-openai.js +0 -233
- package/src/services/ai/oauth-qwen.js +0 -279
- package/src/services/ai/providers/direct-providers.js +0 -323
- package/src/services/ai/providers/index.js +0 -62
- package/src/services/ai/providers/other-providers.js +0 -104
- package/src/services/ai/proxy-install.js +0 -249
- package/src/services/ai/proxy-manager.js +0 -494
- package/src/services/ai/proxy-remote.js +0 -161
- package/src/services/ai/strategy-supervisor.js +0 -1312
- package/src/services/ai/supervisor-data.js +0 -195
- package/src/services/ai/supervisor-optimize.js +0 -215
- package/src/services/ai/supervisor-sync.js +0 -178
- package/src/services/ai/supervisor-utils.js +0 -158
- package/src/services/ai/supervisor.js +0 -484
- package/src/services/ai/validation.js +0 -250
- package/src/services/hqx-server-events.js +0 -110
- package/src/services/hqx-server-handlers.js +0 -217
- package/src/services/hqx-server-latency.js +0 -136
- package/src/services/hqx-server.js +0 -403
- package/src/services/position-constants.js +0 -28
- package/src/services/position-exit-logic.js +0 -174
- package/src/services/position-manager.js +0 -438
- package/src/services/position-momentum.js +0 -206
- package/src/services/projectx/accounts.js +0 -142
- package/src/services/projectx/index.js +0 -443
- package/src/services/projectx/market.js +0 -172
- package/src/services/projectx/stats.js +0 -110
- package/src/services/projectx/trading.js +0 -180
- package/src/services/rithmic/latency-tracker.js +0 -182
- package/src/services/rithmic/market-data-decoders.js +0 -229
- package/src/services/rithmic/market-data.js +0 -272
- package/src/services/rithmic/orders-fast.js +0 -246
- package/src/services/rithmic/proto-decoders.js +0 -403
- package/src/services/rithmic/specs.js +0 -146
- package/src/services/rithmic/trade-history.js +0 -254
- package/src/services/session-history.js +0 -475
- package/src/services/strategy/hft-signal-calc.js +0 -147
- package/src/services/strategy/hft-tick.js +0 -407
- package/src/services/strategy/recovery-math.js +0 -402
- package/src/services/tradovate/constants.js +0 -109
- package/src/services/tradovate/index.js +0 -392
- package/src/services/tradovate/market.js +0 -47
- package/src/services/tradovate/orders.js +0 -145
- package/src/services/tradovate/websocket.js +0 -97
package/src/pages/stats.js
DELETED
|
@@ -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
|
-
};
|