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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/src/pages/algo.js +61 -102
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hedgequantx",
3
- "version": "1.2.60",
3
+ "version": "1.2.62",
4
4
  "description": "Prop Futures Algo Trading CLI - Connect to Topstep, Alpha Futures, and other prop firms",
5
5
  "main": "src/app.js",
6
6
  "bin": {
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
- const addLog = (type, message) => {
325
- const timestamp = new Date().toLocaleTimeString();
326
- logs.push({ timestamp, type, message });
327
- if (logs.length > MAX_LOGS) logs.shift();
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 clearScreen = () => {
331
- console.clear();
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
- const displayUI = () => {
356
- clearScreen();
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(` Server: ${hqxConnected ? chalk.green('CONNECTED') : chalk.red('DISCONNECTED')}`));
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
- addLog(data.type || 'info', data.message);
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
- addLog('signal', `${side} Signal @ ${data.entry?.toFixed(2) || 'N/A'} | SL: ${data.stop?.toFixed(2) || 'N/A'} | TP: ${data.target?.toFixed(2) || 'N/A'}`);
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
- addLog('trade', `Closed +$${data.pnl.toFixed(2)} (${data.reason || 'take_profit'})`);
445
+ printLog('trade', `Closed +$${data.pnl.toFixed(2)} (${data.reason || 'take_profit'})`);
482
446
  } else {
483
447
  stats.losses++;
484
- addLog('trade', `Closed -$${Math.abs(data.pnl).toFixed(2)} (${data.reason || 'stop_loss'})`);
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
- addLog('success', `Daily target reached! +$${stats.pnl.toFixed(2)}`);
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
- addLog('error', `Max risk reached! -$${Math.abs(stats.pnl).toFixed(2)}`);
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
- displayUI();
478
+ // Don't print stats every time, only on trades
514
479
  });
515
480
 
516
481
  hqxServer.on('error', (data) => {
517
- addLog('error', data.message || 'Unknown error');
518
- displayUI();
482
+ printLog('error', data.message || 'Unknown error');
519
483
  });
520
484
 
521
485
  hqxServer.on('disconnected', () => {
522
486
  hqxConnected = false;
523
- addLog('warning', 'Disconnected from HQX Server');
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
- addLog('info', 'Starting HQX Ultra-Scalping...');
530
- addLog('info', `Target: $${dailyTarget.toFixed(2)} | Risk: $${maxRisk.toFixed(2)}`);
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
- addLog('warning', 'Running in offline demo mode');
544
- addLog('info', 'No real trades will be executed');
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
- addLog('warning', 'Stopping algo...');
548
+ printLog('warning', 'Stopping algo...');
584
549
  }
585
550
 
586
551
  // Cancel all pending orders and close positions
587
- addLog('info', 'Cancelling pending orders...');
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
- addLog('success', 'All pending orders cancelled');
558
+ printLog('success', 'All pending orders cancelled');
595
559
  } else {
596
- addLog('warning', 'No pending orders to cancel');
560
+ printLog('warning', 'No pending orders to cancel');
597
561
  }
598
562
  } catch (e) {
599
- addLog('warning', 'Could not cancel orders: ' + e.message);
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
- addLog('info', 'Closing open positions...');
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
- addLog('success', `Position closed: ${Math.abs(symbolPos.quantity)} ${symbol}`);
580
+ printLog('success', `Position closed: ${Math.abs(symbolPos.quantity)} ${symbol}`);
620
581
  } else {
621
- addLog('error', 'Failed to close position: ' + (closeResult.error || 'Unknown'));
582
+ printLog('error', 'Failed to close position: ' + (closeResult.error || 'Unknown'));
622
583
  }
623
584
  } else {
624
- addLog('info', 'No open position to close');
585
+ printLog('info', 'No open position to close');
625
586
  }
626
587
  }
627
588
  } catch (e) {
628
- addLog('warning', 'Could not close positions: ' + e.message);
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 = 12;
966
+ const MAX_LOGS = 25;
1008
967
 
1009
968
  const stats = {
1010
969
  copiedTrades: 0,