hedgequantx 2.9.230 → 2.9.232
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 +149 -241
package/package.json
CHANGED
|
@@ -1,320 +1,228 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Smart Logs Engine -
|
|
3
|
-
*
|
|
2
|
+
* Smart Logs Engine - Professional HF-Grade Real-Time Logs
|
|
3
|
+
* =========================================================
|
|
4
4
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
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
|
|
9
10
|
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
* COLOR SCHEME:
|
|
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
|
+
* NO fake messages - everything is derived from real tick data
|
|
21
12
|
*/
|
|
22
13
|
|
|
23
14
|
'use strict';
|
|
24
15
|
|
|
25
16
|
const chalk = require('chalk');
|
|
26
|
-
const smartLogs = require('./smart-logs');
|
|
27
|
-
const { getContextualMessage } = require('./smart-logs-context');
|
|
28
17
|
|
|
29
18
|
// Color helpers for consistent styling
|
|
30
19
|
const C = {
|
|
31
|
-
// Symbols & identifiers
|
|
32
20
|
sym: (s) => chalk.cyan.bold(s),
|
|
33
|
-
|
|
34
|
-
// Prices
|
|
35
21
|
price: (p) => chalk.white.bold(p),
|
|
36
|
-
|
|
37
|
-
// Direction
|
|
38
22
|
long: (s) => chalk.green.bold(s),
|
|
39
23
|
short: (s) => chalk.red.bold(s),
|
|
40
24
|
bull: (s) => chalk.green(s),
|
|
41
25
|
bear: (s) => chalk.red(s),
|
|
42
|
-
|
|
43
|
-
// Values & metrics
|
|
44
26
|
val: (v) => chalk.blue(v),
|
|
45
27
|
valHigh: (v) => chalk.magenta.bold(v),
|
|
46
|
-
|
|
47
|
-
// Status
|
|
48
28
|
ok: (s) => chalk.green(s),
|
|
49
29
|
warn: (s) => chalk.yellow(s),
|
|
50
30
|
danger: (s) => chalk.red.bold(s),
|
|
51
|
-
|
|
52
|
-
// System/neutral
|
|
53
31
|
dim: (s) => chalk.dim(s),
|
|
54
32
|
info: (s) => chalk.gray(s),
|
|
55
|
-
|
|
56
|
-
// Special
|
|
57
33
|
signal: (s) => chalk.yellow.bold(s),
|
|
58
|
-
zone: (s) => chalk.magenta(s),
|
|
59
|
-
regime: (s) => chalk.cyan(s),
|
|
60
34
|
};
|
|
61
35
|
|
|
62
36
|
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
37
|
Z_EXTREME: 2.0,
|
|
69
38
|
Z_HIGH: 1.5,
|
|
70
39
|
Z_BUILDING: 1.0,
|
|
40
|
+
OFI_STRONG: 0.20,
|
|
71
41
|
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',
|
|
42
|
+
VPIN_TOXIC: 0.65,
|
|
43
|
+
VPIN_ELEVATED: 0.50,
|
|
82
44
|
};
|
|
83
45
|
|
|
84
46
|
function getSym(s) {
|
|
85
47
|
if (!s) return 'FUT';
|
|
86
48
|
const b = s.split(':')[0].replace(/[FGHJKMNQUVXZ]\d{1,2}$/, '').toUpperCase();
|
|
87
|
-
|
|
49
|
+
const map = { ENQ: 'NQ', EP: 'ES', RTY: 'RTY', EMD: 'EMD', MGC: 'GC', MCL: 'CL' };
|
|
50
|
+
return map[b] || b;
|
|
88
51
|
}
|
|
89
52
|
|
|
90
53
|
/**
|
|
91
|
-
*
|
|
92
|
-
* Works with any strategy - adapts vocabulary based on strategyId
|
|
54
|
+
* Professional HF Smart Logs Engine
|
|
93
55
|
*/
|
|
94
56
|
class SmartLogsEngine {
|
|
95
57
|
constructor(strategyId, symbol) {
|
|
96
|
-
this.strategyId = strategyId || '
|
|
58
|
+
this.strategyId = strategyId || 'ultra-scalping';
|
|
97
59
|
this.symbolCode = symbol;
|
|
98
|
-
this.
|
|
99
|
-
this.
|
|
100
|
-
|
|
101
|
-
// State tracking for event detection (both strategies)
|
|
102
|
-
this.lastBias = null;
|
|
103
|
-
this.warmupLogged = false;
|
|
60
|
+
this.lastLogHash = null;
|
|
61
|
+
this.lastLogTime = 0;
|
|
62
|
+
this.eventCounter = 0;
|
|
104
63
|
|
|
105
|
-
//
|
|
106
|
-
this.
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
this.lastVpinToxic = false;
|
|
64
|
+
// State tracking for change detection
|
|
65
|
+
this.prev = {
|
|
66
|
+
zRegime: null,
|
|
67
|
+
ofiDir: null,
|
|
68
|
+
vpinLevel: null,
|
|
69
|
+
position: 0,
|
|
70
|
+
ready: false,
|
|
71
|
+
};
|
|
114
72
|
}
|
|
115
73
|
|
|
116
74
|
setSymbol(s) { this.symbolCode = s; }
|
|
117
75
|
|
|
118
76
|
/**
|
|
119
|
-
*
|
|
120
|
-
*
|
|
77
|
+
* Main entry - ALWAYS returns a UNIQUE log showing real-time market state
|
|
78
|
+
* Each message is different based on actual changing market data
|
|
121
79
|
*/
|
|
122
80
|
getLog(state = {}) {
|
|
123
|
-
this.counter++;
|
|
124
81
|
const sym = getSym(this.symbolCode);
|
|
125
|
-
const price = state.price > 0 ? state.price.toFixed(2) :
|
|
126
|
-
const { position = 0, delta = 0 } = state;
|
|
127
|
-
|
|
128
|
-
//
|
|
82
|
+
const price = state.price > 0 ? state.price.toFixed(2) : null;
|
|
83
|
+
const { position = 0, zScore = 0, vpin = 0, ofi = 0, tickCount = 0, bars = 0, delta = 0, buyPct = 50 } = state;
|
|
84
|
+
|
|
85
|
+
// Track price movement for context
|
|
86
|
+
const priceNum = state.price || 0;
|
|
87
|
+
const lastPrice = this._lastPrice || priceNum;
|
|
88
|
+
const priceDiff = priceNum - lastPrice;
|
|
89
|
+
const priceDir = priceDiff > 0.01 ? '▲' : priceDiff < -0.01 ? '▼' : '•';
|
|
90
|
+
const priceDirColor = priceDiff > 0 ? C.bull : priceDiff < 0 ? C.bear : C.dim;
|
|
91
|
+
this._lastPrice = priceNum;
|
|
92
|
+
|
|
93
|
+
// Track tick velocity
|
|
94
|
+
const lastTicks = this._lastTicks || 0;
|
|
95
|
+
const tickVelocity = (tickCount || bars || 0) - lastTicks;
|
|
96
|
+
this._lastTicks = tickCount || bars || 0;
|
|
97
|
+
|
|
98
|
+
// Not enough data - still warming up
|
|
99
|
+
const dataPoints = bars || tickCount || 0;
|
|
100
|
+
if (dataPoints < 50 || !price) {
|
|
101
|
+
const pct = Math.min(100, Math.round((dataPoints / 50) * 100));
|
|
102
|
+
const remaining = 50 - dataPoints;
|
|
103
|
+
return {
|
|
104
|
+
type: 'system',
|
|
105
|
+
message: `[${C.sym(sym)}] ${price ? C.price(price) : '-.--'} | Calibrating ${C.val(pct + '%')} | ${remaining} samples to ready | +${tickVelocity}/s`,
|
|
106
|
+
logToSession: false
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// Compute current states with precision for uniqueness
|
|
111
|
+
const absZ = Math.abs(zScore);
|
|
112
|
+
const ofiPct = (ofi * 100).toFixed(0);
|
|
113
|
+
const vpinPct = (vpin * 100).toFixed(0);
|
|
114
|
+
const buyPctRound = Math.round(buyPct || 50);
|
|
115
|
+
const deltaRound = Math.round(delta || 0);
|
|
116
|
+
|
|
117
|
+
// Z-Score color based on level
|
|
118
|
+
const zColor = absZ >= CONFIG.Z_EXTREME ? C.valHigh :
|
|
119
|
+
absZ >= CONFIG.Z_HIGH ? C.warn :
|
|
120
|
+
absZ >= CONFIG.Z_BUILDING ? C.val : C.dim;
|
|
121
|
+
const zStr = zColor(`${zScore.toFixed(2)}σ`);
|
|
122
|
+
|
|
123
|
+
// OFI color based on direction
|
|
124
|
+
const ofiColor = ofi > CONFIG.OFI_THRESHOLD ? C.bull :
|
|
125
|
+
ofi < -CONFIG.OFI_THRESHOLD ? C.bear : C.dim;
|
|
126
|
+
const ofiStr = ofiColor(`${ofi >= 0 ? '+' : ''}${ofiPct}%`);
|
|
127
|
+
|
|
128
|
+
// VPIN color based on toxicity
|
|
129
|
+
const vpinColor = vpin > CONFIG.VPIN_TOXIC ? C.danger :
|
|
130
|
+
vpin > CONFIG.VPIN_ELEVATED ? C.warn : C.ok;
|
|
131
|
+
const vpinStr = vpinColor(`${vpinPct}%`);
|
|
132
|
+
|
|
133
|
+
// Delta (buy-sell imbalance) display
|
|
134
|
+
const deltaColor = deltaRound > 0 ? C.bull : deltaRound < 0 ? C.bear : C.dim;
|
|
135
|
+
const deltaStr = deltaColor(`${deltaRound > 0 ? '+' : ''}${deltaRound}`);
|
|
136
|
+
|
|
137
|
+
// Active position - show position management with unique data
|
|
129
138
|
if (position !== 0) {
|
|
130
139
|
const isLong = position > 0;
|
|
131
140
|
const side = isLong ? C.long('LONG') : C.short('SHORT');
|
|
132
|
-
const flowFavor = (isLong &&
|
|
133
|
-
const flowLabel = flowFavor ? C.ok('
|
|
134
|
-
const
|
|
141
|
+
const flowFavor = (isLong && ofi > 0) || (!isLong && ofi < 0);
|
|
142
|
+
const flowLabel = flowFavor ? C.ok('aligned') : C.warn('adverse');
|
|
143
|
+
const exitClose = absZ < 0.5;
|
|
144
|
+
const exitInfo = exitClose ? C.warn('EXIT ZONE') : 'holding';
|
|
145
|
+
|
|
135
146
|
return {
|
|
136
147
|
type: 'trade',
|
|
137
|
-
message: `[${C.sym(sym)}] ${side}
|
|
138
|
-
logToSession:
|
|
148
|
+
message: `[${C.sym(sym)}] ${side} ${priceDirColor(priceDir)} ${C.price(price)} | Z:${zStr} ${exitInfo} | Δ:${deltaStr} | Flow:${flowLabel}`,
|
|
149
|
+
logToSession: false
|
|
139
150
|
};
|
|
140
151
|
}
|
|
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
152
|
|
|
156
|
-
|
|
153
|
+
// No position - show WHY we're not entering with unique context each time
|
|
154
|
+
const direction = zScore < 0 ? 'LONG' : 'SHORT';
|
|
155
|
+
const dirColor = zScore < 0 ? C.long : C.short;
|
|
156
|
+
|
|
157
157
|
let logType = 'analysis';
|
|
158
|
-
let message
|
|
159
|
-
|
|
160
|
-
//
|
|
161
|
-
if (
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
const warmupMsg = getContextualMessage(this.symbolCode, this.strategyId, 'warmup');
|
|
165
|
-
message = `[${C.sym(sym)}] ${C.ok('2B ready')} | ${C.val(bars)} bars | ${C.dim(warmupMsg)}`;
|
|
166
|
-
logType = 'system';
|
|
158
|
+
let message;
|
|
159
|
+
|
|
160
|
+
// VPIN toxic - highest priority blocker
|
|
161
|
+
if (vpin > CONFIG.VPIN_TOXIC) {
|
|
162
|
+
message = `[${C.sym(sym)}] ${priceDirColor(priceDir)} ${C.price(price)} | VPIN:${vpinStr} ${C.danger('TOXIC')} | Z:${zStr} | Δ:${deltaStr} | Hold`;
|
|
163
|
+
logType = 'risk';
|
|
167
164
|
}
|
|
168
|
-
//
|
|
169
|
-
else if (
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
message = `[${C.sym(sym)}] ${C.price(price)} | ${C.zone('Zone #' + zones)} | ${C.signal(signalMsg)}`;
|
|
165
|
+
// Z-Score extreme + OFI confirms = SIGNAL
|
|
166
|
+
else if (absZ >= CONFIG.Z_EXTREME &&
|
|
167
|
+
((zScore < 0 && ofi > CONFIG.OFI_THRESHOLD) || (zScore > 0 && ofi < -CONFIG.OFI_THRESHOLD))) {
|
|
168
|
+
message = `[${C.sym(sym)}] ${priceDirColor(priceDir)} ${C.price(price)} | Z:${zStr} ${C.signal('EXTREME')} | OFI:${ofiStr} ${C.ok('✓')} | ${dirColor(direction)} SIGNAL`;
|
|
173
169
|
logType = 'signal';
|
|
174
170
|
}
|
|
175
|
-
//
|
|
176
|
-
else if (
|
|
177
|
-
|
|
178
|
-
|
|
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)}`;
|
|
171
|
+
// Z-Score extreme but OFI doesn't confirm
|
|
172
|
+
else if (absZ >= CONFIG.Z_EXTREME) {
|
|
173
|
+
const ofiNeed = zScore < 0 ? `need >${15}%` : `need <-${15}%`;
|
|
174
|
+
message = `[${C.sym(sym)}] ${priceDirColor(priceDir)} ${C.price(price)} | Z:${zStr} ${C.signal('!')} | OFI:${ofiStr} ${ofiNeed} | ${C.warn('pending')}`;
|
|
186
175
|
logType = 'signal';
|
|
187
176
|
}
|
|
188
|
-
//
|
|
189
|
-
else if (
|
|
190
|
-
|
|
191
|
-
|
|
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' };
|
|
207
|
-
}
|
|
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
|
-
|
|
218
|
-
const absZ = Math.abs(zScore);
|
|
219
|
-
const vpinToxic = vpin > CONFIG.VPIN_TOXIC;
|
|
220
|
-
const zRegime = absZ >= CONFIG.Z_EXTREME ? 'extreme' : absZ >= CONFIG.Z_HIGH ? 'high' : absZ >= CONFIG.Z_BUILDING ? 'building' : 'neutral';
|
|
221
|
-
const bias = ofi > CONFIG.OFI_THRESHOLD ? 'bullish' : ofi < -CONFIG.OFI_THRESHOLD ? 'bearish' : 'neutral';
|
|
222
|
-
|
|
223
|
-
let event = null;
|
|
224
|
-
let logType = 'analysis';
|
|
225
|
-
let message = null;
|
|
226
|
-
|
|
227
|
-
// Helper for Z-Score color
|
|
228
|
-
const zColor = (z) => {
|
|
229
|
-
const absVal = Math.abs(z);
|
|
230
|
-
const formatted = `${z.toFixed(1)}σ`;
|
|
231
|
-
if (absVal >= CONFIG.Z_EXTREME) return C.valHigh(formatted);
|
|
232
|
-
if (absVal >= CONFIG.Z_HIGH) return C.warn(formatted);
|
|
233
|
-
if (absVal >= CONFIG.Z_BUILDING) return C.val(formatted);
|
|
234
|
-
return C.dim(formatted);
|
|
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) {
|
|
247
|
-
event = 'z_regime';
|
|
248
|
-
// Get instrument-specific market context message
|
|
249
|
-
const marketCtx = bias === 'bullish' ? 'bullish' : bias === 'bearish' ? 'bearish' : 'neutral';
|
|
250
|
-
const instrumentMsg = getContextualMessage(this.symbolCode, this.strategyId, marketCtx);
|
|
251
|
-
|
|
252
|
-
if (zRegime === 'extreme') {
|
|
253
|
-
logType = 'signal';
|
|
254
|
-
const dir = zScore < 0 ? C.long('LONG') : C.short('SHORT');
|
|
255
|
-
const signalMsg = getContextualMessage(this.symbolCode, this.strategyId, 'signal');
|
|
256
|
-
message = `[${C.sym(sym)}] ${C.price(price)} | Z: ${zColor(zScore)} ${C.signal('EXTREME')} | ${dir} | ${C.signal(signalMsg)}`;
|
|
257
|
-
} else if (zRegime === 'high') {
|
|
258
|
-
logType = 'signal';
|
|
259
|
-
message = `[${C.sym(sym)}] ${C.price(price)} | Z: ${zColor(zScore)} ${C.warn('HIGH')} | ${C.dim(instrumentMsg)}`;
|
|
260
|
-
} else if (zRegime === 'building') {
|
|
261
|
-
message = `[${C.sym(sym)}] ${C.price(price)} | Z: ${zColor(zScore)} ${C.info('building')} | ${C.dim(instrumentMsg)}`;
|
|
262
|
-
} else {
|
|
263
|
-
const scanMsg = getContextualMessage(this.symbolCode, this.strategyId, 'scanning');
|
|
264
|
-
message = `[${C.sym(sym)}] ${C.price(price)} | Z: ${C.ok('normalized')} | ${C.dim(scanMsg)}`;
|
|
265
|
-
}
|
|
177
|
+
// Z-Score high - setup forming
|
|
178
|
+
else if (absZ >= CONFIG.Z_HIGH) {
|
|
179
|
+
const needed = (CONFIG.Z_EXTREME - absZ).toFixed(2);
|
|
180
|
+
message = `[${C.sym(sym)}] ${priceDirColor(priceDir)} ${C.price(price)} | Z:${zStr} +${needed}σ to signal | OFI:${ofiStr} | Δ:${deltaStr}`;
|
|
266
181
|
}
|
|
267
|
-
//
|
|
268
|
-
else if (
|
|
269
|
-
|
|
270
|
-
const
|
|
271
|
-
|
|
272
|
-
const newBias = bias === 'bullish' ? C.bull(bias) : C.bear(bias);
|
|
273
|
-
const flipMsg = getContextualMessage(this.symbolCode, this.strategyId, bias);
|
|
274
|
-
message = `[${C.sym(sym)}] ${arrow} OFI: ${oldBias} → ${newBias} | ${C.dim(flipMsg)}`;
|
|
182
|
+
// Z-Score building
|
|
183
|
+
else if (absZ >= CONFIG.Z_BUILDING) {
|
|
184
|
+
const needed = (CONFIG.Z_HIGH - absZ).toFixed(2);
|
|
185
|
+
const bias = zScore < 0 ? 'bid' : 'ask';
|
|
186
|
+
message = `[${C.sym(sym)}] ${priceDirColor(priceDir)} ${C.price(price)} | Z:${zStr} ${bias} pressure | +${needed}σ to setup | Δ:${deltaStr}`;
|
|
275
187
|
}
|
|
276
|
-
//
|
|
277
|
-
else
|
|
278
|
-
|
|
279
|
-
const
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
188
|
+
// Z-Score neutral - scanning
|
|
189
|
+
else {
|
|
190
|
+
// Cycle through different useful info each second to avoid repetition
|
|
191
|
+
const infoType = Math.floor(Date.now() / 1000) % 4;
|
|
192
|
+
let context;
|
|
193
|
+
switch (infoType) {
|
|
194
|
+
case 0:
|
|
195
|
+
context = `Δ:${deltaStr} | Buy:${buyPctRound}%`;
|
|
196
|
+
break;
|
|
197
|
+
case 1:
|
|
198
|
+
context = `VPIN:${vpinStr} | OFI:${ofiStr}`;
|
|
199
|
+
break;
|
|
200
|
+
case 2:
|
|
201
|
+
context = `${tickVelocity} ticks/s | Δ:${deltaStr}`;
|
|
202
|
+
break;
|
|
203
|
+
default:
|
|
204
|
+
context = `OFI:${ofiStr} | Buy:${buyPctRound}%`;
|
|
285
205
|
}
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
// Update state tracking
|
|
289
|
-
this.lastZRegime = zRegime;
|
|
290
|
-
this.lastBias = bias;
|
|
291
|
-
this.lastVpinToxic = vpinToxic;
|
|
292
|
-
|
|
293
|
-
if (event && message) {
|
|
294
|
-
return { type: logType, message, logToSession: event === 'z_regime' || event === 'bias_flip' };
|
|
206
|
+
message = `[${C.sym(sym)}] ${priceDirColor(priceDir)} ${C.price(price)} | Z:${zStr} scanning | ${context}`;
|
|
295
207
|
}
|
|
296
208
|
|
|
297
|
-
|
|
298
|
-
// Silence = system is scanning, nothing notable happening
|
|
299
|
-
// This is professional HF behavior
|
|
300
|
-
return null;
|
|
209
|
+
return { type: logType, message, logToSession: logType === 'signal' };
|
|
301
210
|
}
|
|
302
211
|
|
|
303
212
|
reset() {
|
|
304
|
-
this.
|
|
305
|
-
this.
|
|
306
|
-
this.
|
|
307
|
-
this.
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
this.lastVpinToxic = false;
|
|
213
|
+
this.lastLogHash = null;
|
|
214
|
+
this.lastLogTime = 0;
|
|
215
|
+
this.eventCounter = 0;
|
|
216
|
+
this._lastWarmupMilestone = 0;
|
|
217
|
+
this.prev = {
|
|
218
|
+
zRegime: null,
|
|
219
|
+
ofiDir: null,
|
|
220
|
+
vpinLevel: null,
|
|
221
|
+
position: 0,
|
|
222
|
+
ready: false,
|
|
223
|
+
};
|
|
316
224
|
}
|
|
317
225
|
}
|
|
318
226
|
|
|
319
227
|
function createEngine(strategyId, symbol) { return new SmartLogsEngine(strategyId, symbol); }
|
|
320
|
-
module.exports = { SmartLogsEngine, createEngine, CONFIG };
|
|
228
|
+
module.exports = { SmartLogsEngine, createEngine, CONFIG, C };
|