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 +1 -1
- package/src/lib/smart-logs.js +419 -0
- package/src/pages/algo/algo-executor.js +78 -33
package/package.json
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
104
|
+
const riskLog = smartLogs.getRiskCheckLog(false, 'Algo stopped');
|
|
105
|
+
ui.addLog('info', riskLog.message);
|
|
100
106
|
return;
|
|
101
107
|
}
|
|
102
108
|
if (pendingOrder) {
|
|
103
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
177
|
-
|
|
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('
|
|
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
|
-
//
|
|
235
|
-
if (
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
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
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
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:
|
|
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(
|
|
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
|
}
|