hedgequantx 2.6.161 → 2.6.163

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 (57) hide show
  1. package/package.json +1 -1
  2. package/src/menus/ai-agent-connect.js +181 -0
  3. package/src/menus/ai-agent-models.js +219 -0
  4. package/src/menus/ai-agent-oauth.js +292 -0
  5. package/src/menus/ai-agent-ui.js +141 -0
  6. package/src/menus/ai-agent.js +88 -1489
  7. package/src/pages/algo/copy-engine.js +449 -0
  8. package/src/pages/algo/copy-trading.js +11 -543
  9. package/src/pages/algo/smart-logs-data.js +218 -0
  10. package/src/pages/algo/smart-logs.js +9 -214
  11. package/src/pages/algo/ui-constants.js +144 -0
  12. package/src/pages/algo/ui-summary.js +184 -0
  13. package/src/pages/algo/ui.js +42 -526
  14. package/src/pages/stats-calculations.js +191 -0
  15. package/src/pages/stats-ui.js +381 -0
  16. package/src/pages/stats.js +14 -507
  17. package/src/services/ai/client-analysis.js +194 -0
  18. package/src/services/ai/client-models.js +333 -0
  19. package/src/services/ai/client.js +6 -489
  20. package/src/services/ai/index.js +2 -257
  21. package/src/services/ai/providers/direct-providers.js +323 -0
  22. package/src/services/ai/providers/index.js +8 -472
  23. package/src/services/ai/providers/other-providers.js +104 -0
  24. package/src/services/ai/proxy-install.js +249 -0
  25. package/src/services/ai/proxy-manager.js +29 -411
  26. package/src/services/ai/proxy-remote.js +161 -0
  27. package/src/services/ai/supervisor-optimize.js +215 -0
  28. package/src/services/ai/supervisor-sync.js +178 -0
  29. package/src/services/ai/supervisor.js +50 -515
  30. package/src/services/ai/validation.js +250 -0
  31. package/src/services/hqx-server-events.js +110 -0
  32. package/src/services/hqx-server-handlers.js +217 -0
  33. package/src/services/hqx-server-latency.js +136 -0
  34. package/src/services/hqx-server.js +51 -403
  35. package/src/services/position-constants.js +28 -0
  36. package/src/services/position-exit-logic.js +174 -0
  37. package/src/services/position-manager.js +90 -629
  38. package/src/services/position-momentum.js +206 -0
  39. package/src/services/projectx/accounts.js +142 -0
  40. package/src/services/projectx/index.js +40 -289
  41. package/src/services/projectx/trading.js +180 -0
  42. package/src/services/rithmic/contracts.js +218 -0
  43. package/src/services/rithmic/handlers.js +2 -208
  44. package/src/services/rithmic/index.js +28 -712
  45. package/src/services/rithmic/latency-tracker.js +182 -0
  46. package/src/services/rithmic/market-data-decoders.js +229 -0
  47. package/src/services/rithmic/market-data.js +1 -278
  48. package/src/services/rithmic/orders-fast.js +246 -0
  49. package/src/services/rithmic/orders.js +1 -251
  50. package/src/services/rithmic/proto-decoders.js +403 -0
  51. package/src/services/rithmic/protobuf.js +7 -443
  52. package/src/services/rithmic/specs.js +146 -0
  53. package/src/services/rithmic/trade-history.js +254 -0
  54. package/src/services/strategy/hft-signal-calc.js +147 -0
  55. package/src/services/strategy/hft-tick.js +33 -133
  56. package/src/services/tradovate/index.js +6 -119
  57. package/src/services/tradovate/orders.js +145 -0
