hedgequantx 1.3.3 → 1.3.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json
CHANGED
|
@@ -7,6 +7,10 @@
|
|
|
7
7
|
|
|
8
8
|
const https = require('https');
|
|
9
9
|
const { PROPFIRMS } = require('../../config');
|
|
10
|
+
|
|
11
|
+
// Debug mode - set HQX_DEBUG=1 to enable
|
|
12
|
+
const DEBUG = process.env.HQX_DEBUG === '1';
|
|
13
|
+
const debug = (...args) => DEBUG && console.log('[ProjectX]', ...args);
|
|
10
14
|
const {
|
|
11
15
|
validateUsername,
|
|
12
16
|
validatePassword,
|
|
@@ -149,53 +153,35 @@ class ProjectXService {
|
|
|
149
153
|
|
|
150
154
|
/**
|
|
151
155
|
* Get trading accounts - ONLY returns values from API
|
|
152
|
-
*
|
|
156
|
+
* For banner display: returns basic account info quickly
|
|
157
|
+
* Use getAccountPnL() for detailed P&L data
|
|
153
158
|
*/
|
|
154
159
|
async getTradingAccounts() {
|
|
155
160
|
try {
|
|
156
161
|
const response = await this._request(this.propfirm.userApi, '/TradingAccount', 'GET');
|
|
162
|
+
debug('getTradingAccounts response:', JSON.stringify(response.data, null, 2));
|
|
163
|
+
|
|
157
164
|
if (response.statusCode !== 200) {
|
|
158
165
|
return { success: false, accounts: [], error: 'Failed to get accounts' };
|
|
159
166
|
}
|
|
160
167
|
|
|
161
168
|
const accounts = Array.isArray(response.data) ? response.data : [];
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
startingBalance: null,
|
|
179
|
-
};
|
|
180
|
-
|
|
181
|
-
// Only fetch P&L for active accounts
|
|
182
|
-
if (account.status === 0) {
|
|
183
|
-
// Get today's realized P&L from trades API
|
|
184
|
-
const todayPnL = await this._getTodayRealizedPnL(account.accountId);
|
|
185
|
-
enriched.todayPnL = todayPnL;
|
|
186
|
-
|
|
187
|
-
// Get unrealized P&L from open positions API
|
|
188
|
-
const openPnL = await this._getOpenPositionsPnL(account.accountId);
|
|
189
|
-
enriched.openPnL = openPnL;
|
|
190
|
-
|
|
191
|
-
// Total P&L = realized + unrealized (both from API)
|
|
192
|
-
if (todayPnL !== null || openPnL !== null) {
|
|
193
|
-
enriched.profitAndLoss = (todayPnL || 0) + (openPnL || 0);
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
enrichedAccounts.push(enriched);
|
|
198
|
-
}
|
|
169
|
+
|
|
170
|
+
// Return RAW API data only - no additional calls for speed
|
|
171
|
+
const enrichedAccounts = accounts.map(account => ({
|
|
172
|
+
accountId: account.accountId,
|
|
173
|
+
accountName: account.accountName,
|
|
174
|
+
balance: account.balance, // From API
|
|
175
|
+
status: account.status, // From API
|
|
176
|
+
type: account.type, // From API
|
|
177
|
+
platform: 'ProjectX',
|
|
178
|
+
propfirm: this.propfirm.name,
|
|
179
|
+
// P&L not available from /TradingAccount endpoint
|
|
180
|
+
todayPnL: null,
|
|
181
|
+
openPnL: null,
|
|
182
|
+
profitAndLoss: null,
|
|
183
|
+
startingBalance: null,
|
|
184
|
+
}));
|
|
199
185
|
|
|
200
186
|
return { success: true, accounts: enrichedAccounts };
|
|
201
187
|
} catch (error) {
|
|
@@ -203,6 +189,28 @@ class ProjectXService {
|
|
|
203
189
|
}
|
|
204
190
|
}
|
|
205
191
|
|
|
192
|
+
/**
|
|
193
|
+
* Get detailed P&L for a specific account
|
|
194
|
+
* Call this separately when P&L details are needed (e.g., stats page)
|
|
195
|
+
*/
|
|
196
|
+
async getAccountPnL(accountId) {
|
|
197
|
+
const todayPnL = await this._getTodayRealizedPnL(accountId);
|
|
198
|
+
const openPnL = await this._getOpenPositionsPnL(accountId);
|
|
199
|
+
|
|
200
|
+
let totalPnL = null;
|
|
201
|
+
if (todayPnL !== null || openPnL !== null) {
|
|
202
|
+
totalPnL = (todayPnL || 0) + (openPnL || 0);
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
debug(`Account ${accountId} P&L:`, { todayPnL, openPnL, totalPnL });
|
|
206
|
+
|
|
207
|
+
return {
|
|
208
|
+
todayPnL,
|
|
209
|
+
openPnL,
|
|
210
|
+
profitAndLoss: totalPnL
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
|
|
206
214
|
/**
|
|
207
215
|
* Get today's realized P&L from Trade API
|
|
208
216
|
* Returns null if API fails (not 0)
|
|
@@ -227,15 +235,20 @@ class ProjectXService {
|
|
|
227
235
|
? response.data
|
|
228
236
|
: (response.data.trades || []);
|
|
229
237
|
|
|
238
|
+
debug(`_getTodayRealizedPnL: ${trades.length} trades found`);
|
|
239
|
+
|
|
230
240
|
// Sum P&L from API response only
|
|
231
241
|
let totalPnL = 0;
|
|
232
242
|
for (const trade of trades) {
|
|
233
243
|
if (trade.profitAndLoss !== undefined && trade.profitAndLoss !== null) {
|
|
234
244
|
totalPnL += trade.profitAndLoss;
|
|
245
|
+
debug(` Trade P&L: ${trade.profitAndLoss}`);
|
|
235
246
|
}
|
|
236
247
|
}
|
|
248
|
+
debug(` Total realized P&L: ${totalPnL}`);
|
|
237
249
|
return totalPnL;
|
|
238
250
|
}
|
|
251
|
+
debug('_getTodayRealizedPnL: API failed or no data');
|
|
239
252
|
return null; // API failed - return null, not 0
|
|
240
253
|
} catch (e) {
|
|
241
254
|
return null;
|
|
@@ -256,16 +269,21 @@ class ProjectXService {
|
|
|
256
269
|
|
|
257
270
|
if (response.statusCode === 200 && response.data) {
|
|
258
271
|
const positions = response.data.positions || response.data || [];
|
|
272
|
+
debug(`_getOpenPositionsPnL: ${positions.length} positions found`);
|
|
273
|
+
|
|
259
274
|
if (Array.isArray(positions)) {
|
|
260
275
|
let totalPnL = 0;
|
|
261
276
|
for (const pos of positions) {
|
|
262
277
|
if (pos.profitAndLoss !== undefined && pos.profitAndLoss !== null) {
|
|
263
278
|
totalPnL += pos.profitAndLoss;
|
|
279
|
+
debug(` Position ${pos.symbolId || 'unknown'} P&L: ${pos.profitAndLoss}`);
|
|
264
280
|
}
|
|
265
281
|
}
|
|
282
|
+
debug(` Total open P&L: ${totalPnL}`);
|
|
266
283
|
return totalPnL;
|
|
267
284
|
}
|
|
268
285
|
}
|
|
286
|
+
debug('_getOpenPositionsPnL: API failed or no data');
|
|
269
287
|
return null;
|
|
270
288
|
} catch (e) {
|
|
271
289
|
return null;
|
|
@@ -7,6 +7,10 @@
|
|
|
7
7
|
|
|
8
8
|
const { REQ } = require('./constants');
|
|
9
9
|
|
|
10
|
+
// Debug mode - set HQX_DEBUG=1 to enable
|
|
11
|
+
const DEBUG = process.env.HQX_DEBUG === '1';
|
|
12
|
+
const debug = (...args) => DEBUG && console.log('[Rithmic]', ...args);
|
|
13
|
+
|
|
10
14
|
/**
|
|
11
15
|
* Hash account ID to numeric (for compatibility)
|
|
12
16
|
*/
|
package/src/ui/index.js
CHANGED
|
@@ -29,15 +29,8 @@ const { createBoxMenu } = require('./menu');
|
|
|
29
29
|
* This fixes input leaking to bash after session restore or algo trading
|
|
30
30
|
*/
|
|
31
31
|
const prepareStdin = () => {
|
|
32
|
+
// Minimal intervention - just ensure stdin is flowing
|
|
32
33
|
try {
|
|
33
|
-
// Remove any raw mode that might be left from previous operations
|
|
34
|
-
if (process.stdin.isTTY && process.stdin.isRaw) {
|
|
35
|
-
process.stdin.setRawMode(false);
|
|
36
|
-
}
|
|
37
|
-
// Remove any lingering keypress listeners
|
|
38
|
-
process.stdin.removeAllListeners('keypress');
|
|
39
|
-
process.stdin.removeAllListeners('data');
|
|
40
|
-
// Resume stdin so inquirer can take control
|
|
41
34
|
if (process.stdin.isPaused()) {
|
|
42
35
|
process.stdin.resume();
|
|
43
36
|
}
|