hedgequantx 2.4.30 → 2.4.31

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.4.30",
3
+ "version": "2.4.31",
4
4
  "description": "HedgeQuantX - Prop Futures Trading CLI",
5
5
  "main": "src/app.js",
6
6
  "bin": {
@@ -11,6 +11,7 @@ const { connections } = require('../../services');
11
11
  const { AlgoUI, renderSessionSummary } = require('./ui');
12
12
  const { logger, prompts } = require('../../utils');
13
13
  const { checkMarketHours } = require('../../services/projectx/market');
14
+ const { algoLogger } = require('./logger');
14
15
 
15
16
  const log = logger.scope('CopyTrading');
16
17
 
@@ -299,10 +300,17 @@ const launchCopyTrading = async (config) => {
299
300
  }
300
301
  };
301
302
 
302
- // Local copy trading - no external server needed
303
- ui.addLog('info', `Starting copy trading on ${stats.platform}...`);
304
- ui.addLog('info', `Lead: ${stats.leadName} -> Follower: ${stats.followerName}`);
305
- ui.addLog('info', `Symbol: ${stats.symbol} | Target: $${dailyTarget} | Risk: $${maxRisk}`);
303
+ // Smart startup logs (same as HQX-TG)
304
+ const market = checkMarketHours();
305
+ const sessionName = market.session || 'AMERICAN';
306
+ const etTime = new Date().toLocaleTimeString('en-US', { hour: '2-digit', minute: '2-digit', timeZone: 'America/New_York' });
307
+
308
+ algoLogger.connectingToEngine(ui, lead.account.accountId);
309
+ algoLogger.engineStarting(ui, stats.platform, dailyTarget, maxRisk);
310
+ algoLogger.marketOpen(ui, sessionName.toUpperCase(), etTime);
311
+ algoLogger.info(ui, 'COPY MODE', `Lead: ${lead.propfirm} -> Follower: ${follower.propfirm}`);
312
+ algoLogger.dataConnected(ui, 'API');
313
+ algoLogger.algoOperational(ui, stats.platform);
306
314
  stats.connected = true;
307
315
 
308
316
  // Track lead positions and copy to follower
@@ -321,7 +329,12 @@ const launchCopyTrading = async (config) => {
321
329
  const existing = lastLeadPositions.find(p => p.contractId === pos.contractId);
322
330
  if (!existing && pos.quantity !== 0) {
323
331
  // New position opened - copy to follower
324
- ui.addLog('trade', `Lead opened: ${pos.quantity > 0 ? 'LONG' : 'SHORT'} ${Math.abs(pos.quantity)}x ${pos.symbol || pos.contractId}`);
332
+ const side = pos.quantity > 0 ? 'LONG' : 'SHORT';
333
+ const symbol = pos.symbol || pos.contractId;
334
+ const size = Math.abs(pos.quantity);
335
+ const entry = pos.averagePrice || 0;
336
+ algoLogger.positionOpened(ui, symbol, side, size, entry);
337
+ algoLogger.info(ui, 'COPYING TO FOLLOWER', `${side} ${size}x ${symbol}`);
325
338
  // TODO: Place order on follower account
326
339
  }
327
340
  }
