hedgequantx 2.9.153 → 2.9.154
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
|
@@ -188,68 +188,59 @@ const QUANT = {
|
|
|
188
188
|
`[${d.sym}] Sharpe estimation | ${d.bars} bars | Risk-adjusted return`,
|
|
189
189
|
]),
|
|
190
190
|
|
|
191
|
-
zones: (d) =>
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
`[${d.sym}] Fair value divergence | ${d.price} | Z: ${z}σ | Reversion setup`,
|
|
209
|
-
]);
|
|
210
|
-
},
|
|
191
|
+
zones: (d) => pick([
|
|
192
|
+
`[${d.sym}] ${d.price} | Z: ${d.zScore}σ | VPIN: ${d.vpin}% | Factors converging`,
|
|
193
|
+
`[${d.sym}] ${d.price} | Statistical edge forming | Z: ${d.zScore}σ | OFI: ${d.ofi}`,
|
|
194
|
+
`[${d.sym}] Factor alignment | ${d.ticks} ticks | Z: ${d.zScore}σ | Threshold proximity`,
|
|
195
|
+
`[${d.sym}] ${d.price} | Multi-factor scan | Z: ${d.zScore}σ | VPIN: ${d.vpin}%`,
|
|
196
|
+
`[${d.sym}] Edge probability rising | Z: ${d.zScore}σ | VPIN: ${d.vpin}% | OFI: ${d.ofi}`,
|
|
197
|
+
`[${d.sym}] ${d.price} | Regime analysis | Z: ${d.zScore}σ | ${d.ticks} observations`,
|
|
198
|
+
`[${d.sym}] Information ratio calc | ${d.price} | Z: ${d.zScore}σ | Converging`,
|
|
199
|
+
`[${d.sym}] ${d.price} | Alpha scan | Z: ${d.zScore}σ | VPIN: ${d.vpin}%`,
|
|
200
|
+
`[${d.sym}] Signal strength building | ${d.price} | Z: ${d.zScore}σ | OFI: ${d.ofi}`,
|
|
201
|
+
`[${d.sym}] ${d.price} | Factor model active | Z: ${d.zScore}σ | VPIN: ${d.vpin}%`,
|
|
202
|
+
`[${d.sym}] Convergence scan | ${d.price} | OFI: ${d.ofi} | Z: ${d.zScore}σ`,
|
|
203
|
+
`[${d.sym}] ${d.price} | Statistical tension | Z: ${d.zScore}σ | Snap pending`,
|
|
204
|
+
`[${d.sym}] Edge forming @ ${d.price} | Z: ${d.zScore}σ | ${d.ticks} ticks`,
|
|
205
|
+
`[${d.sym}] ${d.price} | Model confidence: ${d.vpin}% VPIN | Z: ${d.zScore}σ`,
|
|
206
|
+
`[${d.sym}] Fair value analysis | ${d.price} | Z: ${d.zScore}σ | OFI: ${d.ofi}`,
|
|
207
|
+
]),
|
|
211
208
|
|
|
212
|
-
bull: (d) =>
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
`[${d.sym}] Statistical momentum | ${d.price} | Delta: +${Math.abs(d.delta)} | Bullish`,
|
|
230
|
-
]);
|
|
231
|
-
},
|
|
209
|
+
bull: (d) => pick([
|
|
210
|
+
`[${d.sym}] ${d.price} | Z: +${d.zScoreAbs}σ | OFI: ${d.ofi} | BUY edge detected`,
|
|
211
|
+
`[${d.sym}] ${d.price} | VPIN: ${d.vpin}% buy | Z: +${d.zScoreAbs}σ | Bullish`,
|
|
212
|
+
`[${d.sym}] Statistical long | Z: +${d.zScoreAbs}σ | Mean reversion BUY | ${d.ticks} ticks`,
|
|
213
|
+
`[${d.sym}] ${d.price} | Factor model: LONG | Z/VPIN/OFI aligned | +EV`,
|
|
214
|
+
`[${d.sym}] Microstructure bullish | Z: +${d.zScoreAbs}σ | VPIN: ${d.vpin}%`,
|
|
215
|
+
`[${d.sym}] ${d.price} | Positive alpha | Z: +${d.zScoreAbs}σ | OFI: ${d.ofi}`,
|
|
216
|
+
`[${d.sym}] Momentum factor bullish | ${d.price} | OFI: ${d.ofi} | Z: +${d.zScoreAbs}σ`,
|
|
217
|
+
`[${d.sym}] ${d.price} | Info ratio: positive | Z: +${d.zScoreAbs}σ | Long edge`,
|
|
218
|
+
`[${d.sym}] Mean below price | ${d.price} | Z: +${d.zScoreAbs}σ | VPIN: ${d.vpin}%`,
|
|
219
|
+
`[${d.sym}] ${d.price} | Buy confidence | OFI: ${d.ofi} | Z: +${d.zScoreAbs}σ`,
|
|
220
|
+
`[${d.sym}] Regime: bullish | ${d.price} | Z: +${d.zScoreAbs}σ | VPIN: ${d.vpin}%`,
|
|
221
|
+
`[${d.sym}] ${d.price} | Positive skew | Z: +${d.zScoreAbs}σ | OFI: ${d.ofi}`,
|
|
222
|
+
`[${d.sym}] Alpha extraction: long | ${d.price} | Z/OFI positive`,
|
|
223
|
+
`[${d.sym}] ${d.price} | Model: BUY | Z: +${d.zScoreAbs}σ | VPIN: ${d.vpin}%`,
|
|
224
|
+
`[${d.sym}] Statistical momentum | ${d.price} | OFI: ${d.ofi} | Bullish`,
|
|
225
|
+
]),
|
|
232
226
|
|
|
233
|
-
bear: (d) =>
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
`[${d.sym}] Statistical momentum | ${d.price} | Delta: ${d.delta} | Bearish`,
|
|
251
|
-
]);
|
|
252
|
-
},
|
|
227
|
+
bear: (d) => pick([
|
|
228
|
+
`[${d.sym}] ${d.price} | Z: -${d.zScoreAbs}σ | OFI: ${d.ofi} | SELL edge detected`,
|
|
229
|
+
`[${d.sym}] ${d.price} | VPIN: ${d.vpin}% sell | Z: -${d.zScoreAbs}σ | Bearish`,
|
|
230
|
+
`[${d.sym}] Statistical short | Z: -${d.zScoreAbs}σ | Mean reversion SELL | ${d.ticks} ticks`,
|
|
231
|
+
`[${d.sym}] ${d.price} | Factor model: SHORT | Z/VPIN/OFI aligned | -EV`,
|
|
232
|
+
`[${d.sym}] Microstructure bearish | Z: -${d.zScoreAbs}σ | VPIN: ${d.vpin}%`,
|
|
233
|
+
`[${d.sym}] ${d.price} | Negative alpha | Z: -${d.zScoreAbs}σ | OFI: ${d.ofi}`,
|
|
234
|
+
`[${d.sym}] Momentum factor bearish | ${d.price} | OFI: ${d.ofi} | Z: -${d.zScoreAbs}σ`,
|
|
235
|
+
`[${d.sym}] ${d.price} | Info ratio: negative | Z: -${d.zScoreAbs}σ | Short edge`,
|
|
236
|
+
`[${d.sym}] Mean above price | ${d.price} | Z: -${d.zScoreAbs}σ | VPIN: ${d.vpin}%`,
|
|
237
|
+
`[${d.sym}] ${d.price} | Sell confidence | OFI: ${d.ofi} | Z: -${d.zScoreAbs}σ`,
|
|
238
|
+
`[${d.sym}] Regime: bearish | ${d.price} | Z: -${d.zScoreAbs}σ | VPIN: ${d.vpin}%`,
|
|
239
|
+
`[${d.sym}] ${d.price} | Negative skew | Z: -${d.zScoreAbs}σ | OFI: ${d.ofi}`,
|
|
240
|
+
`[${d.sym}] Alpha extraction: short | ${d.price} | Z/OFI negative`,
|
|
241
|
+
`[${d.sym}] ${d.price} | Model: SELL | Z: -${d.zScoreAbs}σ | VPIN: ${d.vpin}%`,
|
|
242
|
+
`[${d.sym}] Statistical momentum | ${d.price} | OFI: ${d.ofi} | Bearish`,
|
|
243
|
+
]),
|
|
253
244
|
|
|
254
245
|
neutral: (d) => pick([
|
|
255
246
|
`[${d.sym}] ${d.price} | Z: 0σ | OFI: neutral | No statistical edge | HOLD`,
|
|
@@ -270,19 +261,20 @@ const QUANT = {
|
|
|
270
261
|
]),
|
|
271
262
|
|
|
272
263
|
ready: (d) => {
|
|
273
|
-
|
|
274
|
-
const
|
|
264
|
+
// Use real zScore for direction (rawZScore keeps the sign)
|
|
265
|
+
const side = d.rawZScore > 0 ? 'LONG' : 'SHORT';
|
|
266
|
+
const zSign = d.rawZScore > 0 ? '+' : '-';
|
|
275
267
|
return pick([
|
|
276
|
-
`${chalk.green('■')} [${d.sym}] Z-SCORE BREACH | ${
|
|
277
|
-
`${chalk.green('■')} [${d.sym}] FACTOR CONSENSUS | OFI: ${d.
|
|
278
|
-
`${chalk.green('■')} [${d.sym}] STATISTICAL TRIGGER | VPIN
|
|
279
|
-
`${chalk.green('■')} [${d.sym}] ALPHA DETECTED | ${d.price} |
|
|
280
|
-
`${chalk.green('■')} [${d.sym}] REGIME CONFIRMED | Z: ${
|
|
281
|
-
`${chalk.green('■')} [${d.sym}] MODEL SIGNAL |
|
|
282
|
-
`${chalk.green('■')} [${d.sym}] THRESHOLD BREACH |
|
|
283
|
-
`${chalk.green('■')} [${d.sym}] MEAN REVERSION | Z: ${
|
|
284
|
-
`${chalk.green('■')} [${d.sym}] EDGE CONFIRMED | ${d.price} | ${
|
|
285
|
-
`${chalk.green('■')} [${d.sym}] FACTOR SIGNAL | Z: ${
|
|
268
|
+
`${chalk.green('■')} [${d.sym}] Z-SCORE BREACH | ${zSign}${d.zScoreAbs}σ @ ${d.price} | EXECUTE ${side}`,
|
|
269
|
+
`${chalk.green('■')} [${d.sym}] FACTOR CONSENSUS | Z: ${zSign}${d.zScoreAbs}σ | OFI: ${d.ofi} | ${side} @ ${d.price}`,
|
|
270
|
+
`${chalk.green('■')} [${d.sym}] STATISTICAL TRIGGER | VPIN: ${d.vpin}% | Z: ${zSign}${d.zScoreAbs}σ | ${side}`,
|
|
271
|
+
`${chalk.green('■')} [${d.sym}] ALPHA DETECTED | ${d.price} | Z: ${zSign}${d.zScoreAbs}σ | EXECUTE ${side}`,
|
|
272
|
+
`${chalk.green('■')} [${d.sym}] REGIME CONFIRMED | Z: ${zSign}${d.zScoreAbs}σ | OFI: ${d.ofi} | ${side}`,
|
|
273
|
+
`${chalk.green('■')} [${d.sym}] MODEL SIGNAL | Z: ${zSign}${d.zScoreAbs}σ | VPIN: ${d.vpin}% | ${side} TRIGGER`,
|
|
274
|
+
`${chalk.green('■')} [${d.sym}] THRESHOLD BREACH | Z: ${zSign}${d.zScoreAbs}σ | OFI: ${d.ofi} | ${side} @ ${d.price}`,
|
|
275
|
+
`${chalk.green('■')} [${d.sym}] MEAN REVERSION | Z: ${zSign}${d.zScoreAbs}σ | ${side} CONFIRMED | ${d.price}`,
|
|
276
|
+
`${chalk.green('■')} [${d.sym}] EDGE CONFIRMED | ${d.price} | Z: ${zSign}${d.zScoreAbs}σ | OFI: ${d.ofi} | ${side}`,
|
|
277
|
+
`${chalk.green('■')} [${d.sym}] FACTOR SIGNAL | Z: ${zSign}${d.zScoreAbs}σ | VPIN: ${d.vpin}% | ${side} ACTIVE`,
|
|
286
278
|
]);
|
|
287
279
|
},
|
|
288
280
|
};
|
|
@@ -301,12 +293,6 @@ class SmartLogsEngine {
|
|
|
301
293
|
|
|
302
294
|
setSymbol(s) { this.symbolCode = s; }
|
|
303
295
|
|
|
304
|
-
_phase(st) {
|
|
305
|
-
if (st.setupForming && st.zones > 0) return 'ready';
|
|
306
|
-
if (st.zones > 0 || st.swings >= 2) return 'zones';
|
|
307
|
-
return 'building';
|
|
308
|
-
}
|
|
309
|
-
|
|
310
296
|
_unique(gen, d) {
|
|
311
297
|
let msg, i = 0;
|
|
312
298
|
do { msg = gen(d); i++; } while (this.recent.includes(msg) && i < 15);
|
|
@@ -318,18 +304,23 @@ class SmartLogsEngine {
|
|
|
318
304
|
getLog(state = {}) {
|
|
319
305
|
this.counter++;
|
|
320
306
|
const { trend = 'neutral', position = 0, zones = 0, swings = 0, bars = 0,
|
|
321
|
-
price = 0, delta = 0, buyPct = 50, tickCount = 0
|
|
307
|
+
price = 0, delta = 0, buyPct = 50, tickCount = 0,
|
|
308
|
+
zScore = 0, vpin = 0, ofi = 0, setupForming = false } = state;
|
|
322
309
|
|
|
323
|
-
const
|
|
324
|
-
const
|
|
325
|
-
const bear = trend === 'bearish' || buyPct < 45;
|
|
326
|
-
const T = this.strategyId === 'hqx-2b' ? HQX2B : QUANT;
|
|
310
|
+
const isQuant = this.strategyId !== 'hqx-2b';
|
|
311
|
+
const T = isQuant ? QUANT : HQX2B;
|
|
327
312
|
|
|
328
313
|
const d = {
|
|
329
314
|
sym: getSym(this.symbolCode),
|
|
330
315
|
price: price > 0 ? price.toFixed(2) : '-.--',
|
|
331
316
|
delta, zones, swings, bars,
|
|
332
317
|
ticks: tickCount > 1000 ? `${(tickCount/1000).toFixed(0)}k` : String(tickCount),
|
|
318
|
+
// Real QUANT metrics from strategy (keep sign for direction)
|
|
319
|
+
zScore: zScore.toFixed(2),
|
|
320
|
+
zScoreAbs: Math.abs(zScore).toFixed(2),
|
|
321
|
+
vpin: (vpin * 100).toFixed(0),
|
|
322
|
+
ofi: ofi > 0 ? `+${ofi.toFixed(0)}` : ofi.toFixed(0),
|
|
323
|
+
rawZScore: zScore, // For direction calculation
|
|
333
324
|
};
|
|
334
325
|
|
|
335
326
|
if (position !== 0) {
|
|
@@ -342,14 +333,38 @@ class SmartLogsEngine {
|
|
|
342
333
|
};
|
|
343
334
|
}
|
|
344
335
|
|
|
345
|
-
//
|
|
336
|
+
// Determine phase and message type based on strategy
|
|
346
337
|
let gen, type;
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
338
|
+
|
|
339
|
+
if (isQuant) {
|
|
340
|
+
// QUANT: tick-based, uses zScore/vpin/ofi
|
|
341
|
+
const minTicks = 50;
|
|
342
|
+
const isBuilding = bars < minTicks;
|
|
343
|
+
const bull = trend === 'bullish' || zScore > 1.5 || buyPct > 58;
|
|
344
|
+
const bear = trend === 'bearish' || zScore < -1.5 || buyPct < 42;
|
|
345
|
+
const ready = Math.abs(zScore) > 2.0 && setupForming;
|
|
346
|
+
|
|
347
|
+
if (ready) { gen = T.ready; type = 'signal'; }
|
|
348
|
+
else if (isBuilding) { gen = T.building; type = 'system'; }
|
|
349
|
+
else if (bull) { gen = T.bull; type = 'bullish'; }
|
|
350
|
+
else if (bear) { gen = T.bear; type = 'bearish'; }
|
|
351
|
+
else { gen = T.zones; type = 'analysis'; } // zones = analysis for QUANT
|
|
352
|
+
} else {
|
|
353
|
+
// HQX-2B: bar-based, uses zones/swings
|
|
354
|
+
const minBars = 3;
|
|
355
|
+
const isBuilding = bars < minBars;
|
|
356
|
+
const hasZones = zones > 0 || swings >= 2;
|
|
357
|
+
const bull = trend === 'bullish' || buyPct > 55;
|
|
358
|
+
const bear = trend === 'bearish' || buyPct < 45;
|
|
359
|
+
const ready = setupForming && zones > 0;
|
|
360
|
+
|
|
361
|
+
if (ready) { gen = T.ready; type = 'signal'; }
|
|
362
|
+
else if (isBuilding) { gen = T.building; type = 'system'; }
|
|
363
|
+
else if (bull) { gen = T.bull; type = 'bullish'; }
|
|
364
|
+
else if (bear) { gen = T.bear; type = 'bearish'; }
|
|
365
|
+
else if (hasZones) { gen = T.zones; type = 'analysis'; }
|
|
366
|
+
else { gen = T.neutral; type = 'analysis'; }
|
|
367
|
+
}
|
|
353
368
|
|
|
354
369
|
return {
|
|
355
370
|
type,
|
|
@@ -224,6 +224,7 @@ const executeAlgo = async ({ service, account, contract, config, strategy: strat
|
|
|
224
224
|
let ticksPerSecond = 0, lastTickSecond = Math.floor(Date.now() / 1000);
|
|
225
225
|
let lastBiasLogSecond = 0, lastStateLogSecond = 0;
|
|
226
226
|
let buyVolume = 0, sellVolume = 0, lastTickTime = 0, tickLatencies = [];
|
|
227
|
+
let runningDelta = 0, runningBuyPct = 50; // For live logs
|
|
227
228
|
|
|
228
229
|
marketFeed.on('tick', (tick) => {
|
|
229
230
|
tickCount++;
|
|
@@ -271,6 +272,8 @@ const executeAlgo = async ({ service, account, contract, config, strategy: strat
|
|
|
271
272
|
const totalVol = buyVolume + sellVolume;
|
|
272
273
|
const buyPressure = totalVol > 0 ? (buyVolume / totalVol) * 100 : 50;
|
|
273
274
|
lastBias = buyPressure > 55 ? 'LONG' : buyPressure < 45 ? 'SHORT' : 'FLAT';
|
|
275
|
+
runningDelta = buyVolume - sellVolume;
|
|
276
|
+
runningBuyPct = buyPressure;
|
|
274
277
|
sessionLogger.log('TICK', `count=${tickCount} last=${price?.toFixed(2)} bias=${lastBias} vol=${totalVol}`);
|
|
275
278
|
buyVolume = 0; sellVolume = 0;
|
|
276
279
|
}
|
|
@@ -294,9 +297,10 @@ const executeAlgo = async ({ service, account, contract, config, strategy: strat
|
|
|
294
297
|
lastAsk = ask;
|
|
295
298
|
|
|
296
299
|
// Only process tick if we have a valid price
|
|
300
|
+
// IMPORTANT: Always use our contractId for consistency with getAnalysisState
|
|
297
301
|
if (price && price > 0) {
|
|
298
302
|
strategy.processTick({
|
|
299
|
-
contractId:
|
|
303
|
+
contractId: contractId,
|
|
300
304
|
price: price, bid: bid, ask: ask,
|
|
301
305
|
volume: volume,
|
|
302
306
|
side: tick.side || tick.lastTradeSide || 'unknown',
|
|
@@ -437,7 +441,13 @@ const executeAlgo = async ({ service, account, contract, config, strategy: strat
|
|
|
437
441
|
setupForming: state?.ready && state?.activeZones > 0,
|
|
438
442
|
position: currentPosition,
|
|
439
443
|
price: lastPrice || 0,
|
|
444
|
+
delta: runningDelta,
|
|
445
|
+
buyPct: runningBuyPct,
|
|
440
446
|
tickCount,
|
|
447
|
+
// QUANT strategy metrics (real from strategy)
|
|
448
|
+
zScore: state?.zScore || 0,
|
|
449
|
+
vpin: state?.vpin || 0,
|
|
450
|
+
ofi: state?.ofi || 0,
|
|
441
451
|
};
|
|
442
452
|
|
|
443
453
|
const log = logsEngine.getLog(logState);
|
|
@@ -56,7 +56,11 @@ const executeMultiSymbol = async ({ service, account, contracts, config, strateg
|
|
|
56
56
|
losses: 0,
|
|
57
57
|
tickCount: 0,
|
|
58
58
|
lastPrice: null,
|
|
59
|
-
position: 0
|
|
59
|
+
position: 0,
|
|
60
|
+
buyVolume: 0,
|
|
61
|
+
sellVolume: 0,
|
|
62
|
+
runningDelta: 0,
|
|
63
|
+
runningBuyPct: 50
|
|
60
64
|
},
|
|
61
65
|
pendingOrder: false,
|
|
62
66
|
startingPnL: null
|
|
@@ -219,6 +223,27 @@ const executeMultiSymbol = async ({ service, account, contracts, config, strateg
|
|
|
219
223
|
|
|
220
224
|
data.stats.lastPrice = price;
|
|
221
225
|
|
|
226
|
+
// Track buy/sell volume for delta calculation
|
|
227
|
+
if (tick.side === 'buy' || tick.aggressor === 1) {
|
|
228
|
+
data.stats.buyVolume += volume;
|
|
229
|
+
} else if (tick.side === 'sell' || tick.aggressor === 2) {
|
|
230
|
+
data.stats.sellVolume += volume;
|
|
231
|
+
} else if (price && data.stats.lastPrice) {
|
|
232
|
+
if (price > data.stats.lastPrice) data.stats.buyVolume += volume;
|
|
233
|
+
else if (price < data.stats.lastPrice) data.stats.sellVolume += volume;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
// Update running delta/buyPct every 1000 ticks
|
|
237
|
+
if (data.stats.tickCount % 1000 === 0) {
|
|
238
|
+
const totalVol = data.stats.buyVolume + data.stats.sellVolume;
|
|
239
|
+
if (totalVol > 0) {
|
|
240
|
+
data.stats.runningDelta = data.stats.buyVolume - data.stats.sellVolume;
|
|
241
|
+
data.stats.runningBuyPct = (data.stats.buyVolume / totalVol) * 100;
|
|
242
|
+
}
|
|
243
|
+
data.stats.buyVolume = 0;
|
|
244
|
+
data.stats.sellVolume = 0;
|
|
245
|
+
}
|
|
246
|
+
|
|
222
247
|
// Process tick through strategy
|
|
223
248
|
if (price && price > 0) {
|
|
224
249
|
data.strategy.processTick({
|
|
@@ -363,16 +388,23 @@ const executeMultiSymbol = async ({ service, account, contracts, config, strateg
|
|
|
363
388
|
if (!data) return;
|
|
364
389
|
|
|
365
390
|
const state = data.strategy.getAnalysisState?.(symbolCode, data.stats.lastPrice);
|
|
391
|
+
const buyPct = data.stats.runningBuyPct || 50;
|
|
366
392
|
const logState = {
|
|
367
393
|
bars: state?.barsProcessed || 0,
|
|
368
394
|
swings: state?.swingsDetected || 0,
|
|
369
395
|
zones: state?.activeZones || 0,
|
|
370
|
-
trend: 'neutral',
|
|
396
|
+
trend: buyPct > 55 ? 'bullish' : buyPct < 45 ? 'bearish' : 'neutral',
|
|
371
397
|
nearZone: (state?.nearestSupport || state?.nearestResistance) ? true : false,
|
|
372
398
|
setupForming: state?.ready && state?.activeZones > 0,
|
|
373
399
|
position: data.stats.position || 0,
|
|
374
400
|
price: data.stats.lastPrice || 0,
|
|
401
|
+
delta: data.stats.runningDelta || 0,
|
|
402
|
+
buyPct: buyPct,
|
|
375
403
|
tickCount: data.stats.tickCount || 0,
|
|
404
|
+
// QUANT metrics - REAL values from strategy
|
|
405
|
+
zScore: state?.zScore || 0,
|
|
406
|
+
vpin: state?.vpin || 0,
|
|
407
|
+
ofi: state?.ofi || 0,
|
|
376
408
|
};
|
|
377
409
|
|
|
378
410
|
// Only log if we have meaningful data
|