hedgequantx 2.6.89 → 2.6.90
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
|
@@ -853,20 +853,32 @@ const launchAlgo = async (service, account, contract, config) => {
|
|
|
853
853
|
algoLogger.error(ui, 'CONNECTION ERROR', e.message.substring(0, 50));
|
|
854
854
|
}
|
|
855
855
|
|
|
856
|
-
// Poll account P&L and sync with real trades from API
|
|
856
|
+
// Poll account P&L and sync with real trades from API
|
|
857
|
+
// For ProjectX: This is the PRIMARY source of P&L data (no WebSocket events)
|
|
858
|
+
// For Rithmic: This is a fallback (WebSocket events are primary)
|
|
857
859
|
const pollPnL = async () => {
|
|
858
860
|
try {
|
|
859
|
-
// Get account P&L
|
|
861
|
+
// Get account P&L
|
|
860
862
|
const accountResult = await service.getTradingAccounts();
|
|
861
863
|
if (accountResult.success && accountResult.accounts) {
|
|
862
864
|
const acc = accountResult.accounts.find(a => a.accountId === account.accountId);
|
|
863
|
-
if (acc
|
|
864
|
-
//
|
|
865
|
-
|
|
865
|
+
if (acc) {
|
|
866
|
+
// Total day P&L
|
|
867
|
+
if (acc.profitAndLoss !== undefined && acc.profitAndLoss !== null) {
|
|
868
|
+
stats.pnl = acc.profitAndLoss;
|
|
869
|
+
}
|
|
870
|
+
// Closed P&L (realized)
|
|
871
|
+
if (acc.realizedPnl !== undefined) {
|
|
872
|
+
stats.closedPnl = acc.realizedPnl;
|
|
873
|
+
}
|
|
874
|
+
// Balance
|
|
875
|
+
if (acc.balance !== undefined) {
|
|
876
|
+
stats.balance = acc.balance;
|
|
877
|
+
}
|
|
866
878
|
}
|
|
867
879
|
}
|
|
868
880
|
|
|
869
|
-
// Check positions - detect when position closes
|
|
881
|
+
// Check positions - get Open P&L and detect when position closes
|
|
870
882
|
const posResult = await service.getPositions(account.accountId);
|
|
871
883
|
if (posResult.success && posResult.positions) {
|
|
872
884
|
const pos = posResult.positions.find(p => {
|
|
@@ -876,6 +888,20 @@ const launchAlgo = async (service, account, contract, config) => {
|
|
|
876
888
|
|
|
877
889
|
const newPositionQty = pos?.quantity || 0;
|
|
878
890
|
|
|
891
|
+
// Update Open P&L from position (unrealized P&L)
|
|
892
|
+
if (pos && pos.unrealizedPnl !== undefined) {
|
|
893
|
+
stats.openPnl = pos.unrealizedPnl;
|
|
894
|
+
} else if (pos && pos.profitAndLoss !== undefined) {
|
|
895
|
+
stats.openPnl = pos.profitAndLoss;
|
|
896
|
+
} else if (newPositionQty === 0) {
|
|
897
|
+
stats.openPnl = 0; // Flat = no open P&L
|
|
898
|
+
}
|
|
899
|
+
|
|
900
|
+
// Recalculate total P&L if we have components
|
|
901
|
+
if (stats.openPnl !== null && stats.closedPnl !== null) {
|
|
902
|
+
stats.pnl = stats.openPnl + stats.closedPnl;
|
|
903
|
+
}
|
|
904
|
+
|
|
879
905
|
// Position just closed - cancel remaining orders and log result
|
|
880
906
|
if (lastPositionQty !== 0 && newPositionQty === 0) {
|
|
881
907
|
// Cancel all open orders to prevent new positions
|
|
@@ -244,7 +244,11 @@ function getMarketBiasLog(direction, delta, ofi) {
|
|
|
244
244
|
* Get a momentum log
|
|
245
245
|
*/
|
|
246
246
|
function getMomentumLog(momentum, zscore) {
|
|
247
|
-
|
|
247
|
+
// Handle undefined/NaN values
|
|
248
|
+
const mom = typeof momentum === 'number' && !isNaN(momentum) ? momentum : 0;
|
|
249
|
+
const z = typeof zscore === 'number' && !isNaN(zscore) ? zscore : 0;
|
|
250
|
+
|
|
251
|
+
const isUp = mom > 0;
|
|
248
252
|
const pool = isUp ? MOMENTUM_UP_MESSAGES : MOMENTUM_DOWN_MESSAGES;
|
|
249
253
|
const category = isUp ? 'mom_up' : 'mom_down';
|
|
250
254
|
const message = getVariedMessage(category, pool, isUp ? 'Momentum up' : 'Momentum down');
|
|
@@ -252,7 +256,7 @@ function getMomentumLog(momentum, zscore) {
|
|
|
252
256
|
|
|
253
257
|
return {
|
|
254
258
|
message: `${arrow} ${message}`,
|
|
255
|
-
details: `Mom=${
|
|
259
|
+
details: `Mom=${mom.toFixed(1)} | Z=${z.toFixed(2)}`,
|
|
256
260
|
};
|
|
257
261
|
}
|
|
258
262
|
|
|
@@ -260,7 +264,10 @@ function getMomentumLog(momentum, zscore) {
|
|
|
260
264
|
* Get a mean reversion log
|
|
261
265
|
*/
|
|
262
266
|
function getMeanReversionLog(zscore) {
|
|
263
|
-
|
|
267
|
+
// Handle undefined/NaN values
|
|
268
|
+
const z = typeof zscore === 'number' && !isNaN(zscore) ? zscore : 0;
|
|
269
|
+
|
|
270
|
+
const isOverbought = z > 0;
|
|
264
271
|
const pool = isOverbought ? OVERBOUGHT_MESSAGES : OVERSOLD_MESSAGES;
|
|
265
272
|
const category = isOverbought ? 'mr_overbought' : 'mr_oversold';
|
|
266
273
|
const message = getVariedMessage(category, pool, isOverbought ? 'Overbought' : 'Oversold');
|
|
@@ -268,7 +275,7 @@ function getMeanReversionLog(zscore) {
|
|
|
268
275
|
|
|
269
276
|
return {
|
|
270
277
|
message: `${arrow} ${message}`,
|
|
271
|
-
details: `Z-Score: ${
|
|
278
|
+
details: `Z-Score: ${z.toFixed(2)} | Looking for ${isOverbought ? 'SHORT' : 'LONG'}`,
|
|
272
279
|
};
|
|
273
280
|
}
|
|
274
281
|
|