hedgequantx 2.6.40 → 2.6.42
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
|
@@ -362,6 +362,33 @@ const launchAlgo = async (service, account, contract, config) => {
|
|
|
362
362
|
});
|
|
363
363
|
}
|
|
364
364
|
|
|
365
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
366
|
+
// REAL-TIME P&L VIA WEBSOCKET (like R Trader)
|
|
367
|
+
// Listen to pnlUpdate events from Rithmic PNL_PLANT WebSocket
|
|
368
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
369
|
+
const rithmicAccountId = account.rithmicAccountId || account.accountId;
|
|
370
|
+
|
|
371
|
+
service.on('pnlUpdate', (pnlData) => {
|
|
372
|
+
// Only update for our account
|
|
373
|
+
if (pnlData.accountId !== rithmicAccountId) return;
|
|
374
|
+
|
|
375
|
+
// Calculate P&L exactly like R Trader: openPositionPnl + closedPositionPnl
|
|
376
|
+
const openPnl = parseFloat(pnlData.openPositionPnl || 0);
|
|
377
|
+
const closedPnl = parseFloat(pnlData.closedPositionPnl || 0);
|
|
378
|
+
|
|
379
|
+
// R Trader "Today's P&L" = unrealized + realized
|
|
380
|
+
stats.pnl = openPnl + closedPnl;
|
|
381
|
+
});
|
|
382
|
+
|
|
383
|
+
// Also listen to position updates for real-time position tracking
|
|
384
|
+
service.on('positionUpdate', (pos) => {
|
|
385
|
+
if (!pos || pos.accountId !== rithmicAccountId) return;
|
|
386
|
+
if (pos.symbol !== symbolName && !pos.symbol?.includes(symbolName.replace(/[A-Z]\d+$/, ''))) return;
|
|
387
|
+
|
|
388
|
+
// Update current position from WebSocket
|
|
389
|
+
currentPosition = pos.quantity || 0;
|
|
390
|
+
});
|
|
391
|
+
|
|
365
392
|
// Initialize AI Strategy Supervisor - agents observe, learn & optimize
|
|
366
393
|
// Only if user enabled AI in config
|
|
367
394
|
let aiAgentCount = 0;
|
|
@@ -579,9 +606,11 @@ const launchAlgo = async (service, account, contract, config) => {
|
|
|
579
606
|
tps++;
|
|
580
607
|
const latencyStart = Date.now();
|
|
581
608
|
|
|
582
|
-
// Debug: log first tick
|
|
609
|
+
// Debug: log first tick and confirm data flow after 5s
|
|
583
610
|
if (tickCount === 1) {
|
|
584
611
|
algoLogger.info(ui, 'FIRST TICK', `price=${tick.price} bid=${tick.bid} ask=${tick.ask} vol=${tick.volume || tick.size || 0}`);
|
|
612
|
+
} else if (tickCount === 100) {
|
|
613
|
+
algoLogger.info(ui, 'DATA FLOWING', `100 ticks received - market data OK`);
|
|
585
614
|
}
|
|
586
615
|
|
|
587
616
|
// Feed tick to strategy
|
|
@@ -625,8 +654,8 @@ const launchAlgo = async (service, account, contract, config) => {
|
|
|
625
654
|
|
|
626
655
|
stats.latency = Date.now() - latencyStart;
|
|
627
656
|
|
|
628
|
-
// Heartbeat every
|
|
629
|
-
if (Date.now() - lastHeartbeat >
|
|
657
|
+
// Heartbeat every 15 seconds - show strategy model values
|
|
658
|
+
if (Date.now() - lastHeartbeat > 15000) {
|
|
630
659
|
// Try to get model values from strategy
|
|
631
660
|
const modelValues = strategy.getModelValues?.() || strategy.getModelValues?.(contractId) || null;
|
|
632
661
|
|
|
@@ -638,10 +667,10 @@ const launchAlgo = async (service, account, contract, config) => {
|
|
|
638
667
|
const mom = (modelValues.momentum || 0).toFixed(1);
|
|
639
668
|
const signals = modelValues.signalCount || 0;
|
|
640
669
|
const deltaStr = delta >= 0 ? `+${delta}` : `${delta}`;
|
|
641
|
-
algoLogger.info(ui, strategyName, `OFI=${ofi} Z=${zscore} Mom=${mom} Δ=${deltaStr} | ${
|
|
670
|
+
algoLogger.info(ui, strategyName, `OFI=${ofi} Z=${zscore} Mom=${mom} Δ=${deltaStr} | ${tps} t/15s | ${tickCount} total`);
|
|
642
671
|
} else {
|
|
643
672
|
// Fallback
|
|
644
|
-
algoLogger.info(ui, 'SCANNING', `${tps} ticks/
|
|
673
|
+
algoLogger.info(ui, 'SCANNING', `${tps} ticks/15s | ${tickCount} total | price=${tickData.price}`);
|
|
645
674
|
}
|
|
646
675
|
lastHeartbeat = Date.now();
|
|
647
676
|
tps = 0;
|
|
@@ -714,16 +743,16 @@ const launchAlgo = async (service, account, contract, config) => {
|
|
|
714
743
|
algoLogger.error(ui, 'CONNECTION ERROR', e.message.substring(0, 50));
|
|
715
744
|
}
|
|
716
745
|
|
|
717
|
-
// Poll account P&L and sync with real trades from API
|
|
746
|
+
// Poll account P&L and sync with real trades from API (fallback, WebSocket is primary)
|
|
718
747
|
const pollPnL = async () => {
|
|
719
748
|
try {
|
|
720
|
-
// Get account P&L
|
|
749
|
+
// Get account P&L (fallback if WebSocket not updating)
|
|
721
750
|
const accountResult = await service.getTradingAccounts();
|
|
722
751
|
if (accountResult.success && accountResult.accounts) {
|
|
723
752
|
const acc = accountResult.accounts.find(a => a.accountId === account.accountId);
|
|
724
|
-
if (acc && acc.profitAndLoss !== undefined) {
|
|
725
|
-
|
|
726
|
-
stats.pnl = acc.profitAndLoss
|
|
753
|
+
if (acc && acc.profitAndLoss !== undefined && acc.profitAndLoss !== null) {
|
|
754
|
+
// Use day P&L directly (same as R Trader)
|
|
755
|
+
stats.pnl = acc.profitAndLoss;
|
|
727
756
|
}
|
|
728
757
|
}
|
|
729
758
|
|
|
@@ -826,8 +855,9 @@ const launchAlgo = async (service, account, contract, config) => {
|
|
|
826
855
|
};
|
|
827
856
|
|
|
828
857
|
// Start polling and UI refresh
|
|
858
|
+
// UI refreshes every 250ms, P&L polling every 10s (WebSocket is primary for P&L)
|
|
829
859
|
const refreshInterval = setInterval(() => { if (running) ui.render(stats); }, 250);
|
|
830
|
-
const pnlInterval = setInterval(() => { if (running) pollPnL(); },
|
|
860
|
+
const pnlInterval = setInterval(() => { if (running) pollPnL(); }, 10000);
|
|
831
861
|
pollPnL(); // Initial poll
|
|
832
862
|
|
|
833
863
|
// Keyboard handler
|
|
@@ -115,15 +115,22 @@ const getTradingAccounts = async (service) => {
|
|
|
115
115
|
const closedPnL = pnlData.closedPositionPnl ? parseFloat(pnlData.closedPositionPnl) : null;
|
|
116
116
|
const dayPnL = pnlData.dayPnl ? parseFloat(pnlData.dayPnl) : null;
|
|
117
117
|
|
|
118
|
+
// Calculate P&L like R Trader: openPositionPnl + closedPositionPnl
|
|
119
|
+
// This matches what R Trader shows as "Today's P&L"
|
|
120
|
+
const totalPnL = (openPnL !== null || closedPnL !== null)
|
|
121
|
+
? (openPnL || 0) + (closedPnL || 0)
|
|
122
|
+
: null;
|
|
123
|
+
|
|
118
124
|
return {
|
|
119
125
|
accountId: hashAccountId(acc.accountId),
|
|
120
126
|
rithmicAccountId: acc.accountId,
|
|
121
127
|
accountName: acc.accountId, // Never expose real name - only account ID
|
|
122
128
|
name: acc.accountId, // Never expose real name - only account ID
|
|
123
129
|
balance: accountBalance,
|
|
124
|
-
profitAndLoss:
|
|
130
|
+
profitAndLoss: totalPnL, // Same as R Trader: open + closed
|
|
125
131
|
openPnL: openPnL,
|
|
126
|
-
|
|
132
|
+
closedPnL: closedPnL,
|
|
133
|
+
dayPnL: dayPnL, // Keep for reference
|
|
127
134
|
status: 0,
|
|
128
135
|
platform: 'Rithmic',
|
|
129
136
|
propfirm: service.propfirm.name,
|