hedgequantx 1.2.60 → 1.2.63
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 +1 -1
- package/src/pages/algo.js +76 -93
package/package.json
CHANGED
package/src/pages/algo.js
CHANGED
|
@@ -308,9 +308,6 @@ const launchAlgo = async (service, account, contract, numContracts, dailyTarget,
|
|
|
308
308
|
let stopReason = null;
|
|
309
309
|
|
|
310
310
|
// Activity logs
|
|
311
|
-
const logs = [];
|
|
312
|
-
const MAX_LOGS = 10;
|
|
313
|
-
|
|
314
311
|
// Stats
|
|
315
312
|
let stats = {
|
|
316
313
|
trades: 0,
|
|
@@ -321,14 +318,41 @@ const launchAlgo = async (service, account, contract, numContracts, dailyTarget,
|
|
|
321
318
|
winRate: '0.0'
|
|
322
319
|
};
|
|
323
320
|
|
|
321
|
+
// Logs buffer (newest first)
|
|
322
|
+
const logs = [];
|
|
323
|
+
const MAX_LOGS = 20;
|
|
324
|
+
|
|
325
|
+
// Log colors
|
|
326
|
+
const typeColors = {
|
|
327
|
+
info: chalk.cyan,
|
|
328
|
+
success: chalk.green,
|
|
329
|
+
signal: chalk.yellow.bold,
|
|
330
|
+
trade: chalk.green.bold,
|
|
331
|
+
error: chalk.red,
|
|
332
|
+
warning: chalk.yellow
|
|
333
|
+
};
|
|
334
|
+
|
|
335
|
+
const getIcon = (type) => {
|
|
336
|
+
switch(type) {
|
|
337
|
+
case 'signal': return '[*]';
|
|
338
|
+
case 'trade': return '[>]';
|
|
339
|
+
case 'error': return '[X]';
|
|
340
|
+
case 'success': return '[OK]';
|
|
341
|
+
default: return '[.]';
|
|
342
|
+
}
|
|
343
|
+
};
|
|
344
|
+
|
|
345
|
+
// Add log (newest first)
|
|
324
346
|
const addLog = (type, message) => {
|
|
325
347
|
const timestamp = new Date().toLocaleTimeString();
|
|
326
|
-
logs.
|
|
327
|
-
if (logs.length > MAX_LOGS) logs.
|
|
348
|
+
logs.unshift({ timestamp, type, message }); // Add at beginning
|
|
349
|
+
if (logs.length > MAX_LOGS) logs.pop(); // Remove oldest
|
|
328
350
|
};
|
|
329
351
|
|
|
330
|
-
|
|
331
|
-
|
|
352
|
+
// Print log and refresh display
|
|
353
|
+
const printLog = (type, message) => {
|
|
354
|
+
addLog(type, message);
|
|
355
|
+
displayUI();
|
|
332
356
|
};
|
|
333
357
|
|
|
334
358
|
// Check market hours
|
|
@@ -352,72 +376,38 @@ const launchAlgo = async (service, account, contract, numContracts, dailyTarget,
|
|
|
352
376
|
return { isOpen: true, message: 'Market OPEN' };
|
|
353
377
|
};
|
|
354
378
|
|
|
379
|
+
// Display full UI with logs (newest first)
|
|
355
380
|
const displayUI = () => {
|
|
356
|
-
|
|
381
|
+
console.clear();
|
|
357
382
|
const marketStatus = checkMarketStatus();
|
|
383
|
+
|
|
384
|
+
// Header
|
|
358
385
|
console.log();
|
|
359
386
|
console.log(chalk.gray(getSeparator()));
|
|
360
|
-
console.log(chalk.cyan.bold(' HQX Ultra-Scalping Algo'));
|
|
361
|
-
console.log(chalk.gray(getSeparator()));
|
|
362
|
-
console.log(chalk.white(` Status: ${algoRunning ? chalk.green('RUNNING') : chalk.yellow('CONNECTING...')}`));
|
|
363
|
-
console.log(chalk.white(` Account: ${chalk.cyan(accountName)}`));
|
|
364
|
-
console.log(chalk.white(` Symbol: ${chalk.cyan(symbolName)}`));
|
|
365
|
-
console.log(chalk.white(` Contracts: ${chalk.cyan(numContracts)}`));
|
|
366
|
-
console.log(chalk.white(` Server: ${hqxConnected ? chalk.green('CONNECTED') : chalk.red('DISCONNECTED')}`));
|
|
367
|
-
console.log(chalk.white(` Market: ${marketStatus.isOpen ? chalk.green(marketStatus.message) : chalk.red(marketStatus.message)}`));
|
|
387
|
+
console.log(chalk.cyan.bold(' HQX Ultra-Scalping Algo') + chalk.gray(' | ') + chalk.yellow('Press X to stop'));
|
|
368
388
|
console.log(chalk.gray(getSeparator()));
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
console.log();
|
|
372
|
-
const targetProgress = Math.min(100, Math.max(0, (stats.pnl / dailyTarget) * 100));
|
|
373
|
-
const riskProgress = Math.min(100, (Math.abs(Math.min(0, stats.pnl)) / maxRisk) * 100);
|
|
374
|
-
console.log(chalk.white(' Target: ') + chalk.green('$' + dailyTarget.toFixed(2)) +
|
|
375
|
-
chalk.gray(' | Progress: ') + (targetProgress >= 100 ? chalk.green.bold(targetProgress.toFixed(1) + '%') : chalk.yellow(targetProgress.toFixed(1) + '%')));
|
|
376
|
-
console.log(chalk.white(' Risk: ') + chalk.red('$' + maxRisk.toFixed(2)) +
|
|
377
|
-
chalk.gray(' | Used: ') + (riskProgress >= 100 ? chalk.red.bold(riskProgress.toFixed(1) + '%') : chalk.cyan(riskProgress.toFixed(1) + '%')));
|
|
389
|
+
console.log(chalk.white(` Account: ${chalk.cyan(accountName)} | Symbol: ${chalk.cyan(symbolName)} | Qty: ${chalk.cyan(numContracts)}`));
|
|
390
|
+
console.log(chalk.white(` Target: ${chalk.green('$' + dailyTarget.toFixed(2))} | Risk: ${chalk.red('$' + maxRisk.toFixed(2))} | Server: ${hqxConnected ? chalk.green('ON') : chalk.red('OFF')}`));
|
|
378
391
|
|
|
379
|
-
// Stats
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
chalk.gray(' | Wins: ') + chalk.green(stats.wins) +
|
|
384
|
-
chalk.gray(' | Losses: ') + chalk.red(stats.losses) +
|
|
385
|
-
chalk.gray(' | Win Rate: ') + chalk.yellow(stats.winRate + '%') +
|
|
386
|
-
chalk.gray(' | P&L: ') + (stats.pnl >= 0 ? chalk.green('+$' + stats.pnl.toFixed(2)) : chalk.red('-$' + Math.abs(stats.pnl).toFixed(2)))
|
|
387
|
-
);
|
|
388
|
-
console.log();
|
|
392
|
+
// Stats line
|
|
393
|
+
const pnlColor = stats.pnl >= 0 ? chalk.green : chalk.red;
|
|
394
|
+
const pnlStr = stats.pnl >= 0 ? '+$' + stats.pnl.toFixed(2) : '-$' + Math.abs(stats.pnl).toFixed(2);
|
|
395
|
+
console.log(chalk.white(` P&L: ${pnlColor(pnlStr)} | Trades: ${chalk.cyan(stats.trades)} | Wins: ${chalk.green(stats.wins)} | Losses: ${chalk.red(stats.losses)}`));
|
|
389
396
|
|
|
390
|
-
// Activity logs
|
|
391
|
-
console.log(chalk.gray(getSeparator()));
|
|
392
|
-
console.log(chalk.white.bold(' Activity Log'));
|
|
393
397
|
console.log(chalk.gray(getSeparator()));
|
|
394
398
|
|
|
395
|
-
|
|
396
|
-
info: chalk.cyan,
|
|
397
|
-
success: chalk.green,
|
|
398
|
-
signal: chalk.yellow.bold,
|
|
399
|
-
trade: chalk.green.bold,
|
|
400
|
-
error: chalk.red,
|
|
401
|
-
warning: chalk.yellow
|
|
402
|
-
};
|
|
403
|
-
|
|
399
|
+
// Logs (newest first - already in correct order)
|
|
404
400
|
if (logs.length === 0) {
|
|
405
401
|
console.log(chalk.gray(' Waiting for activity...'));
|
|
406
402
|
} else {
|
|
407
403
|
logs.forEach(log => {
|
|
408
404
|
const color = typeColors[log.type] || chalk.white;
|
|
409
|
-
const icon = log.type
|
|
410
|
-
log.type === 'trade' ? '[>]' :
|
|
411
|
-
log.type === 'error' ? '[X]' :
|
|
412
|
-
log.type === 'success' ? '[OK]' : '[.]';
|
|
405
|
+
const icon = getIcon(log.type);
|
|
413
406
|
console.log(chalk.gray(` [${log.timestamp}]`) + ' ' + color(`${icon} ${log.message}`));
|
|
414
407
|
});
|
|
415
408
|
}
|
|
416
409
|
|
|
417
410
|
console.log(chalk.gray(getSeparator()));
|
|
418
|
-
console.log();
|
|
419
|
-
console.log(chalk.yellow(' Press X to stop algo...'));
|
|
420
|
-
console.log();
|
|
421
411
|
};
|
|
422
412
|
|
|
423
413
|
// Connect to HQX Server
|
|
@@ -455,17 +445,15 @@ const launchAlgo = async (service, account, contract, numContracts, dailyTarget,
|
|
|
455
445
|
hqxConnected = false;
|
|
456
446
|
}
|
|
457
447
|
|
|
458
|
-
// Setup event handlers
|
|
448
|
+
// Setup event handlers - logs scroll down naturally
|
|
459
449
|
hqxServer.on('log', (data) => {
|
|
460
|
-
|
|
461
|
-
displayUI();
|
|
450
|
+
printLog(data.type || 'info', data.message);
|
|
462
451
|
});
|
|
463
452
|
|
|
464
453
|
hqxServer.on('signal', (data) => {
|
|
465
454
|
stats.signals++;
|
|
466
455
|
const side = data.side === 'long' ? 'BUY' : 'SELL';
|
|
467
|
-
|
|
468
|
-
displayUI();
|
|
456
|
+
printLog('signal', `${side} Signal @ ${data.entry?.toFixed(2) || 'N/A'} | SL: ${data.stop?.toFixed(2) || 'N/A'} | TP: ${data.target?.toFixed(2) || 'N/A'}`);
|
|
469
457
|
|
|
470
458
|
// Execute order via PropFirm API if connected
|
|
471
459
|
if (hqxConnected && service) {
|
|
@@ -478,17 +466,20 @@ const launchAlgo = async (service, account, contract, numContracts, dailyTarget,
|
|
|
478
466
|
stats.pnl += data.pnl || 0;
|
|
479
467
|
if (data.pnl > 0) {
|
|
480
468
|
stats.wins++;
|
|
481
|
-
|
|
469
|
+
printLog('trade', `Closed +$${data.pnl.toFixed(2)} (${data.reason || 'take_profit'})`);
|
|
482
470
|
} else {
|
|
483
471
|
stats.losses++;
|
|
484
|
-
|
|
472
|
+
printLog('trade', `Closed -$${Math.abs(data.pnl).toFixed(2)} (${data.reason || 'stop_loss'})`);
|
|
485
473
|
}
|
|
486
474
|
stats.winRate = stats.trades > 0 ? ((stats.wins / stats.trades) * 100).toFixed(1) : '0.0';
|
|
487
475
|
|
|
476
|
+
// Print updated stats
|
|
477
|
+
printLog('info', `Stats: Trades: ${stats.trades} | Wins: ${stats.wins} | P&L: $${stats.pnl.toFixed(2)}`);
|
|
478
|
+
|
|
488
479
|
// Check daily target
|
|
489
480
|
if (stats.pnl >= dailyTarget) {
|
|
490
481
|
stopReason = 'target';
|
|
491
|
-
|
|
482
|
+
printLog('success', `Daily target reached! +$${stats.pnl.toFixed(2)}`);
|
|
492
483
|
algoRunning = false;
|
|
493
484
|
if (hqxConnected) {
|
|
494
485
|
hqxServer.stopAlgo();
|
|
@@ -498,36 +489,35 @@ const launchAlgo = async (service, account, contract, numContracts, dailyTarget,
|
|
|
498
489
|
// Check max risk
|
|
499
490
|
if (stats.pnl <= -maxRisk) {
|
|
500
491
|
stopReason = 'risk';
|
|
501
|
-
|
|
492
|
+
printLog('error', `Max risk reached! -$${Math.abs(stats.pnl).toFixed(2)}`);
|
|
502
493
|
algoRunning = false;
|
|
503
494
|
if (hqxConnected) {
|
|
504
495
|
hqxServer.stopAlgo();
|
|
505
496
|
}
|
|
506
497
|
}
|
|
507
|
-
|
|
508
|
-
displayUI();
|
|
509
498
|
});
|
|
510
499
|
|
|
511
500
|
hqxServer.on('stats', (data) => {
|
|
512
501
|
stats = { ...stats, ...data };
|
|
513
|
-
|
|
502
|
+
// Don't print stats every time, only on trades
|
|
514
503
|
});
|
|
515
504
|
|
|
516
505
|
hqxServer.on('error', (data) => {
|
|
517
|
-
|
|
518
|
-
displayUI();
|
|
506
|
+
printLog('error', data.message || 'Unknown error');
|
|
519
507
|
});
|
|
520
508
|
|
|
521
509
|
hqxServer.on('disconnected', () => {
|
|
522
510
|
hqxConnected = false;
|
|
523
|
-
|
|
524
|
-
displayUI();
|
|
511
|
+
printLog('warning', 'Disconnected from HQX Server');
|
|
525
512
|
});
|
|
526
513
|
|
|
514
|
+
// Display header once
|
|
515
|
+
displayUI();
|
|
516
|
+
|
|
527
517
|
// Start algo
|
|
528
518
|
if (hqxConnected) {
|
|
529
|
-
|
|
530
|
-
|
|
519
|
+
printLog('info', 'Starting HQX Ultra-Scalping...');
|
|
520
|
+
printLog('info', `Target: $${dailyTarget.toFixed(2)} | Risk: $${maxRisk.toFixed(2)}`);
|
|
531
521
|
hqxServer.startAlgo({
|
|
532
522
|
accountId: account.accountId,
|
|
533
523
|
contractId: contract.id || contract.contractId,
|
|
@@ -540,13 +530,11 @@ const launchAlgo = async (service, account, contract, numContracts, dailyTarget,
|
|
|
540
530
|
});
|
|
541
531
|
algoRunning = true;
|
|
542
532
|
} else {
|
|
543
|
-
|
|
544
|
-
|
|
533
|
+
printLog('warning', 'Running in offline demo mode');
|
|
534
|
+
printLog('info', 'No real trades will be executed');
|
|
545
535
|
algoRunning = true;
|
|
546
536
|
}
|
|
547
537
|
|
|
548
|
-
displayUI();
|
|
549
|
-
|
|
550
538
|
// Wait for X key OR auto-stop (target/risk reached)
|
|
551
539
|
await new Promise((resolve) => {
|
|
552
540
|
// Check for auto-stop every 500ms
|
|
@@ -579,31 +567,28 @@ const launchAlgo = async (service, account, contract, numContracts, dailyTarget,
|
|
|
579
567
|
});
|
|
580
568
|
|
|
581
569
|
// Stop algo
|
|
570
|
+
console.log();
|
|
582
571
|
if (!stopReason) {
|
|
583
|
-
|
|
572
|
+
printLog('warning', 'Stopping algo...');
|
|
584
573
|
}
|
|
585
574
|
|
|
586
575
|
// Cancel all pending orders and close positions
|
|
587
|
-
|
|
588
|
-
displayUI();
|
|
576
|
+
printLog('info', 'Cancelling pending orders...');
|
|
589
577
|
|
|
590
578
|
try {
|
|
591
579
|
// Cancel all orders
|
|
592
580
|
const cancelResult = await service.cancelAllOrders(account.accountId);
|
|
593
581
|
if (cancelResult.success) {
|
|
594
|
-
|
|
582
|
+
printLog('success', 'All pending orders cancelled');
|
|
595
583
|
} else {
|
|
596
|
-
|
|
584
|
+
printLog('warning', 'No pending orders to cancel');
|
|
597
585
|
}
|
|
598
586
|
} catch (e) {
|
|
599
|
-
|
|
587
|
+
printLog('warning', 'Could not cancel orders: ' + e.message);
|
|
600
588
|
}
|
|
601
589
|
|
|
602
|
-
displayUI();
|
|
603
|
-
|
|
604
590
|
// Close all positions for this symbol
|
|
605
|
-
|
|
606
|
-
displayUI();
|
|
591
|
+
printLog('info', 'Closing open positions...');
|
|
607
592
|
|
|
608
593
|
try {
|
|
609
594
|
const positions = await service.getPositions(account.accountId);
|
|
@@ -616,20 +601,18 @@ const launchAlgo = async (service, account, contract, numContracts, dailyTarget,
|
|
|
616
601
|
if (symbolPos && symbolPos.quantity !== 0) {
|
|
617
602
|
const closeResult = await service.closePosition(account.accountId, symbolPos.contractId || symbolPos.symbol);
|
|
618
603
|
if (closeResult.success) {
|
|
619
|
-
|
|
604
|
+
printLog('success', `Position closed: ${Math.abs(symbolPos.quantity)} ${symbol}`);
|
|
620
605
|
} else {
|
|
621
|
-
|
|
606
|
+
printLog('error', 'Failed to close position: ' + (closeResult.error || 'Unknown'));
|
|
622
607
|
}
|
|
623
608
|
} else {
|
|
624
|
-
|
|
609
|
+
printLog('info', 'No open position to close');
|
|
625
610
|
}
|
|
626
611
|
}
|
|
627
612
|
} catch (e) {
|
|
628
|
-
|
|
613
|
+
printLog('warning', 'Could not close positions: ' + e.message);
|
|
629
614
|
}
|
|
630
615
|
|
|
631
|
-
displayUI();
|
|
632
|
-
|
|
633
616
|
if (hqxConnected && algoRunning) {
|
|
634
617
|
hqxServer.stopAlgo();
|
|
635
618
|
}
|
|
@@ -1004,7 +987,7 @@ const launchCopyTrading = async (config) => {
|
|
|
1004
987
|
let stopReason = null;
|
|
1005
988
|
let lastLeadPosition = null;
|
|
1006
989
|
const logs = [];
|
|
1007
|
-
const MAX_LOGS =
|
|
990
|
+
const MAX_LOGS = 25;
|
|
1008
991
|
|
|
1009
992
|
const stats = {
|
|
1010
993
|
copiedTrades: 0,
|