hedgequantx 2.9.52 → 2.9.54
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/data.js +43 -18
- package/src/pages/algo/algo-executor.js +5 -5
- package/src/pages/algo/ui.js +23 -11
package/package.json
CHANGED
package/src/lib/data.js
CHANGED
|
@@ -209,23 +209,36 @@ class MarketDataFeed extends EventEmitter {
|
|
|
209
209
|
_handleLastTrade(data) {
|
|
210
210
|
try {
|
|
211
211
|
const trade = proto.decode('LastTrade', data);
|
|
212
|
+
const tradeObj = trade.toJSON ? trade.toJSON() : trade;
|
|
213
|
+
|
|
214
|
+
// protobufjs converts to camelCase and enums to strings
|
|
215
|
+
const price = tradeObj.tradePrice;
|
|
216
|
+
const size = Number(tradeObj.tradeSize) || 1;
|
|
217
|
+
const volume = Number(tradeObj.volume) || size;
|
|
218
|
+
|
|
219
|
+
// aggressor can be 1, 2, "BUY", "SELL"
|
|
220
|
+
const agg = tradeObj.aggressor;
|
|
221
|
+
const side = (agg === 1 || agg === 'BUY') ? 'buy' :
|
|
222
|
+
(agg === 2 || agg === 'SELL') ? 'sell' : 'unknown';
|
|
223
|
+
|
|
224
|
+
if (price === undefined || price === null) return;
|
|
212
225
|
|
|
213
226
|
const tick = {
|
|
214
227
|
type: 'trade',
|
|
215
|
-
symbol:
|
|
216
|
-
exchange:
|
|
217
|
-
price:
|
|
218
|
-
size:
|
|
219
|
-
volume:
|
|
220
|
-
side:
|
|
228
|
+
symbol: tradeObj.symbol,
|
|
229
|
+
exchange: tradeObj.exchange,
|
|
230
|
+
price: Number(price),
|
|
231
|
+
size: size,
|
|
232
|
+
volume: volume,
|
|
233
|
+
side: side,
|
|
221
234
|
timestamp: Date.now(),
|
|
222
|
-
ssboe:
|
|
223
|
-
usecs:
|
|
235
|
+
ssboe: tradeObj.ssboe,
|
|
236
|
+
usecs: tradeObj.usecs,
|
|
224
237
|
};
|
|
225
238
|
|
|
226
239
|
this.emit('tick', tick);
|
|
227
240
|
} catch (e) {
|
|
228
|
-
//
|
|
241
|
+
// Silent - don't spam errors
|
|
229
242
|
}
|
|
230
243
|
}
|
|
231
244
|
|
|
@@ -235,19 +248,31 @@ class MarketDataFeed extends EventEmitter {
|
|
|
235
248
|
_handleBBO(data) {
|
|
236
249
|
try {
|
|
237
250
|
const bbo = proto.decode('BestBidOffer', data);
|
|
251
|
+
const bboObj = bbo.toJSON ? bbo.toJSON() : bbo;
|
|
252
|
+
|
|
253
|
+
// protobufjs converts to camelCase
|
|
254
|
+
const bid = bboObj.bidPrice;
|
|
255
|
+
const ask = bboObj.askPrice;
|
|
256
|
+
const bidSize = Number(bboObj.bidSize) || 0;
|
|
257
|
+
const askSize = Number(bboObj.askSize) || 0;
|
|
258
|
+
|
|
259
|
+
// Calculate mid price
|
|
260
|
+
const price = (bid && ask) ? (Number(bid) + Number(ask)) / 2 : (bid || ask || null);
|
|
261
|
+
|
|
262
|
+
if (price === null) return;
|
|
238
263
|
|
|
239
264
|
const tick = {
|
|
240
265
|
type: 'quote',
|
|
241
|
-
symbol:
|
|
242
|
-
exchange:
|
|
243
|
-
bid:
|
|
244
|
-
bidSize:
|
|
245
|
-
ask:
|
|
246
|
-
askSize:
|
|
247
|
-
price:
|
|
266
|
+
symbol: bboObj.symbol,
|
|
267
|
+
exchange: bboObj.exchange,
|
|
268
|
+
bid: bid ? Number(bid) : null,
|
|
269
|
+
bidSize: bidSize,
|
|
270
|
+
ask: ask ? Number(ask) : null,
|
|
271
|
+
askSize: askSize,
|
|
272
|
+
price: Number(price),
|
|
248
273
|
timestamp: Date.now(),
|
|
249
|
-
ssboe:
|
|
250
|
-
usecs:
|
|
274
|
+
ssboe: bboObj.ssboe,
|
|
275
|
+
usecs: bboObj.usecs,
|
|
251
276
|
};
|
|
252
277
|
|
|
253
278
|
this.emit('tick', tick);
|
|
@@ -234,12 +234,12 @@ const executeAlgo = async ({ service, account, contract, config, strategy: strat
|
|
|
234
234
|
aiContext.recentTicks.push(tick);
|
|
235
235
|
if (aiContext.recentTicks.length > aiContext.maxTicks) aiContext.recentTicks.shift();
|
|
236
236
|
|
|
237
|
-
const price = tick.price || tick.tradePrice;
|
|
238
|
-
const bid = tick.bid || tick.bidPrice;
|
|
239
|
-
const ask = tick.ask || tick.askPrice;
|
|
240
|
-
const volume = tick.volume || tick.size || 1;
|
|
237
|
+
const price = Number(tick.price) || Number(tick.tradePrice) || null;
|
|
238
|
+
const bid = Number(tick.bid) || Number(tick.bidPrice) || null;
|
|
239
|
+
const ask = Number(tick.ask) || Number(tick.askPrice) || null;
|
|
240
|
+
const volume = Number(tick.volume) || Number(tick.size) || 1;
|
|
241
241
|
|
|
242
|
-
// Track buy/sell volume
|
|
242
|
+
// Track buy/sell volume (ensure numeric addition)
|
|
243
243
|
if (tick.side === 'buy' || tick.aggressor === 1) buyVolume += volume;
|
|
244
244
|
else if (tick.side === 'sell' || tick.aggressor === 2) sellVolume += volume;
|
|
245
245
|
else if (price && lastPrice) {
|
package/src/pages/algo/ui.js
CHANGED
|
@@ -15,7 +15,7 @@ const BOX = {
|
|
|
15
15
|
// Spinner characters
|
|
16
16
|
const SPINNER = ['\u280B', '\u2819', '\u2839', '\u2838', '\u283C', '\u2834', '\u2826', '\u2827', '\u2807', '\u280F'];
|
|
17
17
|
|
|
18
|
-
// Log type colors - HF grade
|
|
18
|
+
// Log type colors - HF grade with variety
|
|
19
19
|
const LOG_COLORS = {
|
|
20
20
|
// Executions
|
|
21
21
|
fill_buy: chalk.green.bold,
|
|
@@ -23,14 +23,19 @@ const LOG_COLORS = {
|
|
|
23
23
|
fill_win: chalk.green.bold,
|
|
24
24
|
fill_loss: chalk.red.bold,
|
|
25
25
|
// Status
|
|
26
|
-
connected: chalk.green,
|
|
26
|
+
connected: chalk.green.bold,
|
|
27
27
|
ready: chalk.cyan,
|
|
28
28
|
// Errors
|
|
29
29
|
error: chalk.red.bold,
|
|
30
30
|
reject: chalk.red,
|
|
31
|
-
// Info
|
|
32
|
-
info: chalk.
|
|
33
|
-
|
|
31
|
+
// Info - varied colors
|
|
32
|
+
info: chalk.white,
|
|
33
|
+
signal: chalk.yellow.bold,
|
|
34
|
+
trade: chalk.magenta.bold,
|
|
35
|
+
analysis: chalk.blue,
|
|
36
|
+
risk: chalk.yellow,
|
|
37
|
+
system: chalk.blue,
|
|
38
|
+
debug: chalk.gray
|
|
34
39
|
};
|
|
35
40
|
|
|
36
41
|
// Log type icons - compact HF style
|
|
@@ -44,7 +49,12 @@ const LOG_ICONS = {
|
|
|
44
49
|
error: 'ERR ',
|
|
45
50
|
reject: 'REJ ',
|
|
46
51
|
info: 'INFO ',
|
|
47
|
-
|
|
52
|
+
signal: 'SIG ',
|
|
53
|
+
trade: 'TRADE',
|
|
54
|
+
analysis: 'ANLZ ',
|
|
55
|
+
risk: 'RISK ',
|
|
56
|
+
system: 'SYS ',
|
|
57
|
+
debug: 'DBG '
|
|
48
58
|
};
|
|
49
59
|
|
|
50
60
|
/**
|
|
@@ -129,7 +139,7 @@ class AlgoUI {
|
|
|
129
139
|
this._line(chalk.cyan(BOX.ML + BOX.H.repeat(W) + BOX.MR));
|
|
130
140
|
this._line(chalk.cyan(BOX.V) + chalk.yellow(center(`PROP FUTURES ALGO TRADING V${version}`, W)) + chalk.cyan(BOX.V));
|
|
131
141
|
this._line(chalk.cyan(BOX.ML + BOX.H.repeat(W) + BOX.MR));
|
|
132
|
-
this._line(chalk.cyan(BOX.V) + chalk.
|
|
142
|
+
this._line(chalk.cyan(BOX.V) + chalk.cyan.bold(center((this.config.subtitle || 'HQX ALGO TRADING').toUpperCase(), W)) + chalk.cyan(BOX.V));
|
|
133
143
|
}
|
|
134
144
|
|
|
135
145
|
_drawStats(stats) {
|
|
@@ -199,7 +209,7 @@ class AlgoUI {
|
|
|
199
209
|
|
|
200
210
|
// Row 5: Connection | Propfirm
|
|
201
211
|
const connection = stats.platform || 'Rithmic';
|
|
202
|
-
const r5c1 = buildCell('Connection', connection, chalk.
|
|
212
|
+
const r5c1 = buildCell('Connection', connection, chalk.cyan, colL);
|
|
203
213
|
const r5c2 = buildCell('Propfirm', stats.propfirm || 'N/A', chalk.cyan, colR);
|
|
204
214
|
row(r5c1.padded, r5c2.padded);
|
|
205
215
|
|
|
@@ -267,9 +277,11 @@ class AlgoUI {
|
|
|
267
277
|
_drawLogs() {
|
|
268
278
|
const { W, logs, maxLogs } = this;
|
|
269
279
|
|
|
270
|
-
// Activity header - HF style
|
|
271
|
-
|
|
272
|
-
|
|
280
|
+
// Activity header - HF style with animated spinner
|
|
281
|
+
const elapsed = Math.floor((Date.now() - (this.startTime || Date.now())) / 100);
|
|
282
|
+
if (!this.startTime) this.startTime = Date.now();
|
|
283
|
+
const spinnerIdx = elapsed % SPINNER.length;
|
|
284
|
+
const spinner = SPINNER[spinnerIdx];
|
|
273
285
|
const now = new Date();
|
|
274
286
|
const timeStr = now.toLocaleTimeString('en-US', { hour12: false });
|
|
275
287
|
const dateStr = now.toLocaleDateString('en-US', { month: 'short', day: 'numeric' });
|