hedgequantx 2.6.59 → 2.6.61
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
package/src/config/settings.js
CHANGED
|
@@ -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
|
|
@@ -877,12 +877,14 @@ const launchCopyTrading = async (config) => {
|
|
|
877
877
|
platform: lead.type === 'rithmic' ? 'Rithmic' : 'ProjectX',
|
|
878
878
|
startTime: Date.now(),
|
|
879
879
|
aiSupervision: false,
|
|
880
|
-
aiMode: null
|
|
880
|
+
aiMode: null,
|
|
881
|
+
agentCount: 0 // Number of AI agents active
|
|
881
882
|
};
|
|
882
883
|
|
|
883
884
|
// Initialize AI Supervisor - only if user enabled it
|
|
884
885
|
if (enableAI) {
|
|
885
886
|
const aiAgents = aiService.getAgents();
|
|
887
|
+
stats.agentCount = aiAgents.length;
|
|
886
888
|
if (aiAgents.length > 0) {
|
|
887
889
|
const supervisorResult = StrategySupervisor.initialize(null, aiAgents, lead.service, lead.account.accountId);
|
|
888
890
|
stats.aiSupervision = supervisorResult.success;
|
|
@@ -269,6 +269,7 @@ const launchAlgo = async (service, account, contract, config) => {
|
|
|
269
269
|
startTime: Date.now(),
|
|
270
270
|
aiSupervision: false,
|
|
271
271
|
aiMode: null,
|
|
272
|
+
agentCount: 0, // Number of AI agents active
|
|
272
273
|
// Fast path stats
|
|
273
274
|
fastPath: useFastPath,
|
|
274
275
|
avgEntryLatency: 0,
|
|
@@ -356,6 +357,10 @@ const launchAlgo = async (service, account, contract, config) => {
|
|
|
356
357
|
algoLogger.info(ui, 'READY', `Hold complete - monitoring exit`);
|
|
357
358
|
});
|
|
358
359
|
|
|
360
|
+
positionManager.on('breakevenActivated', ({ orderTag, position, breakevenPrice, pnlTicks }) => {
|
|
361
|
+
algoLogger.info(ui, 'BE', `Breakeven activated @ ${breakevenPrice} | +${pnlTicks} ticks`);
|
|
362
|
+
});
|
|
363
|
+
|
|
359
364
|
positionManager.on('exitOrderFired', ({ orderTag, exitReason, latencyMs }) => {
|
|
360
365
|
// Don't log here - exitFilled will log the result
|
|
361
366
|
});
|
|
@@ -450,6 +455,7 @@ const launchAlgo = async (service, account, contract, config) => {
|
|
|
450
455
|
if (config.enableAI) {
|
|
451
456
|
const aiAgents = aiService.getAgents();
|
|
452
457
|
aiAgentCount = aiAgents.length;
|
|
458
|
+
stats.agentCount = aiAgentCount;
|
|
453
459
|
if (aiAgents.length > 0) {
|
|
454
460
|
const supervisorResult = StrategySupervisor.initialize(strategy, aiAgents, service, account.accountId);
|
|
455
461
|
stats.aiSupervision = supervisorResult.success;
|
package/src/pages/algo/ui.js
CHANGED
|
@@ -239,6 +239,18 @@ class AlgoUI {
|
|
|
239
239
|
const r4c2 = buildCell('PROPFIRM', stats.propfirm || 'N/A', chalk.cyan, colR);
|
|
240
240
|
row(r4c1t + pad(colL - r4c1p.length), r4c2.padded);
|
|
241
241
|
|
|
242
|
+
this._line(chalk.cyan(GM));
|
|
243
|
+
|
|
244
|
+
// Row 5: Connection | Agents
|
|
245
|
+
const connectionType = stats.platform || stats.connection || 'N/A';
|
|
246
|
+
const connectionColor = connectionType.toLowerCase().includes('rithmic') ? chalk.green : chalk.yellow;
|
|
247
|
+
const agentCount = stats.agentCount || 0;
|
|
248
|
+
const agentStr = agentCount > 0 ? `${agentCount} agent${agentCount > 1 ? 's' : ''} active` : 'None';
|
|
249
|
+
const agentColor = agentCount > 0 ? chalk.green : chalk.gray;
|
|
250
|
+
const r5c1 = buildCell('CONNECTION', connectionType, connectionColor, colL);
|
|
251
|
+
const r5c2 = buildCell('AGENTS', agentStr, agentColor, colR);
|
|
252
|
+
row(r5c1.padded, r5c2.padded);
|
|
253
|
+
|
|
242
254
|
this._line(chalk.cyan(GB));
|
|
243
255
|
}
|
|
244
256
|
|
|
@@ -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.
|
|
487
|
-
if (
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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
|
-
//
|
|
555
|
+
// 7. MOMENTUM-BASED EXIT (using strategy's math models)
|
|
506
556
|
const momentum = this._calculateMomentum(position);
|
|
507
557
|
|
|
508
558
|
if (momentum !== null) {
|