hedgequantx 1.2.60 → 1.2.62
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 +61 -102
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,32 @@ const launchAlgo = async (service, account, contract, numContracts, dailyTarget,
|
|
|
321
318
|
winRate: '0.0'
|
|
322
319
|
};
|
|
323
320
|
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
321
|
+
// Log colors
|
|
322
|
+
const typeColors = {
|
|
323
|
+
info: chalk.cyan,
|
|
324
|
+
success: chalk.green,
|
|
325
|
+
signal: chalk.yellow.bold,
|
|
326
|
+
trade: chalk.green.bold,
|
|
327
|
+
error: chalk.red,
|
|
328
|
+
warning: chalk.yellow
|
|
328
329
|
};
|
|
329
330
|
|
|
330
|
-
const
|
|
331
|
-
|
|
331
|
+
const getIcon = (type) => {
|
|
332
|
+
switch(type) {
|
|
333
|
+
case 'signal': return '[*]';
|
|
334
|
+
case 'trade': return '[>]';
|
|
335
|
+
case 'error': return '[X]';
|
|
336
|
+
case 'success': return '[OK]';
|
|
337
|
+
default: return '[.]';
|
|
338
|
+
}
|
|
339
|
+
};
|
|
340
|
+
|
|
341
|
+
// Print log directly to console (no clear screen)
|
|
342
|
+
const printLog = (type, message) => {
|
|
343
|
+
const timestamp = new Date().toLocaleTimeString();
|
|
344
|
+
const color = typeColors[type] || chalk.white;
|
|
345
|
+
const icon = getIcon(type);
|
|
346
|
+
console.log(chalk.gray(` [${timestamp}]`) + ' ' + color(`${icon} ${message}`));
|
|
332
347
|
};
|
|
333
348
|
|
|
334
349
|
// Check market hours
|
|
@@ -352,71 +367,22 @@ const launchAlgo = async (service, account, contract, numContracts, dailyTarget,
|
|
|
352
367
|
return { isOpen: true, message: 'Market OPEN' };
|
|
353
368
|
};
|
|
354
369
|
|
|
355
|
-
|
|
356
|
-
|
|
370
|
+
// Display header once at start
|
|
371
|
+
const displayHeader = () => {
|
|
372
|
+
console.clear();
|
|
357
373
|
const marketStatus = checkMarketStatus();
|
|
358
374
|
console.log();
|
|
359
375
|
console.log(chalk.gray(getSeparator()));
|
|
360
376
|
console.log(chalk.cyan.bold(' HQX Ultra-Scalping Algo'));
|
|
361
377
|
console.log(chalk.gray(getSeparator()));
|
|
362
|
-
console.log(chalk.white(` Status: ${algoRunning ? chalk.green('RUNNING') : chalk.yellow('CONNECTING...')}`));
|
|
363
378
|
console.log(chalk.white(` Account: ${chalk.cyan(accountName)}`));
|
|
364
379
|
console.log(chalk.white(` Symbol: ${chalk.cyan(symbolName)}`));
|
|
365
380
|
console.log(chalk.white(` Contracts: ${chalk.cyan(numContracts)}`));
|
|
366
|
-
console.log(chalk.white(`
|
|
381
|
+
console.log(chalk.white(` Target: ${chalk.green('$' + dailyTarget.toFixed(2))} | Risk: ${chalk.red('$' + maxRisk.toFixed(2))}`));
|
|
367
382
|
console.log(chalk.white(` Market: ${marketStatus.isOpen ? chalk.green(marketStatus.message) : chalk.red(marketStatus.message)}`));
|
|
368
383
|
console.log(chalk.gray(getSeparator()));
|
|
369
|
-
|
|
370
|
-
// Risk Management
|
|
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) + '%')));
|
|
378
|
-
|
|
379
|
-
// Stats bar
|
|
380
|
-
console.log();
|
|
381
|
-
console.log(chalk.white(' Stats: ') +
|
|
382
|
-
chalk.gray('Trades: ') + chalk.cyan(stats.trades) +
|
|
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();
|
|
389
|
-
|
|
390
|
-
// Activity logs
|
|
391
|
-
console.log(chalk.gray(getSeparator()));
|
|
392
|
-
console.log(chalk.white.bold(' Activity Log'));
|
|
393
|
-
console.log(chalk.gray(getSeparator()));
|
|
394
|
-
|
|
395
|
-
const typeColors = {
|
|
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
|
-
|
|
404
|
-
if (logs.length === 0) {
|
|
405
|
-
console.log(chalk.gray(' Waiting for activity...'));
|
|
406
|
-
} else {
|
|
407
|
-
logs.forEach(log => {
|
|
408
|
-
const color = typeColors[log.type] || chalk.white;
|
|
409
|
-
const icon = log.type === 'signal' ? '[*]' :
|
|
410
|
-
log.type === 'trade' ? '[>]' :
|
|
411
|
-
log.type === 'error' ? '[X]' :
|
|
412
|
-
log.type === 'success' ? '[OK]' : '[.]';
|
|
413
|
-
console.log(chalk.gray(` [${log.timestamp}]`) + ' ' + color(`${icon} ${log.message}`));
|
|
414
|
-
});
|
|
415
|
-
}
|
|
416
|
-
|
|
417
|
-
console.log(chalk.gray(getSeparator()));
|
|
418
|
-
console.log();
|
|
419
384
|
console.log(chalk.yellow(' Press X to stop algo...'));
|
|
385
|
+
console.log(chalk.gray(getSeparator()));
|
|
420
386
|
console.log();
|
|
421
387
|
};
|
|
422
388
|
|
|
@@ -455,17 +421,15 @@ const launchAlgo = async (service, account, contract, numContracts, dailyTarget,
|
|
|
455
421
|
hqxConnected = false;
|
|
456
422
|
}
|
|
457
423
|
|
|
458
|
-
// Setup event handlers
|
|
424
|
+
// Setup event handlers - logs scroll down naturally
|
|
459
425
|
hqxServer.on('log', (data) => {
|
|
460
|
-
|
|
461
|
-
displayUI();
|
|
426
|
+
printLog(data.type || 'info', data.message);
|
|
462
427
|
});
|
|
463
428
|
|
|
464
429
|
hqxServer.on('signal', (data) => {
|
|
465
430
|
stats.signals++;
|
|
466
431
|
const side = data.side === 'long' ? 'BUY' : 'SELL';
|
|
467
|
-
|
|
468
|
-
displayUI();
|
|
432
|
+
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
433
|
|
|
470
434
|
// Execute order via PropFirm API if connected
|
|
471
435
|
if (hqxConnected && service) {
|
|
@@ -478,17 +442,20 @@ const launchAlgo = async (service, account, contract, numContracts, dailyTarget,
|
|
|
478
442
|
stats.pnl += data.pnl || 0;
|
|
479
443
|
if (data.pnl > 0) {
|
|
480
444
|
stats.wins++;
|
|
481
|
-
|
|
445
|
+
printLog('trade', `Closed +$${data.pnl.toFixed(2)} (${data.reason || 'take_profit'})`);
|
|
482
446
|
} else {
|
|
483
447
|
stats.losses++;
|
|
484
|
-
|
|
448
|
+
printLog('trade', `Closed -$${Math.abs(data.pnl).toFixed(2)} (${data.reason || 'stop_loss'})`);
|
|
485
449
|
}
|
|
486
450
|
stats.winRate = stats.trades > 0 ? ((stats.wins / stats.trades) * 100).toFixed(1) : '0.0';
|
|
487
451
|
|
|
452
|
+
// Print updated stats
|
|
453
|
+
printLog('info', `Stats: Trades: ${stats.trades} | Wins: ${stats.wins} | P&L: $${stats.pnl.toFixed(2)}`);
|
|
454
|
+
|
|
488
455
|
// Check daily target
|
|
489
456
|
if (stats.pnl >= dailyTarget) {
|
|
490
457
|
stopReason = 'target';
|
|
491
|
-
|
|
458
|
+
printLog('success', `Daily target reached! +$${stats.pnl.toFixed(2)}`);
|
|
492
459
|
algoRunning = false;
|
|
493
460
|
if (hqxConnected) {
|
|
494
461
|
hqxServer.stopAlgo();
|
|
@@ -498,36 +465,35 @@ const launchAlgo = async (service, account, contract, numContracts, dailyTarget,
|
|
|
498
465
|
// Check max risk
|
|
499
466
|
if (stats.pnl <= -maxRisk) {
|
|
500
467
|
stopReason = 'risk';
|
|
501
|
-
|
|
468
|
+
printLog('error', `Max risk reached! -$${Math.abs(stats.pnl).toFixed(2)}`);
|
|
502
469
|
algoRunning = false;
|
|
503
470
|
if (hqxConnected) {
|
|
504
471
|
hqxServer.stopAlgo();
|
|
505
472
|
}
|
|
506
473
|
}
|
|
507
|
-
|
|
508
|
-
displayUI();
|
|
509
474
|
});
|
|
510
475
|
|
|
511
476
|
hqxServer.on('stats', (data) => {
|
|
512
477
|
stats = { ...stats, ...data };
|
|
513
|
-
|
|
478
|
+
// Don't print stats every time, only on trades
|
|
514
479
|
});
|
|
515
480
|
|
|
516
481
|
hqxServer.on('error', (data) => {
|
|
517
|
-
|
|
518
|
-
displayUI();
|
|
482
|
+
printLog('error', data.message || 'Unknown error');
|
|
519
483
|
});
|
|
520
484
|
|
|
521
485
|
hqxServer.on('disconnected', () => {
|
|
522
486
|
hqxConnected = false;
|
|
523
|
-
|
|
524
|
-
displayUI();
|
|
487
|
+
printLog('warning', 'Disconnected from HQX Server');
|
|
525
488
|
});
|
|
526
489
|
|
|
490
|
+
// Display header once
|
|
491
|
+
displayHeader();
|
|
492
|
+
|
|
527
493
|
// Start algo
|
|
528
494
|
if (hqxConnected) {
|
|
529
|
-
|
|
530
|
-
|
|
495
|
+
printLog('info', 'Starting HQX Ultra-Scalping...');
|
|
496
|
+
printLog('info', `Target: $${dailyTarget.toFixed(2)} | Risk: $${maxRisk.toFixed(2)}`);
|
|
531
497
|
hqxServer.startAlgo({
|
|
532
498
|
accountId: account.accountId,
|
|
533
499
|
contractId: contract.id || contract.contractId,
|
|
@@ -540,13 +506,11 @@ const launchAlgo = async (service, account, contract, numContracts, dailyTarget,
|
|
|
540
506
|
});
|
|
541
507
|
algoRunning = true;
|
|
542
508
|
} else {
|
|
543
|
-
|
|
544
|
-
|
|
509
|
+
printLog('warning', 'Running in offline demo mode');
|
|
510
|
+
printLog('info', 'No real trades will be executed');
|
|
545
511
|
algoRunning = true;
|
|
546
512
|
}
|
|
547
513
|
|
|
548
|
-
displayUI();
|
|
549
|
-
|
|
550
514
|
// Wait for X key OR auto-stop (target/risk reached)
|
|
551
515
|
await new Promise((resolve) => {
|
|
552
516
|
// Check for auto-stop every 500ms
|
|
@@ -579,31 +543,28 @@ const launchAlgo = async (service, account, contract, numContracts, dailyTarget,
|
|
|
579
543
|
});
|
|
580
544
|
|
|
581
545
|
// Stop algo
|
|
546
|
+
console.log();
|
|
582
547
|
if (!stopReason) {
|
|
583
|
-
|
|
548
|
+
printLog('warning', 'Stopping algo...');
|
|
584
549
|
}
|
|
585
550
|
|
|
586
551
|
// Cancel all pending orders and close positions
|
|
587
|
-
|
|
588
|
-
displayUI();
|
|
552
|
+
printLog('info', 'Cancelling pending orders...');
|
|
589
553
|
|
|
590
554
|
try {
|
|
591
555
|
// Cancel all orders
|
|
592
556
|
const cancelResult = await service.cancelAllOrders(account.accountId);
|
|
593
557
|
if (cancelResult.success) {
|
|
594
|
-
|
|
558
|
+
printLog('success', 'All pending orders cancelled');
|
|
595
559
|
} else {
|
|
596
|
-
|
|
560
|
+
printLog('warning', 'No pending orders to cancel');
|
|
597
561
|
}
|
|
598
562
|
} catch (e) {
|
|
599
|
-
|
|
563
|
+
printLog('warning', 'Could not cancel orders: ' + e.message);
|
|
600
564
|
}
|
|
601
565
|
|
|
602
|
-
displayUI();
|
|
603
|
-
|
|
604
566
|
// Close all positions for this symbol
|
|
605
|
-
|
|
606
|
-
displayUI();
|
|
567
|
+
printLog('info', 'Closing open positions...');
|
|
607
568
|
|
|
608
569
|
try {
|
|
609
570
|
const positions = await service.getPositions(account.accountId);
|
|
@@ -616,20 +577,18 @@ const launchAlgo = async (service, account, contract, numContracts, dailyTarget,
|
|
|
616
577
|
if (symbolPos && symbolPos.quantity !== 0) {
|
|
617
578
|
const closeResult = await service.closePosition(account.accountId, symbolPos.contractId || symbolPos.symbol);
|
|
618
579
|
if (closeResult.success) {
|
|
619
|
-
|
|
580
|
+
printLog('success', `Position closed: ${Math.abs(symbolPos.quantity)} ${symbol}`);
|
|
620
581
|
} else {
|
|
621
|
-
|
|
582
|
+
printLog('error', 'Failed to close position: ' + (closeResult.error || 'Unknown'));
|
|
622
583
|
}
|
|
623
584
|
} else {
|
|
624
|
-
|
|
585
|
+
printLog('info', 'No open position to close');
|
|
625
586
|
}
|
|
626
587
|
}
|
|
627
588
|
} catch (e) {
|
|
628
|
-
|
|
589
|
+
printLog('warning', 'Could not close positions: ' + e.message);
|
|
629
590
|
}
|
|
630
591
|
|
|
631
|
-
displayUI();
|
|
632
|
-
|
|
633
592
|
if (hqxConnected && algoRunning) {
|
|
634
593
|
hqxServer.stopAlgo();
|
|
635
594
|
}
|
|
@@ -1004,7 +963,7 @@ const launchCopyTrading = async (config) => {
|
|
|
1004
963
|
let stopReason = null;
|
|
1005
964
|
let lastLeadPosition = null;
|
|
1006
965
|
const logs = [];
|
|
1007
|
-
const MAX_LOGS =
|
|
966
|
+
const MAX_LOGS = 25;
|
|
1008
967
|
|
|
1009
968
|
const stats = {
|
|
1010
969
|
copiedTrades: 0,
|