hedgequantx 2.9.208 → 2.9.210

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.9.208",
3
+ "version": "2.9.210",
4
4
  "description": "HedgeQuantX - Prop Futures Trading CLI",
5
5
  "main": "src/app.js",
6
6
  "bin": {
@@ -1,22 +1,32 @@
1
1
  /**
2
- * Smart Logs Engine - Event-Driven Intelligent Logs
3
- * Only logs when something SIGNIFICANT happens in the strategy
4
- * No spam, no repetitive messages - just real events
2
+ * Smart Logs Engine - Unified Event-Driven Intelligent Logs
3
+ * ==========================================================
4
+ *
5
+ * UNIFIED SYSTEM for all CLI strategies:
6
+ * - Same engine, same event detection logic
7
+ * - Strategy-specific vocabulary (HQX-2B: bars/swings/zones, QUANT: ticks/Z-Score/VPIN/OFI)
8
+ * - Uses smartLogs.getLiveAnalysisLog() for varied, non-repetitive messages
9
+ *
10
+ * Only logs when something SIGNIFICANT happens - no spam, no repetitive messages
5
11
  */
6
12
 
7
13
  'use strict';
8
14
 
9
15
  const chalk = require('chalk');
10
- const HQX2B = require('./smart-logs-hqx2b');
11
- const QUANT = require('./smart-logs-quant');
12
16
  const smartLogs = require('./smart-logs');
13
17
 
14
18
  const CONFIG = {
15
19
  SESSION_LOG_INTERVAL: 10,
16
- PRICE_CHANGE_TICKS: 4, // Log when price moves 4+ ticks
17
- DELTA_CHANGE_THRESHOLD: 200, // Log when delta changes 200+
18
- ZONE_APPROACH_TICKS: 5, // Log when within 5 ticks of zone
19
- LOG_INTERVAL_SECONDS: 5, // Log every N seconds with quant data
20
+ // HQX-2B thresholds
21
+ PRICE_CHANGE_TICKS: 4,
22
+ DELTA_CHANGE_THRESHOLD: 200,
23
+ // QUANT thresholds
24
+ Z_EXTREME: 2.0,
25
+ Z_HIGH: 1.5,
26
+ Z_BUILDING: 1.0,
27
+ OFI_THRESHOLD: 0.15,
28
+ VPIN_TOXIC: 0.6,
29
+ QUANT_WARMUP_TICKS: 250,
20
30
  };
21
31
 
22
32
  const SYMBOLS = {
@@ -31,255 +41,203 @@ function getSym(s) {
31
41
  return SYMBOLS[b] || b;
32
42
  }
33
43
 
44
+ /**
45
+ * Unified Smart Logs Engine
46
+ * Works with any strategy - adapts vocabulary based on strategyId
47
+ */
34
48
  class SmartLogsEngine {
35
49
  constructor(strategyId, symbol) {
36
50
  this.strategyId = strategyId || 'hqx-2b';
37
51
  this.symbolCode = symbol;
38
52
  this.counter = 0;
39
53
  this.lastState = null;
40
- this.lastLogTime = 0;
41
- // QUANT-specific state tracking for event detection
42
- this.lastZRegime = null; // 'extreme' | 'high' | 'building' | 'neutral'
43
- this.lastBias = null; // 'bullish' | 'bearish' | 'neutral'
44
- this.lastVpinToxic = false; // true if VPIN > 0.6
45
- this.warmupLogged = false; // Track if we logged warmup milestones
46
- }
47
-
48
- setSymbol(s) { this.symbolCode = s; }
49
-
50
- /**
51
- * Detect significant events by comparing current vs previous state
52
- * Returns array of events sorted by priority (1 = highest)
53
- */
54
- _detectEvents(current, previous) {
55
- if (!previous) return [{ type: 'init', priority: 5 }];
56
-
57
- const events = [];
58
- const tickSize = 0.25; // Default, should come from config
59
-
60
- // New bar created
61
- if (current.bars > previous.bars) {
62
- events.push({ type: 'newBar', priority: 4, data: { count: current.bars } });
63
- }
64
-
65
- // New swing detected
66
- if (current.swings > previous.swings) {
67
- events.push({ type: 'newSwing', priority: 2, data: { count: current.swings } });
68
- }
69
-
70
- // New zone created
71
- if (current.zones > previous.zones) {
72
- events.push({ type: 'newZone', priority: 1, data: { count: current.zones } });
73
- }
74
54
 
75
- // Zone approached (became near when wasn't before)
76
- if (current.nearZone && !previous.nearZone) {
77
- events.push({ type: 'approachZone', priority: 1, data: {
78
- zonePrice: current.nearestSupport || current.nearestResistance
79
- }});
80
- }
81
-
82
- // Bias flip (bull <-> bear)
83
- if (previous.trend && current.trend !== previous.trend &&
84
- current.trend !== 'neutral' && previous.trend !== 'neutral') {
85
- events.push({ type: 'biasFlip', priority: 2, data: {
86
- from: previous.trend, to: current.trend
87
- }});
88
- }
89
-
90
- // Significant price move (4+ ticks)
91
- if (current.price > 0 && previous.price > 0) {
92
- const priceDiff = Math.abs(current.price - previous.price);
93
- const ticksMoved = priceDiff / tickSize;
94
- if (ticksMoved >= CONFIG.PRICE_CHANGE_TICKS) {
95
- events.push({ type: 'priceMove', priority: 3, data: {
96
- from: previous.price, to: current.price, ticks: ticksMoved
97
- }});
98
- }
99
- }
55
+ // State tracking for event detection (both strategies)
56
+ this.lastBias = null;
57
+ this.warmupLogged = false;
100
58
 
101
- // Delta shift (significant change in order flow)
102
- const deltaDiff = Math.abs(current.delta - (previous.delta || 0));
103
- if (deltaDiff >= CONFIG.DELTA_CHANGE_THRESHOLD) {
104
- events.push({ type: 'deltaShift', priority: 3, data: {
105
- from: previous.delta || 0, to: current.delta
106
- }});
107
- }
59
+ // HQX-2B specific
60
+ this.lastBars = 0;
61
+ this.lastSwings = 0;
62
+ this.lastZones = 0;
63
+ this.lastNearZone = false;
108
64
 
109
- // Sort by priority (lower = more important)
110
- return events.sort((a, b) => a.priority - b.priority);
65
+ // QUANT specific
66
+ this.lastZRegime = null;
67
+ this.lastVpinToxic = false;
111
68
  }
112
69
 
70
+ setSymbol(s) { this.symbolCode = s; }
71
+
113
72
  /**
114
- * Format event into display message
73
+ * Get log message - unified entry point
74
+ * Detects strategy and routes to appropriate handler
115
75
  */
116
- _formatEvent(event, state) {
117
- const sym = getSym(this.symbolCode);
118
- const price = state.price > 0 ? state.price.toFixed(2) : '-.--';
119
- const T = this.strategyId === 'hqx-2b' ? HQX2B : QUANT;
120
-
121
- switch (event.type) {
122
- case 'init':
123
- return { type: 'system', message: T.init({ sym, bars: state.bars, swings: state.swings, zones: state.zones }) };
124
-
125
- case 'newBar':
126
- return { type: 'system', message: T.newBar({ sym, bars: state.bars, price }) };
127
-
128
- case 'newSwing':
129
- return { type: 'analysis', message: T.newSwing({ sym, swings: state.swings, price }) };
130
-
131
- case 'newZone':
132
- return { type: 'signal', message: T.newZone({ sym, zones: state.zones, price }) };
133
-
134
- case 'approachZone':
135
- const zonePrice = event.data.zonePrice;
136
- const distance = zonePrice ? Math.abs(state.price - zonePrice) / 0.25 : 0;
137
- return { type: 'signal', message: T.approachZone({ sym, price, zonePrice: zonePrice?.toFixed(2) || 'N/A', distance: distance.toFixed(1) }) };
138
-
139
- case 'biasFlip':
140
- return { type: 'analysis', message: T.biasFlip({ sym, from: event.data.from, to: event.data.to, delta: state.delta }) };
141
-
142
- case 'priceMove':
143
- const dir = event.data.to > event.data.from ? 'up' : 'down';
144
- return { type: 'analysis', message: T.priceMove({ sym, price, dir, ticks: event.data.ticks.toFixed(1) }) };
145
-
146
- case 'deltaShift':
147
- return { type: 'analysis', message: T.deltaShift({ sym, from: event.data.from, to: event.data.to }) };
148
-
149
- default:
150
- return null;
151
- }
152
- }
153
-
154
76
  getLog(state = {}) {
155
77
  this.counter++;
156
- const { position = 0, delta = 0, zScore = 0, vpin = 0, ofi = 0 } = state;
157
78
  const sym = getSym(this.symbolCode);
158
79
  const price = state.price > 0 ? state.price.toFixed(2) : '-.--';
159
- const T = this.strategyId === 'hqx-2b' ? HQX2B : QUANT;
160
- const now = Date.now();
80
+ const { position = 0, delta = 0 } = state;
161
81
 
162
- // Active position - always log
82
+ // Active position - same for all strategies
163
83
  if (position !== 0) {
164
84
  const side = position > 0 ? 'LONG' : 'SHORT';
165
- const pnl = (position > 0 && delta > 0) || (position < 0 && delta < 0) ? 'FAVOR' : 'ADVERSE';
85
+ const flow = (position > 0 && delta > 0) || (position < 0 && delta < 0) ? 'FAVOR' : 'ADVERSE';
166
86
  return {
167
87
  type: 'trade',
168
- message: `[${sym}] ${side} ACTIVE @ ${price} | Delta: ${delta > 0 ? '+' : ''}${delta} | Flow: ${pnl}`,
88
+ message: `[${sym}] ${side} ACTIVE @ ${price} | Delta: ${delta > 0 ? '+' : ''}${delta} | Flow: ${flow}`,
169
89
  logToSession: true
170
90
  };
171
91
  }
172
92
 
173
- // Detect events
174
- const events = this._detectEvents(state, this.lastState);
175
- this.lastState = { ...state };
176
-
177
- // For QUANT strategy: EVENT-DRIVEN logs based on regime changes
178
- // Uses the same smart-logs system as HQX-2B for consistency
93
+ // Route to strategy-specific handler
179
94
  if (this.strategyId === 'ultra-scalping') {
180
- const ticks = state.tickCount || state.bars || 0;
181
- const absZ = Math.abs(zScore);
182
- const vpinToxic = vpin > 0.6;
183
-
184
- // Determine current regimes
185
- const zRegime = absZ >= 2.0 ? 'extreme' : absZ >= 1.5 ? 'high' : absZ >= 1.0 ? 'building' : 'neutral';
186
- const bias = ofi > 0.15 ? 'bullish' : ofi < -0.15 ? 'bearish' : 'neutral';
187
-
188
- let event = null;
189
- let logType = 'analysis';
190
- let message = null;
95
+ return this._getQuantLog(state, sym, price);
96
+ } else {
97
+ return this._getHqx2bLog(state, sym, price);
98
+ }
99
+ }
100
+
101
+ /**
102
+ * HQX-2B Liquidity Sweep - Bar/Swing/Zone based events
103
+ */
104
+ _getHqx2bLog(state, sym, price) {
105
+ const { bars = 0, swings = 0, zones = 0, nearZone = false, trend = 'neutral', delta = 0 } = state;
106
+
107
+ let event = null;
108
+ let logType = 'analysis';
109
+ let message = null;
110
+
111
+ // EVENT 1: Warmup complete (10+ bars)
112
+ if (bars >= 10 && !this.warmupLogged) {
113
+ this.warmupLogged = true;
114
+ event = 'warmup';
115
+ message = `[${sym}] Strategy ready | ${bars} bars | Scanning for setups`;
116
+ logType = 'system';
117
+ }
118
+ // EVENT 2: New zone created
119
+ else if (zones > this.lastZones && zones > 0) {
120
+ event = 'new_zone';
121
+ const liveMsg = smartLogs.getLiveAnalysisLog({ trend, bars, swings, zones, nearZone, setupForming: false });
122
+ message = `[${sym}] ${price} | Zone #${zones} created | ${liveMsg}`;
123
+ logType = 'signal';
124
+ }
125
+ // EVENT 3: New swing detected
126
+ else if (swings > this.lastSwings && swings > 0) {
127
+ event = 'new_swing';
128
+ const liveMsg = smartLogs.getLiveAnalysisLog({ trend, bars, swings, zones, nearZone, setupForming: false });
129
+ message = `[${sym}] ${price} | Swing #${swings} | ${liveMsg}`;
130
+ }
131
+ // EVENT 4: Zone approach (price near zone)
132
+ else if (nearZone && !this.lastNearZone && zones > 0) {
133
+ event = 'zone_approach';
134
+ const liveMsg = smartLogs.getLiveAnalysisLog({ trend, bars, swings, zones, nearZone: true, setupForming: true });
135
+ message = `[${sym}] ${price} | Approaching zone | ${liveMsg}`;
136
+ logType = 'signal';
137
+ }
138
+ // EVENT 5: Bias flip
139
+ else if (this.lastBias && trend !== this.lastBias && trend !== 'neutral' && this.lastBias !== 'neutral') {
140
+ event = 'bias_flip';
141
+ const arrow = trend === 'bullish' ? chalk.green('▲') : chalk.red('▼');
142
+ message = `[${sym}] ${arrow} Bias: ${this.lastBias} → ${trend} | Delta: ${delta}`;
143
+ }
144
+
145
+ // Update state tracking
146
+ this.lastBars = bars;
147
+ this.lastSwings = swings;
148
+ this.lastZones = zones;
149
+ this.lastNearZone = nearZone;
150
+ this.lastBias = trend;
151
+
152
+ if (event && message) {
153
+ return { type: logType, message, logToSession: event === 'new_zone' || event === 'bias_flip' };
154
+ }
155
+ return null;
156
+ }
157
+
158
+ /**
159
+ * QUANT (HQX Ultra Scalping) - Tick/Z-Score/VPIN/OFI based events
160
+ */
161
+ _getQuantLog(state, sym, price) {
162
+ const { tickCount = 0, zScore = 0, vpin = 0, ofi = 0 } = state;
163
+ const ticks = tickCount || state.bars || 0;
164
+
165
+ const absZ = Math.abs(zScore);
166
+ const vpinToxic = vpin > CONFIG.VPIN_TOXIC;
167
+ const zRegime = absZ >= CONFIG.Z_EXTREME ? 'extreme' : absZ >= CONFIG.Z_HIGH ? 'high' : absZ >= CONFIG.Z_BUILDING ? 'building' : 'neutral';
168
+ const bias = ofi > CONFIG.OFI_THRESHOLD ? 'bullish' : ofi < -CONFIG.OFI_THRESHOLD ? 'bearish' : 'neutral';
169
+
170
+ let event = null;
171
+ let logType = 'analysis';
172
+ let message = null;
173
+
174
+ // EVENT 1: Warmup complete (250 ticks for QUANT models)
175
+ if (ticks >= CONFIG.QUANT_WARMUP_TICKS && !this.warmupLogged) {
176
+ this.warmupLogged = true;
177
+ event = 'warmup';
178
+ message = `[${sym}] QUANT models ready | ${ticks} ticks | Z-Score/VPIN/OFI active`;
179
+ logType = 'system';
180
+ }
181
+ // EVENT 2: Z-Score regime change
182
+ else if (this.lastZRegime !== null && zRegime !== this.lastZRegime) {
183
+ event = 'z_regime';
184
+ const liveState = { trend: bias, bars: ticks, swings: absZ >= 1.0 ? 1 : 0, zones: absZ >= 1.5 ? 1 : 0, nearZone: absZ >= 1.5, setupForming: absZ >= 2.0 };
185
+ const liveMsg = smartLogs.getLiveAnalysisLog(liveState);
191
186
 
192
- // EVENT 1: Warmup complete (only log once at 250 ticks)
193
- if (ticks >= 250 && !this.warmupLogged) {
194
- this.warmupLogged = true;
195
- event = 'warmup_complete';
196
- message = `[${sym}] QUANT models ready | ${ticks} ticks processed`;
197
- logType = 'system';
187
+ if (zRegime === 'extreme') {
188
+ logType = 'signal';
189
+ const dir = zScore < 0 ? 'LONG' : 'SHORT';
190
+ message = `[${sym}] ${price} | Z: ${zScore.toFixed(1)}σ | ${dir} edge | ${liveMsg}`;
191
+ } else if (zRegime === 'high') {
192
+ logType = 'signal';
193
+ message = `[${sym}] ${price} | Z: ${zScore.toFixed(1)}σ approaching | ${liveMsg}`;
194
+ } else if (zRegime === 'building') {
195
+ message = `[${sym}] ${price} | Z building (${zScore.toFixed(1)}σ) | ${liveMsg}`;
196
+ } else {
197
+ message = `[${sym}] ${price} | Z normalized | ${liveMsg}`;
198
198
  }
199
- // EVENT 2: Z-Score regime change (significant threshold crossing)
200
- else if (this.lastZRegime !== null && zRegime !== this.lastZRegime) {
201
- event = 'z_regime_change';
202
- // Use smartLogs.getLiveAnalysisLog for varied contextual messages
203
- const liveState = {
204
- trend: bias,
205
- bars: ticks,
206
- swings: absZ >= 1.0 ? 1 : 0,
207
- zones: absZ >= 1.5 ? 1 : 0,
208
- nearZone: absZ >= 1.5,
209
- setupForming: absZ >= 2.0,
210
- };
211
- const baseMsg = smartLogs.getLiveAnalysisLog(liveState);
212
-
213
- if (zRegime === 'extreme') {
214
- logType = 'signal';
215
- const dir = zScore < 0 ? 'LONG' : 'SHORT';
216
- message = `[${sym}] ${price} | Z: ${zScore.toFixed(1)}σ | ${dir} edge | ${baseMsg}`;
217
- } else if (zRegime === 'high') {
218
- logType = 'signal';
219
- message = `[${sym}] ${price} | Z: ${zScore.toFixed(1)}σ | ${baseMsg}`;
220
- } else if (zRegime === 'building') {
221
- message = `[${sym}] ${price} | Z building (${zScore.toFixed(1)}σ) | ${baseMsg}`;
222
- } else {
223
- message = `[${sym}] ${price} | Z normalized | ${baseMsg}`;
224
- }
225
- }
226
- // EVENT 3: Bias flip (bullish ↔ bearish) - significant directional change
227
- else if (this.lastBias !== null && bias !== this.lastBias && bias !== 'neutral' && this.lastBias !== 'neutral') {
228
- event = 'bias_flip';
229
- const arrow = bias === 'bullish' ? chalk.green('▲') : chalk.red('▼');
230
- message = `[${sym}] ${arrow} Flow flip: ${this.lastBias} → ${bias} | OFI: ${(ofi * 100).toFixed(0)}%`;
231
- }
232
- // EVENT 4: VPIN toxicity threshold crossing
233
- else if (this.lastVpinToxic !== null && vpinToxic !== this.lastVpinToxic) {
234
- event = 'vpin_change';
235
- if (vpinToxic) {
236
- message = `[${sym}] ${price} | VPIN elevated (${(vpin * 100).toFixed(0)}%) - informed flow`;
237
- logType = 'risk';
238
- } else {
239
- message = `[${sym}] ${price} | VPIN normalized (${(vpin * 100).toFixed(0)}%) - clean flow`;
240
- }
241
- }
242
-
243
- // Update state tracking
244
- this.lastZRegime = zRegime;
245
- this.lastBias = bias;
246
- this.lastVpinToxic = vpinToxic;
247
-
248
- // Only return if we have an event
249
- if (event && message) {
250
- return {
251
- type: logType,
252
- message,
253
- logToSession: event === 'z_regime_change' || event === 'bias_flip'
254
- };
199
+ }
200
+ // EVENT 3: Bias flip (OFI direction change)
201
+ else if (this.lastBias !== null && bias !== this.lastBias && bias !== 'neutral' && this.lastBias !== 'neutral') {
202
+ event = 'bias_flip';
203
+ const arrow = bias === 'bullish' ? chalk.green('▲') : chalk.red('▼');
204
+ message = `[${sym}] ${arrow} OFI flip: ${this.lastBias} → ${bias} | ${(ofi * 100).toFixed(0)}%`;
205
+ }
206
+ // EVENT 4: VPIN toxicity change
207
+ else if (this.lastVpinToxic !== null && vpinToxic !== this.lastVpinToxic) {
208
+ event = 'vpin';
209
+ if (vpinToxic) {
210
+ message = `[${sym}] ${price} | VPIN toxic (${(vpin * 100).toFixed(0)}%) - informed flow detected`;
211
+ logType = 'risk';
212
+ } else {
213
+ message = `[${sym}] ${price} | VPIN clean (${(vpin * 100).toFixed(0)}%) - normal flow`;
255
214
  }
256
-
257
- return null; // No event = silence
258
215
  }
259
216
 
260
- // HQX-2B strategy: event-based logging
261
- // No events = no log (SILENCE)
262
- if (events.length === 0) {
263
- return null;
264
- }
217
+ // Update state tracking
218
+ this.lastZRegime = zRegime;
219
+ this.lastBias = bias;
220
+ this.lastVpinToxic = vpinToxic;
265
221
 
266
- // Format the most important event
267
- const log = this._formatEvent(events[0], state);
268
- if (log) {
269
- log.logToSession = this.counter % CONFIG.SESSION_LOG_INTERVAL === 0;
222
+ if (event && message) {
223
+ return { type: logType, message, logToSession: event === 'z_regime' || event === 'bias_flip' };
270
224
  }
271
- return log;
225
+ return null;
272
226
  }
273
227
 
274
228
  reset() {
275
- this.lastState = null;
276
- this.counter = 0;
277
- this.lastLogTime = 0;
278
- // Reset QUANT tracking
279
- this.lastZRegime = null;
229
+ this.lastState = null;
230
+ this.counter = 0;
280
231
  this.lastBias = null;
281
- this.lastVpinToxic = false;
282
232
  this.warmupLogged = false;
233
+ // HQX-2B
234
+ this.lastBars = 0;
235
+ this.lastSwings = 0;
236
+ this.lastZones = 0;
237
+ this.lastNearZone = false;
238
+ // QUANT
239
+ this.lastZRegime = null;
240
+ this.lastVpinToxic = false;
283
241
  }
284
242
  }
285
243