hedgequantx 2.9.94 → 2.9.96

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.
@@ -1,845 +1 @@
1
- var __getOwnPropNames = Object.getOwnPropertyNames;
2
- var __commonJS = (cb, mod) => function __require() {
3
- return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
4
- };
5
-
6
- // hqx-2b/config.js
7
- var require_config = __commonJS({
8
- "hqx-2b/config.js"(exports2, module2) {
9
- var SweepType2 = { HIGH_SWEEP: "high", LOW_SWEEP: "low" };
10
- var ZoneType2 = { RESISTANCE: "resistance", SUPPORT: "support" };
11
- var DEFAULT_CONFIG2 = {
12
- // Instrument
13
- tickSize: 0.25,
14
- tickValue: 5,
15
- // Swing Detection (HYPER AGGRESSIVE)
16
- swing: {
17
- lookbackBars: 1,
18
- // Minimum lookback - detect swings faster
19
- minStrength: 1,
20
- // Any swing counts
21
- confirmationBars: 1
22
- // Immediate confirmation
23
- },
24
- // Zone Detection (HYPER AGGRESSIVE)
25
- zone: {
26
- clusterToleranceTicks: 8,
27
- // Wider tolerance for zone clustering
28
- minTouches: 1,
29
- // Single-touch zones OK
30
- maxZoneAgeBars: 500,
31
- // Keep zones longer
32
- maxZoneDistanceTicks: 80,
33
- // Look for zones further away
34
- cooldownBars: 3
35
- // Quick zone reuse (was 10)
36
- },
37
- // Sweep Detection (HYPER AGGRESSIVE)
38
- sweep: {
39
- minPenetrationTicks: 0.5,
40
- // Even tiny penetration counts
41
- maxPenetrationTicks: 20,
42
- // Allow deeper sweeps
43
- maxDurationBars: 10,
44
- // Allow slower sweeps
45
- minQualityScore: 0.2,
46
- // Lower quality threshold (was 0.40)
47
- minVolumeRatio: 0.5,
48
- // Lower volume requirement (was 0.8)
49
- minBodyRatio: 0.1
50
- // Lower body ratio (was 0.2)
51
- },
52
- // Execution (OPTIMIZED 4:1 R:R)
53
- execution: {
54
- stopTicks: 10,
55
- // $50 stop
56
- targetTicks: 40,
57
- // $200 target (4:1 R:R)
58
- breakevenTicks: 4,
59
- // Move to BE at +4 ticks
60
- trailTriggerTicks: 8,
61
- // Activate trailing at +8 ticks
62
- trailDistanceTicks: 4,
63
- // Trail by 4 ticks
64
- cooldownMs: 15e3,
65
- // 15 seconds between signals (was 30)
66
- minHoldTimeMs: 5e3,
67
- // 5 seconds min hold (was 10)
68
- slippageTicks: 1,
69
- commissionPerSide: 2
70
- // $4 round-trip
71
- },
72
- // Session filter (US Regular Hours only - matches backtest)
73
- session: {
74
- enabled: true,
75
- // MUST be enabled to match backtest results
76
- startHour: 9,
77
- // 9:30 AM EST
78
- startMinute: 30,
79
- endHour: 16,
80
- // 4:00 PM EST
81
- endMinute: 0,
82
- timezone: "America/New_York"
83
- }
84
- };
85
- module2.exports = { DEFAULT_CONFIG: DEFAULT_CONFIG2, SweepType: SweepType2, ZoneType: ZoneType2 };
86
- }
87
- });
88
-
89
- // common/types.js
90
- var require_types = __commonJS({
91
- "common/types.js"(exports2, module2) {
92
- var OrderSide2 = { BID: 0, ASK: 1 };
93
- var SignalStrength2 = { WEAK: 1, MODERATE: 2, STRONG: 3, VERY_STRONG: 4 };
94
- module2.exports = { OrderSide: OrderSide2, SignalStrength: SignalStrength2 };
95
- }
96
- });
97
-
98
- // hqx-2b/signal.js
99
- var require_signal = __commonJS({
100
- "hqx-2b/signal.js"(exports2, module2) {
101
- var { v4: uuidv4 } = require("uuid");
102
- var { OrderSide: OrderSide2, SignalStrength: SignalStrength2 } = require_types();
103
- var { SweepType: SweepType2 } = require_config();
104
- function generateSignal(params) {
105
- const {
106
- contractId,
107
- currentBar,
108
- currentIndex,
109
- sweep,
110
- config,
111
- tickSize
112
- } = params;
113
- const exec = config.execution;
114
- const currentPrice = currentBar.close;
115
- const direction = sweep.sweepType === SweepType2.HIGH_SWEEP ? "short" : "long";
116
- let stopLoss, takeProfit, beLevel, trailTrigger;
117
- if (direction === "long") {
118
- stopLoss = currentPrice - exec.stopTicks * tickSize;
119
- takeProfit = currentPrice + exec.targetTicks * tickSize;
120
- beLevel = currentPrice + exec.breakevenTicks * tickSize;
121
- trailTrigger = currentPrice + exec.trailTriggerTicks * tickSize;
122
- } else {
123
- stopLoss = currentPrice + exec.stopTicks * tickSize;
124
- takeProfit = currentPrice - exec.targetTicks * tickSize;
125
- beLevel = currentPrice - exec.breakevenTicks * tickSize;
126
- trailTrigger = currentPrice - exec.trailTriggerTicks * tickSize;
127
- }
128
- const riskReward = exec.targetTicks / exec.stopTicks;
129
- const confidence = Math.min(
130
- 1,
131
- sweep.qualityScore * 0.5 + sweep.zone.qualityScore * 0.3 + (sweep.volumeRatio > 1.5 ? 0.2 : sweep.volumeRatio * 0.1)
132
- );
133
- let strength = SignalStrength2.MODERATE;
134
- if (confidence >= 0.8) strength = SignalStrength2.VERY_STRONG;
135
- else if (confidence >= 0.65) strength = SignalStrength2.STRONG;
136
- else if (confidence < 0.5) strength = SignalStrength2.WEAK;
137
- const winProb = 0.5 + (confidence - 0.5) * 0.4;
138
- const edge = winProb * Math.abs(takeProfit - currentPrice) - (1 - winProb) * Math.abs(currentPrice - stopLoss);
139
- sweep.zone.lastUsedBarIndex = currentIndex;
140
- sweep.zone.swept = true;
141
- sweep.zone.sweptAt = new Date(currentBar.timestamp);
142
- return {
143
- id: uuidv4(),
144
- timestamp: Date.now(),
145
- symbol: contractId.split(".")[0] || contractId,
146
- contractId,
147
- side: direction === "long" ? OrderSide2.BID : OrderSide2.ASK,
148
- direction,
149
- strategy: "HQX_2B_LIQUIDITY_SWEEP",
150
- strength,
151
- edge,
152
- confidence,
153
- entry: currentPrice,
154
- entryPrice: currentPrice,
155
- stopLoss,
156
- takeProfit,
157
- riskReward,
158
- stopTicks: exec.stopTicks,
159
- targetTicks: exec.targetTicks,
160
- breakevenTicks: exec.breakevenTicks,
161
- trailTriggerTicks: exec.trailTriggerTicks,
162
- trailDistanceTicks: exec.trailDistanceTicks,
163
- beLevel,
164
- trailTrigger,
165
- // Sweep details
166
- sweepType: sweep.sweepType,
167
- penetrationTicks: sweep.penetrationTicks,
168
- sweepDurationBars: sweep.durationBars,
169
- sweepQuality: sweep.qualityScore,
170
- volumeRatio: sweep.volumeRatio,
171
- // Zone details
172
- zoneType: sweep.zone.type,
173
- zoneLevel: sweep.zone.getLevel(),
174
- zoneTouches: sweep.zone.touches,
175
- zoneQuality: sweep.zone.qualityScore,
176
- expires: Date.now() + 6e4
177
- };
178
- }
179
- module2.exports = { generateSignal };
180
- }
181
- });
182
-
183
- // hqx-2b/detection/swings.js
184
- var require_swings = __commonJS({
185
- "hqx-2b/detection/swings.js"(exports2, module2) {
186
- var SwingPoint = class {
187
- constructor(type, price, barIndex, timestamp, strength = 1) {
188
- this.type = type;
189
- this.price = price;
190
- this.barIndex = barIndex;
191
- this.timestamp = timestamp;
192
- this.strength = strength;
193
- }
194
- };
195
- function detectSwings(bars, currentIndex, existingSwings, config, maxAge) {
196
- const { lookbackBars, minStrength } = config;
197
- const swings = [...existingSwings];
198
- if (currentIndex < lookbackBars * 2) return swings;
199
- const pivotIndex = currentIndex - lookbackBars;
200
- const pivotBar = bars[pivotIndex];
201
- let isSwingHigh = true;
202
- let highStrength = 0;
203
- for (let i = pivotIndex - lookbackBars; i <= pivotIndex + lookbackBars; i++) {
204
- if (i === pivotIndex || i < 0 || i >= bars.length) continue;
205
- if (bars[i].high >= pivotBar.high) {
206
- isSwingHigh = false;
207
- break;
208
- }
209
- highStrength++;
210
- }
211
- if (isSwingHigh && highStrength >= minStrength) {
212
- const existing = swings.find((s) => s.barIndex === pivotIndex && s.type === "high");
213
- if (!existing) {
214
- swings.push(new SwingPoint("high", pivotBar.high, pivotIndex, pivotBar.timestamp, highStrength));
215
- }
216
- }
217
- let isSwingLow = true;
218
- let lowStrength = 0;
219
- for (let i = pivotIndex - lookbackBars; i <= pivotIndex + lookbackBars; i++) {
220
- if (i === pivotIndex || i < 0 || i >= bars.length) continue;
221
- if (bars[i].low <= pivotBar.low) {
222
- isSwingLow = false;
223
- break;
224
- }
225
- lowStrength++;
226
- }
227
- if (isSwingLow && lowStrength >= minStrength) {
228
- const existing = swings.find((s) => s.barIndex === pivotIndex && s.type === "low");
229
- if (!existing) {
230
- swings.push(new SwingPoint("low", pivotBar.low, pivotIndex, pivotBar.timestamp, lowStrength));
231
- }
232
- }
233
- while (swings.length > 0 && swings[0].barIndex < currentIndex - maxAge) {
234
- swings.shift();
235
- }
236
- return swings;
237
- }
238
- module2.exports = { SwingPoint, detectSwings };
239
- }
240
- });
241
-
242
- // hqx-2b/detection/zones.js
243
- var require_zones = __commonJS({
244
- "hqx-2b/detection/zones.js"(exports2, module2) {
245
- var { v4: uuidv4 } = require("uuid");
246
- var { ZoneType: ZoneType2 } = require_config();
247
- var LiquidityZone = class {
248
- constructor(type, priceHigh, priceLow, createdAt, barIndex) {
249
- this.id = uuidv4();
250
- this.type = type;
251
- this.priceHigh = priceHigh;
252
- this.priceLow = priceLow;
253
- this.createdAt = createdAt;
254
- this.barIndex = barIndex;
255
- this.touches = 1;
256
- this.swept = false;
257
- this.sweptAt = null;
258
- this.lastUsedBarIndex = -999;
259
- this.qualityScore = 0.5;
260
- }
261
- containsPrice(price, toleranceTicks, tickSize) {
262
- const tolerance = toleranceTicks * tickSize;
263
- return price >= this.priceLow - tolerance && price <= this.priceHigh + tolerance;
264
- }
265
- getLevel() {
266
- return (this.priceHigh + this.priceLow) / 2;
267
- }
268
- };
269
- function updateZones(swings, existingZones, currentIndex, config, tickSize) {
270
- const { clusterToleranceTicks, maxZoneAgeBars } = config;
271
- const zones = [...existingZones];
272
- const tolerance = clusterToleranceTicks * tickSize;
273
- for (let i = zones.length - 1; i >= 0; i--) {
274
- if (currentIndex - zones[i].barIndex > maxZoneAgeBars) {
275
- zones.splice(i, 1);
276
- }
277
- }
278
- for (const swing of swings) {
279
- let foundZone = null;
280
- for (const zone of zones) {
281
- if (zone.containsPrice(swing.price, clusterToleranceTicks, tickSize)) {
282
- foundZone = zone;
283
- break;
284
- }
285
- }
286
- if (foundZone) {
287
- foundZone.touches++;
288
- if (swing.price > foundZone.priceHigh) foundZone.priceHigh = swing.price;
289
- if (swing.price < foundZone.priceLow) foundZone.priceLow = swing.price;
290
- foundZone.qualityScore = Math.min(1, 0.3 + foundZone.touches * 0.15);
291
- } else {
292
- const zoneType = swing.type === "high" ? ZoneType2.RESISTANCE : ZoneType2.SUPPORT;
293
- const newZone = new LiquidityZone(
294
- zoneType,
295
- swing.price + tolerance / 2,
296
- swing.price - tolerance / 2,
297
- swing.timestamp,
298
- swing.barIndex
299
- );
300
- newZone.qualityScore = 0.3 + swing.strength * 0.1;
301
- zones.push(newZone);
302
- }
303
- }
304
- return zones;
305
- }
306
- module2.exports = { LiquidityZone, updateZones };
307
- }
308
- });
309
-
310
- // hqx-2b/detection/sweeps.js
311
- var require_sweeps = __commonJS({
312
- "hqx-2b/detection/sweeps.js"(exports2, module2) {
313
- var { SweepType: SweepType2, ZoneType: ZoneType2 } = require_config();
314
- var SweepEvent = class {
315
- constructor(sweepType, zone, entryBarIndex, extremeBarIndex, extremePrice) {
316
- this.sweepType = sweepType;
317
- this.zone = zone;
318
- this.entryBarIndex = entryBarIndex;
319
- this.extremeBarIndex = extremeBarIndex;
320
- this.extremePrice = extremePrice;
321
- this.exitBarIndex = null;
322
- this.isValid = false;
323
- this.qualityScore = 0;
324
- this.penetrationTicks = 0;
325
- this.durationBars = 0;
326
- this.volumeRatio = 1;
327
- }
328
- };
329
- function getVolumeRatio(bars, index, lookback) {
330
- const start = Math.max(0, index - lookback);
331
- const recentBars = bars.slice(start, index);
332
- if (recentBars.length === 0) return 1;
333
- const volumes = recentBars.map((b) => b.volume).sort((a, b) => a - b);
334
- const medianIdx = Math.floor(volumes.length / 2);
335
- const medianVolume = volumes[medianIdx] || 1;
336
- return bars[index].volume / medianVolume;
337
- }
338
- function scoreSweep(sweep, bodyRatio) {
339
- let score = 0;
340
- const optimalPen = 4;
341
- const penDiff = Math.abs(sweep.penetrationTicks - optimalPen);
342
- score += Math.max(0, 0.3 - penDiff * 0.03);
343
- score += Math.max(0, 0.25 - sweep.durationBars * 0.05);
344
- score += Math.min(0.25, sweep.volumeRatio * 0.1);
345
- score += Math.min(0.2, bodyRatio * 0.4);
346
- return Math.min(1, score);
347
- }
348
- function detectSweep(zones, bars, currentIndex, sweepConfig, zoneConfig, tickSize) {
349
- const currentBar = bars[currentIndex];
350
- const currentPrice = currentBar.close;
351
- const cfg = sweepConfig;
352
- for (const zone of zones) {
353
- if (zone.lastUsedBarIndex >= 0 && currentIndex - zone.lastUsedBarIndex < zoneConfig.cooldownBars) {
354
- continue;
355
- }
356
- const zoneLevel = zone.getLevel();
357
- const distanceTicks = Math.abs(currentPrice - zoneLevel) / tickSize;
358
- if (distanceTicks > zoneConfig.maxZoneDistanceTicks) continue;
359
- const lookbackStart = Math.max(0, currentIndex - cfg.maxDurationBars * 2);
360
- for (let i = lookbackStart; i < currentIndex; i++) {
361
- const bar = bars[i];
362
- if (zone.type === ZoneType2.RESISTANCE) {
363
- const penetration = (bar.high - zone.priceHigh) / tickSize;
364
- if (penetration >= cfg.minPenetrationTicks && penetration <= cfg.maxPenetrationTicks) {
365
- if (currentPrice < zone.priceHigh) {
366
- const barRange = bar.high - bar.low;
367
- const bodySize = Math.abs(bar.close - bar.open);
368
- const bodyRatio = barRange > 0 ? bodySize / barRange : 0;
369
- if (bodyRatio >= cfg.minBodyRatio) {
370
- const volumeRatio = getVolumeRatio(bars, i, 20);
371
- if (volumeRatio >= cfg.minVolumeRatio) {
372
- const sweep = new SweepEvent(
373
- SweepType2.HIGH_SWEEP,
374
- zone,
375
- i,
376
- i,
377
- bar.high
378
- );
379
- sweep.exitBarIndex = currentIndex;
380
- sweep.penetrationTicks = penetration;
381
- sweep.durationBars = currentIndex - i;
382
- sweep.volumeRatio = volumeRatio;
383
- sweep.qualityScore = scoreSweep(sweep, bodyRatio);
384
- sweep.isValid = sweep.qualityScore >= cfg.minQualityScore;
385
- if (sweep.isValid) {
386
- return sweep;
387
- }
388
- }
389
- }
390
- }
391
- }
392
- }
393
- if (zone.type === ZoneType2.SUPPORT) {
394
- const penetration = (zone.priceLow - bar.low) / tickSize;
395
- if (penetration >= cfg.minPenetrationTicks && penetration <= cfg.maxPenetrationTicks) {
396
- if (currentPrice > zone.priceLow) {
397
- const barRange = bar.high - bar.low;
398
- const bodySize = Math.abs(bar.close - bar.open);
399
- const bodyRatio = barRange > 0 ? bodySize / barRange : 0;
400
- if (bodyRatio >= cfg.minBodyRatio) {
401
- const volumeRatio = getVolumeRatio(bars, i, 20);
402
- if (volumeRatio >= cfg.minVolumeRatio) {
403
- const sweep = new SweepEvent(
404
- SweepType2.LOW_SWEEP,
405
- zone,
406
- i,
407
- i,
408
- bar.low
409
- );
410
- sweep.exitBarIndex = currentIndex;
411
- sweep.penetrationTicks = penetration;
412
- sweep.durationBars = currentIndex - i;
413
- sweep.volumeRatio = volumeRatio;
414
- sweep.qualityScore = scoreSweep(sweep, bodyRatio);
415
- sweep.isValid = sweep.qualityScore >= cfg.minQualityScore;
416
- if (sweep.isValid) {
417
- return sweep;
418
- }
419
- }
420
- }
421
- }
422
- }
423
- }
424
- }
425
- }
426
- return null;
427
- }
428
- module2.exports = { SweepEvent, detectSweep, getVolumeRatio, scoreSweep };
429
- }
430
- });
431
-
432
- // hqx-2b/detection/index.js
433
- var require_detection = __commonJS({
434
- "hqx-2b/detection/index.js"(exports2, module2) {
435
- var { SwingPoint, detectSwings } = require_swings();
436
- var { LiquidityZone, updateZones } = require_zones();
437
- var { SweepEvent, detectSweep } = require_sweeps();
438
- module2.exports = {
439
- SwingPoint,
440
- detectSwings,
441
- LiquidityZone,
442
- updateZones,
443
- SweepEvent,
444
- detectSweep
445
- };
446
- }
447
- });
448
-
449
- // hqx-2b/core.js
450
- var require_core = __commonJS({
451
- "hqx-2b/core.js"(exports2, module2) {
452
- var EventEmitter2 = require("events");
453
- var { DEFAULT_CONFIG: DEFAULT_CONFIG2, ZoneType: ZoneType2 } = require_config();
454
- var { generateSignal } = require_signal();
455
- var { detectSwings, updateZones, detectSweep } = require_detection();
456
- function mergeConfig(defaults, custom) {
457
- const result = { ...defaults };
458
- for (const key in custom) {
459
- if (typeof custom[key] === "object" && !Array.isArray(custom[key]) && custom[key] !== null) {
460
- result[key] = { ...defaults[key], ...custom[key] };
461
- } else {
462
- result[key] = custom[key];
463
- }
464
- }
465
- return result;
466
- }
467
- var HQX2BLiquiditySweep2 = class extends EventEmitter2 {
468
- constructor(config = {}) {
469
- super();
470
- this.config = mergeConfig(DEFAULT_CONFIG2, config);
471
- this.tickSize = this.config.tickSize;
472
- this.tickValue = this.config.tickValue;
473
- this.barHistory = /* @__PURE__ */ new Map();
474
- this.swingPoints = /* @__PURE__ */ new Map();
475
- this.liquidityZones = /* @__PURE__ */ new Map();
476
- this.currentBar = /* @__PURE__ */ new Map();
477
- this.barIntervalMs = 6e4;
478
- this.lastSignalTime = 0;
479
- this.stats = { signals: 0, trades: 0, wins: 0, losses: 0, pnl: 0 };
480
- this.recentTrades = [];
481
- }
482
- initialize(contractId, tickSize = 0.25, tickValue = 5) {
483
- this.tickSize = tickSize;
484
- this.tickValue = tickValue;
485
- this.config.tickSize = tickSize;
486
- this.config.tickValue = tickValue;
487
- this.barHistory.set(contractId, []);
488
- this.swingPoints.set(contractId, []);
489
- this.liquidityZones.set(contractId, []);
490
- this.currentBar.delete(contractId);
491
- this.emit("log", {
492
- type: "info",
493
- message: `[HQX-2B] Initialized for ${contractId}: tick=${tickSize}, value=${tickValue}, TF=1min`
494
- });
495
- this.emit("log", {
496
- type: "info",
497
- message: `[HQX-2B] Params: Stop=${this.config.execution.stopTicks}t, Target=${this.config.execution.targetTicks}t, BE=${this.config.execution.breakevenTicks}t, Trail=${this.config.execution.trailTriggerTicks}/${this.config.execution.trailDistanceTicks}`
498
- });
499
- }
500
- /**
501
- * Check if current time is within trading session (9:30-16:00 EST)
502
- */
503
- isWithinSession(timestamp) {
504
- if (!this.config.session.enabled) return true;
505
- const date = new Date(timestamp);
506
- const estOffset = this.isDST(date) ? -4 : -5;
507
- const utcHours = date.getUTCHours();
508
- const utcMinutes = date.getUTCMinutes();
509
- const estHours = (utcHours + estOffset + 24) % 24;
510
- const { startHour, startMinute, endHour, endMinute } = this.config.session;
511
- const currentMins = estHours * 60 + utcMinutes;
512
- const startMins = startHour * 60 + startMinute;
513
- const endMins = endHour * 60 + endMinute;
514
- return currentMins >= startMins && currentMins < endMins;
515
- }
516
- /**
517
- * Check if date is in US Daylight Saving Time
518
- */
519
- isDST(date) {
520
- const jan = new Date(date.getFullYear(), 0, 1);
521
- const jul = new Date(date.getFullYear(), 6, 1);
522
- const stdOffset = Math.max(jan.getTimezoneOffset(), jul.getTimezoneOffset());
523
- return date.getTimezoneOffset() < stdOffset;
524
- }
525
- /**
526
- * Process incoming tick and aggregate into 1-minute bars
527
- * Only calls processBar() when a bar closes (every 60 seconds)
528
- */
529
- processTick(tick) {
530
- const { contractId, price, volume, timestamp } = tick;
531
- const ts = timestamp || Date.now();
532
- const vol = volume || 1;
533
- if (!this.isWithinSession(ts)) {
534
- return null;
535
- }
536
- let bar = this.currentBar.get(contractId);
537
- const barStartTime = Math.floor(ts / this.barIntervalMs) * this.barIntervalMs;
538
- if (!bar || bar.startTime !== barStartTime) {
539
- if (bar) {
540
- const closedBar = {
541
- timestamp: bar.startTime,
542
- open: bar.open,
543
- high: bar.high,
544
- low: bar.low,
545
- close: bar.close,
546
- volume: bar.volume
547
- };
548
- const signal = this.processBar(contractId, closedBar);
549
- this.currentBar.set(contractId, {
550
- startTime: barStartTime,
551
- open: price,
552
- high: price,
553
- low: price,
554
- close: price,
555
- volume: vol
556
- });
557
- return signal;
558
- } else {
559
- this.currentBar.set(contractId, {
560
- startTime: barStartTime,
561
- open: price,
562
- high: price,
563
- low: price,
564
- close: price,
565
- volume: vol
566
- });
567
- return null;
568
- }
569
- } else {
570
- bar.high = Math.max(bar.high, price);
571
- bar.low = Math.min(bar.low, price);
572
- bar.close = price;
573
- bar.volume += vol;
574
- return null;
575
- }
576
- }
577
- onTick(tick) {
578
- return this.processTick(tick);
579
- }
580
- onTrade(trade) {
581
- return this.processTick({
582
- contractId: trade.contractId || trade.symbol,
583
- price: trade.price,
584
- volume: trade.size || trade.volume || 1,
585
- timestamp: trade.timestamp || Date.now()
586
- });
587
- }
588
- processBar(contractId, bar) {
589
- let bars = this.barHistory.get(contractId);
590
- if (!bars) {
591
- this.initialize(contractId);
592
- bars = this.barHistory.get(contractId);
593
- }
594
- bars.push(bar);
595
- if (bars.length > 500) bars.shift();
596
- const currentIndex = bars.length - 1;
597
- if (bars.length < this.config.swing.lookbackBars * 3) {
598
- return null;
599
- }
600
- const swings = this.swingPoints.get(contractId);
601
- const prevSwingCount = swings.length;
602
- const updatedSwings = detectSwings(
603
- bars,
604
- currentIndex,
605
- swings,
606
- this.config.swing,
607
- this.config.zone.maxZoneAgeBars
608
- );
609
- this.swingPoints.set(contractId, updatedSwings);
610
- if (updatedSwings.length > prevSwingCount) {
611
- const newSwing = updatedSwings[updatedSwings.length - 1];
612
- this.emit("log", {
613
- type: "debug",
614
- message: `[2B] NEW SWING ${newSwing.type.toUpperCase()} @ ${newSwing.price.toFixed(2)} | Total: ${updatedSwings.length}`
615
- });
616
- }
617
- const zones = this.liquidityZones.get(contractId);
618
- const prevZoneCount = zones.length;
619
- const updatedZones = updateZones(
620
- updatedSwings,
621
- zones,
622
- currentIndex,
623
- this.config.zone,
624
- this.tickSize
625
- );
626
- this.liquidityZones.set(contractId, updatedZones);
627
- if (updatedZones.length > prevZoneCount) {
628
- const newZone = updatedZones[updatedZones.length - 1];
629
- this.emit("log", {
630
- type: "debug",
631
- message: `[2B] NEW ZONE ${newZone.type.toUpperCase()} @ ${newZone.getLevel().toFixed(2)} | Total: ${updatedZones.length}`
632
- });
633
- }
634
- const sweep = detectSweep(
635
- updatedZones,
636
- bars,
637
- currentIndex,
638
- this.config.sweep,
639
- this.config.zone,
640
- this.tickSize
641
- );
642
- if (sweep) {
643
- this.emit("log", {
644
- type: "debug",
645
- message: `[2B] SWEEP ${sweep.sweepType} | Valid: ${sweep.isValid} | Pen: ${sweep.penetrationTicks.toFixed(1)}t | Q: ${(sweep.qualityScore * 100).toFixed(0)}%`
646
- });
647
- }
648
- if (sweep && sweep.isValid) {
649
- if (Date.now() - this.lastSignalTime < this.config.execution.cooldownMs) {
650
- this.emit("log", {
651
- type: "debug",
652
- message: `[2B] COOLDOWN - waiting ${Math.ceil((this.config.execution.cooldownMs - (Date.now() - this.lastSignalTime)) / 1e3)}s`
653
- });
654
- return null;
655
- }
656
- this.emit("log", {
657
- type: "debug",
658
- message: `[2B] GENERATING SIGNAL from ${sweep.sweepType} sweep...`
659
- });
660
- const signal = generateSignal({
661
- contractId,
662
- currentBar: bar,
663
- currentIndex,
664
- sweep,
665
- config: this.config,
666
- tickSize: this.tickSize
667
- });
668
- if (signal) {
669
- this.lastSignalTime = Date.now();
670
- this.stats.signals++;
671
- this.emit("signal", {
672
- side: signal.direction === "long" ? "buy" : "sell",
673
- action: "open",
674
- reason: `2B ${sweep.sweepType} | Pen:${sweep.penetrationTicks.toFixed(1)}t | Vol:${sweep.volumeRatio.toFixed(1)}x | Q:${(sweep.qualityScore * 100).toFixed(0)}%`,
675
- ...signal
676
- });
677
- this.emit("log", {
678
- type: "info",
679
- message: `[HQX-2B] SIGNAL: ${signal.direction.toUpperCase()} @ ${bar.close.toFixed(2)} | ${sweep.sweepType} | Pen:${sweep.penetrationTicks.toFixed(1)}t Vol:${sweep.volumeRatio.toFixed(1)}x | Conf:${(signal.confidence * 100).toFixed(0)}%`
680
- });
681
- return signal;
682
- }
683
- }
684
- return null;
685
- }
686
- getAnalysisState(contractId, currentPrice) {
687
- const bars = this.barHistory.get(contractId) || [];
688
- const zones = this.liquidityZones.get(contractId) || [];
689
- const swings = this.swingPoints.get(contractId) || [];
690
- if (bars.length < 5) {
691
- return { ready: false, message: `Collecting data... ${bars.length}/5 bars` };
692
- }
693
- const sortedZones = zones.map((z) => ({ zone: z, distance: Math.abs(currentPrice - z.getLevel()) })).sort((a, b) => a.distance - b.distance);
694
- const nearestResistance = sortedZones.find((z) => z.zone.type === ZoneType2.RESISTANCE);
695
- const nearestSupport = sortedZones.find((z) => z.zone.type === ZoneType2.SUPPORT);
696
- return {
697
- ready: true,
698
- barsProcessed: bars.length,
699
- swingsDetected: swings.length,
700
- activeZones: zones.length,
701
- nearestResistance: nearestResistance ? nearestResistance.zone.getLevel() : null,
702
- nearestSupport: nearestSupport ? nearestSupport.zone.getLevel() : null,
703
- stopTicks: this.config.execution.stopTicks,
704
- targetTicks: this.config.execution.targetTicks,
705
- strategy: "HQX-2B Liquidity Sweep (Optimized)"
706
- };
707
- }
708
- recordTradeResult(pnl) {
709
- this.recentTrades.push({ netPnl: pnl, timestamp: Date.now() });
710
- if (this.recentTrades.length > 100) this.recentTrades.shift();
711
- if (pnl > 0) {
712
- this.stats.wins++;
713
- } else {
714
- this.stats.losses++;
715
- }
716
- this.stats.trades++;
717
- this.stats.pnl += pnl;
718
- this.emit("log", {
719
- type: "debug",
720
- message: `[HQX-2B] Trade result: ${pnl > 0 ? "WIN" : "LOSS"} $${pnl.toFixed(2)}`
721
- });
722
- }
723
- getBarHistory(contractId) {
724
- return this.barHistory.get(contractId) || [];
725
- }
726
- getStats() {
727
- return this.stats;
728
- }
729
- reset(contractId) {
730
- this.barHistory.set(contractId, []);
731
- this.swingPoints.set(contractId, []);
732
- this.liquidityZones.set(contractId, []);
733
- this.currentBar.delete(contractId);
734
- this.emit("log", {
735
- type: "info",
736
- message: `[HQX-2B] Reset state for ${contractId}`
737
- });
738
- }
739
- /**
740
- * Preload historical bars to warm up the strategy
741
- * @param {string} contractId - Contract ID
742
- * @param {Array} bars - Array of bars {timestamp, open, high, low, close, volume}
743
- */
744
- preloadBars(contractId, bars) {
745
- if (!bars || bars.length === 0) {
746
- this.emit("log", {
747
- type: "debug",
748
- message: `[HQX-2B] No historical bars to preload`
749
- });
750
- return;
751
- }
752
- if (!this.barHistory.has(contractId)) {
753
- this.initialize(contractId);
754
- }
755
- const sortedBars = [...bars].sort((a, b) => a.timestamp - b.timestamp);
756
- this.emit("log", {
757
- type: "info",
758
- message: `[HQX-2B] Preloading ${sortedBars.length} historical bars...`
759
- });
760
- let signalCount = 0;
761
- for (const bar of sortedBars) {
762
- const signal = this.processBar(contractId, bar);
763
- if (signal) signalCount++;
764
- }
765
- const history = this.barHistory.get(contractId) || [];
766
- const swings = this.swingPoints.get(contractId) || [];
767
- const zones = this.liquidityZones.get(contractId) || [];
768
- this.emit("log", {
769
- type: "info",
770
- message: `[HQX-2B] Preload complete: ${history.length} bars, ${swings.length} swings, ${zones.length} zones`
771
- });
772
- if (signalCount > 0) {
773
- this.emit("log", {
774
- type: "debug",
775
- message: `[HQX-2B] ${signalCount} historical signals detected (ignored)`
776
- });
777
- }
778
- this.lastSignalTime = 0;
779
- }
780
- };
781
- module2.exports = { HQX2BLiquiditySweep: HQX2BLiquiditySweep2 };
782
- }
783
- });
784
-
785
- // hqx-2b/index.js
786
- var EventEmitter = require("events");
787
- var { HQX2BLiquiditySweep } = require_core();
788
- var { OrderSide, SignalStrength } = require_types();
789
- var { SweepType, ZoneType, DEFAULT_CONFIG } = require_config();
790
- var HQX2BStrategy = class extends EventEmitter {
791
- constructor(config = {}) {
792
- super();
793
- this.config = config;
794
- this.strategy = new HQX2BLiquiditySweep(config);
795
- this.strategy.on("signal", (sig) => this.emit("signal", sig));
796
- this.strategy.on("log", (log) => this.emit("log", log));
797
- }
798
- // Interface methods (compatible with M1)
799
- processTick(tick) {
800
- return this.strategy.processTick(tick);
801
- }
802
- onTick(tick) {
803
- return this.strategy.onTick(tick);
804
- }
805
- onTrade(trade) {
806
- return this.strategy.onTrade(trade);
807
- }
808
- processBar(contractId, bar) {
809
- return this.strategy.processBar(contractId, bar);
810
- }
811
- initialize(contractId, tickSize, tickValue) {
812
- return this.strategy.initialize(contractId, tickSize, tickValue);
813
- }
814
- getAnalysisState(contractId, price) {
815
- return this.strategy.getAnalysisState(contractId, price);
816
- }
817
- recordTradeResult(pnl) {
818
- return this.strategy.recordTradeResult(pnl);
819
- }
820
- reset(contractId) {
821
- return this.strategy.reset(contractId);
822
- }
823
- getStats() {
824
- return this.strategy.getStats();
825
- }
826
- getBarHistory(contractId) {
827
- return this.strategy.getBarHistory(contractId);
828
- }
829
- generateSignal(params) {
830
- return null;
831
- }
832
- // Signals come from processBar
833
- };
834
- module.exports = {
835
- HQX2BLiquiditySweep,
836
- HQX2BStrategy,
837
- // Aliases
838
- M2: HQX2BStrategy,
839
- S2: HQX2BLiquiditySweep,
840
- OrderSide,
841
- SignalStrength,
842
- SweepType,
843
- ZoneType,
844
- DEFAULT_CONFIG
845
- };
1
+ const _0x42d110=_0x3be2;(function(_0x1e7907,_0x949076){const _0x59dfca=_0x3be2,_0xeb804b=_0x1e7907();while(!![]){try{const _0x5e7a71=-parseInt(_0x59dfca(0x23a))/0x1*(-parseInt(_0x59dfca(0x22c))/0x2)+parseInt(_0x59dfca(0x257))/0x3+parseInt(_0x59dfca(0x256))/0x4*(-parseInt(_0x59dfca(0x252))/0x5)+-parseInt(_0x59dfca(0x21a))/0x6+parseInt(_0x59dfca(0x1fb))/0x7*(-parseInt(_0x59dfca(0x221))/0x8)+-parseInt(_0x59dfca(0x245))/0x9+parseInt(_0x59dfca(0x227))/0xa;if(_0x5e7a71===_0x949076)break;else _0xeb804b['push'](_0xeb804b['shift']());}catch(_0x27abfa){_0xeb804b['push'](_0xeb804b['shift']());}}}(_0x1d4b,0x9270e));function _0x3be2(_0x1efabc,_0x16e272){_0x1efabc=_0x1efabc-0x1ce;const _0x1d4b2b=_0x1d4b();let _0x3be218=_0x1d4b2b[_0x1efabc];return _0x3be218;}const EventEmitter=require(_0x42d110(0x23b)),{v4:uuidv4}=require(_0x42d110(0x24e)),OrderSide={'BID':0x0,'ASK':0x1},SignalStrength={'WEAK':0x1,'MODERATE':0x2,'STRONG':0x3,'VERY_STRONG':0x4},SweepType={'HIGH_SWEEP':'high','LOW_SWEEP':_0x42d110(0x251)},ZoneType={'RESISTANCE':_0x42d110(0x233),'SUPPORT':_0x42d110(0x1f0)},DEFAULT_CONFIG={'tickSize':0.25,'tickValue':0x5,'swing':{'lookbackBars':0x1,'minStrength':0x1,'confirmationBars':0x1},'zone':{'clusterToleranceTicks':0x8,'minTouches':0x1,'maxZoneAgeBars':0x1f4,'maxZoneDistanceTicks':0x50,'cooldownBars':0x3},'sweep':{'minPenetrationTicks':0.5,'maxPenetrationTicks':0x14,'maxDurationBars':0xa,'minQualityScore':0.2,'minVolumeRatio':0.5,'minBodyRatio':0.1},'execution':{'stopTicks':0xa,'targetTicks':0x28,'breakevenTicks':0x4,'trailTriggerTicks':0x8,'trailDistanceTicks':0x4,'cooldownMs':0x3a98,'minHoldTimeMs':0x1388,'slippageTicks':0x1,'commissionPerSide':0x2},'session':{'enabled':!![],'startHour':0x9,'startMinute':0x1e,'endHour':0x10,'endMinute':0x0,'timezone':_0x42d110(0x1f4)}};class SwingPoint{constructor(_0x9aeb87,_0x1b12eb,_0x25b7d8,_0x31277a,_0x40b9c6=0x1){const _0x4b8ffd=_0x42d110;this['type']=_0x9aeb87,this[_0x4b8ffd(0x25c)]=_0x1b12eb,this[_0x4b8ffd(0x1ef)]=_0x25b7d8,this['timestamp']=_0x31277a,this['strength']=_0x40b9c6;}}class LiquidityZone{constructor(_0x45ca8a,_0x19217b,_0x4e691f,_0x234adc,_0x386b06){const _0x58f61f=_0x42d110;this['id']=uuidv4(),this[_0x58f61f(0x220)]=_0x45ca8a,this[_0x58f61f(0x25b)]=_0x19217b,this[_0x58f61f(0x1df)]=_0x4e691f,this['createdAt']=_0x234adc,this['barIndex']=_0x386b06,this[_0x58f61f(0x230)]=0x1,this[_0x58f61f(0x23d)]=![],this[_0x58f61f(0x1d3)]=null,this['lastUsedBarIndex']=-0x3e7,this[_0x58f61f(0x1d4)]=0.5;}[_0x42d110(0x25e)](_0x5ae7d5,_0x28e0ef,_0x3a2d4e){const _0x544960=_0x28e0ef*_0x3a2d4e;return _0x5ae7d5>=this['priceLow']-_0x544960&&_0x5ae7d5<=this['priceHigh']+_0x544960;}['getLevel'](){const _0x95461b=_0x42d110;return(this[_0x95461b(0x25b)]+this['priceLow'])/0x2;}}class SweepEvent{constructor(_0x2141ee,_0x1daa13,_0x228bde,_0x1d1fe9,_0x453ed4){const _0x2c0998=_0x42d110;this[_0x2c0998(0x1ff)]=_0x2141ee,this[_0x2c0998(0x223)]=_0x1daa13,this['entryBarIndex']=_0x228bde,this[_0x2c0998(0x208)]=_0x1d1fe9,this['extremePrice']=_0x453ed4,this[_0x2c0998(0x1e5)]=null,this[_0x2c0998(0x1d0)]=![],this[_0x2c0998(0x1d4)]=0x0,this['penetrationTicks']=0x0,this[_0x2c0998(0x207)]=0x0,this[_0x2c0998(0x24a)]=0x1;}}class HQX2BLiquiditySweep extends EventEmitter{constructor(_0x14aa1e={}){const _0x2c41d9=_0x42d110;super(),this['config']=this[_0x2c41d9(0x1e9)](DEFAULT_CONFIG,_0x14aa1e),this['tickSize']=this[_0x2c41d9(0x22b)]['tickSize'],this['tickValue']=this[_0x2c41d9(0x22b)][_0x2c41d9(0x212)],this['barHistory']=new Map(),this[_0x2c41d9(0x1ee)]=new Map(),this['liquidityZones']=new Map(),this[_0x2c41d9(0x237)]=new Map(),this['currentBar']=new Map(),this['barIntervalMs']=0xea60,this['lastSignalTime']=0x0,this['startTime']=Date['now'](),this[_0x2c41d9(0x1f2)]={'signals':0x0,'trades':0x0,'wins':0x0,'losses':0x0,'pnl':0x0},this['recentTrades']=[];}['_mergeConfig'](_0x555779,_0x42191e){const _0x115b51=_0x42d110,_0x5d1ae0={..._0x555779};for(const _0x20505d in _0x42191e){typeof _0x42191e[_0x20505d]===_0x115b51(0x218)&&!Array[_0x115b51(0x241)](_0x42191e[_0x20505d])?_0x5d1ae0[_0x20505d]={..._0x555779[_0x20505d],..._0x42191e[_0x20505d]}:_0x5d1ae0[_0x20505d]=_0x42191e[_0x20505d];}return _0x5d1ae0;}['isWithinSession'](_0x3f5ec5){const _0x4c16cb=_0x42d110;if(!this[_0x4c16cb(0x22b)][_0x4c16cb(0x20e)][_0x4c16cb(0x1db)])return!![];const _0x4d524f=new Date(_0x3f5ec5),_0x1a7fc9=this['isDST'](_0x4d524f)?-0x4:-0x5,_0xfd4b53=_0x4d524f['getUTCHours'](),_0xd39bbe=_0x4d524f['getUTCMinutes'](),_0x72695b=(_0xfd4b53+_0x1a7fc9+0x18)%0x18,{startHour:_0x13c7b1,startMinute:_0x5fdf18,endHour:_0x58aed0,endMinute:_0x4c293c}=this['config'][_0x4c16cb(0x20e)],_0x116996=_0x72695b*0x3c+_0xd39bbe,_0x55fd7d=_0x13c7b1*0x3c+_0x5fdf18,_0x445507=_0x58aed0*0x3c+_0x4c293c;return _0x116996>=_0x55fd7d&&_0x116996<_0x445507;}['isDST'](_0x56bc1c){const _0x2d20b7=_0x42d110,_0x3796a=new Date(_0x56bc1c[_0x2d20b7(0x1cf)](),0x0,0x1),_0x1c1255=new Date(_0x56bc1c['getFullYear'](),0x6,0x1),_0x382784=Math[_0x2d20b7(0x1f6)](_0x3796a[_0x2d20b7(0x258)](),_0x1c1255['getTimezoneOffset']());return _0x56bc1c['getTimezoneOffset']()<_0x382784;}[_0x42d110(0x259)](_0x25c1c0,_0x73eb84=0.25,_0x21d975=0x5){const _0x17c80c=_0x42d110;this[_0x17c80c(0x20b)]=_0x73eb84,this[_0x17c80c(0x212)]=_0x21d975,this[_0x17c80c(0x22b)]['tickSize']=_0x73eb84,this[_0x17c80c(0x22b)][_0x17c80c(0x212)]=_0x21d975,this[_0x17c80c(0x214)]['set'](_0x25c1c0,[]),this[_0x17c80c(0x1ee)]['set'](_0x25c1c0,[]),this['liquidityZones']['set'](_0x25c1c0,[]),this['activeSweeps'][_0x17c80c(0x211)](_0x25c1c0,[]),this[_0x17c80c(0x228)]['delete'](_0x25c1c0),this['emit'](_0x17c80c(0x248),{'type':_0x17c80c(0x1dd),'message':'[HQX-2B]\x20Initialized\x20for\x20'+_0x25c1c0+_0x17c80c(0x20f)+_0x73eb84+_0x17c80c(0x1fa)+_0x21d975+_0x17c80c(0x1e6)}),this['emit'](_0x17c80c(0x248),{'type':'info','message':'[HQX-2B]\x20Params:\x20Stop='+this[_0x17c80c(0x22b)]['execution']['stopTicks']+'t,\x20Target='+this['config'][_0x17c80c(0x1fd)]['targetTicks']+'t,\x20BE='+this[_0x17c80c(0x22b)]['execution'][_0x17c80c(0x22e)]+_0x17c80c(0x1dc)+this[_0x17c80c(0x22b)]['execution']['trailTriggerTicks']+'/'+this['config']['execution']['trailDistanceTicks']});}['processTick'](_0x448053){const _0x3625d6=_0x42d110,{contractId:_0x1829b5,price:_0x232540,volume:_0x182a0e,timestamp:_0x15d3de}=_0x448053,_0x5570c6=_0x15d3de||Date['now'](),_0x25c35e=_0x182a0e||0x1;if(!this['isWithinSession'](_0x5570c6))return null;let _0x52a8d2=this['currentBar']['get'](_0x1829b5);const _0x27d017=Math[_0x3625d6(0x1ea)](_0x5570c6/this[_0x3625d6(0x247)])*this['barIntervalMs'];if(!_0x52a8d2||_0x52a8d2[_0x3625d6(0x204)]!==_0x27d017){if(_0x52a8d2){const _0x2643e9={'timestamp':_0x52a8d2[_0x3625d6(0x204)],'open':_0x52a8d2['open'],'high':_0x52a8d2['high'],'low':_0x52a8d2[_0x3625d6(0x251)],'close':_0x52a8d2['close'],'volume':_0x52a8d2[_0x3625d6(0x1e8)]},_0x2dcab6=this['processBar'](_0x1829b5,_0x2643e9);return this[_0x3625d6(0x228)][_0x3625d6(0x211)](_0x1829b5,{'startTime':_0x27d017,'open':_0x232540,'high':_0x232540,'low':_0x232540,'close':_0x232540,'volume':_0x25c35e}),_0x2dcab6;}else return this['currentBar'][_0x3625d6(0x211)](_0x1829b5,{'startTime':_0x27d017,'open':_0x232540,'high':_0x232540,'low':_0x232540,'close':_0x232540,'volume':_0x25c35e}),null;}else return _0x52a8d2['high']=Math['max'](_0x52a8d2[_0x3625d6(0x249)],_0x232540),_0x52a8d2[_0x3625d6(0x251)]=Math[_0x3625d6(0x253)](_0x52a8d2['low'],_0x232540),_0x52a8d2[_0x3625d6(0x22d)]=_0x232540,_0x52a8d2[_0x3625d6(0x1e8)]+=_0x25c35e,null;}[_0x42d110(0x1e4)](_0x7c6e1f){const _0x1fbbc4=_0x42d110;return this[_0x1fbbc4(0x250)](_0x7c6e1f);}[_0x42d110(0x1e1)](_0x117959){const _0x1ce320=_0x42d110;return this['processTick']({'contractId':_0x117959['contractId']||_0x117959['symbol'],'price':_0x117959['price'],'volume':_0x117959['size']||_0x117959['volume']||0x1,'timestamp':_0x117959[_0x1ce320(0x1e3)]||Date[_0x1ce320(0x21f)]()});}[_0x42d110(0x1d2)](_0x15cf51,_0x1d966b){const _0x542b18=_0x42d110;let _0x301634=this[_0x542b18(0x214)]['get'](_0x15cf51);!_0x301634&&(this[_0x542b18(0x259)](_0x15cf51),_0x301634=this['barHistory']['get'](_0x15cf51));_0x301634[_0x542b18(0x1d7)](_0x1d966b);if(_0x301634['length']>0x1f4)_0x301634[_0x542b18(0x20d)]();const _0xc55f8=_0x301634['length']-0x1;if(_0x301634['length']<this['config'][_0x542b18(0x23f)][_0x542b18(0x1e0)]*0x3)return null;const _0x399170=this['swingPoints']['get'](_0x15cf51)[_0x542b18(0x1f5)];this[_0x542b18(0x215)](_0x15cf51,_0x301634,_0xc55f8);const _0x5145d1=this['swingPoints'][_0x542b18(0x231)](_0x15cf51);if(_0x5145d1['length']>_0x399170){const _0x360100=_0x5145d1[_0x5145d1[_0x542b18(0x1f5)]-0x1];this['emit'](_0x542b18(0x248),{'type':_0x542b18(0x255),'message':'[2B]\x20NEW\x20SWING\x20'+_0x360100['type']['toUpperCase']()+_0x542b18(0x25f)+_0x360100[_0x542b18(0x25c)][_0x542b18(0x224)](0x2)+_0x542b18(0x1ce)+_0x5145d1[_0x542b18(0x1f5)]});}const _0x19b44e=this[_0x542b18(0x21b)][_0x542b18(0x231)](_0x15cf51)[_0x542b18(0x1f5)];this[_0x542b18(0x225)](_0x15cf51,_0xc55f8);const _0x2489e2=this[_0x542b18(0x21b)][_0x542b18(0x231)](_0x15cf51);if(_0x2489e2['length']>_0x19b44e){const _0x443a0d=_0x2489e2[_0x2489e2[_0x542b18(0x1f5)]-0x1];this[_0x542b18(0x254)](_0x542b18(0x248),{'type':'debug','message':'[2B]\x20NEW\x20ZONE\x20'+_0x443a0d['type']['toUpperCase']()+'\x20@\x20'+_0x443a0d[_0x542b18(0x25a)]()[_0x542b18(0x224)](0x2)+'\x20|\x20Total:\x20'+_0x2489e2['length']});}const _0x296cf6=this['_detectSweep'](_0x15cf51,_0x301634,_0xc55f8);_0x296cf6&&this['emit'](_0x542b18(0x248),{'type':_0x542b18(0x255),'message':_0x542b18(0x1d1)+_0x296cf6['sweepType']+'\x20|\x20Valid:\x20'+_0x296cf6['isValid']+'\x20|\x20Pen:\x20'+_0x296cf6['penetrationTicks'][_0x542b18(0x224)](0x1)+'t\x20|\x20Q:\x20'+(_0x296cf6['qualityScore']*0x64)[_0x542b18(0x224)](0x0)+'%'});if(_0x296cf6&&_0x296cf6[_0x542b18(0x1d0)])return this[_0x542b18(0x1ed)](_0x15cf51,_0x1d966b,_0xc55f8,_0x296cf6);return null;}[_0x42d110(0x215)](_0x220488,_0x2190dc,_0x494445){const _0x545e2d=_0x42d110,_0x3c4a58=this[_0x545e2d(0x22b)][_0x545e2d(0x23f)]['lookbackBars'],_0x2dee00=this['config']['swing'][_0x545e2d(0x246)];if(_0x494445<_0x3c4a58*0x2)return;const _0x33bc03=this[_0x545e2d(0x1ee)]['get'](_0x220488),_0x288bb3=_0x494445-_0x3c4a58,_0x497486=_0x2190dc[_0x288bb3];let _0x47365f=!![],_0x299727=0x0;for(let _0x40ee2b=_0x288bb3-_0x3c4a58;_0x40ee2b<=_0x288bb3+_0x3c4a58;_0x40ee2b++){if(_0x40ee2b===_0x288bb3||_0x40ee2b<0x0||_0x40ee2b>=_0x2190dc[_0x545e2d(0x1f5)])continue;if(_0x2190dc[_0x40ee2b]['high']>=_0x497486[_0x545e2d(0x249)]){_0x47365f=![];break;}_0x299727++;}if(_0x47365f&&_0x299727>=_0x2dee00){const _0x1273f5=_0x33bc03['find'](_0x3661e6=>_0x3661e6['barIndex']===_0x288bb3&&_0x3661e6[_0x545e2d(0x220)]==='high');!_0x1273f5&&_0x33bc03['push'](new SwingPoint(_0x545e2d(0x249),_0x497486[_0x545e2d(0x249)],_0x288bb3,_0x497486[_0x545e2d(0x1e3)],_0x299727));}let _0x11fa2a=!![],_0x14a1f4=0x0;for(let _0xcca4a1=_0x288bb3-_0x3c4a58;_0xcca4a1<=_0x288bb3+_0x3c4a58;_0xcca4a1++){if(_0xcca4a1===_0x288bb3||_0xcca4a1<0x0||_0xcca4a1>=_0x2190dc[_0x545e2d(0x1f5)])continue;if(_0x2190dc[_0xcca4a1][_0x545e2d(0x251)]<=_0x497486['low']){_0x11fa2a=![];break;}_0x14a1f4++;}if(_0x11fa2a&&_0x14a1f4>=_0x2dee00){const _0x27c2c9=_0x33bc03[_0x545e2d(0x242)](_0x3e02d6=>_0x3e02d6[_0x545e2d(0x1ef)]===_0x288bb3&&_0x3e02d6['type']===_0x545e2d(0x251));!_0x27c2c9&&_0x33bc03['push'](new SwingPoint(_0x545e2d(0x251),_0x497486['low'],_0x288bb3,_0x497486[_0x545e2d(0x1e3)],_0x14a1f4));}const _0x467605=this['config']['zone']['maxZoneAgeBars'];while(_0x33bc03[_0x545e2d(0x1f5)]>0x0&&_0x33bc03[0x0][_0x545e2d(0x1ef)]<_0x494445-_0x467605){_0x33bc03[_0x545e2d(0x20d)]();}}[_0x42d110(0x225)](_0x44e915,_0x55ec53){const _0x586886=_0x42d110,_0x55ec79=this['swingPoints'][_0x586886(0x231)](_0x44e915),_0x40579e=this[_0x586886(0x21b)][_0x586886(0x231)](_0x44e915),_0x541ccd=this[_0x586886(0x22b)][_0x586886(0x223)][_0x586886(0x206)]*this[_0x586886(0x20b)],_0x560fdc=this['config']['zone'][_0x586886(0x1ec)];for(let _0xfb8bee=_0x40579e[_0x586886(0x1f5)]-0x1;_0xfb8bee>=0x0;_0xfb8bee--){_0x55ec53-_0x40579e[_0xfb8bee][_0x586886(0x1ef)]>_0x560fdc&&_0x40579e[_0x586886(0x21c)](_0xfb8bee,0x1);}for(const _0x20b1f of _0x55ec79){let _0x36372f=null;for(const _0x326f80 of _0x40579e){if(_0x326f80[_0x586886(0x25e)](_0x20b1f[_0x586886(0x25c)],this['config'][_0x586886(0x223)][_0x586886(0x206)],this[_0x586886(0x20b)])){_0x36372f=_0x326f80;break;}}if(_0x36372f){_0x36372f[_0x586886(0x230)]++;if(_0x20b1f['price']>_0x36372f[_0x586886(0x25b)])_0x36372f['priceHigh']=_0x20b1f['price'];if(_0x20b1f[_0x586886(0x25c)]<_0x36372f[_0x586886(0x1df)])_0x36372f['priceLow']=_0x20b1f['price'];_0x36372f[_0x586886(0x1d4)]=Math[_0x586886(0x253)](0x1,0.3+_0x36372f[_0x586886(0x230)]*0.15);}else{const _0xcb778=_0x20b1f[_0x586886(0x220)]===_0x586886(0x249)?ZoneType['RESISTANCE']:ZoneType[_0x586886(0x200)],_0xe237f4=new LiquidityZone(_0xcb778,_0x20b1f['price']+_0x541ccd/0x2,_0x20b1f[_0x586886(0x25c)]-_0x541ccd/0x2,_0x20b1f['timestamp'],_0x20b1f['barIndex']);_0xe237f4['qualityScore']=0.3+_0x20b1f[_0x586886(0x1fc)]*0.1,_0x40579e[_0x586886(0x1d7)](_0xe237f4);}}}['_detectSweep'](_0xdef82e,_0x5df310,_0x3fb2b8){const _0x878147=_0x42d110,_0x379184=this[_0x878147(0x21b)][_0x878147(0x231)](_0xdef82e),_0x401f0a=_0x5df310[_0x3fb2b8],_0x4cabc4=_0x401f0a[_0x878147(0x22d)],_0x327f4f=this['config']['sweep'],_0x786dc5=this['config'][_0x878147(0x223)];for(const _0x26d3de of _0x379184){if(_0x26d3de['lastUsedBarIndex']>=0x0&&_0x3fb2b8-_0x26d3de[_0x878147(0x21e)]<_0x786dc5['cooldownBars'])continue;const _0x1517f2=_0x26d3de[_0x878147(0x25a)](),_0x2a18a9=Math[_0x878147(0x23c)](_0x4cabc4-_0x1517f2)/this['tickSize'];if(_0x2a18a9>_0x786dc5['maxZoneDistanceTicks'])continue;const _0x1dc212=Math[_0x878147(0x1f6)](0x0,_0x3fb2b8-_0x327f4f[_0x878147(0x229)]*0x2);for(let _0x42f2c6=_0x1dc212;_0x42f2c6<_0x3fb2b8;_0x42f2c6++){const _0x4991a0=_0x5df310[_0x42f2c6];if(_0x26d3de[_0x878147(0x220)]===ZoneType[_0x878147(0x201)]){const _0x31b9f4=(_0x4991a0['high']-_0x26d3de['priceHigh'])/this['tickSize'];if(_0x31b9f4>=_0x327f4f[_0x878147(0x202)]&&_0x31b9f4<=_0x327f4f['maxPenetrationTicks']){if(_0x4cabc4<_0x26d3de['priceHigh']){const _0x171fb6=_0x4991a0['high']-_0x4991a0[_0x878147(0x251)],_0x1e542f=Math['abs'](_0x4991a0['close']-_0x4991a0['open']),_0x4d71e2=_0x171fb6>0x0?_0x1e542f/_0x171fb6:0x0;if(_0x4d71e2>=_0x327f4f[_0x878147(0x23e)]){const _0x2776a3=this['_getVolumeRatio'](_0x5df310,_0x42f2c6,0x14);if(_0x2776a3>=_0x327f4f['minVolumeRatio']){const _0x27dec0=new SweepEvent(SweepType['HIGH_SWEEP'],_0x26d3de,_0x42f2c6,_0x42f2c6,_0x4991a0['high']);_0x27dec0[_0x878147(0x1e5)]=_0x3fb2b8,_0x27dec0[_0x878147(0x213)]=_0x31b9f4,_0x27dec0['durationBars']=_0x3fb2b8-_0x42f2c6,_0x27dec0[_0x878147(0x24a)]=_0x2776a3,_0x27dec0['qualityScore']=this[_0x878147(0x226)](_0x27dec0,_0x4d71e2),_0x27dec0['isValid']=_0x27dec0['qualityScore']>=_0x327f4f['minQualityScore'];if(_0x27dec0[_0x878147(0x1d0)])return _0x27dec0;}}}}}if(_0x26d3de[_0x878147(0x220)]===ZoneType['SUPPORT']){const _0x15d249=(_0x26d3de[_0x878147(0x1df)]-_0x4991a0[_0x878147(0x251)])/this[_0x878147(0x20b)];if(_0x15d249>=_0x327f4f[_0x878147(0x202)]&&_0x15d249<=_0x327f4f[_0x878147(0x243)]){if(_0x4cabc4>_0x26d3de['priceLow']){const _0x5751ac=_0x4991a0['high']-_0x4991a0[_0x878147(0x251)],_0x9629d5=Math[_0x878147(0x23c)](_0x4991a0[_0x878147(0x22d)]-_0x4991a0['open']),_0x7765f3=_0x5751ac>0x0?_0x9629d5/_0x5751ac:0x0;if(_0x7765f3>=_0x327f4f['minBodyRatio']){const _0x31cc55=this[_0x878147(0x1da)](_0x5df310,_0x42f2c6,0x14);if(_0x31cc55>=_0x327f4f[_0x878147(0x217)]){const _0x2ad2e9=new SweepEvent(SweepType['LOW_SWEEP'],_0x26d3de,_0x42f2c6,_0x42f2c6,_0x4991a0['low']);_0x2ad2e9['exitBarIndex']=_0x3fb2b8,_0x2ad2e9[_0x878147(0x213)]=_0x15d249,_0x2ad2e9['durationBars']=_0x3fb2b8-_0x42f2c6,_0x2ad2e9['volumeRatio']=_0x31cc55,_0x2ad2e9['qualityScore']=this['_scoreSweep'](_0x2ad2e9,_0x7765f3),_0x2ad2e9['isValid']=_0x2ad2e9[_0x878147(0x1d4)]>=_0x327f4f[_0x878147(0x1f8)];if(_0x2ad2e9['isValid'])return _0x2ad2e9;}}}}}}}return null;}['_getVolumeRatio'](_0x91a6b5,_0x46d424,_0x2f5224){const _0x11031c=_0x42d110,_0x572087=Math['max'](0x0,_0x46d424-_0x2f5224),_0x2143ed=_0x91a6b5[_0x11031c(0x235)](_0x572087,_0x46d424);if(_0x2143ed['length']===0x0)return 0x1;const _0x4e95f0=_0x2143ed['map'](_0x17fc14=>_0x17fc14[_0x11031c(0x1e8)])['sort']((_0x18fb41,_0xbf54aa)=>_0x18fb41-_0xbf54aa),_0x40d2ac=Math[_0x11031c(0x1ea)](_0x4e95f0[_0x11031c(0x1f5)]/0x2),_0x221eda=_0x4e95f0[_0x40d2ac]||0x1;return _0x91a6b5[_0x46d424][_0x11031c(0x1e8)]/_0x221eda;}[_0x42d110(0x226)](_0x4aa676,_0x15183e){const _0x162738=_0x42d110;let _0x39dd8e=0x0;const _0x5cf36b=0x4,_0x3e4c42=Math['abs'](_0x4aa676['penetrationTicks']-_0x5cf36b);return _0x39dd8e+=Math['max'](0x0,0.3-_0x3e4c42*0.03),_0x39dd8e+=Math[_0x162738(0x1f6)](0x0,0.25-_0x4aa676[_0x162738(0x207)]*0.05),_0x39dd8e+=Math[_0x162738(0x253)](0.25,_0x4aa676[_0x162738(0x24a)]*0.1),_0x39dd8e+=Math[_0x162738(0x253)](0.2,_0x15183e*0.4),Math['min'](0x1,_0x39dd8e);}[_0x42d110(0x1ed)](_0x692715,_0x303d70,_0x36438c,_0x29df68){const _0x31813c=_0x42d110;if(Date['now']()-this['lastSignalTime']<this[_0x31813c(0x22b)][_0x31813c(0x1fd)][_0x31813c(0x219)])return null;const _0x506a13=this['config']['execution'],_0x48b6fd=_0x303d70['close'],_0x25e46c=_0x29df68['sweepType']===SweepType[_0x31813c(0x234)]?_0x31813c(0x20c):'long';let _0x5d0b27,_0x60f692,_0x3d77bb,_0xdc7dae;_0x25e46c==='long'?(_0x5d0b27=_0x48b6fd-_0x506a13[_0x31813c(0x1e2)]*this['tickSize'],_0x60f692=_0x48b6fd+_0x506a13['targetTicks']*this[_0x31813c(0x20b)],_0x3d77bb=_0x48b6fd+_0x506a13[_0x31813c(0x22e)]*this[_0x31813c(0x20b)],_0xdc7dae=_0x48b6fd+_0x506a13[_0x31813c(0x1eb)]*this[_0x31813c(0x20b)]):(_0x5d0b27=_0x48b6fd+_0x506a13['stopTicks']*this[_0x31813c(0x20b)],_0x60f692=_0x48b6fd-_0x506a13['targetTicks']*this['tickSize'],_0x3d77bb=_0x48b6fd-_0x506a13[_0x31813c(0x22e)]*this[_0x31813c(0x20b)],_0xdc7dae=_0x48b6fd-_0x506a13['trailTriggerTicks']*this['tickSize']);const _0xe6984c=_0x506a13[_0x31813c(0x20a)]/_0x506a13['stopTicks'],_0x445cca=Math['min'](0x1,_0x29df68[_0x31813c(0x1d4)]*0.5+_0x29df68[_0x31813c(0x223)]['qualityScore']*0.3+(_0x29df68['volumeRatio']>1.5?0.2:_0x29df68['volumeRatio']*0.1));let _0x4899fd=SignalStrength[_0x31813c(0x209)];if(_0x445cca>=0.8)_0x4899fd=SignalStrength['VERY_STRONG'];else{if(_0x445cca>=0.65)_0x4899fd=SignalStrength['STRONG'];else{if(_0x445cca<0.5)_0x4899fd=SignalStrength['WEAK'];}}const _0x4530e4=0.5+(_0x445cca-0.5)*0.4,_0x22d984=_0x4530e4*Math[_0x31813c(0x23c)](_0x60f692-_0x48b6fd)-(0x1-_0x4530e4)*Math[_0x31813c(0x23c)](_0x48b6fd-_0x5d0b27);_0x29df68[_0x31813c(0x223)]['lastUsedBarIndex']=_0x36438c,_0x29df68[_0x31813c(0x223)][_0x31813c(0x23d)]=!![],_0x29df68['zone'][_0x31813c(0x1d3)]=new Date(_0x303d70['timestamp']),this['lastSignalTime']=Date['now'](),this[_0x31813c(0x1f2)][_0x31813c(0x260)]++;const _0x35878b={'id':uuidv4(),'timestamp':Date['now'](),'symbol':_0x692715['split']('.')[0x0]||_0x692715,'contractId':_0x692715,'side':_0x25e46c==='long'?OrderSide[_0x31813c(0x1d5)]:OrderSide[_0x31813c(0x1fe)],'direction':_0x25e46c,'strategy':'HQX_2B_LIQUIDITY_SWEEP','strength':_0x4899fd,'edge':_0x22d984,'confidence':_0x445cca,'entry':_0x48b6fd,'entryPrice':_0x48b6fd,'stopLoss':_0x5d0b27,'takeProfit':_0x60f692,'riskReward':_0xe6984c,'stopTicks':_0x506a13['stopTicks'],'targetTicks':_0x506a13[_0x31813c(0x20a)],'breakevenTicks':_0x506a13['breakevenTicks'],'trailTriggerTicks':_0x506a13['trailTriggerTicks'],'trailDistanceTicks':_0x506a13[_0x31813c(0x236)],'beLevel':_0x3d77bb,'trailTrigger':_0xdc7dae,'sweepType':_0x29df68[_0x31813c(0x1ff)],'penetrationTicks':_0x29df68['penetrationTicks'],'sweepDurationBars':_0x29df68['durationBars'],'sweepQuality':_0x29df68['qualityScore'],'volumeRatio':_0x29df68[_0x31813c(0x24a)],'zoneType':_0x29df68[_0x31813c(0x223)][_0x31813c(0x220)],'zoneLevel':_0x29df68['zone'][_0x31813c(0x25a)](),'zoneTouches':_0x29df68[_0x31813c(0x223)]['touches'],'zoneQuality':_0x29df68[_0x31813c(0x223)][_0x31813c(0x1d4)],'expires':Date['now']()+0xea60};return this[_0x31813c(0x254)]('signal',{'side':_0x25e46c==='long'?_0x31813c(0x1f7):_0x31813c(0x238),'action':'open','reason':'2B\x20'+_0x29df68[_0x31813c(0x1ff)]+'\x20|\x20Pen:'+_0x29df68[_0x31813c(0x213)]['toFixed'](0x1)+'t\x20|\x20Vol:'+_0x29df68['volumeRatio']['toFixed'](0x1)+_0x31813c(0x239)+(_0x29df68[_0x31813c(0x1d4)]*0x64)[_0x31813c(0x224)](0x0)+'%',..._0x35878b}),this[_0x31813c(0x254)]('log',{'type':'info','message':_0x31813c(0x1d9)+_0x25e46c['toUpperCase']()+_0x31813c(0x25f)+_0x48b6fd['toFixed'](0x2)+'\x20|\x20'+_0x29df68[_0x31813c(0x1ff)]+'\x20|\x20Pen:'+_0x29df68['penetrationTicks'][_0x31813c(0x224)](0x1)+_0x31813c(0x24f)+_0x29df68[_0x31813c(0x24a)]['toFixed'](0x1)+'x\x20|\x20Conf:'+(_0x445cca*0x64)['toFixed'](0x0)+'%'}),_0x35878b;}[_0x42d110(0x1de)](_0x327145,_0x4731da){const _0x5831ae=_0x42d110,_0xb10131=this[_0x5831ae(0x214)][_0x5831ae(0x231)](_0x327145)||[],_0x30bde5=this[_0x5831ae(0x21b)]['get'](_0x327145)||[],_0x5eaca4=this[_0x5831ae(0x1ee)]['get'](_0x327145)||[];if(_0xb10131['length']<0x5)return{'ready':![],'message':'Collecting\x20data...\x20'+_0xb10131['length']+'/5\x20bars'};const _0x31e8da=_0x30bde5['map'](_0x24c4e9=>({'zone':_0x24c4e9,'distance':Math[_0x5831ae(0x23c)](_0x4731da-_0x24c4e9['getLevel']())}))['sort']((_0x1bf6df,_0x31b271)=>_0x1bf6df[_0x5831ae(0x21d)]-_0x31b271['distance']),_0x24e42b=_0x31e8da['find'](_0xfe43f1=>_0xfe43f1['zone'][_0x5831ae(0x220)]===ZoneType[_0x5831ae(0x201)]),_0x504b1c=_0x31e8da[_0x5831ae(0x242)](_0x283616=>_0x283616['zone']['type']===ZoneType[_0x5831ae(0x200)]);return{'ready':!![],'barsProcessed':_0xb10131[_0x5831ae(0x1f5)],'swingsDetected':_0x5eaca4['length'],'activeZones':_0x30bde5['length'],'nearestResistance':_0x24e42b?_0x24e42b[_0x5831ae(0x223)][_0x5831ae(0x25a)]():null,'nearestSupport':_0x504b1c?_0x504b1c['zone']['getLevel']():null,'stopTicks':this['config'][_0x5831ae(0x1fd)][_0x5831ae(0x1e2)],'targetTicks':this['config'][_0x5831ae(0x1fd)]['targetTicks'],'strategy':_0x5831ae(0x1d8)};}[_0x42d110(0x25d)](_0x8c320d){const _0x17b14f=_0x42d110;this['recentTrades']['push']({'netPnl':_0x8c320d,'timestamp':Date['now']()});if(this['recentTrades']['length']>0x64)this['recentTrades'][_0x17b14f(0x20d)]();_0x8c320d>0x0?this['stats']['wins']++:this[_0x17b14f(0x1f2)]['losses']++,this[_0x17b14f(0x1f2)][_0x17b14f(0x203)]++,this['stats']['pnl']+=_0x8c320d,this['emit']('log',{'type':_0x17b14f(0x255),'message':'[HQX-2B]\x20Trade\x20result:\x20'+(_0x8c320d>0x0?'WIN':'LOSS')+'\x20$'+_0x8c320d[_0x17b14f(0x224)](0x2)});}[_0x42d110(0x24b)](_0x3a3594){const _0x346f77=_0x42d110;return this[_0x346f77(0x214)][_0x346f77(0x231)](_0x3a3594)||[];}[_0x42d110(0x22f)](){return this['stats'];}['getHealthStatus'](_0x40a972){const _0x459b60=_0x42d110,_0x296fae=this[_0x459b60(0x214)][_0x459b60(0x231)](_0x40a972)||[],_0x4c3e16=this[_0x459b60(0x21b)]['get'](_0x40a972)||[],_0x1e1e6=this[_0x459b60(0x1ee)]['get'](_0x40a972)||[],_0x49cd28=this[_0x459b60(0x228)]['get'](_0x40a972),_0x5a4cd6=_0x296fae[_0x296fae['length']-0x1],_0x430a85=_0x5a4cd6?Date[_0x459b60(0x21f)]()-_0x5a4cd6[_0x459b60(0x1e3)]:null,_0x53ecf6=_0x4c3e16['filter'](_0x3bad53=>_0x3bad53['type']===ZoneType[_0x459b60(0x201)])['length'],_0x3da4f9=_0x4c3e16[_0x459b60(0x1f9)](_0x249fa7=>_0x249fa7['type']===ZoneType['SUPPORT'])['length'];return{'healthy':_0x296fae['length']>=0x5,'barsTotal':_0x296fae['length'],'barsLast5Min':_0x296fae[_0x459b60(0x1f9)](_0x3bf46c=>Date[_0x459b60(0x21f)]()-_0x3bf46c['timestamp']<0x5*0x3c*0x3e8)['length'],'swingsTotal':_0x1e1e6['length'],'zonesResistance':_0x53ecf6,'zonesSupport':_0x3da4f9,'zonesTotal':_0x4c3e16['length'],'currentBarTicks':_0x49cd28?_0x49cd28['tickCount']:0x0,'isAggregating':_0x49cd28&&_0x49cd28['tickCount']>0x0,'timeSinceLastBarMs':_0x430a85,'lastSignalTime':this['lastSignalTime'],'signalCooldownMs':this[_0x459b60(0x22b)]['execution']['cooldownMs'],'uptime':Date['now']()-(this['startTime']||Date['now']())};}['reset'](_0x1268a2){const _0x747c54=_0x42d110;this[_0x747c54(0x214)]['set'](_0x1268a2,[]),this[_0x747c54(0x1ee)]['set'](_0x1268a2,[]),this['liquidityZones']['set'](_0x1268a2,[]),this['activeSweeps'][_0x747c54(0x211)](_0x1268a2,[]),this['currentBar'][_0x747c54(0x244)](_0x1268a2),this[_0x747c54(0x254)](_0x747c54(0x248),{'type':'info','message':_0x747c54(0x216)+_0x1268a2});}[_0x42d110(0x205)](_0x124293,_0x4300bd){const _0x3dbf5f=_0x42d110;if(!_0x4300bd||_0x4300bd['length']===0x0){this[_0x3dbf5f(0x254)](_0x3dbf5f(0x248),{'type':'debug','message':'[HQX-2B]\x20No\x20historical\x20bars\x20to\x20preload'});return;}!this['barHistory'][_0x3dbf5f(0x1f1)](_0x124293)&&this[_0x3dbf5f(0x259)](_0x124293);const _0x34afda=[..._0x4300bd][_0x3dbf5f(0x24c)]((_0xda6fb7,_0x111e8c)=>_0xda6fb7[_0x3dbf5f(0x1e3)]-_0x111e8c['timestamp']);this[_0x3dbf5f(0x254)]('log',{'type':'info','message':'[HQX-2B]\x20Preloading\x20'+_0x34afda[_0x3dbf5f(0x1f5)]+_0x3dbf5f(0x210)});let _0x3cc4b9=0x0;for(const _0x2a24d0 of _0x34afda){const _0x4e066d=this[_0x3dbf5f(0x1d2)](_0x124293,_0x2a24d0);if(_0x4e066d)_0x3cc4b9++;}const _0x126fb5=this[_0x3dbf5f(0x214)][_0x3dbf5f(0x231)](_0x124293)||[],_0x3d9a13=this[_0x3dbf5f(0x1ee)][_0x3dbf5f(0x231)](_0x124293)||[],_0x167bc6=this[_0x3dbf5f(0x21b)][_0x3dbf5f(0x231)](_0x124293)||[];this[_0x3dbf5f(0x254)](_0x3dbf5f(0x248),{'type':'info','message':'[HQX-2B]\x20Preload\x20complete:\x20'+_0x126fb5[_0x3dbf5f(0x1f5)]+'\x20bars,\x20'+_0x3d9a13[_0x3dbf5f(0x1f5)]+_0x3dbf5f(0x1d6)+_0x167bc6['length']+_0x3dbf5f(0x24d)}),_0x3cc4b9>0x0&&this[_0x3dbf5f(0x254)](_0x3dbf5f(0x248),{'type':_0x3dbf5f(0x255),'message':_0x3dbf5f(0x1f3)+_0x3cc4b9+'\x20historical\x20signals\x20detected\x20(ignored)'}),this[_0x3dbf5f(0x1e7)]=0x0;}}class HQX2BStrategy extends EventEmitter{constructor(_0x346b57={}){const _0x2051b0=_0x42d110;super(),this[_0x2051b0(0x22b)]=_0x346b57,this[_0x2051b0(0x232)]=new HQX2BLiquiditySweep(_0x346b57),this['strategy']['on']('signal',_0x300e6e=>this['emit']('signal',_0x300e6e)),this[_0x2051b0(0x232)]['on'](_0x2051b0(0x248),_0x9cdab9=>this['emit'](_0x2051b0(0x248),_0x9cdab9));}[_0x42d110(0x250)](_0x20c752){return this['strategy']['processTick'](_0x20c752);}[_0x42d110(0x1e4)](_0x116fc5){return this['strategy']['onTick'](_0x116fc5);}['onTrade'](_0x47dbf6){const _0x2888f7=_0x42d110;return this[_0x2888f7(0x232)][_0x2888f7(0x1e1)](_0x47dbf6);}['processBar'](_0x317eab,_0x604ec7){return this['strategy']['processBar'](_0x317eab,_0x604ec7);}[_0x42d110(0x259)](_0xe0a442,_0x4a38c5,_0x3abb15){return this['strategy']['initialize'](_0xe0a442,_0x4a38c5,_0x3abb15);}['getAnalysisState'](_0x2d9353,_0x286950){const _0x731018=_0x42d110;return this[_0x731018(0x232)][_0x731018(0x1de)](_0x2d9353,_0x286950);}[_0x42d110(0x25d)](_0x4c04be){const _0xe52c3f=_0x42d110;return this['strategy'][_0xe52c3f(0x25d)](_0x4c04be);}['reset'](_0x36ef08){const _0x187f7e=_0x42d110;return this[_0x187f7e(0x232)][_0x187f7e(0x222)](_0x36ef08);}[_0x42d110(0x22f)](){const _0x41e25a=_0x42d110;return this['strategy'][_0x41e25a(0x22f)]();}[_0x42d110(0x24b)](_0x584ae){const _0x5b4b4f=_0x42d110;return this[_0x5b4b4f(0x232)]['getBarHistory'](_0x584ae);}[_0x42d110(0x205)](_0x1f88a7,_0x19d1b2){const _0x2956a8=_0x42d110;return this['strategy'][_0x2956a8(0x205)](_0x1f88a7,_0x19d1b2);}[_0x42d110(0x22a)](_0x4f5c6a){const _0xd52c29=_0x42d110;return this['strategy'][_0xd52c29(0x22a)](_0x4f5c6a);}[_0x42d110(0x240)](_0x2d9552){return null;}}function _0x1d4b(){const _0x2c55d4=['[HQX-2B]\x20','America/New_York','length','max','buy','minQualityScore','filter',',\x20value=','2737ZFlBTB','strength','execution','ASK','sweepType','SUPPORT','RESISTANCE','minPenetrationTicks','trades','startTime','preloadBars','clusterToleranceTicks','durationBars','extremeBarIndex','MODERATE','targetTicks','tickSize','short','shift','session',':\x20tick=','\x20historical\x20bars...','set','tickValue','penetrationTicks','barHistory','_detectSwings','[HQX-2B]\x20Reset\x20state\x20for\x20','minVolumeRatio','object','cooldownMs','1777194TEhowt','liquidityZones','splice','distance','lastUsedBarIndex','now','type','19736JJjqGN','reset','zone','toFixed','_updateZones','_scoreSweep','19095890MzkmJM','currentBar','maxDurationBars','getHealthStatus','config','1245382WiHmjj','close','breakevenTicks','getStats','touches','get','strategy','resistance','HIGH_SWEEP','slice','trailDistanceTicks','activeSweeps','sell','x\x20|\x20Q:','1jDFrqs','events','abs','swept','minBodyRatio','swing','generateSignal','isArray','find','maxPenetrationTicks','delete','10021392hImrbv','minStrength','barIntervalMs','log','high','volumeRatio','getBarHistory','sort','\x20zones','uuid','t\x20Vol:','processTick','low','55vTPwkt','min','emit','debug','253384ZrnUDP','3415896CKXZdB','getTimezoneOffset','initialize','getLevel','priceHigh','price','recordTradeResult','containsPrice','\x20@\x20','signals','\x20|\x20Total:\x20','getFullYear','isValid','[2B]\x20SWEEP\x20','processBar','sweptAt','qualityScore','BID','\x20swings,\x20','push','HQX-2B\x20Liquidity\x20Sweep\x20(Optimized)','[HQX-2B]\x20SIGNAL:\x20','_getVolumeRatio','enabled','t,\x20Trail=','info','getAnalysisState','priceLow','lookbackBars','onTrade','stopTicks','timestamp','onTick','exitBarIndex',',\x20TF=1min','lastSignalTime','volume','_mergeConfig','floor','trailTriggerTicks','maxZoneAgeBars','_generateSignal','swingPoints','barIndex','support','has','stats'];_0x1d4b=function(){return _0x2c55d4;};return _0x1d4b();}module['exports']={'HQX2BLiquiditySweep':HQX2BLiquiditySweep,'HQX2BStrategy':HQX2BStrategy,'M2':HQX2BStrategy,'S2':HQX2BLiquiditySweep,'OrderSide':OrderSide,'SignalStrength':SignalStrength,'SweepType':SweepType,'ZoneType':ZoneType,'DEFAULT_CONFIG':DEFAULT_CONFIG};