hedgequantx 2.9.51 → 2.9.52

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.51",
3
+ "version": "2.9.52",
4
4
  "description": "HedgeQuantX - Prop Futures Trading CLI",
5
5
  "main": "src/app.js",
6
6
  "bin": {
@@ -0,0 +1,419 @@
1
+ /**
2
+ * =============================================================================
3
+ * Smart Logging System
4
+ * =============================================================================
5
+ * Non-repetitive, contextual, varied log messages
6
+ * - Uses message pools to avoid repetition
7
+ * - Tracks recent messages to ensure variety
8
+ * - Provides market-context-aware messages
9
+ */
10
+
11
+ 'use strict';
12
+
13
+ // Track recently used messages to avoid repetition
14
+ const recentMessages = new Map();
15
+ const MAX_RECENT = 5;
16
+
17
+ /**
18
+ * Get a message from a pool, avoiding recent ones
19
+ */
20
+ function getVariedMessage(category, pool, defaultMsg) {
21
+ const recent = recentMessages.get(category) || [];
22
+
23
+ // Filter out recently used messages
24
+ const available = pool.filter(msg => !recent.includes(msg));
25
+
26
+ // If all messages were recently used, reset
27
+ if (available.length === 0) {
28
+ recentMessages.set(category, []);
29
+ return pool[Math.floor(Math.random() * pool.length)] || defaultMsg;
30
+ }
31
+
32
+ // Pick a random available message
33
+ const chosen = available[Math.floor(Math.random() * available.length)] || defaultMsg;
34
+
35
+ // Track it
36
+ recent.push(chosen);
37
+ if (recent.length > MAX_RECENT) recent.shift();
38
+ recentMessages.set(category, recent);
39
+
40
+ return chosen;
41
+ }
42
+
43
+ // =============================================================================
44
+ // MESSAGE POOLS - Market Flow
45
+ // =============================================================================
46
+
47
+ const LONG_BIAS_MESSAGES = [
48
+ 'Bullish bias detected',
49
+ 'Buyers in control',
50
+ 'Long-side pressure',
51
+ 'Bid accumulation',
52
+ 'Buy programs active',
53
+ ];
54
+
55
+ const SHORT_BIAS_MESSAGES = [
56
+ 'Bearish bias detected',
57
+ 'Sellers in control',
58
+ 'Short-side pressure',
59
+ 'Offer distribution',
60
+ 'Sell programs active',
61
+ ];
62
+
63
+ const FLAT_BIAS_MESSAGES = [
64
+ 'Market balanced',
65
+ 'Two-way flow',
66
+ 'Consolidation mode',
67
+ 'No clear direction',
68
+ 'Mixed signals',
69
+ ];
70
+
71
+ // =============================================================================
72
+ // MESSAGE POOLS - Trading Events
73
+ // =============================================================================
74
+
75
+ const SIGNAL_LONG_MESSAGES = [
76
+ 'Buy signal generated',
77
+ 'Long opportunity detected',
78
+ 'Bullish setup confirmed',
79
+ 'Entry signal: LONG',
80
+ 'Buy zone activated',
81
+ ];
82
+
83
+ const SIGNAL_SHORT_MESSAGES = [
84
+ 'Sell signal generated',
85
+ 'Short opportunity detected',
86
+ 'Bearish setup confirmed',
87
+ 'Entry signal: SHORT',
88
+ 'Sell zone activated',
89
+ ];
90
+
91
+ const ENTRY_LONG_MESSAGES = [
92
+ 'Long position opened',
93
+ 'Buy order filled',
94
+ 'Entered long',
95
+ 'Long initiated',
96
+ 'Position: LONG',
97
+ ];
98
+
99
+ const ENTRY_SHORT_MESSAGES = [
100
+ 'Short position opened',
101
+ 'Sell order filled',
102
+ 'Entered short',
103
+ 'Short initiated',
104
+ 'Position: SHORT',
105
+ ];
106
+
107
+ const EXIT_PROFIT_MESSAGES = [
108
+ 'Target reached',
109
+ 'Profit taken',
110
+ 'Winner closed',
111
+ 'TP hit',
112
+ 'Profit locked',
113
+ ];
114
+
115
+ const EXIT_LOSS_MESSAGES = [
116
+ 'Stop triggered',
117
+ 'Loss taken',
118
+ 'Loser closed',
119
+ 'SL hit',
120
+ 'Risk contained',
121
+ ];
122
+
123
+ // =============================================================================
124
+ // MESSAGE POOLS - Analysis
125
+ // =============================================================================
126
+
127
+ const ZONE_APPROACH_MESSAGES = [
128
+ 'Approaching key level',
129
+ 'Zone test incoming',
130
+ 'Near decision point',
131
+ 'Level approach detected',
132
+ 'Key zone in range',
133
+ ];
134
+
135
+ const ZONE_CONFIRMED_MESSAGES = [
136
+ 'Zone confirmation',
137
+ 'Level validated',
138
+ 'Support/resistance active',
139
+ 'Zone reaction detected',
140
+ 'Level holding',
141
+ ];
142
+
143
+ const HIGH_VOLATILITY_MESSAGES = [
144
+ 'Volatility elevated',
145
+ 'High ATR detected',
146
+ 'Increased price range',
147
+ 'Market volatile',
148
+ 'Wide swings detected',
149
+ ];
150
+
151
+ const LOW_VOLATILITY_MESSAGES = [
152
+ 'Low volatility',
153
+ 'Tight range detected',
154
+ 'Compressed price action',
155
+ 'Market quiet',
156
+ 'Narrow swings',
157
+ ];
158
+
159
+ // =============================================================================
160
+ // MESSAGE POOLS - Risk
161
+ // =============================================================================
162
+
163
+ const RISK_PASSED_MESSAGES = [
164
+ 'Risk check passed',
165
+ 'Trade approved',
166
+ 'Within risk limits',
167
+ 'Risk validated',
168
+ 'Clear to trade',
169
+ ];
170
+
171
+ const RISK_BLOCKED_MESSAGES = [
172
+ 'Risk limit reached',
173
+ 'Trade blocked',
174
+ 'Exceeds risk threshold',
175
+ 'Risk rejected',
176
+ 'Waiting for conditions',
177
+ ];
178
+
179
+ // =============================================================================
180
+ // MESSAGE POOLS - Status
181
+ // =============================================================================
182
+
183
+ const SCANNING_MESSAGES = [
184
+ 'Scanning market...',
185
+ 'Analyzing flow...',
186
+ 'Monitoring structure...',
187
+ 'Watching for setups...',
188
+ 'Evaluating conditions...',
189
+ ];
190
+
191
+ const WAITING_MESSAGES = [
192
+ 'Waiting for confirmation...',
193
+ 'Pending trigger...',
194
+ 'Standby mode...',
195
+ 'Awaiting signal...',
196
+ 'Ready to act...',
197
+ ];
198
+
199
+ // =============================================================================
200
+ // MESSAGE POOLS - Tick Flow
201
+ // =============================================================================
202
+
203
+ const TICK_FLOW_MESSAGES = [
204
+ 'Processing tick data',
205
+ 'Market data flowing',
206
+ 'Live feed active',
207
+ 'Tick stream healthy',
208
+ 'Data streaming',
209
+ ];
210
+
211
+ const BUILDING_BARS_MESSAGES = [
212
+ 'Building price bars',
213
+ 'Aggregating ticks',
214
+ 'Forming candles',
215
+ 'Bar construction',
216
+ 'Chart building',
217
+ ];
218
+
219
+ const MODEL_ANALYSIS_MESSAGES = [
220
+ 'Running models',
221
+ 'Analyzing patterns',
222
+ 'Computing signals',
223
+ 'Model evaluation',
224
+ 'Strategy analysis',
225
+ ];
226
+
227
+ // =============================================================================
228
+ // SMART LOG GENERATORS
229
+ // =============================================================================
230
+
231
+ /**
232
+ * Get a market bias log
233
+ */
234
+ function getMarketBiasLog(direction, delta, buyPressure) {
235
+ let pool;
236
+ switch (direction) {
237
+ case 'LONG': pool = LONG_BIAS_MESSAGES; break;
238
+ case 'SHORT': pool = SHORT_BIAS_MESSAGES; break;
239
+ default: pool = FLAT_BIAS_MESSAGES;
240
+ }
241
+
242
+ const message = getVariedMessage(`bias_${direction}`, pool, `${direction} bias`);
243
+ const arrow = direction === 'LONG' ? '▲' : direction === 'SHORT' ? '▼' : '=';
244
+
245
+ let details;
246
+ if (delta !== undefined && buyPressure !== undefined) {
247
+ details = `${arrow} delta: ${delta > 0 ? '+' : ''}${delta} | buy: ${buyPressure.toFixed(0)}%`;
248
+ }
249
+
250
+ return { message, details };
251
+ }
252
+
253
+ /**
254
+ * Get a signal log
255
+ */
256
+ function getSignalLog(direction, symbol, confidence, strategy) {
257
+ const pool = direction === 'LONG' ? SIGNAL_LONG_MESSAGES : SIGNAL_SHORT_MESSAGES;
258
+ const message = getVariedMessage(`signal_${direction}`, pool, `${direction} signal`);
259
+ const arrow = direction === 'LONG' ? '▲' : '▼';
260
+
261
+ return {
262
+ message: `${arrow} ${message}`,
263
+ details: `${symbol} | ${confidence.toFixed(0)}% | ${strategy}`,
264
+ };
265
+ }
266
+
267
+ /**
268
+ * Get an entry log
269
+ */
270
+ function getEntryLog(direction, symbol, size, price) {
271
+ const pool = direction === 'LONG' ? ENTRY_LONG_MESSAGES : ENTRY_SHORT_MESSAGES;
272
+ const message = getVariedMessage(`entry_${direction}`, pool, `${direction} entry`);
273
+ const arrow = direction === 'LONG' ? '▲' : '▼';
274
+
275
+ return {
276
+ message: `${arrow} ${message}`,
277
+ details: `${size}x ${symbol} @ ${price.toFixed(2)}`,
278
+ };
279
+ }
280
+
281
+ /**
282
+ * Get an exit log
283
+ */
284
+ function getExitLog(isProfit, symbol, size, price, pnl) {
285
+ const pool = isProfit ? EXIT_PROFIT_MESSAGES : EXIT_LOSS_MESSAGES;
286
+ const category = isProfit ? 'exit_profit' : 'exit_loss';
287
+ const message = getVariedMessage(category, pool, isProfit ? 'Profit taken' : 'Loss taken');
288
+ const pnlStr = pnl >= 0 ? `+$${pnl.toFixed(2)}` : `-$${Math.abs(pnl).toFixed(2)}`;
289
+
290
+ return {
291
+ message,
292
+ details: `${size}x ${symbol} @ ${price.toFixed(2)} | ${pnlStr}`,
293
+ };
294
+ }
295
+
296
+ /**
297
+ * Get a zone approach log
298
+ */
299
+ function getZoneApproachLog(zoneType, level) {
300
+ const message = getVariedMessage('zone_approach', ZONE_APPROACH_MESSAGES, 'Zone approach');
301
+ return { message, details: `${zoneType} @ ${level.toFixed(2)}` };
302
+ }
303
+
304
+ /**
305
+ * Get a zone confirmation log
306
+ */
307
+ function getZoneConfirmationLog(zoneType, level) {
308
+ const message = getVariedMessage('zone_confirm', ZONE_CONFIRMED_MESSAGES, 'Zone confirmed');
309
+ return { message, details: `${zoneType} @ ${level.toFixed(2)}` };
310
+ }
311
+
312
+ /**
313
+ * Get a volatility log
314
+ */
315
+ function getVolatilityLog(isHigh, atr) {
316
+ const pool = isHigh ? HIGH_VOLATILITY_MESSAGES : LOW_VOLATILITY_MESSAGES;
317
+ const category = isHigh ? 'vol_high' : 'vol_low';
318
+ const message = getVariedMessage(category, pool, isHigh ? 'High volatility' : 'Low volatility');
319
+ return { message, details: atr ? `ATR: ${atr.toFixed(2)}` : undefined };
320
+ }
321
+
322
+ /**
323
+ * Get a risk check log
324
+ */
325
+ function getRiskCheckLog(passed, reason) {
326
+ const pool = passed ? RISK_PASSED_MESSAGES : RISK_BLOCKED_MESSAGES;
327
+ const category = passed ? 'risk_pass' : 'risk_block';
328
+ const message = getVariedMessage(category, pool, passed ? 'Passed' : 'Blocked');
329
+ return { message, details: reason };
330
+ }
331
+
332
+ /**
333
+ * Get a scanning/waiting log
334
+ */
335
+ function getScanningLog(isScanning = true) {
336
+ const pool = isScanning ? SCANNING_MESSAGES : WAITING_MESSAGES;
337
+ const category = isScanning ? 'scanning' : 'waiting';
338
+ const message = getVariedMessage(category, pool, isScanning ? 'Scanning...' : 'Waiting...');
339
+ return { message };
340
+ }
341
+
342
+ /**
343
+ * Get tick flow log
344
+ */
345
+ function getTickFlowLog(tickCount, ticksPerSecond) {
346
+ const message = getVariedMessage('tick_flow', TICK_FLOW_MESSAGES, 'Tick flow');
347
+ return { message, details: `#${tickCount} | ${ticksPerSecond}/sec` };
348
+ }
349
+
350
+ /**
351
+ * Get building bars log
352
+ */
353
+ function getBuildingBarsLog(barCount) {
354
+ const message = getVariedMessage('building_bars', BUILDING_BARS_MESSAGES, 'Building bars');
355
+ return { message, details: `${barCount} bars` };
356
+ }
357
+
358
+ /**
359
+ * Get model analysis log
360
+ */
361
+ function getModelAnalysisLog(modelValues) {
362
+ const message = getVariedMessage('model_analysis', MODEL_ANALYSIS_MESSAGES, 'Analyzing');
363
+ const details = modelValues
364
+ ? `Z:${modelValues.zscore} | VPIN:${modelValues.vpin} | OFI:${modelValues.ofi}`
365
+ : undefined;
366
+ return { message, details };
367
+ }
368
+
369
+ /**
370
+ * Get position update log with varied messaging
371
+ */
372
+ function getPositionUpdateLog(side, size, unrealizedPnL, distanceToStop, distanceToTarget, holdTime) {
373
+ const arrow = side === 'LONG' ? '▲' : '▼';
374
+ const pnlStr = unrealizedPnL >= 0 ? `+$${unrealizedPnL.toFixed(2)}` : `-$${Math.abs(unrealizedPnL).toFixed(2)}`;
375
+
376
+ // Vary the message based on P&L status
377
+ let prefix;
378
+ if (unrealizedPnL > 0 && distanceToTarget < distanceToStop) {
379
+ const targetPct = Math.round((1 - distanceToTarget / (distanceToStop + distanceToTarget)) * 100);
380
+ prefix = targetPct > 75 ? 'Near target' : targetPct > 50 ? 'Running profit' : 'In profit';
381
+ } else if (unrealizedPnL < 0 && distanceToStop < distanceToTarget) {
382
+ const risk = Math.round((1 - distanceToStop / (distanceToStop + distanceToTarget)) * 100);
383
+ prefix = risk > 75 ? 'Stop risk' : risk > 50 ? 'Underwater' : 'Managing loss';
384
+ } else if (Math.abs(unrealizedPnL) < 5) {
385
+ prefix = 'Near entry';
386
+ } else {
387
+ prefix = unrealizedPnL > 0 ? 'In profit' : 'Managing';
388
+ }
389
+
390
+ return {
391
+ message: `${arrow} ${side} ${size}x`,
392
+ details: `${prefix}: ${pnlStr} | SL: ${distanceToStop.toFixed(0)}t | TP: ${distanceToTarget.toFixed(0)}t | ${holdTime}s`,
393
+ };
394
+ }
395
+
396
+ /**
397
+ * Get price change log
398
+ */
399
+ function getPriceChangeLog(direction, price, change) {
400
+ const arrow = direction === 'UP' ? '▲' : '▼';
401
+ return { message: `${arrow} ${price.toFixed(2)}`, details: `${direction} ${change.toFixed(2)}` };
402
+ }
403
+
404
+ module.exports = {
405
+ getMarketBiasLog,
406
+ getSignalLog,
407
+ getEntryLog,
408
+ getExitLog,
409
+ getZoneApproachLog,
410
+ getZoneConfirmationLog,
411
+ getVolatilityLog,
412
+ getRiskCheckLog,
413
+ getScanningLog,
414
+ getTickFlowLog,
415
+ getBuildingBarsLog,
416
+ getModelAnalysisLog,
417
+ getPositionUpdateLog,
418
+ getPriceChangeLog,
419
+ };
@@ -9,6 +9,7 @@ const { AlgoUI, renderSessionSummary } = require('./ui');
9
9
  const { loadStrategy } = require('../../lib/m');
10
10
  const { MarketDataFeed } = require('../../lib/data');
11
11
  const { SupervisionEngine } = require('../../services/ai-supervision');
12
+ const smartLogs = require('../../lib/smart-logs');
12
13
 
13
14
  /**
14
15
  * Execute algo strategy with market data
@@ -37,7 +38,8 @@ const executeAlgo = async ({ service, account, contract, config, strategy: strat
37
38
  const accountName = showName
38
39
  ? (account.accountName || account.rithmicAccountId || account.accountId)
39
40
  : 'HQX *****';
40
- const symbolName = contract.name;
41
+ const symbolName = contract.name; // Display name: "Micro E-mini S&P 500"
42
+ const symbolCode = contract.symbol || contract.id; // Rithmic symbol: "MESH6"
41
43
  const contractId = contract.id;
42
44
  const tickSize = contract.tickSize || 0.25;
43
45
 
@@ -93,18 +95,24 @@ const executeAlgo = async ({ service, account, contract, config, strategy: strat
93
95
 
94
96
  // Handle strategy signals
95
97
  strategy.on('signal', async (signal) => {
96
- ui.addLog('info', `SIGNAL DETECTED: ${signal.direction?.toUpperCase()}`);
98
+ const dir = signal.direction?.toUpperCase() || 'UNKNOWN';
99
+ const signalLog = smartLogs.getSignalLog(dir, symbolCode, (signal.confidence || 0) * 100, strategyName);
100
+ ui.addLog('info', `${signalLog.message}`);
101
+ ui.addLog('info', signalLog.details);
97
102
 
98
103
  if (!running) {
99
- ui.addLog('info', 'Signal ignored: not running');
104
+ const riskLog = smartLogs.getRiskCheckLog(false, 'Algo stopped');
105
+ ui.addLog('info', riskLog.message);
100
106
  return;
101
107
  }
102
108
  if (pendingOrder) {
103
- ui.addLog('info', 'Signal ignored: order pending');
109
+ const riskLog = smartLogs.getRiskCheckLog(false, 'Order pending');
110
+ ui.addLog('info', riskLog.message);
104
111
  return;
105
112
  }
106
113
  if (currentPosition !== 0) {
107
- ui.addLog('info', `Signal ignored: position open (${currentPosition})`);
114
+ const riskLog = smartLogs.getRiskCheckLog(false, `Position open (${currentPosition})`);
115
+ ui.addLog('info', riskLog.message);
108
116
  return;
109
117
  }
110
118
 
@@ -114,7 +122,8 @@ const executeAlgo = async ({ service, account, contract, config, strategy: strat
114
122
  aiContext.recentSignals.push({ ...signal, timestamp: Date.now() });
115
123
  if (aiContext.recentSignals.length > 10) aiContext.recentSignals.shift();
116
124
 
117
- ui.addLog('info', `Signal: ${direction.toUpperCase()} @ ${entry.toFixed(2)} (${(confidence * 100).toFixed(0)}%)`);
125
+ const riskLog = smartLogs.getRiskCheckLog(true, `${direction.toUpperCase()} @ ${entry.toFixed(2)}`);
126
+ ui.addLog('info', `${riskLog.message} - ${riskLog.details}`);
118
127
 
119
128
  // Multi-Agent AI Supervision
120
129
  if (supervisionEnabled && supervisionEngine) {
@@ -173,8 +182,9 @@ const executeAlgo = async ({ service, account, contract, config, strategy: strat
173
182
  if (orderResult.success) {
174
183
  currentPosition = direction === 'long' ? orderSize : -orderSize;
175
184
  stats.trades++;
176
- ui.addLog('fill_' + (direction === 'long' ? 'buy' : 'sell'),
177
- `OPENED ${direction.toUpperCase()} ${orderSize}x @ market`);
185
+ const entryLog = smartLogs.getEntryLog(direction.toUpperCase(), symbolCode, orderSize, entry);
186
+ ui.addLog('fill_' + (direction === 'long' ? 'buy' : 'sell'), entryLog.message);
187
+ ui.addLog('info', entryLog.details);
178
188
 
179
189
  // Bracket orders
180
190
  if (stopLoss && takeProfit) {
@@ -203,6 +213,10 @@ const executeAlgo = async ({ service, account, contract, config, strategy: strat
203
213
  let lastAsk = null;
204
214
  let ticksPerSecond = 0;
205
215
  let lastTickSecond = Math.floor(Date.now() / 1000);
216
+ let lastLogSecond = 0;
217
+ let buyVolume = 0;
218
+ let sellVolume = 0;
219
+ let barCount = 0;
206
220
 
207
221
  marketFeed.on('tick', (tick) => {
208
222
  tickCount++;
@@ -220,32 +234,69 @@ const executeAlgo = async ({ service, account, contract, config, strategy: strat
220
234
  aiContext.recentTicks.push(tick);
221
235
  if (aiContext.recentTicks.length > aiContext.maxTicks) aiContext.recentTicks.shift();
222
236
 
223
- // Smart logs for tick flow
224
237
  const price = tick.price || tick.tradePrice;
225
238
  const bid = tick.bid || tick.bidPrice;
226
239
  const ask = tick.ask || tick.askPrice;
240
+ const volume = tick.volume || tick.size || 1;
241
+
242
+ // Track buy/sell volume
243
+ if (tick.side === 'buy' || tick.aggressor === 1) buyVolume += volume;
244
+ else if (tick.side === 'sell' || tick.aggressor === 2) sellVolume += volume;
245
+ else if (price && lastPrice) {
246
+ if (price > lastPrice) buyVolume += volume;
247
+ else if (price < lastPrice) sellVolume += volume;
248
+ }
227
249
 
228
250
  // Log first tick
229
251
  if (tickCount === 1) {
230
- ui.addLog('info', `First tick received @ ${price?.toFixed(2) || 'N/A'}`);
231
- ui.addLog('info', `Tick type: ${tick.type || 'unknown'}`);
252
+ ui.addLog('connected', `First tick @ ${price?.toFixed(2) || 'N/A'}`);
232
253
  }
233
254
 
234
- // Log price changes
235
- if (price && lastPrice && price !== lastPrice) {
236
- const direction = price > lastPrice ? 'UP' : 'DOWN';
237
- const change = Math.abs(price - lastPrice).toFixed(2);
238
- if (tickCount <= 10 || tickCount % 50 === 0) {
239
- ui.addLog('info', `Price ${direction} ${change} -> ${price.toFixed(2)}`);
255
+ // === SMART LOGS EVERY SECOND ===
256
+ if (currentSecond !== lastLogSecond && tickCount > 1) {
257
+ lastLogSecond = currentSecond;
258
+
259
+ const totalVol = buyVolume + sellVolume;
260
+ const buyPressure = totalVol > 0 ? (buyVolume / totalVol) * 100 : 50;
261
+ const delta = buyVolume - sellVolume;
262
+
263
+ // Determine market bias
264
+ let bias = 'FLAT';
265
+ if (buyPressure > 55) bias = 'LONG';
266
+ else if (buyPressure < 45) bias = 'SHORT';
267
+
268
+ // Get smart log for market bias
269
+ const biasLog = smartLogs.getMarketBiasLog(bias, delta, buyPressure);
270
+ ui.addLog('info', `${biasLog.message} ${biasLog.details || ''}`);
271
+
272
+ // Get model values if available
273
+ const modelValues = strategy.getModelValues?.(contractId);
274
+ if (modelValues) {
275
+ barCount = modelValues.bars || barCount;
276
+ if (barCount >= 50) {
277
+ const modelLog = smartLogs.getModelAnalysisLog(modelValues);
278
+ ui.addLog('info', `${modelLog.message} ${modelLog.details || ''}`);
279
+ } else {
280
+ const barLog = smartLogs.getBuildingBarsLog(barCount);
281
+ ui.addLog('info', `${barLog.message} (${barLog.details})`);
282
+ }
240
283
  }
241
- }
242
-
243
- // Log bid/ask spread
244
- if (bid && ask && (bid !== lastBid || ask !== lastAsk)) {
245
- const spread = (ask - bid).toFixed(2);
246
- if (tickCount <= 5) {
247
- ui.addLog('info', `Spread: ${spread} (Bid: ${bid.toFixed(2)} / Ask: ${ask.toFixed(2)})`);
284
+
285
+ // Scanning log every 3 seconds
286
+ if (currentSecond % 3 === 0 && currentPosition === 0) {
287
+ const scanLog = smartLogs.getScanningLog(true);
288
+ ui.addLog('info', scanLog.message);
289
+ }
290
+
291
+ // Tick flow log every 5 seconds
292
+ if (currentSecond % 5 === 0) {
293
+ const tickLog = smartLogs.getTickFlowLog(tickCount, ticksPerSecond);
294
+ ui.addLog('info', `${tickLog.message} ${tickLog.details}`);
248
295
  }
296
+
297
+ // Reset volume counters
298
+ buyVolume = 0;
299
+ sellVolume = 0;
249
300
  }
250
301
 
251
302
  lastPrice = price;
@@ -255,19 +306,12 @@ const executeAlgo = async ({ service, account, contract, config, strategy: strat
255
306
  strategy.processTick({
256
307
  contractId: tick.contractId || contractId,
257
308
  price: price, bid: bid, ask: ask,
258
- volume: tick.volume || tick.size || 1,
309
+ volume: volume,
259
310
  side: tick.side || tick.lastTradeSide || 'unknown',
260
311
  timestamp: tick.timestamp || Date.now()
261
312
  });
262
313
 
263
314
  stats.latency = Date.now() - latencyStart;
264
-
265
- // Periodic status logs
266
- if (tickCount === 10) ui.addLog('info', `Receiving ticks... (${ticksPerSecond}/sec)`);
267
- if (tickCount === 50) ui.addLog('info', `50 ticks processed, strategy analyzing...`);
268
- if (tickCount % 200 === 0) {
269
- ui.addLog('info', `Tick #${tickCount} @ ${price?.toFixed(2) || 'N/A'} | ${ticksPerSecond}/sec`);
270
- }
271
315
  });
272
316
 
273
317
  marketFeed.on('connected', () => {
@@ -287,7 +331,8 @@ const executeAlgo = async ({ service, account, contract, config, strategy: strat
287
331
  throw new Error('Rithmic credentials not available');
288
332
  }
289
333
  await marketFeed.connect(rithmicCredentials);
290
- await marketFeed.subscribe(symbolName, contract.exchange || 'CME');
334
+ await marketFeed.subscribe(symbolCode, contract.exchange || 'CME');
335
+ ui.addLog('info', `Symbol code: ${symbolCode}`);
291
336
  } catch (e) {
292
337
  ui.addLog('error', `Failed to connect: ${e.message}`);
293
338
  }