hedgequantx 2.4.30 → 2.4.32

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.32",
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,55 +281,67 @@ 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
 
304
+ // Debug: log first tick to see structure
305
+ if (tickCount === 1) {
306
+ algoLogger.info(ui, 'FIRST TICK', `price=${tick.price} bid=${tick.bid} ask=${tick.ask} vol=${tick.volume}`);
307
+ }
308
+
286
309
  // Feed tick to strategy
287
- strategy.processTick({
310
+ const tickData = {
288
311
  contractId: tick.contractId || contractId,
289
- price: tick.price,
312
+ price: tick.price || tick.lastPrice || tick.bid,
290
313
  bid: tick.bid,
291
314
  ask: tick.ask,
292
- volume: tick.volume || 1,
293
- side: tick.lastTradeSide || 'unknown',
315
+ volume: tick.volume || tick.size || 1,
316
+ side: tick.lastTradeSide || tick.side || 'unknown',
294
317
  timestamp: tick.timestamp || Date.now()
295
- });
318
+ };
319
+
320
+ strategy.processTick(tickData);
296
321
 
297
322
  stats.latency = Date.now() - latencyStart;
298
323
 
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) || '--'}`);
324
+ // Heartbeat every 30 seconds (smart log instead of tick count)
325
+ if (Date.now() - lastHeartbeat > 30000) {
326
+ algoLogger.heartbeat(ui, tps, stats.latency);
327
+ lastHeartbeat = Date.now();
328
+ tps = 0;
303
329
  }
304
330
  });
305
331
 
306
332
  marketFeed.on('connected', () => {
307
333
  stats.connected = true;
308
- ui.addLog('success', 'MARKET DATA CONNECTED');
334
+ algoLogger.dataConnected(ui, 'RTC');
335
+ algoLogger.algoOperational(ui, connectionType);
309
336
  });
310
337
 
311
338
  marketFeed.on('error', (err) => {
312
- ui.addLog('error', `MARKET: ${err.message.toUpperCase()}`);
339
+ algoLogger.error(ui, 'MARKET ERROR', err.message);
313
340
  });
314
341
 
315
342
  marketFeed.on('disconnected', (err) => {
316
343
  stats.connected = false;
317
- const reason = err?.message || 'UNKNOWN';
318
- ui.addLog('error', `DISC: ${reason.substring(0, 70).toUpperCase()}`);
344
+ algoLogger.dataDisconnected(ui, 'WEBSOCKET', err?.message);
319
345
  });
320
346
 
321
347
  // Connect to market data
@@ -324,14 +350,14 @@ const launchAlgo = async (service, account, contract, config) => {
324
350
 
325
351
  // CRITICAL: Get a fresh token for WebSocket connection
326
352
  // TopStep invalidates WebSocket sessions for old tokens
327
- ui.addLog('info', 'REFRESHING AUTH TOKEN...');
353
+ algoLogger.info(ui, 'REFRESHING AUTH TOKEN...');
328
354
  const token = await service.getFreshToken?.() || service.token || service.getToken?.();
329
355
 
330
356
  if (!token) {
331
- ui.addLog('error', 'NO AUTH TOKEN - PLEASE RECONNECT');
357
+ algoLogger.error(ui, 'NO AUTH TOKEN', 'Please reconnect');
332
358
  } else {
333
- ui.addLog('info', `TOKEN OK (${token.length} CHARS)`);
334
- ui.addLog('info', `RTC: ${propfirmKey.toUpperCase()} | ${contractId}`);
359
+ algoLogger.info(ui, 'TOKEN OK', `${token.length} chars`);
360
+ algoLogger.info(ui, 'CONNECTING', `${propfirmKey.toUpperCase()} | ${contractId}`);
335
361
 
336
362
  await marketFeed.connect(token, propfirmKey);
337
363
 
@@ -340,13 +366,13 @@ const launchAlgo = async (service, account, contract, config) => {
340
366
 
341
367
  if (marketFeed.isConnected()) {
342
368
  await marketFeed.subscribe(symbolName, contractId);
343
- ui.addLog('success', 'SUBSCRIBED TO MARKET DATA');
369
+ algoLogger.info(ui, 'SUBSCRIBED', `${symbolName} real-time feed active`);
344
370
  } else {
345
- ui.addLog('error', 'CONNECTION LOST BEFORE SUBSCRIBE');
371
+ algoLogger.error(ui, 'CONNECTION LOST', 'Before subscribe');
346
372
  }
347
373
  }
348
374
  } catch (e) {
349
- ui.addLog('error', `ERR: ${e.message.substring(0, 60).toUpperCase()}`);
375
+ algoLogger.error(ui, 'CONNECTION ERROR', e.message.substring(0, 50));
350
376
  }
351
377
 
352
378
  // Poll account P&L from API
@@ -391,11 +417,11 @@ const launchAlgo = async (service, account, contract, config) => {
391
417
  if (stats.pnl >= dailyTarget) {
392
418
  stopReason = 'target';
393
419
  running = false;
394
- ui.addLog('success', `TARGET REACHED +$${stats.pnl.toFixed(2)}`);
420
+ algoLogger.targetHit(ui, symbolName, 0, stats.pnl);
395
421
  } else if (stats.pnl <= -maxRisk) {
396
422
  stopReason = 'risk';
397
423
  running = false;
398
- ui.addLog('error', `MAX RISK -$${Math.abs(stats.pnl).toFixed(2)}`);
424
+ algoLogger.dailyLimitWarning(ui, stats.pnl, -maxRisk);
399
425
  }
400
426
  } catch (e) {
401
427
  // Silently handle polling errors