hedgequantx 2.9.211 → 2.9.213

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.211",
3
+ "version": "2.9.213",
4
4
  "description": "HedgeQuantX - Prop Futures Trading CLI",
5
5
  "main": "src/app.js",
6
6
  "bin": {
@@ -0,0 +1,402 @@
1
+ /**
2
+ * =============================================================================
3
+ * Smart Logs Context - Instrument & Strategy Specific Messages
4
+ * =============================================================================
5
+ * Messages adaptés au contexte:
6
+ * - Instrument (NQ/MNQ, ES/MES, CL, GC, etc.)
7
+ * - Stratégie (HQX Scalping = QUANT/ticks, HQX-2B = bars/zones)
8
+ */
9
+
10
+ 'use strict';
11
+
12
+ // ============================================================================
13
+ // INSTRUMENT CONTEXTS - Vocabulary specific to each market
14
+ // ============================================================================
15
+
16
+ const INSTRUMENT_CONTEXT = {
17
+ // NASDAQ (NQ/MNQ) - Tech-heavy, high beta, momentum-driven
18
+ NQ: {
19
+ name: 'Nasdaq',
20
+ traits: ['tech-driven', 'high-beta', 'momentum'],
21
+ bullish: [
22
+ 'Tech rally lifting index, FAANG leading',
23
+ 'Risk-on sentiment, growth stocks bid',
24
+ 'Nasdaq outperforming, tech momentum strong',
25
+ 'Mega-caps driving index higher',
26
+ 'Tech sector rotation bullish',
27
+ 'Growth over value trade active',
28
+ 'NASDAQ bid on semiconductor strength',
29
+ 'Tech bulls in control, AI momentum',
30
+ 'Index lifting on NVDA/AAPL strength',
31
+ 'Risk appetite strong, tech leading',
32
+ ],
33
+ bearish: [
34
+ 'Tech weakness dragging index',
35
+ 'Risk-off rotation out of growth',
36
+ 'Nasdaq underperforming, rates pressure',
37
+ 'Mega-cap selling pressure',
38
+ 'Tech sector rotation bearish',
39
+ 'Value over growth trade active',
40
+ 'NASDAQ offered on chip weakness',
41
+ 'Tech bears pressing, yields rising',
42
+ 'Index heavy on FAANG weakness',
43
+ 'Risk aversion hitting growth names',
44
+ ],
45
+ neutral: [
46
+ 'Tech consolidating, awaiting catalyst',
47
+ 'Nasdaq range-bound, mixed sector action',
48
+ 'Index digesting recent move',
49
+ 'Tech in balance, watching yields',
50
+ 'Mega-caps mixed, no clear direction',
51
+ ],
52
+ },
53
+
54
+ // S&P 500 (ES/MES) - Broad market, institutional, balanced
55
+ ES: {
56
+ name: 'S&P 500',
57
+ traits: ['broad-market', 'institutional', 'balanced'],
58
+ bullish: [
59
+ 'Broad market strength, risk-on',
60
+ 'S&P breaking out, breadth improving',
61
+ 'Institutional buying across sectors',
62
+ 'Index bid on economic optimism',
63
+ 'Defensive to offensive rotation',
64
+ 'Market internals bullish',
65
+ 'S&P above key moving averages',
66
+ 'Broad rally, advancers leading',
67
+ 'Index strength on volume',
68
+ 'Risk appetite improving broadly',
69
+ ],
70
+ bearish: [
71
+ 'Broad market weakness, risk-off',
72
+ 'S&P breaking down, breadth weak',
73
+ 'Institutional selling pressure',
74
+ 'Index offered on macro concerns',
75
+ 'Offensive to defensive rotation',
76
+ 'Market internals bearish',
77
+ 'S&P below key support levels',
78
+ 'Broad selling, decliners leading',
79
+ 'Index weakness on volume',
80
+ 'Risk aversion across sectors',
81
+ ],
82
+ neutral: [
83
+ 'S&P consolidating at key level',
84
+ 'Broad market in balance',
85
+ 'Index awaiting economic data',
86
+ 'Sector rotation neutral',
87
+ 'Market digesting Fed commentary',
88
+ ],
89
+ },
90
+
91
+ // Crude Oil (CL/MCL) - Energy, geopolitical, supply/demand
92
+ CL: {
93
+ name: 'Crude Oil',
94
+ traits: ['energy', 'geopolitical', 'supply-demand'],
95
+ bullish: [
96
+ 'Crude bid on supply concerns',
97
+ 'Energy rally, OPEC supporting',
98
+ 'Oil lifting on inventory draw',
99
+ 'Geopolitical risk premium rising',
100
+ 'Demand outlook improving',
101
+ 'Refinery demand strong',
102
+ 'Crude above resistance, bulls in control',
103
+ 'Energy sector leading broader market',
104
+ 'WTI bid on dollar weakness',
105
+ 'Supply disruption fears lifting prices',
106
+ ],
107
+ bearish: [
108
+ 'Crude offered on demand fears',
109
+ 'Energy selling, OPEC uncertainty',
110
+ 'Oil dropping on inventory build',
111
+ 'Geopolitical risk premium fading',
112
+ 'Demand outlook weakening',
113
+ 'Refinery maintenance weighing',
114
+ 'Crude below support, bears pressing',
115
+ 'Energy sector lagging market',
116
+ 'WTI offered on dollar strength',
117
+ 'Supply glut concerns pressuring',
118
+ ],
119
+ neutral: [
120
+ 'Crude in balance, awaiting EIA data',
121
+ 'Energy consolidating near OPEC meeting',
122
+ 'Oil range-bound on mixed signals',
123
+ 'Supply/demand in equilibrium',
124
+ 'Crude watching dollar direction',
125
+ ],
126
+ },
127
+
128
+ // Gold (GC/MGC) - Safe haven, inflation hedge, rates sensitive
129
+ GC: {
130
+ name: 'Gold',
131
+ traits: ['safe-haven', 'inflation-hedge', 'rates-sensitive'],
132
+ bullish: [
133
+ 'Gold bid on safe-haven demand',
134
+ 'Precious metals rally, risk-off',
135
+ 'Gold lifting on inflation fears',
136
+ 'Real yields dropping, gold bullish',
137
+ 'Flight to safety supporting gold',
138
+ 'Central bank buying supportive',
139
+ 'Gold above resistance, bulls active',
140
+ 'Dollar weakness lifting gold',
141
+ 'Geopolitical uncertainty bid',
142
+ 'Inflation hedge demand rising',
143
+ ],
144
+ bearish: [
145
+ 'Gold offered on risk-on sentiment',
146
+ 'Precious metals selling, yields rising',
147
+ 'Gold dropping on Fed hawkishness',
148
+ 'Real yields rising, gold bearish',
149
+ 'Risk appetite reducing safe-haven demand',
150
+ 'ETF outflows pressuring gold',
151
+ 'Gold below support, bears in control',
152
+ 'Dollar strength weighing on gold',
153
+ 'Risk-on rotation out of metals',
154
+ 'Inflation expectations cooling',
155
+ ],
156
+ neutral: [
157
+ 'Gold consolidating near key level',
158
+ 'Precious metals in balance',
159
+ 'Gold watching Fed commentary',
160
+ 'Real yields stable, gold range-bound',
161
+ 'Safe-haven demand muted',
162
+ ],
163
+ },
164
+
165
+ // Russell 2000 (RTY/M2K) - Small caps, domestic, risk appetite
166
+ RTY: {
167
+ name: 'Russell 2000',
168
+ traits: ['small-cap', 'domestic', 'risk-appetite'],
169
+ bullish: [
170
+ 'Small caps outperforming, risk-on',
171
+ 'Russell leading, domestic strength',
172
+ 'Risk appetite lifting small caps',
173
+ 'RTY breaking out, breadth strong',
174
+ 'Regional banks supporting index',
175
+ 'Small cap rotation accelerating',
176
+ 'Domestic economy optimism',
177
+ 'Russell above key resistance',
178
+ 'Risk-on favoring high-beta names',
179
+ 'Small caps catching bid',
180
+ ],
181
+ bearish: [
182
+ 'Small caps underperforming, risk-off',
183
+ 'Russell lagging, credit concerns',
184
+ 'Risk aversion hitting small caps',
185
+ 'RTY breaking down, breadth weak',
186
+ 'Regional bank weakness dragging',
187
+ 'Small cap rotation reversing',
188
+ 'Domestic economy concerns',
189
+ 'Russell below support, bears active',
190
+ 'Risk-off hitting high-beta names',
191
+ 'Small caps under pressure',
192
+ ],
193
+ neutral: [
194
+ 'Small caps consolidating',
195
+ 'Russell in balance, watching rates',
196
+ 'RTY range-bound, mixed signals',
197
+ 'Small cap sentiment neutral',
198
+ 'Regional banks mixed',
199
+ ],
200
+ },
201
+
202
+ // Dow Jones (YM/MYM) - Blue chips, value, defensive
203
+ YM: {
204
+ name: 'Dow Jones',
205
+ traits: ['blue-chip', 'value', 'defensive'],
206
+ bullish: [
207
+ 'Blue chips leading, value rotation',
208
+ 'Dow outperforming, defensive strength',
209
+ 'Industrials lifting index',
210
+ 'Value over growth trade active',
211
+ 'Dow breaking out, old economy bid',
212
+ 'Blue chip accumulation',
213
+ 'Defensive sectors leading',
214
+ 'YM above resistance, bulls active',
215
+ 'Dow component strength broad',
216
+ 'Value rotation accelerating',
217
+ ],
218
+ bearish: [
219
+ 'Blue chips lagging, growth leading',
220
+ 'Dow underperforming, cyclicals weak',
221
+ 'Industrials dragging index',
222
+ 'Growth over value trade active',
223
+ 'Dow breaking down, selling pressure',
224
+ 'Blue chip distribution',
225
+ 'Defensive sectors under pressure',
226
+ 'YM below support, bears pressing',
227
+ 'Dow component weakness broad',
228
+ 'Value rotation reversing',
229
+ ],
230
+ neutral: [
231
+ 'Blue chips consolidating',
232
+ 'Dow in balance, rotation mixed',
233
+ 'YM range-bound, awaiting catalyst',
234
+ 'Value/growth neutral',
235
+ 'Industrials mixed',
236
+ ],
237
+ },
238
+ };
239
+
240
+ // Aliases for micro contracts
241
+ INSTRUMENT_CONTEXT.MNQ = INSTRUMENT_CONTEXT.NQ;
242
+ INSTRUMENT_CONTEXT.MES = INSTRUMENT_CONTEXT.ES;
243
+ INSTRUMENT_CONTEXT.MCL = INSTRUMENT_CONTEXT.CL;
244
+ INSTRUMENT_CONTEXT.MGC = INSTRUMENT_CONTEXT.GC;
245
+ INSTRUMENT_CONTEXT.M2K = INSTRUMENT_CONTEXT.RTY;
246
+ INSTRUMENT_CONTEXT.MYM = INSTRUMENT_CONTEXT.YM;
247
+
248
+ // ============================================================================
249
+ // STRATEGY CONTEXTS - Vocabulary specific to each strategy
250
+ // ============================================================================
251
+
252
+ const STRATEGY_CONTEXT = {
253
+ // HQX Ultra Scalping - QUANT based (Z-Score, VPIN, OFI)
254
+ 'ultra-scalping': {
255
+ name: 'QUANT Scalping',
256
+ metrics: ['Z-Score', 'VPIN', 'OFI'],
257
+ warmup: [
258
+ 'QUANT models calibrating',
259
+ 'Statistical edge computation',
260
+ 'Factor model initialization',
261
+ 'Z-Score baseline forming',
262
+ 'VPIN toxicity model loading',
263
+ 'OFI imbalance calc active',
264
+ 'Mean reversion params init',
265
+ 'Volatility regime detection',
266
+ 'Microstructure analysis loading',
267
+ 'Tick distribution fitting',
268
+ ],
269
+ // Dynamic scanning messages - will be combined with real QUANT values
270
+ scanning: [
271
+ 'Mean reversion scan active',
272
+ 'Monitoring Z deviation',
273
+ 'VPIN/OFI correlation check',
274
+ 'Statistical edge scan',
275
+ 'Factor alignment check',
276
+ 'Regime detection active',
277
+ 'Microstructure analysis',
278
+ 'Tick flow monitoring',
279
+ 'Volatility regime stable',
280
+ 'Awaiting Z extremity',
281
+ 'OFI flow balanced',
282
+ 'VPIN toxicity normal',
283
+ 'Mean convergence watch',
284
+ 'Distribution tail scan',
285
+ 'Alpha detection active',
286
+ 'Momentum factor check',
287
+ 'Price discovery tracking',
288
+ 'Orderflow imbalance scan',
289
+ 'Statistical noise filter',
290
+ 'Edge detection running',
291
+ ],
292
+ signal: [
293
+ 'Statistical edge detected',
294
+ 'Z-Score extreme - mean reversion',
295
+ 'VPIN/OFI alignment confirmed',
296
+ 'Factor model signal active',
297
+ 'Mean reversion setup',
298
+ 'Statistical alpha found',
299
+ 'Regime shift confirmed',
300
+ 'Edge exploitation ready',
301
+ 'QUANT signal triggered',
302
+ 'Model confidence high',
303
+ ],
304
+ },
305
+
306
+ // HQX-2B Liquidity Sweep - Price action based (bars, swings, zones)
307
+ 'hqx-2b': {
308
+ name: '2B Liquidity Sweep',
309
+ metrics: ['Swings', 'Zones', 'Sweeps'],
310
+ warmup: [
311
+ 'Building swing structure',
312
+ 'Mapping liquidity zones',
313
+ 'Detecting pivot points',
314
+ 'Zone formation analysis',
315
+ 'Swing detection active',
316
+ 'Price structure mapping',
317
+ 'Liquidity pool scanning',
318
+ 'Support/resistance mapping',
319
+ 'Order block detection',
320
+ 'Market structure loading',
321
+ ],
322
+ scanning: [
323
+ 'Monitoring swing structure',
324
+ 'No zone in range',
325
+ 'Waiting for sweep setup',
326
+ 'Price away from zones',
327
+ 'No liquidity sweep detected',
328
+ 'Watching for pivot break',
329
+ 'Structure intact, no setup',
330
+ 'Zones mapped, awaiting price',
331
+ 'Swing highs/lows holding',
332
+ 'No 2B pattern forming',
333
+ ],
334
+ signal: [
335
+ 'Liquidity sweep detected',
336
+ 'Zone penetration confirmed',
337
+ '2B reversal pattern forming',
338
+ 'Stop hunt completed',
339
+ 'Sweep and reject signal',
340
+ 'Zone touch with rejection',
341
+ 'Liquidity taken, reversing',
342
+ 'False break confirmed',
343
+ '2B setup triggered',
344
+ 'Zone sweep entry active',
345
+ ],
346
+ },
347
+ };
348
+
349
+ // ============================================================================
350
+ // MESSAGE GENERATOR
351
+ // ============================================================================
352
+
353
+ /**
354
+ * Get contextual message based on instrument and strategy
355
+ * @param {string} symbol - Contract symbol (e.g., 'MNQH6', 'ESH6')
356
+ * @param {string} strategyId - Strategy ID ('ultra-scalping' or 'hqx-2b')
357
+ * @param {string} context - Message context ('bullish', 'bearish', 'neutral', 'warmup', 'scanning', 'signal')
358
+ * @returns {string} Contextual message
359
+ */
360
+ function getContextualMessage(symbol, strategyId, context) {
361
+ // Extract base symbol (remove contract month)
362
+ const baseSymbol = symbol.replace(/[FGHJKMNQUVXZ]\d{1,2}(:|$).*/, '').toUpperCase();
363
+
364
+ // Get instrument context
365
+ const instrument = INSTRUMENT_CONTEXT[baseSymbol] || INSTRUMENT_CONTEXT.ES; // Default to ES
366
+
367
+ // Get strategy context
368
+ const strategy = STRATEGY_CONTEXT[strategyId] || STRATEGY_CONTEXT['hqx-2b'];
369
+
370
+ let pool = [];
371
+
372
+ // Market direction messages (from instrument)
373
+ if (context === 'bullish' || context === 'bearish' || context === 'neutral') {
374
+ pool = instrument[context] || [];
375
+ }
376
+ // Strategy state messages
377
+ else if (context === 'warmup' || context === 'scanning' || context === 'signal') {
378
+ pool = strategy[context] || [];
379
+ }
380
+
381
+ // Return random message from pool, or fallback
382
+ if (pool.length > 0) {
383
+ return pool[Math.floor(Math.random() * pool.length)];
384
+ }
385
+
386
+ return 'Analyzing market conditions...';
387
+ }
388
+
389
+ /**
390
+ * Get instrument name from symbol
391
+ */
392
+ function getInstrumentName(symbol) {
393
+ const baseSymbol = symbol.replace(/[FGHJKMNQUVXZ]\d{1,2}(:|$).*/, '').toUpperCase();
394
+ return INSTRUMENT_CONTEXT[baseSymbol]?.name || 'Futures';
395
+ }
396
+
397
+ module.exports = {
398
+ INSTRUMENT_CONTEXT,
399
+ STRATEGY_CONTEXT,
400
+ getContextualMessage,
401
+ getInstrumentName,
402
+ };
@@ -14,6 +14,7 @@
14
14
 
15
15
  const chalk = require('chalk');
16
16
  const smartLogs = require('./smart-logs');
17
+ const { getContextualMessage } = require('./smart-logs-context');
17
18
 
18
19
  const CONFIG = {
19
20
  SESSION_LOG_INTERVAL: 10,
@@ -27,6 +28,8 @@ const CONFIG = {
27
28
  OFI_THRESHOLD: 0.15,
28
29
  VPIN_TOXIC: 0.6,
29
30
  QUANT_WARMUP_TICKS: 250,
31
+ // Heartbeat interval - frequent updates in scanning mode
32
+ HEARTBEAT_MS: 5000, // 5 seconds
30
33
  };
31
34
 
32
35
  const SYMBOLS = {
@@ -51,7 +54,7 @@ class SmartLogsEngine {
51
54
  this.symbolCode = symbol;
52
55
  this.counter = 0;
53
56
  this.lastState = null;
54
- this.lastHeartbeat = 0;
57
+ this.lastLogTime = 0;
55
58
 
56
59
  // State tracking for event detection (both strategies)
57
60
  this.lastBias = null;
@@ -66,6 +69,10 @@ class SmartLogsEngine {
66
69
  // QUANT specific
67
70
  this.lastZRegime = null;
68
71
  this.lastVpinToxic = false;
72
+ this.lastPrice = 0;
73
+ this.lastLoggedZ = null;
74
+ this.lastLoggedOfi = null;
75
+ this.recentMessages = [];
69
76
  }
70
77
 
71
78
  setSymbol(s) { this.symbolCode = s; }
@@ -113,34 +120,36 @@ class SmartLogsEngine {
113
120
  if (bars >= 10 && !this.warmupLogged) {
114
121
  this.warmupLogged = true;
115
122
  event = 'warmup';
116
- message = `[${sym}] Strategy ready | ${bars} bars | Scanning for setups`;
123
+ const warmupMsg = getContextualMessage(this.symbolCode, this.strategyId, 'warmup');
124
+ message = `[${sym}] 2B ready | ${bars} bars | ${warmupMsg}`;
117
125
  logType = 'system';
118
126
  }
119
127
  // EVENT 2: New zone created
120
128
  else if (zones > this.lastZones && zones > 0) {
121
129
  event = 'new_zone';
122
- const liveMsg = smartLogs.getLiveAnalysisLog({ trend, bars, swings, zones, nearZone, setupForming: false });
123
- message = `[${sym}] ${price} | Zone #${zones} created | ${liveMsg}`;
130
+ const signalMsg = getContextualMessage(this.symbolCode, this.strategyId, 'signal');
131
+ message = `[${sym}] ${price} | Zone #${zones} | ${signalMsg}`;
124
132
  logType = 'signal';
125
133
  }
126
134
  // EVENT 3: New swing detected
127
135
  else if (swings > this.lastSwings && swings > 0) {
128
136
  event = 'new_swing';
129
- const liveMsg = smartLogs.getLiveAnalysisLog({ trend, bars, swings, zones, nearZone, setupForming: false });
130
- message = `[${sym}] ${price} | Swing #${swings} | ${liveMsg}`;
137
+ const scanMsg = getContextualMessage(this.symbolCode, this.strategyId, 'scanning');
138
+ message = `[${sym}] ${price} | Swing #${swings} | ${scanMsg}`;
131
139
  }
132
140
  // EVENT 4: Zone approach (price near zone)
133
141
  else if (nearZone && !this.lastNearZone && zones > 0) {
134
142
  event = 'zone_approach';
135
- const liveMsg = smartLogs.getLiveAnalysisLog({ trend, bars, swings, zones, nearZone: true, setupForming: true });
136
- message = `[${sym}] ${price} | Approaching zone | ${liveMsg}`;
143
+ const signalMsg = getContextualMessage(this.symbolCode, this.strategyId, 'signal');
144
+ message = `[${sym}] ${price} | Zone approach | ${signalMsg}`;
137
145
  logType = 'signal';
138
146
  }
139
147
  // EVENT 5: Bias flip
140
148
  else if (this.lastBias && trend !== this.lastBias && trend !== 'neutral' && this.lastBias !== 'neutral') {
141
149
  event = 'bias_flip';
142
150
  const arrow = trend === 'bullish' ? chalk.green('▲') : chalk.red('▼');
143
- message = `[${sym}] ${arrow} Bias: ${this.lastBias} → ${trend} | Delta: ${delta}`;
151
+ const flipMsg = getContextualMessage(this.symbolCode, this.strategyId, trend);
152
+ message = `[${sym}] ${arrow} ${this.lastBias} → ${trend} | ${flipMsg}`;
144
153
  }
145
154
 
146
155
  // Update state tracking
@@ -176,33 +185,38 @@ class SmartLogsEngine {
176
185
  if (ticks >= CONFIG.QUANT_WARMUP_TICKS && !this.warmupLogged) {
177
186
  this.warmupLogged = true;
178
187
  event = 'warmup';
179
- message = `[${sym}] QUANT models ready | ${ticks} ticks | Z-Score/VPIN/OFI active`;
188
+ const warmupMsg = getContextualMessage(this.symbolCode, this.strategyId, 'warmup');
189
+ message = `[${sym}] QUANT ready | ${ticks} ticks | ${warmupMsg}`;
180
190
  logType = 'system';
181
191
  }
182
192
  // EVENT 2: Z-Score regime change
183
193
  else if (this.lastZRegime !== null && zRegime !== this.lastZRegime) {
184
194
  event = 'z_regime';
185
- 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 };
186
- const liveMsg = smartLogs.getLiveAnalysisLog(liveState);
195
+ // Get instrument-specific market context message
196
+ const marketCtx = bias === 'bullish' ? 'bullish' : bias === 'bearish' ? 'bearish' : 'neutral';
197
+ const instrumentMsg = getContextualMessage(this.symbolCode, this.strategyId, marketCtx);
187
198
 
188
199
  if (zRegime === 'extreme') {
189
200
  logType = 'signal';
190
201
  const dir = zScore < 0 ? 'LONG' : 'SHORT';
191
- message = `[${sym}] ${price} | Z: ${zScore.toFixed(1)}σ | ${dir} edge | ${liveMsg}`;
202
+ const signalMsg = getContextualMessage(this.symbolCode, this.strategyId, 'signal');
203
+ message = `[${sym}] ${price} | Z: ${zScore.toFixed(1)}σ | ${dir} | ${signalMsg}`;
192
204
  } else if (zRegime === 'high') {
193
205
  logType = 'signal';
194
- message = `[${sym}] ${price} | Z: ${zScore.toFixed(1)}σ approaching | ${liveMsg}`;
206
+ message = `[${sym}] ${price} | Z: ${zScore.toFixed(1)}σ | ${instrumentMsg}`;
195
207
  } else if (zRegime === 'building') {
196
- message = `[${sym}] ${price} | Z building (${zScore.toFixed(1)}σ) | ${liveMsg}`;
208
+ message = `[${sym}] ${price} | Z building (${zScore.toFixed(1)}σ) | ${instrumentMsg}`;
197
209
  } else {
198
- message = `[${sym}] ${price} | Z normalized | ${liveMsg}`;
210
+ const scanMsg = getContextualMessage(this.symbolCode, this.strategyId, 'scanning');
211
+ message = `[${sym}] ${price} | Z normalized | ${scanMsg}`;
199
212
  }
200
213
  }
201
214
  // EVENT 3: Bias flip (OFI direction change)
202
215
  else if (this.lastBias !== null && bias !== this.lastBias && bias !== 'neutral' && this.lastBias !== 'neutral') {
203
216
  event = 'bias_flip';
204
217
  const arrow = bias === 'bullish' ? chalk.green('▲') : chalk.red('▼');
205
- message = `[${sym}] ${arrow} OFI flip: ${this.lastBias} → ${bias} | ${(ofi * 100).toFixed(0)}%`;
218
+ const flipMsg = getContextualMessage(this.symbolCode, this.strategyId, bias);
219
+ message = `[${sym}] ${arrow} OFI: ${this.lastBias} → ${bias} | ${flipMsg}`;
206
220
  }
207
221
  // EVENT 4: VPIN toxicity change
208
222
  else if (this.lastVpinToxic !== null && vpinToxic !== this.lastVpinToxic) {
@@ -221,18 +235,62 @@ class SmartLogsEngine {
221
235
  this.lastVpinToxic = vpinToxic;
222
236
 
223
237
  if (event && message) {
224
- this.lastHeartbeat = Date.now();
238
+ this.lastLogTime = Date.now();
239
+ this.lastPrice = state.price;
240
+ this.lastLoggedZ = zScore;
241
+ this.lastLoggedOfi = ofi;
225
242
  return { type: logType, message, logToSession: event === 'z_regime' || event === 'bias_flip' };
226
243
  }
227
244
 
228
- // HEARTBEAT: Show status every 30s when no events (proves strategy is active)
245
+ // REAL-TIME LOGS: Every second, show meaningful market activity
229
246
  const now = Date.now();
230
- if (this.warmupLogged && now - this.lastHeartbeat >= 30000) {
231
- this.lastHeartbeat = now;
232
- const liveMsg = smartLogs.getLiveAnalysisLog({ trend: bias, bars: ticks, swings: 0, zones: 0, nearZone: false, setupForming: false });
247
+ if (this.warmupLogged && now - this.lastLogTime >= 1000) {
248
+ const price = state.price || 0;
249
+ const priceChange = this.lastPrice ? price - this.lastPrice : 0;
250
+ const zChange = this.lastLoggedZ !== null ? zScore - this.lastLoggedZ : 0;
251
+ const ofiChange = this.lastLoggedOfi !== null ? ofi - this.lastLoggedOfi : 0;
252
+
253
+ this.lastLogTime = now;
254
+ this.lastPrice = price;
255
+ this.lastLoggedZ = zScore;
256
+ this.lastLoggedOfi = ofi;
257
+
258
+ // Build contextual message based on what's actually happening
259
+ const zStr = zScore >= 0 ? `+${zScore.toFixed(1)}` : zScore.toFixed(1);
260
+ const ofiPct = (ofi * 100).toFixed(0);
261
+ const vpinPct = (vpin * 100).toFixed(0);
262
+
263
+ // Determine what's notable RIGHT NOW
264
+ let context;
265
+ if (Math.abs(priceChange) >= 0.5) {
266
+ // Price moved significantly
267
+ const dir = priceChange > 0 ? 'uptick' : 'downtick';
268
+ const ticks = Math.abs(priceChange / 0.25).toFixed(0);
269
+ context = `${dir} ${ticks}t`;
270
+ } else if (Math.abs(zChange) >= 0.3) {
271
+ // Z-Score shifting
272
+ context = zChange > 0 ? 'Z expanding' : 'Z contracting';
273
+ } else if (Math.abs(ofiChange) >= 0.05) {
274
+ // OFI shifting
275
+ context = ofiChange > 0 ? 'buying pressure' : 'selling pressure';
276
+ } else if (absZ >= 1.5) {
277
+ // In signal zone
278
+ const dir = zScore < 0 ? 'LONG zone' : 'SHORT zone';
279
+ context = dir;
280
+ } else if (Math.abs(ofi) >= 0.15) {
281
+ // Strong flow
282
+ context = ofi > 0 ? 'bid strength' : 'offer strength';
283
+ } else if (vpin > 0.4) {
284
+ // Elevated VPIN
285
+ context = 'elevated toxicity';
286
+ } else {
287
+ // Get instrument-specific neutral message
288
+ context = getContextualMessage(this.symbolCode, this.strategyId, 'neutral');
289
+ }
290
+
233
291
  return {
234
292
  type: 'analysis',
235
- message: `[${sym}] ${price} | Z: ${zScore.toFixed(1)}σ | OFI: ${(ofi * 100).toFixed(0)}% | ${liveMsg}`,
293
+ message: `[${sym}] ${price.toFixed(2)} | Z: ${zStr}σ | OFI: ${ofiPct}% | ${context}`,
236
294
  logToSession: false
237
295
  };
238
296
  }
@@ -245,7 +303,7 @@ class SmartLogsEngine {
245
303
  this.counter = 0;
246
304
  this.lastBias = null;
247
305
  this.warmupLogged = false;
248
- this.lastHeartbeat = 0;
306
+ this.lastLogTime = 0;
249
307
  // HQX-2B
250
308
  this.lastBars = 0;
251
309
  this.lastSwings = 0;
@@ -254,6 +312,10 @@ class SmartLogsEngine {
254
312
  // QUANT
255
313
  this.lastZRegime = null;
256
314
  this.lastVpinToxic = false;
315
+ this.lastPrice = 0;
316
+ this.lastLoggedZ = null;
317
+ this.lastLoggedOfi = null;
318
+ this.recentMessages = [];
257
319
  }
258
320
  }
259
321