@@ -0,0 +1,206 @@
1
+ /**
2
+ * @fileoverview Position Momentum Calculator
3
+ * Calculates momentum using strategy's math models (OFI, Kalman, Z-Score)
4
+ *
5
+ * Data sources:
6
+ * - OFI: Strategy's computeOrderFlowImbalance()
7
+ * - Kalman: Strategy's kalmanStates
8
+ * - Z-Score: Strategy's computeZScore()
9
+ * - VPIN: Strategy's computeVPIN()
10
+ */
11
+
12
+ const { logger } = require('../utils/logger');
13
+ const { WEIGHTS } = require('./position-constants');
14
+
15
+ const log = logger.scope('PositionMomentum');
16
+
17
+ /**
18
+ * Get OFI (Order Flow Imbalance) from strategy
19
+ * @param {Object} strategy - Strategy instance
20
+ * @param {string} contractId - Contract identifier
21
+ * @returns {number|null} OFI value [-1, 1] or null if unavailable
22
+ */
23
+ const getOFI = (strategy, contractId) => {
24
+ if (!strategy) return null;
25
+
26
+ // Try strategy's computeOrderFlowImbalance (direct calculation from bars)
27
+ if (typeof strategy.computeOrderFlowImbalance === 'function') {
28
+ const bars = strategy.getBarHistory?.(contractId);
29
+ if (bars && bars.length >= 20) {
30
+ try {
31
+ return strategy.computeOrderFlowImbalance(bars);
32
+ } catch (error) {
33
+ log.debug('OFI calculation failed', { error: error.message });
34
+ }
35
+ }
36
+ }
37
+
38
+ // Try getModelValues (pre-calculated values)
39
+ const modelValues = strategy.getModelValues?.(contractId);
40
+ if (modelValues && modelValues.rawOfi !== undefined) {
41
+ return modelValues.rawOfi;
42
+ }
43
+
44
+ return null;
45
+ };
46
+
47
+ /**
48
+ * Get Kalman velocity from strategy's Kalman filter
49
+ * @param {Object} strategy - Strategy instance
50
+ * @param {string} contractId - Contract identifier
51
+ * @param {number} currentPrice - Latest price
52
+ * @returns {number|null} Velocity value or null if unavailable
53
+ */
54
+ const getKalmanVelocity = (strategy, contractId, currentPrice) => {
55
+ if (!strategy) return null;
56
+
57
+ // Try to access kalmanStates from strategy
58
+ if (strategy.kalmanStates) {
59
+ const state = strategy.kalmanStates.get(contractId);
60
+ if (state && typeof state.estimate === 'number') {
61
+ if (currentPrice !== undefined && currentPrice !== null) {
62
+ return currentPrice - state.estimate;
63
+ }
64
+ }
65
+ }
66
+
67
+ return null;
68
+ };
69
+
70
+ /**
71
+ * Get Z-Score from strategy
72
+ * @param {Object} strategy - Strategy instance
73
+ * @param {string} contractId - Contract identifier
74
+ * @returns {number|null} Z-Score value or null if unavailable
75
+ */
76
+ const getZScore = (strategy, contractId) => {
77
+ if (!strategy) return null;
78
+
79
+ // Try strategy's computeZScore (direct calculation from price buffer)
80
+ if (typeof strategy.computeZScore === 'function') {
81
+ const prices = strategy.priceBuffer?.get(contractId);
82
+ if (prices && prices.length >= 50) {
83
+ try {
84
+ return strategy.computeZScore(prices);
85
+ } catch (error) {
86
+ log.debug('Z-Score calculation failed', { error: error.message });
87
+ }
88
+ }
89
+ }
90
+
91
+ return null;
92
+ };
93
+
94
+ /**
95
+ * Get VPIN from strategy
96
+ * @param {Object} strategy - Strategy instance
97
+ * @param {string} contractId - Contract identifier
98
+ * @returns {number|null} VPIN value [0, 1] or null if unavailable
99
+ */
100
+ const getVPIN = (strategy, contractId) => {
101
+ if (!strategy) return null;
102
+
103
+ // Try strategy's computeVPIN (direct calculation from volume buffer)
104
+ if (typeof strategy.computeVPIN === 'function') {
105
+ const volumes = strategy.volumeBuffer?.get(contractId);
106
+ if (volumes && volumes.length >= 50) {
107
+ try {
108
+ return strategy.computeVPIN(volumes);
109
+ } catch (error) {
110
+ log.debug('VPIN calculation failed', { error: error.message });
111
+ }
112
+ }
113
+ }
114
+
115
+ // Try getModelValues (pre-calculated, stored as 1 - vpin for scoring)
116
+ const modelValues = strategy.getModelValues?.(contractId);
117
+ if (modelValues && typeof modelValues.vpin === 'number') {
118
+ return 1 - modelValues.vpin;
119
+ }
120
+
121
+ return null;
122
+ };
123
+
124
+ /**
125
+ * Calculate momentum score using strategy's existing math models
126
+ * Weighted: OFI (50%) + Kalman Velocity (25%) + Z-Score (25%)
127
+ *
128
+ * @param {Object} params - Parameters
129
+ * @param {Object} params.strategy - Strategy instance
130
+ * @param {string} params.contractId - Contract identifier
131
+ * @param {number} params.side - Position side (0=Long, 1=Short)
132
+ * @param {number} params.currentPrice - Latest price
133
+ * @param {number|null} params.tickSize - Tick size from API
134
+ * @returns {number|null} Momentum score [-1 to 1], positive = favorable, null if insufficient data
135
+ */
136
+ const calculateMomentum = ({ strategy, contractId, side, currentPrice, tickSize }) => {
137
+ if (!strategy) {
138
+ return null;
139
+ }
140
+
141
+ // Get individual model values (all from API/strategy, not invented)
142
+ const ofi = getOFI(strategy, contractId);
143
+ const velocity = getKalmanVelocity(strategy, contractId, currentPrice);
144
+ const zscore = getZScore(strategy, contractId);
145
+
146
+ // Count how many models have data
147
+ let availableModels = 0;
148
+ let totalWeight = 0;
149
+ let weightedSum = 0;
150
+
151
+ // 1. OFI (50%) - Order Flow Imbalance
152
+ if (ofi !== null) {
153
+ // For long: positive OFI = favorable, For short: negative OFI = favorable
154
+ const favorableOfi = side === 0 ? ofi : -ofi;
155
+ const ofiScore = Math.min(1, Math.max(-1, favorableOfi));
156
+ weightedSum += ofiScore * WEIGHTS.OFI;
157
+ totalWeight += WEIGHTS.OFI;
158
+ availableModels++;
159
+ }
160
+
161
+ // 2. Kalman Velocity (25%)
162
+ if (velocity !== null && tickSize !== null) {
163
+ // Normalize velocity: favorable direction = positive
164
+ const favorableVelocity = side === 0 ? velocity : -velocity;
165
+ // Normalize to [-1, 1]: 4 ticks of velocity = 1.0 score
166
+ const normalizedVelocity = favorableVelocity / (tickSize * 4);
167
+ const velocityScore = Math.min(1, Math.max(-1, normalizedVelocity));
168
+ weightedSum += velocityScore * WEIGHTS.KALMAN;
169
+ totalWeight += WEIGHTS.KALMAN;
170
+ availableModels++;
171
+ }
172
+
173
+ // 3. Z-Score (25%) - Progression toward mean
174
+ if (zscore !== null) {
175
+ let zscoreScore;
176
+ if (side === 0) {
177
+ // Long: entered when Z < -threshold, improving = Z moving toward 0
178
+ zscoreScore = zscore > -0.5 ? 0.5 : -0.5;
179
+ } else {
180
+ // Short: entered when Z > threshold, improving = Z moving toward 0
181
+ zscoreScore = zscore < 0.5 ? 0.5 : -0.5;
182
+ }
183
+ weightedSum += zscoreScore * WEIGHTS.ZSCORE;
184
+ totalWeight += WEIGHTS.ZSCORE;
185
+ availableModels++;
186
+ }
187
+
188
+ // Need at least 1 model with data to calculate momentum
189
+ if (availableModels === 0 || totalWeight === 0) {
190
+ return null;
191
+ }
192
+
193
+ // Normalize by actual total weight (in case some models unavailable)
194
+ const momentum = weightedSum / totalWeight;
195
+
196
+ // Clamp to [-1, 1]
197
+ return Math.min(1, Math.max(-1, momentum));
198
+ };
199
+
200
+ module.exports = {
201
+ getOFI,
202
+ getKalmanVelocity,
203
+ getZScore,
204
+ getVPIN,
205
+ calculateMomentum,
206
+ };
@@ -0,0 +1,142 @@
1
+ /**
2
+ * ProjectX Account Management
3
+ * @module services/projectx/accounts
4
+ *
5
+ * Account enrichment and P&L calculations.
6
+ */
7
+
8
+ const { logger } = require('../../utils/logger');
9
+
10
+ const log = logger.scope('ProjectX');
11
+
12
+ /**
13
+ * Enrich account with P&L data from API
14
+ * @param {Function} request - Request function
15
+ * @param {Object} propfirm - Propfirm config
16
+ * @param {Object} account - Account object
17
+ * @param {Array} templates - Account templates
18
+ */
19
+ async function enrichAccount(request, propfirm, account, templates) {
20
+ const template = templates.find(t =>
21
+ account.accountName && (
22
+ account.accountName.includes(t.title) ||
23
+ t.title.includes(account.accountName)
24
+ )
25
+ );
26
+
27
+ const enriched = {
28
+ accountId: account.accountId,
29
+ accountName: account.accountName,
30
+ balance: account.balance,
31
+ status: account.status,
32
+ type: account.type,
33
+ startingBalance: template?.startingBalance || null,
34
+ platform: 'ProjectX',
35
+ propfirm: propfirm.name,
36
+ openPnL: null,
37
+ todayPnL: null,
38
+ profitAndLoss: null,
39
+ };
40
+
41
+ // Only fetch P&L for active accounts
42
+ if (account.status !== 0) {
43
+ return enriched;
44
+ }
45
+
46
+ // Get unrealized P&L from open positions
47
+ let openPnL = 0;
48
+ try {
49
+ const posRes = await request(
50
+ propfirm.userApi,
51
+ `/Position?accountId=${account.accountId}`,
52
+ 'GET'
53
+ );
54
+
55
+ if (posRes.statusCode === 200 && Array.isArray(posRes.data)) {
56
+ for (const pos of posRes.data) {
57
+ if (pos.profitAndLoss != null) {
58
+ openPnL += pos.profitAndLoss;
59
+ }
60
+ }
61
+ }
62
+ } catch {
63
+ log.debug('Failed to get positions', { accountId: account.accountId });
64
+ }
65
+
66
+ // Get realized P&L from today's trades
67
+ let todayPnL = 0;
68
+ try {
69
+ const today = new Date();
70
+ today.setHours(0, 0, 0, 0);
71
+
72
+ const tradesRes = await request(
73
+ propfirm.gatewayApi,
74
+ '/api/Trade/search',
75
+ 'POST',
76
+ {
77
+ accountId: account.accountId,
78
+ startTimestamp: today.toISOString(),
79
+ endTimestamp: new Date().toISOString(),
80
+ }
81
+ );
82
+
83
+ if (tradesRes.statusCode === 200) {
84
+ const trades = Array.isArray(tradesRes.data) ? tradesRes.data : (tradesRes.data.trades || []);
85
+ for (const trade of trades) {
86
+ if (trade.profitAndLoss != null) {
87
+ todayPnL += trade.profitAndLoss;
88
+ }
89
+ }
90
+ }
91
+ } catch {
92
+ log.debug('Failed to get today trades', { accountId: account.accountId });
93
+ }
94
+
95
+ enriched.openPnL = openPnL;
96
+ enriched.todayPnL = todayPnL;
97
+ enriched.profitAndLoss = openPnL + todayPnL;
98
+
99
+ return enriched;
100
+ }
101
+
102
+ /**
103
+ * Get trading accounts with REAL P&L from API
104
+ * @param {Function} request - Request function
105
+ * @param {Object} propfirm - Propfirm config
106
+ */
107
+ async function getTradingAccounts(request, propfirm) {
108
+ try {
109
+ const response = await request(propfirm.userApi, '/TradingAccount', 'GET');
110
+
111
+ if (response.statusCode !== 200) {
112
+ return { success: false, accounts: [], error: 'Failed to get accounts' };
113
+ }
114
+
115
+ const accounts = Array.isArray(response.data) ? response.data : [];
116
+
117
+ // Get account templates for startingBalance
118
+ let templates = [];
119
+ try {
120
+ const templateRes = await request(propfirm.userApi, '/AccountTemplate/userTemplates', 'GET');
121
+ if (templateRes.statusCode === 200 && Array.isArray(templateRes.data)) {
122
+ templates = templateRes.data;
123
+ }
124
+ } catch {
125
+ log.debug('Failed to get templates');
126
+ }
127
+
128
+ const enrichedAccounts = await Promise.all(
129
+ accounts.map(account => enrichAccount(request, propfirm, account, templates))
130
+ );
131
+
132
+ return { success: true, accounts: enrichedAccounts };
133
+ } catch (err) {
134
+ log.error('Failed to get accounts', { error: err.message });
135
+ return { success: false, accounts: [], error: err.message };
136
+ }
137
+ }
138
+
139
+ module.exports = {
140
+ enrichAccount,
141
+ getTradingAccounts,
142
+ };