hedgequantx 2.9.231 → 2.9.233

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.231",
3
+ "version": "2.9.233",
4
4
  "description": "HedgeQuantX - Prop Futures Trading CLI",
5
5
  "main": "src/app.js",
6
6
  "bin": {
@@ -1,38 +1,58 @@
1
1
  /**
2
- * Smart Logs Engine - Professional HF-Grade Adaptive Logs
3
- * ========================================================
2
+ * Smart Logs Engine - Professional HF-Grade Real-Time Logs
3
+ * =========================================================
4
4
  *
5
- * PRINCIPLES:
6
- * 1. NO repetitive messages - each log must be unique and meaningful
7
- * 2. Adaptive to real market context - uses actual QUANT metrics
8
- * 3. Professional HF language - precise, technical, actionable
9
- * 4. Event-driven only - silence means scanning, no spam
5
+ * REAL-TIME logs every second showing:
6
+ * 1. Current price action
7
+ * 2. QUANT model states (Z-Score, VPIN, OFI)
8
+ * 3. Why we're not entering (or why we ARE entering)
9
+ * 4. Market microstructure insights
10
10
  *
11
- * This replaces the old rotating generic messages with
12
- * intelligent, context-aware logs that reflect the actual
13
- * algorithmic decision process.
11
+ * NO fake messages - everything is derived from real tick data
14
12
  */
15
13
 
16
14
  'use strict';
17
15
 
18
16
  const chalk = require('chalk');
19
17
 
20
- // Color helpers for consistent styling
18
+ // Rich color helpers for professional HF display
21
19
  const C = {
22
- sym: (s) => chalk.cyan.bold(s),
23
- price: (p) => chalk.white.bold(p),
24
- long: (s) => chalk.green.bold(s),
25
- short: (s) => chalk.red.bold(s),
26
- bull: (s) => chalk.green(s),
27
- bear: (s) => chalk.red(s),
28
- val: (v) => chalk.blue(v),
29
- valHigh: (v) => chalk.magenta.bold(v),
30
- ok: (s) => chalk.green(s),
31
- warn: (s) => chalk.yellow(s),
32
- danger: (s) => chalk.red.bold(s),
33
- dim: (s) => chalk.dim(s),
34
- info: (s) => chalk.gray(s),
35
- signal: (s) => chalk.yellow.bold(s),
20
+ // Symbol - bright cyan
21
+ sym: (s) => chalk.hex('#00FFFF').bold(s),
22
+
23
+ // Price - bright white/yellow
24
+ price: (p) => chalk.hex('#FFFFFF').bold(p),
25
+ priceUp: (p) => chalk.hex('#00FF00').bold(p),
26
+ priceDown: (p) => chalk.hex('#FF4444').bold(p),
27
+
28
+ // Direction
29
+ long: (s) => chalk.hex('#00FF00').bold(s),
30
+ short: (s) => chalk.hex('#FF4444').bold(s),
31
+ bull: (s) => chalk.hex('#00DD00')(s),
32
+ bear: (s) => chalk.hex('#FF6666')(s),
33
+
34
+ // Values & metrics
35
+ val: (v) => chalk.hex('#00BFFF')(v), // Deep sky blue
36
+ valHigh: (v) => chalk.hex('#FF00FF').bold(v), // Magenta for extreme
37
+ zscore: (v) => chalk.hex('#FFD700')(v), // Gold for Z-score
38
+
39
+ // Status indicators
40
+ ok: (s) => chalk.hex('#00FF00')(s),
41
+ warn: (s) => chalk.hex('#FFA500').bold(s), // Orange warning
42
+ danger: (s) => chalk.hex('#FF0000').bold(s), // Red danger
43
+
44
+ // Neutral/info
45
+ dim: (s) => chalk.hex('#888888')(s),
46
+ info: (s) => chalk.hex('#AAAAAA')(s),
47
+ muted: (s) => chalk.hex('#666666')(s),
48
+
49
+ // Special states
50
+ signal: (s) => chalk.hex('#FFFF00').bold(s), // Bright yellow signal
51
+ toxic: (s) => chalk.hex('#FF0000').bgHex('#330000').bold(s),
52
+
53
+ // Labels
54
+ label: (s) => chalk.hex('#888888')(s),
55
+ separator: () => chalk.hex('#444444')('|'),
36
56
  };
37
57
 
38
58
  const CONFIG = {
@@ -76,151 +96,149 @@ class SmartLogsEngine {
76
96
  setSymbol(s) { this.symbolCode = s; }
77
97
 
78
98
  /**
79
- * Main entry - returns log only when meaningful event occurs
80
- * Returns null for silence (professional: no news = scanning)
99
+ * Main entry - ALWAYS returns a UNIQUE log showing real-time market state
100
+ * Each message is different based on actual changing market data
81
101
  */
82
102
  getLog(state = {}) {
83
103
  const sym = getSym(this.symbolCode);
84
104
  const price = state.price > 0 ? state.price.toFixed(2) : null;
85
- const { position = 0, zScore = 0, vpin = 0, ofi = 0, tickCount = 0, bars = 0 } = state;
105
+ const { position = 0, zScore = 0, vpin = 0, ofi = 0, tickCount = 0, bars = 0, delta = 0, buyPct = 50 } = state;
106
+
107
+ // Track price movement for context
108
+ const priceNum = state.price || 0;
109
+ const lastPrice = this._lastPrice || priceNum;
110
+ const priceDiff = priceNum - lastPrice;
111
+ const priceDir = priceDiff > 0.01 ? '▲' : priceDiff < -0.01 ? '▼' : '─';
112
+ const priceDirColor = priceDiff > 0 ? C.bull : priceDiff < 0 ? C.bear : C.muted;
113
+ const priceDisplay = priceDiff > 0 ? C.priceUp(price) : priceDiff < 0 ? C.priceDown(price) : C.price(price);
114
+ this._lastPrice = priceNum;
115
+
116
+ // Track tick velocity
117
+ const lastTicks = this._lastTicks || 0;
118
+ const tickVelocity = (tickCount || bars || 0) - lastTicks;
119
+ this._lastTicks = tickCount || bars || 0;
86
120
 
87
121
  // Not enough data - still warming up
88
- const dataPoints = tickCount || bars || 0;
122
+ const dataPoints = bars || tickCount || 0;
89
123
  if (dataPoints < 50 || !price) {
90
- // Only log warmup progress at milestones
91
- if (!this.prev.ready && dataPoints > 0) {
92
- const pct = Math.min(100, Math.round((dataPoints / 50) * 100));
93
- const milestone = Math.floor(pct / 25) * 25;
94
- const lastMilestone = this._lastWarmupMilestone || 0;
95
- if (milestone > lastMilestone) {
96
- this._lastWarmupMilestone = milestone;
97
- return {
98
- type: 'system',
99
- message: `[${C.sym(sym)}] Calibrating QUANT models... ${C.val(pct + '%')} (${dataPoints} samples)`,
100
- logToSession: false
101
- };
102
- }
103
- }
104
- return null;
105
- }
106
-
107
- // Mark as ready
108
- if (!this.prev.ready) {
109
- this.prev.ready = true;
124
+ const pct = Math.min(100, Math.round((dataPoints / 50) * 100));
125
+ const remaining = 50 - dataPoints;
126
+ const pctColor = pct < 50 ? C.warn : C.ok;
110
127
  return {
111
128
  type: 'system',
112
- message: `[${C.sym(sym)}] ${C.price(price)} | ${C.ok('QUANT models calibrated')} | Scanning for alpha`,
113
- logToSession: true
129
+ message: `[${C.sym(sym)}] ${price ? C.price(price) : C.dim('-.--')} ${C.separator()} ${C.label('Calibrating')} ${pctColor(pct + '%')} ${C.separator()} ${C.val(remaining)} ${C.label('samples to ready')} ${C.separator()} ${C.dim('+' + tickVelocity + '/s')}`,
130
+ logToSession: false
114
131
  };
115
132
  }
116
133
 
117
- // Active position - always show
134
+ // Compute current states with precision for uniqueness
135
+ const absZ = Math.abs(zScore);
136
+ const ofiPct = (ofi * 100).toFixed(0);
137
+ const vpinPct = (vpin * 100).toFixed(0);
138
+ const buyPctRound = Math.round(buyPct || 50);
139
+ const deltaRound = Math.round(delta || 0);
140
+
141
+ // Z-Score color based on level - more vivid
142
+ const zColor = absZ >= CONFIG.Z_EXTREME ? C.valHigh :
143
+ absZ >= CONFIG.Z_HIGH ? C.signal :
144
+ absZ >= CONFIG.Z_BUILDING ? C.zscore : C.muted;
145
+ const zStr = zColor(`${zScore.toFixed(2)}σ`);
146
+
147
+ // OFI color based on direction - more vivid
148
+ const ofiColor = ofi > CONFIG.OFI_STRONG ? C.long :
149
+ ofi > CONFIG.OFI_THRESHOLD ? C.bull :
150
+ ofi < -CONFIG.OFI_STRONG ? C.short :
151
+ ofi < -CONFIG.OFI_THRESHOLD ? C.bear : C.muted;
152
+ const ofiStr = ofiColor(`${ofi >= 0 ? '+' : ''}${ofiPct}%`);
153
+
154
+ // VPIN color based on toxicity - more vivid
155
+ const vpinColor = vpin > CONFIG.VPIN_TOXIC ? C.toxic :
156
+ vpin > CONFIG.VPIN_ELEVATED ? C.warn : C.ok;
157
+ const vpinStr = vpinColor(`${vpinPct}%`);
158
+
159
+ // Delta (buy-sell imbalance) display - more vivid
160
+ const deltaAbs = Math.abs(deltaRound);
161
+ const deltaColor = deltaRound > 50 ? C.long : deltaRound > 0 ? C.bull :
162
+ deltaRound < -50 ? C.short : deltaRound < 0 ? C.bear : C.muted;
163
+ const deltaStr = deltaColor(`${deltaRound > 0 ? '+' : ''}${deltaRound}`);
164
+
165
+ // Buy percentage color
166
+ const buyColor = buyPctRound > 60 ? C.bull : buyPctRound < 40 ? C.bear : C.muted;
167
+ const buyStr = buyColor(`${buyPctRound}%`);
168
+
169
+ // Active position - show position management with unique data
118
170
  if (position !== 0) {
119
171
  const isLong = position > 0;
120
- const side = isLong ? C.long('LONG') : C.short('SHORT');
121
- const deltaFavor = (isLong && ofi > 0) || (!isLong && ofi < 0);
122
- const flowLabel = deltaFavor ? C.ok('ALIGNED') : C.warn('ADVERSE');
123
- const ofiStr = (ofi * 100).toFixed(0);
124
- const zStr = zScore.toFixed(2);
172
+ const side = isLong ? C.long('LONG') : C.short('SHORT');
173
+ const flowFavor = (isLong && ofi > 0) || (!isLong && ofi < 0);
174
+ const flowLabel = flowFavor ? C.ok('✓ aligned') : C.warn('⚠ adverse');
175
+ const exitClose = absZ < 0.5;
176
+ const exitInfo = exitClose ? C.warn('⚡ EXIT ZONE') : C.ok('holding');
125
177
 
126
- // Only log position updates when something changes
127
- const posHash = `pos-${position}-${Math.round(ofi * 10)}`;
128
- if (posHash !== this.lastLogHash) {
129
- this.lastLogHash = posHash;
130
- return {
131
- type: 'trade',
132
- message: `[${C.sym(sym)}] ${side} @ ${C.price(price)} | OFI:${ofiStr}% ${flowLabel} | Z:${zStr}σ`,
133
- logToSession: true
134
- };
135
- }
136
- return null;
178
+ return {
179
+ type: 'trade',
180
+ message: `[${C.sym(sym)}] ${side} ${priceDirColor(priceDir)} ${priceDisplay} ${C.separator()} ${C.label('Z:')}${zStr} ${exitInfo} ${C.separator()} ${C.label('Δ:')}${deltaStr} ${C.separator()} ${flowLabel}`,
181
+ logToSession: false
182
+ };
137
183
  }
138
184
 
139
- // Compute current regimes
140
- const absZ = Math.abs(zScore);
141
- const zRegime = absZ >= CONFIG.Z_EXTREME ? 'extreme' :
142
- absZ >= CONFIG.Z_HIGH ? 'high' :
143
- absZ >= CONFIG.Z_BUILDING ? 'building' : 'neutral';
144
- const ofiDir = ofi > CONFIG.OFI_STRONG ? 'strong-bull' :
145
- ofi > CONFIG.OFI_THRESHOLD ? 'bull' :
146
- ofi < -CONFIG.OFI_STRONG ? 'strong-bear' :
147
- ofi < -CONFIG.OFI_THRESHOLD ? 'bear' : 'neutral';
148
- const vpinLevel = vpin > CONFIG.VPIN_TOXIC ? 'toxic' :
149
- vpin > CONFIG.VPIN_ELEVATED ? 'elevated' : 'normal';
185
+ // No position - show WHY we're not entering with unique context each time
186
+ const direction = zScore < 0 ? 'LONG' : 'SHORT';
187
+ const dirColor = zScore < 0 ? C.long : C.short;
150
188
 
151
- // Detect events (changes in regime)
152
- let event = null;
153
- let message = null;
154
189
  let logType = 'analysis';
190
+ let message;
155
191
 
156
- const zColor = absZ >= CONFIG.Z_EXTREME ? C.valHigh :
157
- absZ >= CONFIG.Z_HIGH ? C.warn :
158
- absZ >= CONFIG.Z_BUILDING ? C.val : C.dim;
159
- const zStr = zColor(`${zScore.toFixed(2)}σ`);
160
- const ofiPct = (ofi * 100).toFixed(0);
161
- const vpinPct = (vpin * 100).toFixed(0);
162
-
163
- // EVENT 1: Z-Score regime change (most important)
164
- if (zRegime !== this.prev.zRegime && this.prev.zRegime !== null) {
165
- event = 'z_regime';
166
- const dir = zScore < 0 ? 'LONG' : 'SHORT';
167
-
168
- if (zRegime === 'extreme') {
169
- logType = 'signal';
170
- const ofiConfirm = (zScore < 0 && ofi > CONFIG.OFI_THRESHOLD) ||
171
- (zScore > 0 && ofi < -CONFIG.OFI_THRESHOLD);
172
- if (ofiConfirm) {
173
- message = `[${C.sym(sym)}] ${C.price(price)} | Z:${zStr} ${C.signal('EXTREME')} | ${C.long(dir)} | OFI:${ofiPct}% ${C.ok('CONFIRMS')}`;
174
- } else {
175
- message = `[${C.sym(sym)}] ${C.price(price)} | Z:${zStr} ${C.signal('EXTREME')} | ${C.warn(dir + ' pending')} | OFI:${ofiPct}% awaiting`;
176
- }
177
- } else if (zRegime === 'high') {
178
- logType = 'signal';
179
- message = `[${C.sym(sym)}] ${C.price(price)} | Z:${zStr} ${C.warn('building')} | ${dir} setup forming | OFI:${ofiPct}%`;
180
- } else if (zRegime === 'building' && this.prev.zRegime === 'neutral') {
181
- message = `[${C.sym(sym)}] ${C.price(price)} | Z:${zStr} | Deviation detected | Monitoring`;
182
- } else if (zRegime === 'neutral' && (this.prev.zRegime === 'high' || this.prev.zRegime === 'extreme')) {
183
- message = `[${C.sym(sym)}] ${C.price(price)} | Z:${C.ok('normalized')} | Mean reversion complete`;
184
- }
192
+ // VPIN toxic - highest priority blocker
193
+ if (vpin > CONFIG.VPIN_TOXIC) {
194
+ message = `[${C.sym(sym)}] ${priceDirColor(priceDir)} ${priceDisplay} ${C.separator()} ${C.label('VPIN:')}${vpinStr} ${C.toxic('☠ TOXIC')} ${C.separator()} ${C.label('Z:')}${zStr} ${C.separator()} ${C.label('Δ:')}${deltaStr} ${C.separator()} ${C.danger('NO ENTRY')}`;
195
+ logType = 'risk';
185
196
  }
186
- // EVENT 2: OFI direction flip (significant)
187
- else if (ofiDir !== this.prev.ofiDir && this.prev.ofiDir !== null &&
188
- ofiDir !== 'neutral' && this.prev.ofiDir !== 'neutral') {
189
- event = 'ofi_flip';
190
- const wasLong = this.prev.ofiDir.includes('bull');
191
- const nowLong = ofiDir.includes('bull');
192
- if (wasLong !== nowLong) {
193
- const arrow = nowLong ? C.bull('▲') : C.bear('▼');
194
- const newDir = nowLong ? C.bull('BUY') : C.bear('SELL');
195
- message = `[${C.sym(sym)}] ${C.price(price)} | ${arrow} OFI flip → ${newDir} pressure | ${ofiPct}% | Z:${zStr}`;
196
- }
197
+ // Z-Score extreme + OFI confirms = SIGNAL
198
+ else if (absZ >= CONFIG.Z_EXTREME &&
199
+ ((zScore < 0 && ofi > CONFIG.OFI_THRESHOLD) || (zScore > 0 && ofi < -CONFIG.OFI_THRESHOLD))) {
200
+ message = `[${C.sym(sym)}] ${priceDirColor(priceDir)} ${priceDisplay} ${C.separator()} ${C.label('Z:')}${zStr} ${C.signal('★ EXTREME')} ${C.separator()} ${C.label('OFI:')}${ofiStr} ${C.ok('✓')} ${C.separator()} ${dirColor('► ' + direction + ' SIGNAL')}`;
201
+ logType = 'signal';
197
202
  }
198
- // EVENT 3: VPIN level change (toxicity warning)
199
- else if (vpinLevel !== this.prev.vpinLevel && this.prev.vpinLevel !== null) {
200
- event = 'vpin_change';
201
- if (vpinLevel === 'toxic') {
202
- logType = 'risk';
203
- message = `[${C.sym(sym)}] ${C.price(price)} | VPIN:${C.danger(vpinPct + '% TOXIC')} | Informed flow detected | Hold`;
204
- } else if (vpinLevel === 'elevated' && this.prev.vpinLevel === 'normal') {
205
- message = `[${C.sym(sym)}] ${C.price(price)} | VPIN:${C.warn(vpinPct + '%')} elevated | Monitoring toxicity`;
206
- } else if (vpinLevel === 'normal' && this.prev.vpinLevel === 'toxic') {
207
- message = `[${C.sym(sym)}] ${C.price(price)} | VPIN:${C.ok(vpinPct + '%')} normalized | Flow clean`;
208
- }
203
+ // Z-Score extreme but OFI doesn't confirm
204
+ else if (absZ >= CONFIG.Z_EXTREME) {
205
+ const ofiNeed = zScore < 0 ? C.dim('need >15%') : C.dim('need <-15%');
206
+ message = `[${C.sym(sym)}] ${priceDirColor(priceDir)} ${priceDisplay} ${C.separator()} ${C.label('Z:')}${zStr} ${C.signal('!')} ${C.separator()} ${C.label('OFI:')}${ofiStr} ${ofiNeed} ${C.separator()} ${C.warn('◐ PENDING')}`;
207
+ logType = 'signal';
209
208
  }
210
-
211
- // Update state tracking
212
- this.prev.zRegime = zRegime;
213
- this.prev.ofiDir = ofiDir;
214
- this.prev.vpinLevel = vpinLevel;
215
- this.prev.position = position;
216
-
217
- // Return event or null (silence = professional scanning)
218
- if (event && message) {
219
- this.lastLogHash = `${event}-${zRegime}-${ofiDir}-${vpinLevel}`;
220
- return { type: logType, message, logToSession: logType === 'signal' || logType === 'risk' };
209
+ // Z-Score high - setup forming
210
+ else if (absZ >= CONFIG.Z_HIGH) {
211
+ const needed = (CONFIG.Z_EXTREME - absZ).toFixed(2);
212
+ message = `[${C.sym(sym)}] ${priceDirColor(priceDir)} ${priceDisplay} ${C.separator()} ${C.label('Z:')}${zStr} ${C.val('+' + needed + 'σ')} ${C.label('to signal')} ${C.separator()} ${C.label('OFI:')}${ofiStr} ${C.separator()} ${C.label('Δ:')}${deltaStr}`;
213
+ }
214
+ // Z-Score building
215
+ else if (absZ >= CONFIG.Z_BUILDING) {
216
+ const needed = (CONFIG.Z_HIGH - absZ).toFixed(2);
217
+ const bias = zScore < 0 ? C.bull('bid ↑') : C.bear('ask ↓');
218
+ message = `[${C.sym(sym)}] ${priceDirColor(priceDir)} ${priceDisplay} ${C.separator()} ${C.label('Z:')}${zStr} ${bias} ${C.separator()} ${C.val('+' + needed + 'σ')} ${C.label('to setup')} ${C.separator()} ${C.label('Δ:')}${deltaStr}`;
219
+ }
220
+ // Z-Score neutral - scanning
221
+ else {
222
+ // Cycle through different useful info each second to avoid repetition
223
+ const infoType = Math.floor(Date.now() / 1000) % 4;
224
+ let context;
225
+ switch (infoType) {
226
+ case 0:
227
+ context = `${C.label('Δ:')}${deltaStr} ${C.separator()} ${C.label('Buy:')}${buyStr}`;
228
+ break;
229
+ case 1:
230
+ context = `${C.label('VPIN:')}${vpinStr} ${C.separator()} ${C.label('OFI:')}${ofiStr}`;
231
+ break;
232
+ case 2:
233
+ context = `${C.val(tickVelocity)} ${C.label('ticks/s')} ${C.separator()} ${C.label('Δ:')}${deltaStr}`;
234
+ break;
235
+ default:
236
+ context = `${C.label('OFI:')}${ofiStr} ${C.separator()} ${C.label('Buy:')}${buyStr}`;
237
+ }
238
+ message = `[${C.sym(sym)}] ${priceDirColor(priceDir)} ${priceDisplay} ${C.separator()} ${C.label('Z:')}${zStr} ${C.muted('scanning')} ${C.separator()} ${context}`;
221
239
  }
222
240
 
223
- return null;
241
+ return { type: logType, message, logToSession: logType === 'signal' };
224
242
  }
225
243
 
226
244
  reset() {