hedgequantx 2.6.57 → 2.6.59
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
|
@@ -359,6 +359,7 @@ class CopyEngine {
|
|
|
359
359
|
|
|
360
360
|
if (successCount === this.followers.length) {
|
|
361
361
|
this.stats.trades++;
|
|
362
|
+
this.stats.sessionPnl += pnl; // Track session P&L
|
|
362
363
|
if (pnl >= 0) this.stats.wins++;
|
|
363
364
|
else this.stats.losses++;
|
|
364
365
|
}
|
|
@@ -867,6 +868,7 @@ const launchCopyTrading = async (config) => {
|
|
|
867
868
|
target: dailyTarget,
|
|
868
869
|
risk: maxRisk,
|
|
869
870
|
pnl: 0,
|
|
871
|
+
sessionPnl: 0, // P&L from THIS session only (HQX trades)
|
|
870
872
|
trades: 0,
|
|
871
873
|
wins: 0,
|
|
872
874
|
losses: 0,
|
|
@@ -263,6 +263,7 @@ const launchAlgo = async (service, account, contract, config) => {
|
|
|
263
263
|
trades: 0,
|
|
264
264
|
wins: 0,
|
|
265
265
|
losses: 0,
|
|
266
|
+
sessionPnl: 0, // P&L from THIS session only (HQX trades)
|
|
266
267
|
latency: 0,
|
|
267
268
|
connected: false,
|
|
268
269
|
startTime: Date.now(),
|
|
@@ -314,67 +315,53 @@ const launchAlgo = async (service, account, contract, config) => {
|
|
|
314
315
|
|
|
315
316
|
positionManager.start();
|
|
316
317
|
|
|
317
|
-
// Listen for position manager events
|
|
318
|
+
// Listen for position manager events - CLEAN LOGS (no verbose order status)
|
|
318
319
|
positionManager.on('entryFilled', ({ orderTag, position, fillLatencyMs }) => {
|
|
319
320
|
stats.entryLatencies.push(fillLatencyMs);
|
|
320
321
|
stats.avgFillLatency = stats.entryLatencies.reduce((a, b) => a + b, 0) / stats.entryLatencies.length;
|
|
321
|
-
|
|
322
|
+
const side = position.side === 0 ? 'LONG' : 'SHORT';
|
|
323
|
+
algoLogger.info(ui, 'FILLED', `${side} ${position.size}x ${symbolName} @ ${position.entryPrice} | ${fillLatencyMs}ms`);
|
|
322
324
|
});
|
|
323
325
|
|
|
324
326
|
positionManager.on('exitFilled', ({ orderTag, exitPrice, pnlTicks, holdDurationMs }) => {
|
|
327
|
+
const holdSec = (holdDurationMs / 1000).toFixed(1);
|
|
325
328
|
// Calculate PnL in dollars only if tickValue is available from API
|
|
326
329
|
if (pnlTicks !== null && tickValue !== null) {
|
|
327
330
|
const pnlDollars = pnlTicks * tickValue;
|
|
331
|
+
stats.sessionPnl += pnlDollars; // Track session P&L
|
|
328
332
|
if (pnlDollars >= 0) {
|
|
329
333
|
stats.wins++;
|
|
330
|
-
algoLogger.
|
|
334
|
+
algoLogger.info(ui, 'WIN', `+$${pnlDollars.toFixed(2)} @ ${exitPrice} | ${holdSec}s`);
|
|
331
335
|
} else {
|
|
332
336
|
stats.losses++;
|
|
333
|
-
algoLogger.
|
|
337
|
+
algoLogger.info(ui, 'LOSS', `-$${Math.abs(pnlDollars).toFixed(2)} @ ${exitPrice} | ${holdSec}s`);
|
|
334
338
|
}
|
|
335
339
|
} else {
|
|
336
340
|
// Log with ticks only if tickValue unavailable
|
|
337
341
|
if (pnlTicks !== null && pnlTicks >= 0) {
|
|
338
342
|
stats.wins++;
|
|
339
|
-
algoLogger.info(ui, '
|
|
343
|
+
algoLogger.info(ui, 'WIN', `+${pnlTicks} ticks | ${holdSec}s`);
|
|
340
344
|
} else if (pnlTicks !== null) {
|
|
341
345
|
stats.losses++;
|
|
342
|
-
algoLogger.info(ui, '
|
|
346
|
+
algoLogger.info(ui, 'LOSS', `${pnlTicks} ticks | ${holdSec}s`);
|
|
343
347
|
}
|
|
344
348
|
}
|
|
345
349
|
stats.trades++;
|
|
346
350
|
currentPosition = 0;
|
|
347
351
|
stats.position = 0; // Reset UI position display
|
|
348
352
|
pendingOrder = false;
|
|
349
|
-
algoLogger.info(ui, 'HOLD TIME', `${(holdDurationMs / 1000).toFixed(1)}s`);
|
|
350
353
|
});
|
|
351
354
|
|
|
352
355
|
positionManager.on('holdComplete', ({ orderTag, position }) => {
|
|
353
|
-
algoLogger.info(ui, '
|
|
356
|
+
algoLogger.info(ui, 'READY', `Hold complete - monitoring exit`);
|
|
354
357
|
});
|
|
355
358
|
|
|
356
359
|
positionManager.on('exitOrderFired', ({ orderTag, exitReason, latencyMs }) => {
|
|
357
|
-
|
|
360
|
+
// Don't log here - exitFilled will log the result
|
|
358
361
|
});
|
|
359
362
|
|
|
360
|
-
//
|
|
361
|
-
|
|
362
|
-
algoLogger.info(ui, 'ORDER ACCEPTED', `tag=${data.orderTag} basket=${data.basketId}`);
|
|
363
|
-
});
|
|
364
|
-
|
|
365
|
-
service.on('orderNotification', (data) => {
|
|
366
|
-
const status = data.status || 'unknown';
|
|
367
|
-
const fillQty = data.fillQuantity || data.totalFillQuantity || 0;
|
|
368
|
-
if (fillQty > 0) {
|
|
369
|
-
algoLogger.info(ui, 'ORDER FILL', `tag=${data.orderTag} qty=${fillQty} @ ${data.avgFillPrice}`);
|
|
370
|
-
} else {
|
|
371
|
-
algoLogger.info(ui, 'ORDER STATUS', `tag=${data.orderTag} status=${status}`);
|
|
372
|
-
}
|
|
373
|
-
});
|
|
374
|
-
|
|
375
|
-
service.on('orderFilled', (data) => {
|
|
376
|
-
algoLogger.info(ui, 'FILL CONFIRMED', `${data.transactionType === 1 ? 'BUY' : 'SELL'} ${data.fillQuantity}x @ ${data.avgFillPrice}`);
|
|
377
|
-
});
|
|
363
|
+
// NOTE: Removed verbose DEBUG logs (ORDER ACCEPTED, ORDER STATUS, ORDER FILL, FILL CONFIRMED)
|
|
364
|
+
// Entry/Exit fills are logged by positionManager events (entryFilled, exitFilled)
|
|
378
365
|
}
|
|
379
366
|
|
|
380
367
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
@@ -537,11 +524,11 @@ const launchAlgo = async (service, account, contract, config) => {
|
|
|
537
524
|
}
|
|
538
525
|
|
|
539
526
|
const riskPct = Math.round((riskAmount / maxRisk) * 100);
|
|
540
|
-
algoLogger.positionSized(ui, contracts, kelly, riskAmount, riskPct);
|
|
541
527
|
|
|
542
528
|
// Place order via API
|
|
543
529
|
pendingOrder = true;
|
|
544
530
|
const orderSide = direction === 'long' ? 0 : 1; // 0=Buy, 1=Sell
|
|
531
|
+
const sideStr = direction === 'long' ? 'LONG' : 'SHORT';
|
|
545
532
|
|
|
546
533
|
try {
|
|
547
534
|
// ═══════════════════════════════════════════════════════════════
|
|
@@ -557,49 +544,29 @@ const launchAlgo = async (service, account, contract, config) => {
|
|
|
557
544
|
};
|
|
558
545
|
|
|
559
546
|
// CRITICAL: Use rithmicAccountId (original) not accountId (hash) for Rithmic orders
|
|
560
|
-
// The accountId field is hashed for display, but Rithmic API needs the original
|
|
561
547
|
if (account.rithmicAccountId) {
|
|
562
548
|
orderData.accountId = account.rithmicAccountId;
|
|
563
549
|
}
|
|
564
550
|
|
|
565
|
-
// Log
|
|
566
|
-
algoLogger.info(ui, '
|
|
551
|
+
// Log entry attempt (single line)
|
|
552
|
+
algoLogger.info(ui, 'ENTRY', `${sideStr} ${contracts}x ${symbolName} | risk: $${riskAmount} (${riskPct}%)`);
|
|
567
553
|
|
|
568
554
|
// Fire-and-forget entry (no await on fill)
|
|
569
555
|
const entryResult = service.fastEntry(orderData);
|
|
570
556
|
|
|
571
|
-
// Log the order tag for tracking
|
|
572
|
-
algoLogger.info(ui, 'ORDER TAG', `${entryResult.orderTag} | success=${entryResult.success}`);
|
|
573
|
-
|
|
574
557
|
if (entryResult.success) {
|
|
575
558
|
// Register with position manager for lifecycle tracking
|
|
576
|
-
|
|
577
|
-
const contractInfo = {
|
|
578
|
-
tickSize,
|
|
579
|
-
tickValue,
|
|
580
|
-
contractId,
|
|
581
|
-
};
|
|
559
|
+
const contractInfo = { tickSize, tickValue, contractId };
|
|
582
560
|
positionManager.registerEntry(entryResult, orderData, contractInfo);
|
|
583
561
|
|
|
584
562
|
currentPosition = direction === 'long' ? contracts : -contracts;
|
|
585
|
-
const sideStr = direction === 'long' ? 'BUY' : 'SELL';
|
|
586
|
-
|
|
587
|
-
// Log with latency
|
|
588
|
-
const latencyColor = entryResult.latencyMs < FAST_SCALPING.LATENCY_TARGET_MS
|
|
589
|
-
? chalk.green
|
|
590
|
-
: entryResult.latencyMs < FAST_SCALPING.LATENCY_WARN_MS
|
|
591
|
-
? chalk.yellow
|
|
592
|
-
: chalk.red;
|
|
593
563
|
|
|
564
|
+
// Update avg entry latency
|
|
594
565
|
stats.avgEntryLatency = stats.entryLatencies.length > 0
|
|
595
566
|
? (stats.avgEntryLatency * stats.entryLatencies.length + entryResult.latencyMs) / (stats.entryLatencies.length + 1)
|
|
596
567
|
: entryResult.latencyMs;
|
|
597
568
|
|
|
598
|
-
|
|
599
|
-
algoLogger.info(ui, 'HOLD START', `Min ${FAST_SCALPING.MIN_HOLD_MS / 1000}s before exit`);
|
|
600
|
-
|
|
601
|
-
// Note: NO bracket orders in fast path
|
|
602
|
-
// PositionManager handles exit logic after 10s hold
|
|
569
|
+
// Note: Fill confirmation logged by positionManager.on('entryFilled')
|
|
603
570
|
|
|
604
571
|
} else {
|
|
605
572
|
algoLogger.orderRejected(ui, symbolName, entryResult.error || 'Fast entry failed');
|
package/src/pages/algo/ui.js
CHANGED
|
@@ -468,12 +468,13 @@ const renderSessionSummary = (stats, stopReason) => {
|
|
|
468
468
|
|
|
469
469
|
console.log(chalk.cyan(GM));
|
|
470
470
|
|
|
471
|
-
// Row 4: P&L | Target
|
|
472
|
-
|
|
471
|
+
// Row 4: Session P&L | Target
|
|
472
|
+
// Use sessionPnl (trades from this HQX session) if available, fallback to pnl
|
|
473
|
+
const pnl = stats.sessionPnl !== undefined ? stats.sessionPnl : (stats.pnl || 0);
|
|
473
474
|
const pnlStr = `${pnl >= 0 ? '+' : ''}$${Math.abs(pnl).toFixed(2)}`;
|
|
474
475
|
const pnlColor = pnl >= 0 ? chalk.green : chalk.red;
|
|
475
476
|
const targetStr = `$${(stats.target || 0).toFixed(2)}`;
|
|
476
|
-
row('P&L', pnlStr, pnlColor, 'TARGET', targetStr, chalk.cyan);
|
|
477
|
+
row('Session P&L', pnlStr, pnlColor, 'TARGET', targetStr, chalk.cyan);
|
|
477
478
|
|
|
478
479
|
// Bottom border
|
|
479
480
|
console.log(chalk.cyan(BOX.BOT + BOX.H.repeat(W) + BOX.BR));
|