hedgequantx 2.6.59 → 2.6.60

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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hedgequantx",
3
- "version": "2.6.59",
3
+ "version": "2.6.60",
4
4
  "description": "HedgeQuantX - Prop Futures Trading CLI",
5
5
  "main": "src/app.js",
6
6
  "bin": {
@@ -143,11 +143,15 @@ const FAST_SCALPING = {
143
143
  MAX_HOLD_MS: 60000, // 60 seconds failsafe (force exit if stuck)
144
144
 
145
145
  // Exit targets (in ticks) - defaults, override per symbol
146
- TARGET_TICKS: 16, // Take profit target
147
- STOP_TICKS: 20, // Stop loss
146
+ TARGET_TICKS: 16, // Take profit target (+$80 on NQ)
147
+ STOP_TICKS: 20, // Stop loss (-$100 on NQ)
148
+
149
+ // Breakeven (BE) - move SL to entry price after profit threshold
150
+ BREAKEVEN_ACTIVATION_TICKS: 6, // Activate BE after +6 ticks profit (+$30 on NQ)
151
+ BREAKEVEN_OFFSET_TICKS: 1, // BE at entry + 1 tick (small profit lock)
148
152
 
149
153
  // Trailing stop (activates after MIN_HOLD + profit threshold)
150
- TRAILING_ACTIVATION_TICKS: 8, // Start trailing after +8 ticks profit
154
+ TRAILING_ACTIVATION_TICKS: 8, // Start trailing after +8 ticks profit (+$40 on NQ)
151
155
  TRAILING_DISTANCE_TICKS: 4, // Trail 4 ticks behind high/low
152
156
 
153
157
  // Position monitoring
@@ -356,6 +356,10 @@ const launchAlgo = async (service, account, contract, config) => {
356
356
  algoLogger.info(ui, 'READY', `Hold complete - monitoring exit`);
357
357
  });
358
358
 
359
+ positionManager.on('breakevenActivated', ({ orderTag, position, breakevenPrice, pnlTicks }) => {
360
+ algoLogger.info(ui, 'BE', `Breakeven activated @ ${breakevenPrice} | +${pnlTicks} ticks`);
361
+ });
362
+
359
363
  positionManager.on('exitOrderFired', ({ orderTag, exitReason, latencyMs }) => {
360
364
  // Don't log here - exitFilled will log the result
361
365
  });
@@ -58,6 +58,8 @@ const WEIGHTS = {
58
58
  * @property {number} lowWaterMark - Lowest price since entry (for trailing)
59
59
  * @property {string} status - 'pending' | 'active' | 'holding' | 'exiting' | 'closed'
60
60
  * @property {boolean} holdComplete - True after MIN_HOLD_MS elapsed
61
+ * @property {boolean} breakevenActive - True after BE threshold reached
62
+ * @property {number|null} breakevenPrice - Price at which BE stop is set
61
63
  * @property {Object|null} exitReason - Why position was exited
62
64
  * @property {number} tickSize - Tick size from API
63
65
  * @property {number} tickValue - Tick value from API
@@ -214,6 +216,8 @@ class PositionManager extends EventEmitter {
214
216
  lowWaterMark: null,
215
217
  status: 'pending', // Waiting for fill confirmation
216
218
  holdComplete: false,
219
+ breakevenActive: false, // BE not yet activated
220
+ breakevenPrice: null, // Will be set when BE activates
217
221
  exitReason: null,
218
222
  latencyMs,
219
223
  // Contract info from API (NOT hardcoded)
@@ -483,18 +487,64 @@ class PositionManager extends EventEmitter {
483
487
  return { type: 'target', reason: 'Target reached', pnlTicks };
484
488
  }
485
489
 
486
- // 2. STOP HIT - Always exit at stop
487
- if (pnlTicks <= -stopTicks) {
490
+ // 2. BREAKEVEN CHECK - If BE is active, use BE price as stop
491
+ if (position.breakevenActive && position.breakevenPrice !== null) {
492
+ const tickSize = this._getTickSize(position);
493
+ if (tickSize) {
494
+ // Check if price hit breakeven stop
495
+ if (position.side === 0) { // Long
496
+ if (currentPrice <= position.breakevenPrice) {
497
+ return { type: 'breakeven', reason: 'Breakeven stop hit', pnlTicks };
498
+ }
499
+ } else { // Short
500
+ if (currentPrice >= position.breakevenPrice) {
501
+ return { type: 'breakeven', reason: 'Breakeven stop hit', pnlTicks };
502
+ }
503
+ }
504
+ }
505
+ }
506
+
507
+ // 3. STOP HIT - Only if BE not active (original stop)
508
+ if (!position.breakevenActive && pnlTicks <= -stopTicks) {
488
509
  return { type: 'stop', reason: 'Stop loss hit', pnlTicks };
489
510
  }
490
511
 
491
- // 3. VPIN DANGER - Informed traders detected (from strategy)
512
+ // 4. ACTIVATE BREAKEVEN - Move stop to entry after profit threshold
513
+ if (!position.breakevenActive && pnlTicks >= FAST_SCALPING.BREAKEVEN_ACTIVATION_TICKS) {
514
+ const tickSize = this._getTickSize(position);
515
+ if (tickSize && position.entryPrice) {
516
+ // Set BE price at entry + offset (small profit lock)
517
+ const offset = FAST_SCALPING.BREAKEVEN_OFFSET_TICKS * tickSize;
518
+ if (position.side === 0) { // Long
519
+ position.breakevenPrice = position.entryPrice + offset;
520
+ } else { // Short
521
+ position.breakevenPrice = position.entryPrice - offset;
522
+ }
523
+ position.breakevenActive = true;
524
+
525
+ log.info('BREAKEVEN ACTIVATED', {
526
+ symbol: position.symbol,
527
+ entryPrice: position.entryPrice,
528
+ bePrice: position.breakevenPrice,
529
+ pnlTicks,
530
+ });
531
+
532
+ this.emit('breakevenActivated', {
533
+ orderTag: position.orderTag,
534
+ position,
535
+ breakevenPrice: position.breakevenPrice,
536
+ pnlTicks,
537
+ });
538
+ }
539
+ }
540
+
541
+ // 5. VPIN DANGER - Informed traders detected (from strategy)
492
542
  const vpin = this._getVPIN(position);
493
543
  if (vpin !== null && vpin > MOMENTUM.VPIN_DANGER) {
494
544
  return { type: 'vpin', reason: `VPIN spike ${(vpin * 100).toFixed(0)}% - informed traders`, pnlTicks, vpin };
495
545
  }
496
546
 
497
- // 4. TRAILING STOP (only if in profit above threshold)
547
+ // 6. TRAILING STOP (only if in profit above threshold)
498
548
  if (pnlTicks >= FAST_SCALPING.TRAILING_ACTIVATION_TICKS) {
499
549
  const trailingPnl = this._calculateTrailingPnl(position, currentPrice);
500
550
  if (trailingPnl !== null && trailingPnl <= -FAST_SCALPING.TRAILING_DISTANCE_TICKS) {
@@ -502,7 +552,7 @@ class PositionManager extends EventEmitter {
502
552
  }
503
553
  }
504
554
 
505
- // 5. MOMENTUM-BASED EXIT (using strategy's math models)
555
+ // 7. MOMENTUM-BASED EXIT (using strategy's math models)
506
556
  const momentum = this._calculateMomentum(position);
507
557
 
508
558
  if (momentum !== null) {