hedgequantx 2.9.230 → 2.9.231
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 +1 -1
- package/src/lib/smart-logs-engine.js +155 -233
package/package.json
CHANGED
|
@@ -1,320 +1,242 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Smart Logs Engine -
|
|
3
|
-
*
|
|
2
|
+
* Smart Logs Engine - Professional HF-Grade Adaptive Logs
|
|
3
|
+
* ========================================================
|
|
4
4
|
*
|
|
5
|
-
*
|
|
6
|
-
* -
|
|
7
|
-
*
|
|
8
|
-
*
|
|
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
|
|
9
10
|
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
* - Symbols: cyan (NQ, ES, CL, GC)
|
|
14
|
-
* - Prices: white bold
|
|
15
|
-
* - Bullish/Long: green
|
|
16
|
-
* - Bearish/Short: red
|
|
17
|
-
* - Neutral/System: gray/dim
|
|
18
|
-
* - Signals: yellow/magenta
|
|
19
|
-
* - Risk/Warnings: red bold
|
|
20
|
-
* - Values: blue (Z-Score, VPIN, OFI numbers)
|
|
11
|
+
* This replaces the old rotating generic messages with
|
|
12
|
+
* intelligent, context-aware logs that reflect the actual
|
|
13
|
+
* algorithmic decision process.
|
|
21
14
|
*/
|
|
22
15
|
|
|
23
16
|
'use strict';
|
|
24
17
|
|
|
25
18
|
const chalk = require('chalk');
|
|
26
|
-
const smartLogs = require('./smart-logs');
|
|
27
|
-
const { getContextualMessage } = require('./smart-logs-context');
|
|
28
19
|
|
|
29
20
|
// Color helpers for consistent styling
|
|
30
21
|
const C = {
|
|
31
|
-
// Symbols & identifiers
|
|
32
22
|
sym: (s) => chalk.cyan.bold(s),
|
|
33
|
-
|
|
34
|
-
// Prices
|
|
35
23
|
price: (p) => chalk.white.bold(p),
|
|
36
|
-
|
|
37
|
-
// Direction
|
|
38
24
|
long: (s) => chalk.green.bold(s),
|
|
39
25
|
short: (s) => chalk.red.bold(s),
|
|
40
26
|
bull: (s) => chalk.green(s),
|
|
41
27
|
bear: (s) => chalk.red(s),
|
|
42
|
-
|
|
43
|
-
// Values & metrics
|
|
44
28
|
val: (v) => chalk.blue(v),
|
|
45
29
|
valHigh: (v) => chalk.magenta.bold(v),
|
|
46
|
-
|
|
47
|
-
// Status
|
|
48
30
|
ok: (s) => chalk.green(s),
|
|
49
31
|
warn: (s) => chalk.yellow(s),
|
|
50
32
|
danger: (s) => chalk.red.bold(s),
|
|
51
|
-
|
|
52
|
-
// System/neutral
|
|
53
33
|
dim: (s) => chalk.dim(s),
|
|
54
34
|
info: (s) => chalk.gray(s),
|
|
55
|
-
|
|
56
|
-
// Special
|
|
57
35
|
signal: (s) => chalk.yellow.bold(s),
|
|
58
|
-
zone: (s) => chalk.magenta(s),
|
|
59
|
-
regime: (s) => chalk.cyan(s),
|
|
60
36
|
};
|
|
61
37
|
|
|
62
38
|
const CONFIG = {
|
|
63
|
-
SESSION_LOG_INTERVAL: 10,
|
|
64
|
-
// HQX-2B thresholds
|
|
65
|
-
PRICE_CHANGE_TICKS: 4,
|
|
66
|
-
DELTA_CHANGE_THRESHOLD: 200,
|
|
67
|
-
// QUANT thresholds
|
|
68
39
|
Z_EXTREME: 2.0,
|
|
69
40
|
Z_HIGH: 1.5,
|
|
70
41
|
Z_BUILDING: 1.0,
|
|
42
|
+
OFI_STRONG: 0.20,
|
|
71
43
|
OFI_THRESHOLD: 0.15,
|
|
72
|
-
VPIN_TOXIC: 0.
|
|
73
|
-
|
|
74
|
-
// Heartbeat interval - frequent updates in scanning mode
|
|
75
|
-
HEARTBEAT_MS: 5000, // 5 seconds
|
|
76
|
-
};
|
|
77
|
-
|
|
78
|
-
const SYMBOLS = {
|
|
79
|
-
NQ: 'NQ', MNQ: 'MNQ', ES: 'ES', MES: 'MES', YM: 'YM', MYM: 'MYM',
|
|
80
|
-
CL: 'CL', MCL: 'MCL', GC: 'GC', MGC: 'MGC', SI: 'SI', SIL: 'SIL',
|
|
81
|
-
RTY: 'RTY', M2K: 'M2K', ZB: 'ZB', ZN: 'ZN',
|
|
44
|
+
VPIN_TOXIC: 0.65,
|
|
45
|
+
VPIN_ELEVATED: 0.50,
|
|
82
46
|
};
|
|
83
47
|
|
|
84
48
|
function getSym(s) {
|
|
85
49
|
if (!s) return 'FUT';
|
|
86
50
|
const b = s.split(':')[0].replace(/[FGHJKMNQUVXZ]\d{1,2}$/, '').toUpperCase();
|
|
87
|
-
|
|
51
|
+
const map = { ENQ: 'NQ', EP: 'ES', RTY: 'RTY', EMD: 'EMD', MGC: 'GC', MCL: 'CL' };
|
|
52
|
+
return map[b] || b;
|
|
88
53
|
}
|
|
89
54
|
|
|
90
55
|
/**
|
|
91
|
-
*
|
|
92
|
-
* Works with any strategy - adapts vocabulary based on strategyId
|
|
56
|
+
* Professional HF Smart Logs Engine
|
|
93
57
|
*/
|
|
94
58
|
class SmartLogsEngine {
|
|
95
59
|
constructor(strategyId, symbol) {
|
|
96
|
-
this.strategyId = strategyId || '
|
|
60
|
+
this.strategyId = strategyId || 'ultra-scalping';
|
|
97
61
|
this.symbolCode = symbol;
|
|
98
|
-
this.
|
|
99
|
-
this.
|
|
100
|
-
|
|
101
|
-
// State tracking for event detection (both strategies)
|
|
102
|
-
this.lastBias = null;
|
|
103
|
-
this.warmupLogged = false;
|
|
62
|
+
this.lastLogHash = null;
|
|
63
|
+
this.lastLogTime = 0;
|
|
64
|
+
this.eventCounter = 0;
|
|
104
65
|
|
|
105
|
-
//
|
|
106
|
-
this.
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
this.lastVpinToxic = false;
|
|
66
|
+
// State tracking for change detection
|
|
67
|
+
this.prev = {
|
|
68
|
+
zRegime: null,
|
|
69
|
+
ofiDir: null,
|
|
70
|
+
vpinLevel: null,
|
|
71
|
+
position: 0,
|
|
72
|
+
ready: false,
|
|
73
|
+
};
|
|
114
74
|
}
|
|
115
75
|
|
|
116
76
|
setSymbol(s) { this.symbolCode = s; }
|
|
117
77
|
|
|
118
78
|
/**
|
|
119
|
-
*
|
|
120
|
-
*
|
|
79
|
+
* Main entry - returns log only when meaningful event occurs
|
|
80
|
+
* Returns null for silence (professional: no news = scanning)
|
|
121
81
|
*/
|
|
122
82
|
getLog(state = {}) {
|
|
123
|
-
this.counter++;
|
|
124
83
|
const sym = getSym(this.symbolCode);
|
|
125
|
-
const price = state.price > 0 ? state.price.toFixed(2) :
|
|
126
|
-
const { position = 0,
|
|
127
|
-
|
|
128
|
-
//
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
84
|
+
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;
|
|
86
|
+
|
|
87
|
+
// Not enough data - still warming up
|
|
88
|
+
const dataPoints = tickCount || bars || 0;
|
|
89
|
+
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;
|
|
135
110
|
return {
|
|
136
|
-
type: '
|
|
137
|
-
message: `[${C.sym(sym)}] ${
|
|
111
|
+
type: 'system',
|
|
112
|
+
message: `[${C.sym(sym)}] ${C.price(price)} | ${C.ok('QUANT models calibrated')} | Scanning for alpha`,
|
|
138
113
|
logToSession: true
|
|
139
114
|
};
|
|
140
115
|
}
|
|
141
|
-
|
|
142
|
-
// Route to strategy-specific handler
|
|
143
|
-
if (this.strategyId === 'ultra-scalping') {
|
|
144
|
-
return this._getQuantLog(state, sym, price);
|
|
145
|
-
} else {
|
|
146
|
-
return this._getHqx2bLog(state, sym, price);
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
/**
|
|
151
|
-
* HQX-2B Liquidity Sweep - Bar/Swing/Zone based events
|
|
152
|
-
*/
|
|
153
|
-
_getHqx2bLog(state, sym, price) {
|
|
154
|
-
const { bars = 0, swings = 0, zones = 0, nearZone = false, trend = 'neutral', delta = 0 } = state;
|
|
155
116
|
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
else if (swings > this.lastSwings && swings > 0) {
|
|
177
|
-
event = 'new_swing';
|
|
178
|
-
const scanMsg = getContextualMessage(this.symbolCode, this.strategyId, 'scanning');
|
|
179
|
-
message = `[${C.sym(sym)}] ${C.price(price)} | ${C.info('Swing #' + swings)} | ${C.dim(scanMsg)}`;
|
|
180
|
-
}
|
|
181
|
-
// EVENT 4: Zone approach (price near zone)
|
|
182
|
-
else if (nearZone && !this.lastNearZone && zones > 0) {
|
|
183
|
-
event = 'zone_approach';
|
|
184
|
-
const signalMsg = getContextualMessage(this.symbolCode, this.strategyId, 'signal');
|
|
185
|
-
message = `[${C.sym(sym)}] ${C.price(price)} | ${C.warn('Zone approach')} | ${C.signal(signalMsg)}`;
|
|
186
|
-
logType = 'signal';
|
|
187
|
-
}
|
|
188
|
-
// EVENT 5: Bias flip
|
|
189
|
-
else if (this.lastBias && trend !== this.lastBias && trend !== 'neutral' && this.lastBias !== 'neutral') {
|
|
190
|
-
event = 'bias_flip';
|
|
191
|
-
const arrow = trend === 'bullish' ? C.bull('▲') : C.bear('▼');
|
|
192
|
-
const oldBias = this.lastBias === 'bullish' ? C.bull(this.lastBias) : C.bear(this.lastBias);
|
|
193
|
-
const newBias = trend === 'bullish' ? C.bull(trend) : C.bear(trend);
|
|
194
|
-
const flipMsg = getContextualMessage(this.symbolCode, this.strategyId, trend);
|
|
195
|
-
message = `[${C.sym(sym)}] ${arrow} ${oldBias} → ${newBias} | ${C.dim(flipMsg)}`;
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
// Update state tracking
|
|
199
|
-
this.lastBars = bars;
|
|
200
|
-
this.lastSwings = swings;
|
|
201
|
-
this.lastZones = zones;
|
|
202
|
-
this.lastNearZone = nearZone;
|
|
203
|
-
this.lastBias = trend;
|
|
204
|
-
|
|
205
|
-
if (event && message) {
|
|
206
|
-
return { type: logType, message, logToSession: event === 'new_zone' || event === 'bias_flip' };
|
|
117
|
+
// Active position - always show
|
|
118
|
+
if (position !== 0) {
|
|
119
|
+
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);
|
|
125
|
+
|
|
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;
|
|
207
137
|
}
|
|
208
|
-
return null;
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
/**
|
|
212
|
-
* QUANT (HQX Ultra Scalping) - Tick/Z-Score/VPIN/OFI based events
|
|
213
|
-
*/
|
|
214
|
-
_getQuantLog(state, sym, price) {
|
|
215
|
-
const { tickCount = 0, zScore = 0, vpin = 0, ofi = 0 } = state;
|
|
216
|
-
const ticks = tickCount || state.bars || 0;
|
|
217
138
|
|
|
139
|
+
// Compute current regimes
|
|
218
140
|
const absZ = Math.abs(zScore);
|
|
219
|
-
const
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
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';
|
|
150
|
+
|
|
151
|
+
// Detect events (changes in regime)
|
|
223
152
|
let event = null;
|
|
224
|
-
let logType = 'analysis';
|
|
225
153
|
let message = null;
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
const zColor =
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
// EVENT 1: Warmup complete (250 ticks for QUANT models)
|
|
238
|
-
if (ticks >= CONFIG.QUANT_WARMUP_TICKS && !this.warmupLogged) {
|
|
239
|
-
this.warmupLogged = true;
|
|
240
|
-
event = 'warmup';
|
|
241
|
-
const warmupMsg = getContextualMessage(this.symbolCode, this.strategyId, 'warmup');
|
|
242
|
-
message = `[${C.sym(sym)}] ${C.ok('QUANT ready')} | ${C.val(ticks)} ticks | ${C.dim(warmupMsg)}`;
|
|
243
|
-
logType = 'system';
|
|
244
|
-
}
|
|
245
|
-
// EVENT 2: Z-Score regime change
|
|
246
|
-
else if (this.lastZRegime !== null && zRegime !== this.lastZRegime) {
|
|
154
|
+
let logType = 'analysis';
|
|
155
|
+
|
|
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) {
|
|
247
165
|
event = 'z_regime';
|
|
248
|
-
|
|
249
|
-
const marketCtx = bias === 'bullish' ? 'bullish' : bias === 'bearish' ? 'bearish' : 'neutral';
|
|
250
|
-
const instrumentMsg = getContextualMessage(this.symbolCode, this.strategyId, marketCtx);
|
|
166
|
+
const dir = zScore < 0 ? 'LONG' : 'SHORT';
|
|
251
167
|
|
|
252
168
|
if (zRegime === 'extreme') {
|
|
253
169
|
logType = 'signal';
|
|
254
|
-
const
|
|
255
|
-
|
|
256
|
-
|
|
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
|
+
}
|
|
257
177
|
} else if (zRegime === 'high') {
|
|
258
178
|
logType = 'signal';
|
|
259
|
-
message = `[${C.sym(sym)}] ${C.price(price)} | Z
|
|
260
|
-
} else if (zRegime === 'building') {
|
|
261
|
-
message = `[${C.sym(sym)}] ${C.price(price)} | Z
|
|
262
|
-
} else {
|
|
263
|
-
|
|
264
|
-
message = `[${C.sym(sym)}] ${C.price(price)} | Z: ${C.ok('normalized')} | ${C.dim(scanMsg)}`;
|
|
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`;
|
|
265
184
|
}
|
|
266
185
|
}
|
|
267
|
-
// EVENT
|
|
268
|
-
else if (
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
const
|
|
272
|
-
const
|
|
273
|
-
|
|
274
|
-
|
|
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
|
+
}
|
|
275
197
|
}
|
|
276
|
-
// EVENT
|
|
277
|
-
else if (
|
|
278
|
-
event = '
|
|
279
|
-
|
|
280
|
-
if (vpinToxic) {
|
|
281
|
-
message = `[${C.sym(sym)}] ${C.price(price)} | VPIN: ${C.danger(vpinPct + '%')} ${C.danger('TOXIC')} - informed flow`;
|
|
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') {
|
|
282
202
|
logType = 'risk';
|
|
283
|
-
|
|
284
|
-
|
|
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`;
|
|
285
208
|
}
|
|
286
209
|
}
|
|
287
|
-
|
|
210
|
+
|
|
288
211
|
// Update state tracking
|
|
289
|
-
this.
|
|
290
|
-
this.
|
|
291
|
-
this.
|
|
292
|
-
|
|
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)
|
|
293
218
|
if (event && message) {
|
|
294
|
-
|
|
219
|
+
this.lastLogHash = `${event}-${zRegime}-${ofiDir}-${vpinLevel}`;
|
|
220
|
+
return { type: logType, message, logToSession: logType === 'signal' || logType === 'risk' };
|
|
295
221
|
}
|
|
296
222
|
|
|
297
|
-
// EVENT-DRIVEN ONLY: No spam, no repetitive logs
|
|
298
|
-
// Silence = system is scanning, nothing notable happening
|
|
299
|
-
// This is professional HF behavior
|
|
300
223
|
return null;
|
|
301
224
|
}
|
|
302
225
|
|
|
303
226
|
reset() {
|
|
304
|
-
this.
|
|
305
|
-
this.
|
|
306
|
-
this.
|
|
307
|
-
this.
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
this.lastVpinToxic = false;
|
|
227
|
+
this.lastLogHash = null;
|
|
228
|
+
this.lastLogTime = 0;
|
|
229
|
+
this.eventCounter = 0;
|
|
230
|
+
this._lastWarmupMilestone = 0;
|
|
231
|
+
this.prev = {
|
|
232
|
+
zRegime: null,
|
|
233
|
+
ofiDir: null,
|
|
234
|
+
vpinLevel: null,
|
|
235
|
+
position: 0,
|
|
236
|
+
ready: false,
|
|
237
|
+
};
|
|
316
238
|
}
|
|
317
239
|
}
|
|
318
240
|
|
|
319
241
|
function createEngine(strategyId, symbol) { return new SmartLogsEngine(strategyId, symbol); }
|
|
320
|
-
module.exports = { SmartLogsEngine, createEngine, CONFIG };
|
|
242
|
+
module.exports = { SmartLogsEngine, createEngine, CONFIG, C };
|