hedgequantx 2.6.42 → 2.6.44
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
|
@@ -246,6 +246,13 @@ const launchAlgo = async (service, account, contract, config) => {
|
|
|
246
246
|
propfirm: account.propfirm || 'Unknown',
|
|
247
247
|
platform: connectionType,
|
|
248
248
|
pnl: 0,
|
|
249
|
+
// R Trader style P&L breakdown
|
|
250
|
+
openPnl: 0, // Unrealized P&L (current position)
|
|
251
|
+
closedPnl: 0, // Realized P&L (closed trades today)
|
|
252
|
+
// Position info (like R Trader)
|
|
253
|
+
position: 0, // Current position qty (+ long, - short)
|
|
254
|
+
entryPrice: 0, // Average entry price
|
|
255
|
+
lastPrice: 0, // Last market price
|
|
249
256
|
trades: 0,
|
|
250
257
|
wins: 0,
|
|
251
258
|
losses: 0,
|
|
@@ -372,20 +379,24 @@ const launchAlgo = async (service, account, contract, config) => {
|
|
|
372
379
|
// Only update for our account
|
|
373
380
|
if (pnlData.accountId !== rithmicAccountId) return;
|
|
374
381
|
|
|
375
|
-
//
|
|
382
|
+
// R Trader style P&L breakdown
|
|
376
383
|
const openPnl = parseFloat(pnlData.openPositionPnl || 0);
|
|
377
384
|
const closedPnl = parseFloat(pnlData.closedPositionPnl || 0);
|
|
378
385
|
|
|
379
|
-
//
|
|
380
|
-
stats.
|
|
386
|
+
// Update stats (like R Trader display)
|
|
387
|
+
stats.openPnl = openPnl; // Unrealized
|
|
388
|
+
stats.closedPnl = closedPnl; // Realized
|
|
389
|
+
stats.pnl = openPnl + closedPnl; // Total (same as R Trader "Today's P&L")
|
|
381
390
|
});
|
|
382
391
|
|
|
383
|
-
//
|
|
392
|
+
// Listen to position updates for real-time position tracking (like R Trader)
|
|
384
393
|
service.on('positionUpdate', (pos) => {
|
|
385
394
|
if (!pos || pos.accountId !== rithmicAccountId) return;
|
|
386
395
|
if (pos.symbol !== symbolName && !pos.symbol?.includes(symbolName.replace(/[A-Z]\d+$/, ''))) return;
|
|
387
396
|
|
|
388
|
-
// Update
|
|
397
|
+
// Update position info (like R Trader Positions panel)
|
|
398
|
+
stats.position = pos.quantity || 0;
|
|
399
|
+
stats.entryPrice = pos.averagePrice || 0;
|
|
389
400
|
currentPosition = pos.quantity || 0;
|
|
390
401
|
});
|
|
391
402
|
|
|
@@ -624,6 +635,9 @@ const launchAlgo = async (service, account, contract, config) => {
|
|
|
624
635
|
timestamp: tick.timestamp || Date.now()
|
|
625
636
|
};
|
|
626
637
|
|
|
638
|
+
// Update last price for UI (like R Trader)
|
|
639
|
+
stats.lastPrice = tickData.price;
|
|
640
|
+
|
|
627
641
|
// Feed tick to AI supervisor (agents observe same data as strategy)
|
|
628
642
|
if (stats.aiSupervision) {
|
|
629
643
|
StrategySupervisor.feedTick(tickData);
|
package/src/pages/algo/ui.js
CHANGED
|
@@ -182,35 +182,57 @@ class AlgoUI {
|
|
|
182
182
|
|
|
183
183
|
this._line(chalk.cyan(GM));
|
|
184
184
|
|
|
185
|
-
// Row 2:
|
|
186
|
-
const
|
|
185
|
+
// Row 2: Position | P&L (like R Trader)
|
|
186
|
+
const posQty = stats.position || 0;
|
|
187
|
+
const posStr = posQty === 0 ? 'FLAT' : (posQty > 0 ? `+${posQty} LONG` : `${posQty} SHORT`);
|
|
188
|
+
const posColor = posQty === 0 ? chalk.gray : (posQty > 0 ? chalk.green : chalk.red);
|
|
189
|
+
const r2c1 = buildCell('POSITION', posStr, posColor, colL);
|
|
187
190
|
const r2c2 = buildCell('P&L', pnlStr, pnlColor, colR);
|
|
188
191
|
row(r2c1.padded, r2c2.padded);
|
|
189
192
|
|
|
190
193
|
this._line(chalk.cyan(GM));
|
|
191
194
|
|
|
192
|
-
// Row 3:
|
|
195
|
+
// Row 3: Open P&L | Closed P&L (R Trader style breakdown)
|
|
196
|
+
// Data from Rithmic PNL_PLANT WebSocket - show '--' if null (no data from API)
|
|
197
|
+
const openPnl = stats.openPnl;
|
|
198
|
+
const closedPnl = stats.closedPnl;
|
|
199
|
+
const openPnlStr = openPnl === null || openPnl === undefined
|
|
200
|
+
? '--'
|
|
201
|
+
: (openPnl >= 0 ? `+$${openPnl.toFixed(2)}` : `-$${Math.abs(openPnl).toFixed(2)}`);
|
|
202
|
+
const closedPnlStr = closedPnl === null || closedPnl === undefined
|
|
203
|
+
? '--'
|
|
204
|
+
: (closedPnl >= 0 ? `+$${closedPnl.toFixed(2)}` : `-$${Math.abs(closedPnl).toFixed(2)}`);
|
|
205
|
+
const openPnlColor = (openPnl || 0) >= 0 ? chalk.green : chalk.red;
|
|
206
|
+
const closedPnlColor = (closedPnl || 0) >= 0 ? chalk.green : chalk.red;
|
|
207
|
+
const r3c1 = buildCell('OPEN P&L', openPnlStr, openPnlColor, colL);
|
|
208
|
+
const r3c2 = buildCell('CLOSED P&L', closedPnlStr, closedPnlColor, colR);
|
|
209
|
+
row(r3c1.padded, r3c2.padded);
|
|
210
|
+
|
|
211
|
+
this._line(chalk.cyan(GM));
|
|
212
|
+
|
|
213
|
+
// Row 4: Target | Risk
|
|
193
214
|
const targetStr = stats.target !== null && stats.target !== undefined ? '$' + stats.target.toFixed(2) : '--';
|
|
194
215
|
const riskStr = stats.risk !== null && stats.risk !== undefined ? '$' + stats.risk.toFixed(2) : '--';
|
|
195
|
-
const
|
|
196
|
-
const
|
|
197
|
-
row(
|
|
216
|
+
const r4c1 = buildCell('TARGET', targetStr, chalk.green, colL);
|
|
217
|
+
const r4c2 = buildCell('RISK', riskStr, chalk.red, colR);
|
|
218
|
+
row(r4c1.padded, r4c2.padded);
|
|
198
219
|
|
|
199
220
|
this._line(chalk.cyan(GM));
|
|
200
221
|
|
|
201
|
-
// Row
|
|
202
|
-
const
|
|
203
|
-
const
|
|
204
|
-
const
|
|
205
|
-
|
|
222
|
+
// Row 5: Trades W/L | Entry Price (if in position)
|
|
223
|
+
const r5c1t = ` ${chalk.bold('TRADES')}: ${chalk.cyan.bold(stats.trades || 0)} ${chalk.bold('W/L')}: ${chalk.green.bold(stats.wins || 0)}/${chalk.red.bold(stats.losses || 0)}`;
|
|
224
|
+
const r5c1p = ` TRADES: ${stats.trades || 0} W/L: ${stats.wins || 0}/${stats.losses || 0}`;
|
|
225
|
+
const entryStr = stats.entryPrice > 0 ? stats.entryPrice.toFixed(2) : '--';
|
|
226
|
+
const r5c2 = buildCell('ENTRY', entryStr, chalk.yellow, colR);
|
|
227
|
+
row(r5c1t + pad(colL - r5c1p.length), r5c2.padded);
|
|
206
228
|
|
|
207
229
|
this._line(chalk.cyan(GM));
|
|
208
230
|
|
|
209
|
-
// Row
|
|
231
|
+
// Row 6: Connection | Propfirm
|
|
210
232
|
const connection = stats.platform || 'ProjectX';
|
|
211
|
-
const
|
|
212
|
-
const
|
|
213
|
-
row(
|
|
233
|
+
const r6c1 = buildCell('CONNECTION', connection, chalk.cyan, colL);
|
|
234
|
+
const r6c2 = buildCell('PROPFIRM', stats.propfirm || 'N/A', chalk.cyan, colR);
|
|
235
|
+
row(r6c1.padded, r6c2.padded);
|
|
214
236
|
|
|
215
237
|
this._line(chalk.cyan(GB));
|
|
216
238
|
}
|
|
@@ -529,20 +529,14 @@ const handleOrderNotification = (service, data) => {
|
|
|
529
529
|
const actualFillQty = fillInfo.totalFillQuantity || fillInfo.fillQuantity || notif.quantity || 0;
|
|
530
530
|
const fillPrice = fillInfo.avgFillPrice || fillInfo.lastFillPrice || 0;
|
|
531
531
|
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
debug('ORDER FILLED:', {
|
|
535
|
-
orderTag,
|
|
536
|
-
side: fillInfo.transactionType === 1 ? 'BUY' : 'SELL',
|
|
537
|
-
qty: actualFillQty,
|
|
538
|
-
avgPrice: fillPrice,
|
|
539
|
-
latencyMs: roundTripLatency,
|
|
540
|
-
});
|
|
532
|
+
// Debug only - UI handles display via orderFilled event
|
|
533
|
+
debug('FILL Received:', orderTag, fillInfo.transactionType === 1 ? 'BUY' : 'SELL', actualFillQty, '@', fillPrice, 'latency:', roundTripLatency, 'ms');
|
|
541
534
|
|
|
542
535
|
// Clone for fill event (async handlers may need to keep the data)
|
|
543
536
|
service.emit('orderFilled', FillInfoPool.clone(fillInfo));
|
|
544
537
|
} else {
|
|
545
|
-
|
|
538
|
+
// Debug only - UI handles display via orderNotification event
|
|
539
|
+
debug('ORDER STATUS:', orderTag, 'status:', fillInfo.status, 'text:', fillInfo.text || 'N/A');
|
|
546
540
|
}
|
|
547
541
|
} catch (e) {
|
|
548
542
|
debug('Error decoding order notification:', e.message);
|
|
@@ -135,8 +135,8 @@ const fastEntry = (service, orderData) => {
|
|
|
135
135
|
const orderWithRoute = { ...orderData, tradeRoute };
|
|
136
136
|
const order = OrderPool.fill(orderTag, effectiveLoginInfo, orderWithRoute);
|
|
137
137
|
|
|
138
|
-
//
|
|
139
|
-
|
|
138
|
+
// Debug only - UI handles display via events
|
|
139
|
+
debug('ORDER Sending:', orderTag, orderData.side === 0 ? 'BUY' : 'SELL', orderData.size, 'x', orderData.symbol, 'acct:', orderData.accountId, 'route:', tradeRoute);
|
|
140
140
|
|
|
141
141
|
// OPTIMIZED: Use fastEncode with cached type
|
|
142
142
|
const buffer = proto.fastEncode('RequestNewOrder', order);
|
|
@@ -150,7 +150,7 @@ const fastEntry = (service, orderData) => {
|
|
|
150
150
|
service.orderConn.fastSend(buffer);
|
|
151
151
|
}
|
|
152
152
|
|
|
153
|
-
|
|
153
|
+
debug('ORDER Sent to Rithmic:', orderTag, 'buffer:', buffer.length, 'bytes');
|
|
154
154
|
|
|
155
155
|
// Track for round-trip latency measurement
|
|
156
156
|
LatencyTracker.recordEntry(orderTag, entryTime);
|