@@ -330,7 +343,13 @@ const launchCopyTrading = async (config) => {
330
343
  for (const oldPos of lastLeadPositions) {
331
344
  const stillOpen = currentPositions.find(p => p.contractId === oldPos.contractId);
332
345
  if (!stillOpen || stillOpen.quantity === 0) {
333
- ui.addLog('info', `Lead closed: ${oldPos.symbol || oldPos.contractId}`);
346
+ const side = oldPos.quantity > 0 ? 'LONG' : 'SHORT';
347
+ const symbol = oldPos.symbol || oldPos.contractId;
348
+ const size = Math.abs(oldPos.quantity);
349
+ const exit = stillOpen?.averagePrice || oldPos.averagePrice || 0;
350
+ const pnl = oldPos.profitAndLoss || 0;
351
+ algoLogger.positionClosed(ui, symbol, side, size, exit, pnl);
352
+ algoLogger.info(ui, 'CLOSING ON FOLLOWER', symbol);
334
353
  // TODO: Close position on follower account
335
354
  }
336
355
  }
@@ -353,11 +372,13 @@ const launchCopyTrading = async (config) => {
353
372
  if (stats.pnl >= dailyTarget) {
354
373
  stopReason = 'target';
355
374
  running = false;
356
- ui.addLog('success', `TARGET REACHED! +$${stats.pnl.toFixed(2)}`);
375
+ algoLogger.targetHit(ui, lead.symbol.name, 0, stats.pnl);
376
+ algoLogger.info(ui, 'DAILY TARGET REACHED', `+$${stats.pnl.toFixed(2)} - Stopping algo`);
357
377
  } else if (stats.pnl <= -maxRisk) {
358
378
  stopReason = 'risk';
359
379
  running = false;
360
- ui.addLog('error', `MAX RISK HIT! -$${Math.abs(stats.pnl).toFixed(2)}`);
380
+ algoLogger.dailyLimitWarning(ui, stats.pnl, -maxRisk);
381
+ algoLogger.error(ui, 'MAX RISK HIT', `-$${Math.abs(stats.pnl).toFixed(2)} - Stopping algo`);
361
382
  }
362
383
  } catch (e) {
363
384
  // Silent fail - will retry
@@ -0,0 +1,245 @@
1
+ /**
2
+ * =============================================================================
3
+ * HQX Algo Trading System - Smart Algo Logger
4
+ * =============================================================================
5
+ * Provides rich, detailed logs for the algo UI
6
+ * Copied from HQX-TG algo-logger.ts - All 47 log types
7
+ */
8
+
9
+ 'use strict';
10
+
11
+ /**
12
+ * Smart Algo Logger - All 47 log types from HQX-TG
13
+ */
14
+ const algoLogger = {
15
+ // === MARKET DATA LOGS ===
16
+ quote(ui, symbol, bid, ask, spread) {
17
+ ui.addLog('info', `QUOTE ${symbol} - bid: ${bid.toFixed(2)} | ask: ${ask.toFixed(2)} | spread: ${spread.toFixed(2)}`);
18
+ },
19
+
20
+ tape(ui, symbol, buyVol, sellVol, delta) {
21
+ const sign = delta > 0 ? '+' : '';
22
+ ui.addLog('info', `TAPE ${symbol} - buy: ${buyVol} | sell: ${sellVol} | delta: ${sign}${delta}`);
23
+ },
24
+
25
+ dom(ui, symbol, bidDepth, askDepth, imbalance) {
26
+ const direction = imbalance > 0 ? '▲' : imbalance < 0 ? '▼' : '=';
27
+ ui.addLog('info', `DOM ${symbol} - bidDepth: ${bidDepth} | askDepth: ${askDepth} | imbalance: ${direction}${Math.abs(imbalance).toFixed(1)}%`);
28
+ },
29
+
30
+ volumeSpike(ui, symbol, volume, avgVolume, ratio) {
31
+ ui.addLog('analysis', `VOLUME SPIKE ${symbol} - vol: ${volume} | avg: ${avgVolume.toFixed(0)} | ratio: ${ratio.toFixed(1)}x`);
32
+ },
33
+
34
+ // === ANALYSIS LOGS ===
35
+ orderFlow(ui, symbol, score, direction) {
36
+ const arrow = direction === 'LONG' ? '▲' : direction === 'SHORT' ? '▼' : '=';
37
+ ui.addLog('analysis', `ORDER FLOW ${symbol} - score: ${score.toFixed(0)} | direction: ${arrow} ${direction}`);
38
+ },
39
+
40
+ absorption(ui, symbol, level, side, strength) {
41
+ ui.addLog('analysis', `ABSORPTION ${side} - price: ${level.toFixed(2)} | strength: ${strength.toFixed(0)}%`);
42
+ },
43
+
44
+ sweep(ui, symbol, side, levels, volume) {
45
+ ui.addLog('analysis', `SWEEP ${side} - levels: ${levels} | volume: ${volume}`);
46
+ },
47
+
48
+ iceberg(ui, symbol, price, hiddenSize) {
49
+ ui.addLog('analysis', `ICEBERG DETECTED - price: ${price.toFixed(2)} | hidden: ${hiddenSize}`);
50
+ },
51
+
52
+ deltaDivergence(ui, symbol, priceDir, deltaDir) {
53
+ ui.addLog('analysis', `DELTA DIVERGENCE - price: ${priceDir} | delta: ${deltaDir}`);
54
+ },
55
+
56
+ vpoc(ui, symbol, poc, valueHigh, valueLow) {
57
+ ui.addLog('analysis', `VPOC ${symbol} - poc: ${poc.toFixed(2)} | VAH: ${valueHigh.toFixed(2)} | VAL: ${valueLow.toFixed(2)}`);
58
+ },
59
+
60
+ regime(ui, symbol, regime, confidence) {
61
+ ui.addLog('analysis', `REGIME ${symbol} - ${regime} | confidence: ${confidence.toFixed(0)}%`);
62
+ },
63
+
64
+ volatility(ui, symbol, atr, regime) {
65
+ ui.addLog('analysis', `VOLATILITY ${symbol} - ATR: ${atr.toFixed(2)} | regime: ${regime}`);
66
+ },
67
+
68
+ // === SIGNAL LOGS ===
69
+ signalGenerated(ui, symbol, direction, confidence, strategy) {
70
+ const arrow = direction === 'LONG' ? '▲' : '▼';
71
+ ui.addLog('signal', `SIGNAL ${arrow} ${direction} - ${symbol} | conf: ${confidence.toFixed(0)}% | strategy: ${strategy}`);
72
+ },
73
+
74
+ signalRejected(ui, symbol, reason) {
75
+ ui.addLog('warning', `SIGNAL REJECTED - ${symbol} | reason: ${reason}`);
76
+ },
77
+
78
+ signalExpired(ui, symbol) {
79
+ ui.addLog('info', `SIGNAL EXPIRED - ${symbol}`);
80
+ },
81
+
82
+ // === TRADE LOGS ===
83
+ orderSubmitted(ui, symbol, side, size, price) {
84
+ ui.addLog('trade', `ORDER SUBMITTED - ${side} ${size} ${symbol} @ ${price.toFixed(2)}`);
85
+ },
86
+
87
+ orderFilled(ui, symbol, side, size, price) {
88
+ ui.addLog('trade', `ORDER FILLED - ${side} ${size} ${symbol} @ ${price.toFixed(2)}`);
89
+ },
90
+
91
+ orderRejected(ui, symbol, reason) {
92
+ ui.addLog('error', `ORDER REJECTED - ${symbol} | ${reason}`);
93
+ },
94
+
95
+ orderCancelled(ui, symbol, orderId) {
96
+ ui.addLog('warning', `ORDER CANCELLED - ${symbol} | id: ${orderId}`);
97
+ },
98
+
99
+ positionOpened(ui, symbol, side, size, entry) {
100
+ const arrow = side === 'LONG' ? '▲' : '▼';
101
+ ui.addLog('trade', `POSITION OPENED ${arrow} - ${side} ${size} ${symbol} @ ${entry.toFixed(2)}`);
102
+ },
103
+
104
+ positionClosed(ui, symbol, side, size, exit, pnl) {
105
+ const pnlStr = pnl >= 0 ? `+$${pnl.toFixed(2)}` : `-$${Math.abs(pnl).toFixed(2)}`;
106
+ const type = pnl >= 0 ? 'trade' : 'warning';
107
+ ui.addLog(type, `POSITION CLOSED - ${side} ${size} ${symbol} @ ${exit.toFixed(2)} | PnL: ${pnlStr}`);
108
+ },
109
+
110
+ stopHit(ui, symbol, price, loss) {
111
+ ui.addLog('warning', `STOP LOSS HIT - ${symbol} @ ${price.toFixed(2)} | loss: -$${Math.abs(loss).toFixed(2)}`);
112
+ },
113
+
114
+ targetHit(ui, symbol, price, profit) {
115
+ ui.addLog('trade', `TARGET HIT - ${symbol} @ ${price.toFixed(2)} | profit: +$${profit.toFixed(2)}`);
116
+ },
117
+
118
+ trailingStopMoved(ui, symbol, oldStop, newStop) {
119
+ ui.addLog('info', `TRAILING STOP MOVED - ${symbol} | ${oldStop.toFixed(2)} → ${newStop.toFixed(2)}`);
120
+ },
121
+
122
+ fillSync(ui, side, size, price, orderId) {
123
+ ui.addLog('trade', `FILL (SYNC) - ${side} ${size} @ ${price.toFixed(2)} (order #${orderId})`);
124
+ },
125
+
126
+ entryConfirmed(ui, side, size, symbol, price) {
127
+ ui.addLog('info', `ENTRY CONFIRMED - ${side} ${size}x ${symbol} @ ${price.toFixed(2)}`);
128
+ },
129
+
130
+ stopsSet(ui, sl, tp) {
131
+ ui.addLog('info', `STOPS SET - SL: ${sl.toFixed(2)} | TP: ${tp.toFixed(2)}`);
132
+ },
133
+
134
+ // === RISK LOGS ===
135
+ riskCheck(ui, passed, reason) {
136
+ const type = passed ? 'info' : 'warning';
137
+ ui.addLog(type, `RISK CHECK ${passed ? 'PASSED' : 'BLOCKED'} - ${reason}`);
138
+ },
139
+
140
+ dailyLimitWarning(ui, current, limit) {
141
+ ui.addLog('warning', `DAILY LIMIT WARNING - PnL: $${current.toFixed(2)} / limit: $${limit.toFixed(2)}`);
142
+ },
143
+
144
+ maxDrawdownWarning(ui, current, max) {
145
+ ui.addLog('warning', `DRAWDOWN WARNING - current: ${current.toFixed(1)}% / max: ${max.toFixed(1)}%`);
146
+ },
147
+
148
+ positionSized(ui, contracts, kelly, riskAmount, riskPct) {
149
+ ui.addLog('info', `POSITION SIZE - ${contracts} contracts | kelly: ${kelly.toFixed(2)} | risk: $${riskAmount} (${riskPct}% of max)`);
150
+ },
151
+
152
+ bracketSet(ui, stopTicks, targetTicks, rr) {
153
+ ui.addLog('info', `BRACKET SET - SL: ${stopTicks}t | TP: ${targetTicks}t | R:R: ${rr.toFixed(1)}`);
154
+ },
155
+
156
+ // === STRATEGY LOGS ===
157
+ strategySelected(ui, strategy, session, regime) {
158
+ ui.addLog('info', `STRATEGY SELECTED - ${strategy} | session: ${session} | regime: ${regime}`);
159
+ },
160
+
161
+ strategySwitch(ui, from, to, reason) {
162
+ ui.addLog('info', `STRATEGY SWITCH - ${from} → ${to} | ${reason}`);
163
+ },
164
+
165
+ // === SESSION LOGS ===
166
+ sessionStart(ui, session) {
167
+ ui.addLog('info', `SESSION START - ${session}`);
168
+ },
169
+
170
+ sessionEnd(ui, session) {
171
+ ui.addLog('info', `SESSION END - ${session}`);
172
+ },
173
+
174
+ marketOpen(ui, session, etTime) {
175
+ ui.addLog('info', `MARKET OPEN - ${session} SESSION | ET: ${etTime} ET`);
176
+ },
177
+
178
+ marketClosed(ui) {
179
+ ui.addLog('warning', `MARKET CLOSED - Trading paused`);
180
+ },
181
+
182
+ // === SYSTEM LOGS ===
183
+ connectingToEngine(ui, accountId) {
184
+ ui.addLog('info', `CONNECTING TO ALGO ENGINE... - Account: ${accountId}`);
185
+ },
186
+
187
+ engineStarting(ui, platform, dailyTarget, dailyRisk) {
188
+ ui.addLog('info', `ALGO ENGINE STARTING... - Platform: ${platform} | Daily Target: $${dailyTarget} | Daily Risk: $${dailyRisk}`);
189
+ },
190
+
191
+ engineStarted(ui, platform, status) {
192
+ ui.addLog('info', `ALGO ENGINE STARTED - Status: ${status}`);
193
+ },
194
+
195
+ engineStopped(ui, reason) {
196
+ ui.addLog('info', `ENGINE STOPPED - ${reason || 'All positions flat'}`);
197
+ },
198
+
199
+ algoOperational(ui, platform) {
200
+ ui.addLog('info', `ALGO FULLY OPERATIONAL - Connected to ${platform} - Scanning for alpha...`);
201
+ },
202
+
203
+ dataConnected(ui, source) {
204
+ ui.addLog('info', `WEBSOCKET CONNECTED - Real-time updates enabled`);
205
+ },
206
+
207
+ dataDisconnected(ui, source, reason) {
208
+ ui.addLog('warning', `WEBSOCKET DISCONNECTED - Attempting to reconnect...`);
209
+ },
210
+
211
+ heartbeat(ui, tps, latency) {
212
+ ui.addLog('info', `HEARTBEAT - tps: ${tps} | latency: ${latency}ms`);
213
+ },
214
+
215
+ latencyReport(ui, latency) {
216
+ ui.addLog('analysis', `LATENCY - ${latency}ms order-to-fill`);
217
+ },
218
+
219
+ // === GENERIC ===
220
+ info(ui, message, details) {
221
+ ui.addLog('info', details ? `${message} - ${details}` : message);
222
+ },
223
+
224
+ warning(ui, message, details) {
225
+ ui.addLog('warning', details ? `${message} - ${details}` : message);
226
+ },
227
+
228
+ error(ui, message, details) {
229
+ ui.addLog('error', details ? `${message} - ${details}` : message);
230
+ },
231
+
232
+ signal(ui, message, details) {
233
+ ui.addLog('signal', details ? `${message} - ${details}` : message);
234
+ },
235
+
236
+ trade(ui, message, details) {
237
+ ui.addLog('trade', details ? `${message} - ${details}` : message);
238
+ },
239
+
240
+ analysis(ui, message, details) {
241
+ ui.addLog('analysis', details ? `${message} - ${details}` : message);
242
+ },
243
+ };
244
+
245
+ module.exports = { algoLogger };
@@ -14,6 +14,7 @@ const { checkMarketHours } = require('../../services/projectx/market');
14
14
  // Strategy & Market Data (obfuscated)
15
15
  const { M1 } = require('../../../dist/lib/m/s1');
16
16
  const { MarketDataFeed } = require('../../../dist/lib/data');
17
+ const { algoLogger } = require('./logger');
17
18
 
18
19
 
19
20
 
@@ -213,12 +214,14 @@ const launchAlgo = async (service, account, contract, config) => {
213
214
  // Initialize Market Data Feed
214
215
  const marketFeed = new MarketDataFeed({ propfirm: account.propfirm });
215
216
 
216
- // Log startup - UPPERCASE
217
- ui.addLog('info', `CONNECTION: ${connectionType.toUpperCase()}`);
218
- ui.addLog('info', `ACCOUNT: ${accountName.toUpperCase()}`);
219
- ui.addLog('info', `SYMBOL: ${symbolName.toUpperCase()} | QTY: ${contracts}`);
220
- ui.addLog('info', `TARGET: $${dailyTarget} | MAX RISK: $${maxRisk}`);
221
- ui.addLog('info', 'CONNECTING TO MARKET DATA...');
217
+ // Smart startup logs (same as HQX-TG)
218
+ const market = checkMarketHours();
219
+ const sessionName = market.session || 'AMERICAN';
220
+ const etTime = new Date().toLocaleTimeString('en-US', { hour: '2-digit', minute: '2-digit', timeZone: 'America/New_York' });
221
+
222
+ algoLogger.connectingToEngine(ui, account.accountId);
223
+ algoLogger.engineStarting(ui, connectionType, dailyTarget, maxRisk);
224
+ algoLogger.marketOpen(ui, sessionName.toUpperCase(), etTime);
222
225
 
223
226
  // Handle strategy signals
224
227
  strategy.on('signal', async (signal) => {
@@ -226,7 +229,12 @@ const launchAlgo = async (service, account, contract, config) => {
226
229
 
227
230
  const { side, direction, entry, stopLoss, takeProfit, confidence } = signal;
228
231
 
229
- ui.addLog('signal', `${direction.toUpperCase()} signal @ ${entry.toFixed(2)} (${(confidence * 100).toFixed(0)}%)`);
232
+ // Calculate position size with kelly
233
+ const kelly = Math.min(0.25, confidence);
234
+ const riskAmount = Math.round(maxRisk * kelly);
235
+ const riskPct = Math.round((riskAmount / maxRisk) * 100);
236
+
237
+ algoLogger.positionSized(ui, contracts, kelly, riskAmount, riskPct);
230
238
 
231
239
  // Place order via API
232
240
  pendingOrder = true;
@@ -243,7 +251,13 @@ const launchAlgo = async (service, account, contract, config) => {
243
251
  if (orderResult.success) {
244
252
  currentPosition = direction === 'long' ? contracts : -contracts;
245
253
  stats.trades++;
246
- ui.addLog('trade', `OPENED ${direction.toUpperCase()} ${contracts}x @ market`);
254
+ const sideStr = direction === 'long' ? 'BUY' : 'SELL';
255
+ const positionSide = direction === 'long' ? 'LONG' : 'SHORT';
256
+
257
+ algoLogger.orderSubmitted(ui, symbolName, sideStr, contracts, entry);
258
+ algoLogger.orderFilled(ui, symbolName, sideStr, contracts, entry);
259
+ algoLogger.positionOpened(ui, symbolName, positionSide, contracts, entry);
260
+ algoLogger.entryConfirmed(ui, sideStr, contracts, symbolName, entry);
247
261
 
248
262
  // Place bracket orders (SL/TP)
249
263
  if (stopLoss && takeProfit) {
@@ -267,20 +281,24 @@ const launchAlgo = async (service, account, contract, config) => {
267
281
  limitPrice: takeProfit
268
282
  });
269
283
 
270
- ui.addLog('info', `SL: ${stopLoss.toFixed(2)} | TP: ${takeProfit.toFixed(2)}`);
284
+ algoLogger.stopsSet(ui, stopLoss, takeProfit);
271
285
  }
272
286
  } else {
273
- ui.addLog('error', `Order failed: ${orderResult.error}`);
287
+ algoLogger.orderRejected(ui, symbolName, orderResult.error || 'Unknown error');
274
288
  }
275
289
  } catch (e) {
276
- ui.addLog('error', `Order error: ${e.message}`);
290
+ algoLogger.error(ui, 'ORDER ERROR', e.message);
277
291
  }
278
292
  pendingOrder = false;
279
293
  });
280
294
 
281
295
  // Handle market data ticks
296
+ let lastHeartbeat = Date.now();
297
+ let tps = 0;
298
+
282
299
  marketFeed.on('tick', (tick) => {
283
300
  tickCount++;
301
+ tps++;
284
302
  const latencyStart = Date.now();
285
303
 
286
304
  // Feed tick to strategy
@@ -296,26 +314,27 @@ const launchAlgo = async (service, account, contract, config) => {
296
314
 
297
315
  stats.latency = Date.now() - latencyStart;
298
316
 
299
- // Log every 100th tick to show activity
300
- if (tickCount % 100 === 0) {
301
- const displayPrice = tick.price || tick.bid || tick.ask;
302
- ui.addLog('info', `TICK #${tickCount} @ ${displayPrice?.toFixed(2) || '--'}`);
317
+ // Heartbeat every 30 seconds (smart log instead of tick count)
318
+ if (Date.now() - lastHeartbeat > 30000) {
319
+ algoLogger.heartbeat(ui, tps, stats.latency);
320
+ lastHeartbeat = Date.now();
321
+ tps = 0;
303
322
  }
304
323
  });
305
324
 
306
325
  marketFeed.on('connected', () => {
307
326
  stats.connected = true;
308
- ui.addLog('success', 'MARKET DATA CONNECTED');
327
+ algoLogger.dataConnected(ui, 'RTC');
328
+ algoLogger.algoOperational(ui, connectionType);
309
329
  });
310
330
 
311
331
  marketFeed.on('error', (err) => {
312
- ui.addLog('error', `MARKET: ${err.message.toUpperCase()}`);
332
+ algoLogger.error(ui, 'MARKET ERROR', err.message);
313
333
  });
314
334
 
315
335
  marketFeed.on('disconnected', (err) => {
316
336
  stats.connected = false;
317
- const reason = err?.message || 'UNKNOWN';
318
- ui.addLog('error', `DISC: ${reason.substring(0, 70).toUpperCase()}`);
337
+ algoLogger.dataDisconnected(ui, 'WEBSOCKET', err?.message);
319
338
  });
320
339
 
321
340
  // Connect to market data
@@ -324,14 +343,14 @@ const launchAlgo = async (service, account, contract, config) => {
324
343
 
325
344
  // CRITICAL: Get a fresh token for WebSocket connection
326
345
  // TopStep invalidates WebSocket sessions for old tokens
327
- ui.addLog('info', 'REFRESHING AUTH TOKEN...');
346
+ algoLogger.info(ui, 'REFRESHING AUTH TOKEN...');
328
347
  const token = await service.getFreshToken?.() || service.token || service.getToken?.();
329
348
 
330
349
  if (!token) {
331
- ui.addLog('error', 'NO AUTH TOKEN - PLEASE RECONNECT');
350
+ algoLogger.error(ui, 'NO AUTH TOKEN', 'Please reconnect');
332
351
  } else {
333
- ui.addLog('info', `TOKEN OK (${token.length} CHARS)`);
334
- ui.addLog('info', `RTC: ${propfirmKey.toUpperCase()} | ${contractId}`);
352
+ algoLogger.info(ui, 'TOKEN OK', `${token.length} chars`);
353
+ algoLogger.info(ui, 'CONNECTING', `${propfirmKey.toUpperCase()} | ${contractId}`);
335
354
 
336
355
  await marketFeed.connect(token, propfirmKey);
337
356
 
@@ -340,13 +359,13 @@ const launchAlgo = async (service, account, contract, config) => {
340
359
 
341
360
  if (marketFeed.isConnected()) {
342
361
  await marketFeed.subscribe(symbolName, contractId);
343
- ui.addLog('success', 'SUBSCRIBED TO MARKET DATA');
362
+ algoLogger.info(ui, 'SUBSCRIBED', `${symbolName} real-time feed active`);
344
363
  } else {
345
- ui.addLog('error', 'CONNECTION LOST BEFORE SUBSCRIBE');
364
+ algoLogger.error(ui, 'CONNECTION LOST', 'Before subscribe');
346
365
  }
347
366
  }
348
367
  } catch (e) {
349
- ui.addLog('error', `ERR: ${e.message.substring(0, 60).toUpperCase()}`);
368
+ algoLogger.error(ui, 'CONNECTION ERROR', e.message.substring(0, 50));
350
369
  }
351
370
 
352
371
  // Poll account P&L from API
@@ -391,11 +410,11 @@ const launchAlgo = async (service, account, contract, config) => {
391
410
  if (stats.pnl >= dailyTarget) {
392
411
  stopReason = 'target';
393
412
  running = false;
394
- ui.addLog('success', `TARGET REACHED +$${stats.pnl.toFixed(2)}`);
413
+ algoLogger.targetHit(ui, symbolName, 0, stats.pnl);
395
414
  } else if (stats.pnl <= -maxRisk) {
396
415
  stopReason = 'risk';
397
416
  running = false;
398
- ui.addLog('error', `MAX RISK -$${Math.abs(stats.pnl).toFixed(2)}`);
417
+ algoLogger.dailyLimitWarning(ui, stats.pnl, -maxRisk);
399
418
  }
400
419
  } catch (e) {
401
420
  // Silently handle polling errors