hedgequantx 2.9.140 → 2.9.142
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 +442 -0
- package/src/lib/smart-logs-live.js +341 -0
- package/src/lib/smart-logs-messages/bias-messages.js +432 -0
- package/src/lib/smart-logs-messages/index.js +51 -0
- package/src/lib/smart-logs-messages/strategy-messages.js +176 -0
- package/src/lib/smart-logs-messages/trade-messages.js +187 -0
- package/src/lib/smart-logs-messages.js +3 -852
- package/src/lib/smart-logs.js +70 -0
- package/src/pages/algo/algo-executor.js +48 -83
- package/src/pages/algo/multi-symbol-executor.js +57 -14
package/src/lib/smart-logs.js
CHANGED
|
@@ -37,6 +37,15 @@ const {
|
|
|
37
37
|
STRATEGY_MESSAGES,
|
|
38
38
|
} = require('./smart-logs-messages');
|
|
39
39
|
|
|
40
|
+
const {
|
|
41
|
+
LIVE_BULLISH,
|
|
42
|
+
LIVE_BEARISH,
|
|
43
|
+
LIVE_NEUTRAL,
|
|
44
|
+
LIVE_BUILDING,
|
|
45
|
+
LIVE_ZONES,
|
|
46
|
+
LIVE_READY,
|
|
47
|
+
} = require('./smart-logs-live');
|
|
48
|
+
|
|
40
49
|
// Current strategy ID for context-aware messages
|
|
41
50
|
let currentStrategyId = null;
|
|
42
51
|
|
|
@@ -245,6 +254,66 @@ function getPriceChangeLog(direction, price, change) {
|
|
|
245
254
|
return { message: `${arrow} ${price.toFixed(2)}`, details: `${direction} ${change.toFixed(2)}` };
|
|
246
255
|
}
|
|
247
256
|
|
|
257
|
+
/**
|
|
258
|
+
* Get live analysis log based on market and strategy state
|
|
259
|
+
* @param {Object} state - Current state
|
|
260
|
+
* @param {string} state.trend - 'bullish', 'bearish', or 'neutral'
|
|
261
|
+
* @param {number} state.bars - Number of bars processed
|
|
262
|
+
* @param {number} state.swings - Number of swings detected
|
|
263
|
+
* @param {number} state.zones - Number of active zones
|
|
264
|
+
* @param {number} state.price - Current price
|
|
265
|
+
* @param {boolean} state.nearZone - Whether price is near a zone
|
|
266
|
+
* @param {boolean} state.setupForming - Whether a setup is forming
|
|
267
|
+
* @returns {string} Contextual analysis message
|
|
268
|
+
*/
|
|
269
|
+
function getLiveAnalysisLog(state = {}) {
|
|
270
|
+
const { trend, bars, swings, zones, nearZone, setupForming } = state;
|
|
271
|
+
|
|
272
|
+
let pool;
|
|
273
|
+
let category;
|
|
274
|
+
|
|
275
|
+
// Determine which pool to use based on state priority
|
|
276
|
+
if (setupForming && zones > 0) {
|
|
277
|
+
// Setup is forming - high priority
|
|
278
|
+
pool = LIVE_READY;
|
|
279
|
+
category = 'live_ready';
|
|
280
|
+
} else if (nearZone && zones > 0) {
|
|
281
|
+
// Near a zone - watching
|
|
282
|
+
pool = LIVE_ZONES;
|
|
283
|
+
category = 'live_zones';
|
|
284
|
+
} else if (zones > 0 && swings >= 2) {
|
|
285
|
+
// Have zones and swings - market pool based on trend
|
|
286
|
+
if (trend === 'bullish') {
|
|
287
|
+
pool = LIVE_BULLISH;
|
|
288
|
+
category = 'live_bullish';
|
|
289
|
+
} else if (trend === 'bearish') {
|
|
290
|
+
pool = LIVE_BEARISH;
|
|
291
|
+
category = 'live_bearish';
|
|
292
|
+
} else {
|
|
293
|
+
pool = LIVE_NEUTRAL;
|
|
294
|
+
category = 'live_neutral';
|
|
295
|
+
}
|
|
296
|
+
} else if (bars < 10 || swings < 2) {
|
|
297
|
+
// Still building structure
|
|
298
|
+
pool = LIVE_BUILDING;
|
|
299
|
+
category = 'live_building';
|
|
300
|
+
} else {
|
|
301
|
+
// Default to market trend
|
|
302
|
+
if (trend === 'bullish') {
|
|
303
|
+
pool = LIVE_BULLISH;
|
|
304
|
+
category = 'live_bullish';
|
|
305
|
+
} else if (trend === 'bearish') {
|
|
306
|
+
pool = LIVE_BEARISH;
|
|
307
|
+
category = 'live_bearish';
|
|
308
|
+
} else {
|
|
309
|
+
pool = LIVE_NEUTRAL;
|
|
310
|
+
category = 'live_neutral';
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
return getVariedMessage(category, pool, 'Analyzing market conditions...');
|
|
315
|
+
}
|
|
316
|
+
|
|
248
317
|
module.exports = {
|
|
249
318
|
getMarketBiasLog,
|
|
250
319
|
getSignalLog,
|
|
@@ -260,5 +329,6 @@ module.exports = {
|
|
|
260
329
|
getModelAnalysisLog,
|
|
261
330
|
getPositionUpdateLog,
|
|
262
331
|
getPriceChangeLog,
|
|
332
|
+
getLiveAnalysisLog,
|
|
263
333
|
setStrategy,
|
|
264
334
|
};
|
|
@@ -7,6 +7,7 @@ const { loadStrategy } = require('../../lib/m');
|
|
|
7
7
|
const { MarketDataFeed } = require('../../lib/data');
|
|
8
8
|
const { SupervisionEngine } = require('../../services/ai-supervision');
|
|
9
9
|
const smartLogs = require('../../lib/smart-logs');
|
|
10
|
+
const { createEngine: createLogsEngine } = require('../../lib/smart-logs-engine');
|
|
10
11
|
const { sessionLogger } = require('../../services/session-logger');
|
|
11
12
|
|
|
12
13
|
/**
|
|
@@ -45,29 +46,13 @@ const executeAlgo = async ({ service, account, contract, config, strategy: strat
|
|
|
45
46
|
});
|
|
46
47
|
|
|
47
48
|
const stats = {
|
|
48
|
-
accountName,
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
target: dailyTarget,
|
|
52
|
-
risk: maxRisk,
|
|
53
|
-
propfirm: account.propfirm || 'Unknown',
|
|
54
|
-
platform: account.platform || 'Rithmic',
|
|
55
|
-
pnl: 0,
|
|
56
|
-
trades: 0,
|
|
57
|
-
wins: 0,
|
|
58
|
-
losses: 0,
|
|
59
|
-
latency: 0,
|
|
60
|
-
connected: false,
|
|
61
|
-
startTime: Date.now()
|
|
49
|
+
accountName, symbol: symbolName, qty: contracts, target: dailyTarget, risk: maxRisk,
|
|
50
|
+
propfirm: account.propfirm || 'Unknown', platform: account.platform || 'Rithmic',
|
|
51
|
+
pnl: 0, trades: 0, wins: 0, losses: 0, latency: 0, connected: false, startTime: Date.now()
|
|
62
52
|
};
|
|
63
53
|
|
|
64
|
-
let running = true;
|
|
65
|
-
let
|
|
66
|
-
let startingPnL = null;
|
|
67
|
-
let currentPosition = 0;
|
|
68
|
-
let pendingOrder = false;
|
|
69
|
-
let tickCount = 0;
|
|
70
|
-
let lastBias = 'FLAT';
|
|
54
|
+
let running = true, stopReason = null, startingPnL = null;
|
|
55
|
+
let currentPosition = 0, pendingOrder = false, tickCount = 0, lastBias = 'FLAT';
|
|
71
56
|
|
|
72
57
|
const aiContext = { recentTicks: [], recentSignals: [], recentTrades: [], maxTicks: 100 };
|
|
73
58
|
|
|
@@ -76,6 +61,7 @@ const executeAlgo = async ({ service, account, contract, config, strategy: strat
|
|
|
76
61
|
|
|
77
62
|
// Set strategy for context-aware smart logs
|
|
78
63
|
smartLogs.setStrategy(strategyId);
|
|
64
|
+
const logsEngine = createLogsEngine(strategyId, symbolCode);
|
|
79
65
|
|
|
80
66
|
// Start session logger for persistent logs
|
|
81
67
|
const logFile = sessionLogger.start({
|
|
@@ -234,28 +220,18 @@ const executeAlgo = async ({ service, account, contract, config, strategy: strat
|
|
|
234
220
|
pendingOrder = false;
|
|
235
221
|
});
|
|
236
222
|
|
|
237
|
-
let lastPrice = null;
|
|
238
|
-
let
|
|
239
|
-
let
|
|
240
|
-
let
|
|
241
|
-
let lastTickSecond = Math.floor(Date.now() / 1000);
|
|
242
|
-
let lastBiasLogSecond = 0;
|
|
243
|
-
let lastDebugLogSecond = 0;
|
|
244
|
-
let lastStateLogSecond = 0;
|
|
245
|
-
let buyVolume = 0;
|
|
246
|
-
let sellVolume = 0;
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
let lastTickTime = 0;
|
|
250
|
-
let tickLatencies = [];
|
|
223
|
+
let lastPrice = null, lastBid = null, lastAsk = null;
|
|
224
|
+
let ticksPerSecond = 0, lastTickSecond = Math.floor(Date.now() / 1000);
|
|
225
|
+
let lastBiasLogSecond = 0, lastStateLogSecond = 0;
|
|
226
|
+
let buyVolume = 0, sellVolume = 0, lastTickTime = 0, tickLatencies = [];
|
|
251
227
|
|
|
252
228
|
marketFeed.on('tick', (tick) => {
|
|
253
229
|
tickCount++;
|
|
254
230
|
const now = Date.now();
|
|
255
231
|
const currentSecond = Math.floor(now / 1000);
|
|
256
232
|
|
|
257
|
-
// Debug first
|
|
258
|
-
if (tickCount
|
|
233
|
+
// Debug first tick
|
|
234
|
+
if (tickCount === 1) {
|
|
259
235
|
const p = Number(tick.price) || Number(tick.tradePrice) || 'NULL';
|
|
260
236
|
sessionLogger.log('TICK', `#${tickCount} price=${p} symbol=${tick.symbol || tick.contractId || 'N/A'}`);
|
|
261
237
|
}
|
|
@@ -284,66 +260,27 @@ const executeAlgo = async ({ service, account, contract, config, strategy: strat
|
|
|
284
260
|
else if (price < lastPrice) sellVolume += volume;
|
|
285
261
|
}
|
|
286
262
|
|
|
287
|
-
// Log first tick
|
|
263
|
+
// Log first tick
|
|
288
264
|
if (tickCount === 1) {
|
|
289
265
|
ui.addLog('connected', `First tick @ ${price?.toFixed(2) || 'N/A'}`);
|
|
290
266
|
}
|
|
291
267
|
|
|
292
|
-
//
|
|
293
|
-
if (currentSecond - lastDebugLogSecond >= 60) {
|
|
294
|
-
lastDebugLogSecond = currentSecond;
|
|
295
|
-
const state = strategy.getAnalysisState?.(contractId, price);
|
|
296
|
-
const bars = state?.barsProcessed || 0;
|
|
297
|
-
ui.addLog('debug', `Ticks: ${tickCount} | Bars: ${bars} | Price: ${price?.toFixed(2)}`);
|
|
298
|
-
}
|
|
299
|
-
|
|
300
|
-
// === SMART LOGS - REDUCED FREQUENCY ===
|
|
301
|
-
// Log bias every 30 seconds (was 5s - too verbose)
|
|
268
|
+
// Update bias from volume + log tick stats (every 30s)
|
|
302
269
|
if (currentSecond - lastBiasLogSecond >= 30 && tickCount > 1) {
|
|
303
270
|
lastBiasLogSecond = currentSecond;
|
|
304
|
-
|
|
305
271
|
const totalVol = buyVolume + sellVolume;
|
|
306
272
|
const buyPressure = totalVol > 0 ? (buyVolume / totalVol) * 100 : 50;
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
const biasLog = smartLogs.getMarketBiasLog(bias, delta, buyPressure);
|
|
311
|
-
const biasType = bias === 'LONG' ? 'bullish' : bias === 'SHORT' ? 'bearish' : 'analysis';
|
|
312
|
-
ui.addLog(biasType, `${biasLog.message} ${biasLog.details || ''}`);
|
|
313
|
-
lastBias = bias;
|
|
314
|
-
// Reset volume after logging to avoid accumulation
|
|
315
|
-
buyVolume = 0;
|
|
316
|
-
sellVolume = 0;
|
|
273
|
+
lastBias = buyPressure > 55 ? 'LONG' : buyPressure < 45 ? 'SHORT' : 'FLAT';
|
|
274
|
+
sessionLogger.log('TICK', `count=${tickCount} last=${price?.toFixed(2)} bias=${lastBias} vol=${totalVol}`);
|
|
275
|
+
buyVolume = 0; sellVolume = 0;
|
|
317
276
|
}
|
|
318
277
|
|
|
319
|
-
// Strategy state log
|
|
278
|
+
// Strategy state log for session logger (every 60s)
|
|
320
279
|
if (currentSecond - lastStateLogSecond >= 60 && tickCount > 1) {
|
|
321
280
|
lastStateLogSecond = currentSecond;
|
|
322
281
|
const state = strategy.getAnalysisState?.(contractId, price);
|
|
323
282
|
if (state) {
|
|
324
|
-
|
|
325
|
-
sessionLogger.state(state.activeZones || 0, state.swingsDetected || 0, bars, lastBias);
|
|
326
|
-
if (!state.ready) {
|
|
327
|
-
ui.addLog('system', `${state.message} (${bars} bars)`);
|
|
328
|
-
} else {
|
|
329
|
-
const resStr = state.nearestResistance ? state.nearestResistance.toFixed(2) : '--';
|
|
330
|
-
const supStr = state.nearestSupport ? state.nearestSupport.toFixed(2) : '--';
|
|
331
|
-
|
|
332
|
-
ui.addLog('analysis', `Zones: ${state.activeZones} | R: ${resStr} | S: ${supStr} | Swings: ${state.swingsDetected}`);
|
|
333
|
-
if (price && state.nearestResistance) {
|
|
334
|
-
const gapR = state.nearestResistance - price, ticksR = Math.abs(Math.round(gapR / tickSize));
|
|
335
|
-
if (ticksR <= 50) ui.addLog('analysis', `PROX R: ${Math.abs(gapR).toFixed(2)} pts (${ticksR} ticks) | Sweep ABOVE then reject`);
|
|
336
|
-
}
|
|
337
|
-
if (price && state.nearestSupport) {
|
|
338
|
-
const gapS = price - state.nearestSupport, ticksS = Math.abs(Math.round(gapS / tickSize));
|
|
339
|
-
if (ticksS <= 50) ui.addLog('analysis', `PROX S: ${Math.abs(gapS).toFixed(2)} pts (${ticksS} ticks) | Sweep BELOW then reject`);
|
|
340
|
-
}
|
|
341
|
-
if (state.activeZones === 0) ui.addLog('risk', 'Building liquidity map...');
|
|
342
|
-
else if (!state.nearestSupport && !state.nearestResistance) ui.addLog('risk', 'Zones outside range');
|
|
343
|
-
else if (!state.nearestSupport) ui.addLog('analysis', 'Monitoring R for SHORT sweep');
|
|
344
|
-
else if (!state.nearestResistance) ui.addLog('analysis', 'Monitoring S for LONG sweep');
|
|
345
|
-
else ui.addLog('ready', 'Both zones active - awaiting sweep');
|
|
346
|
-
}
|
|
283
|
+
sessionLogger.state(state.activeZones || 0, state.swingsDetected || 0, state.barsProcessed || 0, lastBias);
|
|
347
284
|
}
|
|
348
285
|
}
|
|
349
286
|
|
|
@@ -468,6 +405,33 @@ const executeAlgo = async ({ service, account, contract, config, strategy: strat
|
|
|
468
405
|
const pnlInterval = setInterval(() => { if (running) pollPnL(); }, 2000);
|
|
469
406
|
pollPnL();
|
|
470
407
|
|
|
408
|
+
// Live analysis logs every 1 second
|
|
409
|
+
let lastLiveLogSecond = 0;
|
|
410
|
+
const liveLogInterval = setInterval(() => {
|
|
411
|
+
if (!running) return;
|
|
412
|
+
const now = Math.floor(Date.now() / 1000);
|
|
413
|
+
if (now === lastLiveLogSecond) return;
|
|
414
|
+
lastLiveLogSecond = now;
|
|
415
|
+
|
|
416
|
+
// Get strategy state for context
|
|
417
|
+
const state = strategy.getAnalysisState?.(contractId, lastPrice);
|
|
418
|
+
const logState = {
|
|
419
|
+
bars: state?.barsProcessed || 0,
|
|
420
|
+
swings: state?.swingsDetected || 0,
|
|
421
|
+
zones: state?.activeZones || 0,
|
|
422
|
+
trend: lastBias === 'LONG' ? 'bullish' : lastBias === 'SHORT' ? 'bearish' : 'neutral',
|
|
423
|
+
nearZone: (state?.nearestSupport || state?.nearestResistance) ? true : false,
|
|
424
|
+
setupForming: state?.ready && state?.activeZones > 0,
|
|
425
|
+
position: currentPosition,
|
|
426
|
+
price: lastPrice || 0,
|
|
427
|
+
tickCount,
|
|
428
|
+
};
|
|
429
|
+
|
|
430
|
+
const log = logsEngine.getLog(logState);
|
|
431
|
+
ui.addLog(log.type, log.message);
|
|
432
|
+
if (log.logToSession) sessionLogger.log('ANALYSIS', log.message);
|
|
433
|
+
}, 1000);
|
|
434
|
+
|
|
471
435
|
const setupKeyHandler = () => {
|
|
472
436
|
if (!process.stdin.isTTY) return null;
|
|
473
437
|
readline.emitKeypressEvents(process.stdin);
|
|
@@ -493,6 +457,7 @@ const executeAlgo = async ({ service, account, contract, config, strategy: strat
|
|
|
493
457
|
|
|
494
458
|
clearInterval(refreshInterval);
|
|
495
459
|
clearInterval(pnlInterval);
|
|
460
|
+
clearInterval(liveLogInterval);
|
|
496
461
|
await marketFeed.disconnect();
|
|
497
462
|
if (cleanupKeys) cleanupKeys();
|
|
498
463
|
ui.cleanup();
|
|
@@ -7,6 +7,7 @@ const { AlgoUI, renderSessionSummary } = require('./ui');
|
|
|
7
7
|
const { loadStrategy } = require('../../lib/m');
|
|
8
8
|
const { MarketDataFeed } = require('../../lib/data');
|
|
9
9
|
const smartLogs = require('../../lib/smart-logs');
|
|
10
|
+
const { createEngine: createLogsEngine } = require('../../lib/smart-logs-engine');
|
|
10
11
|
const { sessionLogger } = require('../../services/session-logger');
|
|
11
12
|
|
|
12
13
|
/**
|
|
@@ -106,6 +107,7 @@ const executeMultiSymbol = async ({ service, account, contracts, config, strateg
|
|
|
106
107
|
});
|
|
107
108
|
|
|
108
109
|
smartLogs.setStrategy(strategyId);
|
|
110
|
+
const logsEngine = createLogsEngine(strategyId);
|
|
109
111
|
|
|
110
112
|
// Start session logger
|
|
111
113
|
const logFile = sessionLogger.start({
|
|
@@ -212,6 +214,7 @@ const executeMultiSymbol = async ({ service, account, contracts, config, strateg
|
|
|
212
214
|
|
|
213
215
|
if (data.stats.tickCount === 1) {
|
|
214
216
|
ui.addLog('connected', `[${symbolCode}] First tick @ ${price?.toFixed(2) || 'N/A'}`);
|
|
217
|
+
sessionLogger.log('TICK', `[${symbolCode}] #1 price=${price} symbol=${symbolCode}`);
|
|
215
218
|
}
|
|
216
219
|
|
|
217
220
|
data.stats.lastPrice = price;
|
|
@@ -237,23 +240,24 @@ const executeMultiSymbol = async ({ service, account, contracts, config, strateg
|
|
|
237
240
|
}
|
|
238
241
|
});
|
|
239
242
|
|
|
240
|
-
// Log aggregated stats periodically (every
|
|
243
|
+
// Log aggregated stats periodically (every 30s to session, every 3min to UI)
|
|
241
244
|
const logInterval = setInterval(() => {
|
|
242
245
|
const now = Math.floor(Date.now() / 1000);
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
246
|
+
let totalTicks = 0, totalBars = 0, totalZones = 0, totalSwings = 0;
|
|
247
|
+
for (const [sym, data] of symbolData) {
|
|
248
|
+
totalTicks += data.stats.tickCount;
|
|
249
|
+
const state = data.strategy.getAnalysisState?.(sym, data.stats.lastPrice);
|
|
250
|
+
totalBars += state?.barsProcessed || 0;
|
|
251
|
+
totalZones += state?.activeZones || 0;
|
|
252
|
+
totalSwings += state?.swingsDetected || 0;
|
|
253
|
+
}
|
|
254
|
+
// Session log every 30s
|
|
255
|
+
if (now - lastLogSecond >= 30) {
|
|
256
|
+
sessionLogger.log('TICK', `count=${totalTicks} bars=${totalBars} zones=${totalZones} swings=${totalSwings}`);
|
|
257
|
+
if (now - lastLogSecond >= 180) {
|
|
258
|
+
ui.addLog('analysis', `Stats: ${totalTicks} ticks | ${totalBars} bars | ${totalZones} zones | ${totalSwings} swings`);
|
|
255
259
|
}
|
|
256
|
-
|
|
260
|
+
lastLogSecond = now;
|
|
257
261
|
}
|
|
258
262
|
}, 10000);
|
|
259
263
|
|
|
@@ -314,6 +318,44 @@ const executeMultiSymbol = async ({ service, account, contracts, config, strateg
|
|
|
314
318
|
const pnlInterval = setInterval(() => { if (running) pollPnL(); }, 2000);
|
|
315
319
|
pollPnL();
|
|
316
320
|
|
|
321
|
+
// Live analysis logs every 1 second (rotates through symbols)
|
|
322
|
+
let liveLogSymbolIndex = 0;
|
|
323
|
+
let lastLiveLogSecond = 0;
|
|
324
|
+
const liveLogInterval = setInterval(() => {
|
|
325
|
+
if (!running) return;
|
|
326
|
+
const now = Math.floor(Date.now() / 1000);
|
|
327
|
+
if (now === lastLiveLogSecond) return;
|
|
328
|
+
lastLiveLogSecond = now;
|
|
329
|
+
|
|
330
|
+
// Get a symbol to log (rotate through all)
|
|
331
|
+
const symbolCodes = Array.from(symbolData.keys());
|
|
332
|
+
if (symbolCodes.length === 0) return;
|
|
333
|
+
|
|
334
|
+
const symbolCode = symbolCodes[liveLogSymbolIndex % symbolCodes.length];
|
|
335
|
+
liveLogSymbolIndex++;
|
|
336
|
+
|
|
337
|
+
const data = symbolData.get(symbolCode);
|
|
338
|
+
if (!data) return;
|
|
339
|
+
|
|
340
|
+
const state = data.strategy.getAnalysisState?.(symbolCode, data.stats.lastPrice);
|
|
341
|
+
const logState = {
|
|
342
|
+
bars: state?.barsProcessed || 0,
|
|
343
|
+
swings: state?.swingsDetected || 0,
|
|
344
|
+
zones: state?.activeZones || 0,
|
|
345
|
+
trend: 'neutral',
|
|
346
|
+
nearZone: (state?.nearestSupport || state?.nearestResistance) ? true : false,
|
|
347
|
+
setupForming: state?.ready && state?.activeZones > 0,
|
|
348
|
+
position: data.stats.position || 0,
|
|
349
|
+
price: data.stats.lastPrice || 0,
|
|
350
|
+
tickCount: data.stats.tickCount || 0,
|
|
351
|
+
};
|
|
352
|
+
|
|
353
|
+
logsEngine.setSymbol(symbolCode);
|
|
354
|
+
const log = logsEngine.getLog(logState);
|
|
355
|
+
ui.addLog(log.type, log.message);
|
|
356
|
+
if (log.logToSession) sessionLogger.log('ANALYSIS', `[${symbolCode}] ${log.message}`);
|
|
357
|
+
}, 1000);
|
|
358
|
+
|
|
317
359
|
// Key handler
|
|
318
360
|
const setupKeyHandler = () => {
|
|
319
361
|
if (!process.stdin.isTTY) return null;
|
|
@@ -344,6 +386,7 @@ const executeMultiSymbol = async ({ service, account, contracts, config, strateg
|
|
|
344
386
|
clearInterval(refreshInterval);
|
|
345
387
|
clearInterval(pnlInterval);
|
|
346
388
|
clearInterval(logInterval);
|
|
389
|
+
clearInterval(liveLogInterval);
|
|
347
390
|
await marketFeed.disconnect();
|
|
348
391
|
if (cleanupKeys) cleanupKeys();
|
|
349
392
|
ui.cleanup();
|