mdas-jsview-sdk 1.0.17-uat.0 → 1.0.21-uat.0
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/dist/mdas-sdk.esm.js +374 -153
- package/dist/mdas-sdk.esm.js.map +1 -1
- package/dist/mdas-sdk.js +374 -153
- package/dist/mdas-sdk.js.map +1 -1
- package/dist/mdas-sdk.min.js +9 -9
- package/dist/mdas-sdk.min.js.map +1 -1
- package/package.json +1 -1
package/dist/mdas-sdk.esm.js
CHANGED
|
@@ -1277,6 +1277,24 @@ const ONBBOLevel2Template = `
|
|
|
1277
1277
|
<span class="l2-market-name"></span>
|
|
1278
1278
|
</div>
|
|
1279
1279
|
<span class="symbol editable-symbol">--</span>
|
|
1280
|
+
<div class="level1-info">
|
|
1281
|
+
<div class="l1-item">
|
|
1282
|
+
<span class="l1-label">Last:</span>
|
|
1283
|
+
<span class="l1-value l1-last-px">--</span>
|
|
1284
|
+
</div>
|
|
1285
|
+
<div class="l1-item">
|
|
1286
|
+
<span class="l1-label">Low:</span>
|
|
1287
|
+
<span class="l1-value l1-low-px">--</span>
|
|
1288
|
+
</div>
|
|
1289
|
+
<div class="l1-item">
|
|
1290
|
+
<span class="l1-label">High:</span>
|
|
1291
|
+
<span class="l1-value l1-high-px">--</span>
|
|
1292
|
+
</div>
|
|
1293
|
+
<div class="l1-item">
|
|
1294
|
+
<span class="l1-label">Volume:</span>
|
|
1295
|
+
<span class="l1-value l1-volume">--</span>
|
|
1296
|
+
</div>
|
|
1297
|
+
</div>
|
|
1280
1298
|
</div>
|
|
1281
1299
|
</div>
|
|
1282
1300
|
|
|
@@ -1951,6 +1969,38 @@ const ONBBOLevel2Styles = `
|
|
|
1951
1969
|
color: #111827;
|
|
1952
1970
|
}
|
|
1953
1971
|
|
|
1972
|
+
/* ========================================
|
|
1973
|
+
LEVEL 1 INFO (INSIDE HEADER)
|
|
1974
|
+
======================================== */
|
|
1975
|
+
|
|
1976
|
+
.onbbo-level2-widget .level1-info {
|
|
1977
|
+
display: grid;
|
|
1978
|
+
grid-template-columns: repeat(4, 1fr);
|
|
1979
|
+
gap: 12px;
|
|
1980
|
+
margin-top: 10px;
|
|
1981
|
+
}
|
|
1982
|
+
|
|
1983
|
+
.onbbo-level2-widget .l1-item {
|
|
1984
|
+
display: flex;
|
|
1985
|
+
flex-direction: column;
|
|
1986
|
+
gap: 3px;
|
|
1987
|
+
}
|
|
1988
|
+
|
|
1989
|
+
.onbbo-level2-widget .l1-label {
|
|
1990
|
+
font-size: 11px;
|
|
1991
|
+
font-weight: 600;
|
|
1992
|
+
color: #6b7280;
|
|
1993
|
+
text-transform: uppercase;
|
|
1994
|
+
letter-spacing: 0.5px;
|
|
1995
|
+
}
|
|
1996
|
+
|
|
1997
|
+
.onbbo-level2-widget .l1-value {
|
|
1998
|
+
font-size: 15px;
|
|
1999
|
+
font-weight: 700;
|
|
2000
|
+
color: #111827;
|
|
2001
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
2002
|
+
}
|
|
2003
|
+
|
|
1954
2004
|
/* ========================================
|
|
1955
2005
|
ORDER BOOK CONTAINER
|
|
1956
2006
|
======================================== */
|
|
@@ -2335,6 +2385,11 @@ const ONBBOLevel2Styles = `
|
|
|
2335
2385
|
.onbbo-level2-widget .orderbook-panel:last-child {
|
|
2336
2386
|
border-bottom: none;
|
|
2337
2387
|
}
|
|
2388
|
+
|
|
2389
|
+
.onbbo-level2-widget .level1-info {
|
|
2390
|
+
grid-template-columns: repeat(2, 1fr);
|
|
2391
|
+
gap: 6px;
|
|
2392
|
+
}
|
|
2338
2393
|
}
|
|
2339
2394
|
|
|
2340
2395
|
@media (max-width: 480px) {
|
|
@@ -2353,6 +2408,19 @@ const ONBBOLevel2Styles = `
|
|
|
2353
2408
|
text-align: left;
|
|
2354
2409
|
}
|
|
2355
2410
|
|
|
2411
|
+
.onbbo-level2-widget .level1-info {
|
|
2412
|
+
grid-template-columns: repeat(2, 1fr);
|
|
2413
|
+
gap: 4px;
|
|
2414
|
+
}
|
|
2415
|
+
|
|
2416
|
+
.onbbo-level2-widget .l1-label {
|
|
2417
|
+
font-size: 9px;
|
|
2418
|
+
}
|
|
2419
|
+
|
|
2420
|
+
.onbbo-level2-widget .l1-value {
|
|
2421
|
+
font-size: 11px;
|
|
2422
|
+
}
|
|
2423
|
+
|
|
2356
2424
|
.onbbo-level2-widget .panel-header {
|
|
2357
2425
|
font-size: 10px;
|
|
2358
2426
|
padding: 6px 2px;
|
|
@@ -4501,13 +4569,14 @@ class MarketDataWidget extends BaseWidget {
|
|
|
4501
4569
|
} */
|
|
4502
4570
|
|
|
4503
4571
|
handleData(message) {
|
|
4572
|
+
console.log('DEBUG', message);
|
|
4504
4573
|
if (this.loadingTimeout) {
|
|
4505
4574
|
clearTimeout(this.loadingTimeout);
|
|
4506
4575
|
this.loadingTimeout = null;
|
|
4507
4576
|
}
|
|
4508
4577
|
|
|
4509
4578
|
// Handle error messages from server (plain text converted to structured format)
|
|
4510
|
-
if (message.type === 'error'
|
|
4579
|
+
if (message.type === 'error') {
|
|
4511
4580
|
if (this.debug) {
|
|
4512
4581
|
console.log('[MarketDataWidget] Received no data message:', message.message);
|
|
4513
4582
|
}
|
|
@@ -5277,13 +5346,16 @@ class NightSessionWidget extends BaseWidget {
|
|
|
5277
5346
|
// to avoid duplicate timeouts
|
|
5278
5347
|
}
|
|
5279
5348
|
handleData(message) {
|
|
5349
|
+
console.log('DEBUG NIGHT', message);
|
|
5350
|
+
//message = message.data || message.Data
|
|
5351
|
+
|
|
5280
5352
|
if (this.loadingTimeout) {
|
|
5281
5353
|
clearTimeout(this.loadingTimeout);
|
|
5282
5354
|
this.loadingTimeout = null;
|
|
5283
5355
|
}
|
|
5284
5356
|
|
|
5285
5357
|
// Handle error messages from server (plain text converted to structured format)
|
|
5286
|
-
if (message.type === 'error'
|
|
5358
|
+
if (message.type === 'error' || message.error == true) {
|
|
5287
5359
|
if (this.debug) {
|
|
5288
5360
|
console.log('[NightSessionWidget] Received no data message:', message.message);
|
|
5289
5361
|
}
|
|
@@ -5339,9 +5411,10 @@ class NightSessionWidget extends BaseWidget {
|
|
|
5339
5411
|
}
|
|
5340
5412
|
|
|
5341
5413
|
// Filter for night session data
|
|
5342
|
-
|
|
5414
|
+
|
|
5415
|
+
if (Array.isArray(message.data)) {
|
|
5343
5416
|
// First, try to find data matching our symbol regardless of MarketName
|
|
5344
|
-
const symbolData = message.find(item => item.Symbol === this.symbol);
|
|
5417
|
+
const symbolData = message.data.find(item => item.Symbol === this.symbol);
|
|
5345
5418
|
if (symbolData) {
|
|
5346
5419
|
if (this.debug) {
|
|
5347
5420
|
console.log('[NightSessionWidget] Found data for symbol:', symbolData);
|
|
@@ -5381,34 +5454,35 @@ class NightSessionWidget extends BaseWidget {
|
|
|
5381
5454
|
}
|
|
5382
5455
|
}
|
|
5383
5456
|
// Handle wrapped format
|
|
5384
|
-
else if (message.type === 'queryblueoceanl1' || message.type === 'querybrucel1' || message.type === 'queryonbbol1') {
|
|
5385
|
-
|
|
5386
|
-
|
|
5387
|
-
|
|
5388
|
-
|
|
5389
|
-
|
|
5390
|
-
|
|
5391
|
-
|
|
5392
|
-
|
|
5393
|
-
|
|
5394
|
-
|
|
5395
|
-
|
|
5396
|
-
|
|
5457
|
+
/* else if (message.type === 'queryblueoceanl1' || message.type === 'querybrucel1' || message.type === 'queryonbbol1') {
|
|
5458
|
+
if (message.data['0']?.Symbol === this.symbol) {
|
|
5459
|
+
// For onbbo source, skip MarketName check
|
|
5460
|
+
const isOnbbo = message.type === 'queryonbbol1';
|
|
5461
|
+
const shouldShowNoData = message['0'].NotFound === true ||
|
|
5462
|
+
(!isOnbbo && (!message['0'].MarketName || message['0'].MarketName !== 'BLUE'));
|
|
5463
|
+
if (shouldShowNoData) {
|
|
5464
|
+
// Only show no data state if we don't have cached data
|
|
5465
|
+
if (!this.data) {
|
|
5466
|
+
this.showNoDataState(message['0']);
|
|
5467
|
+
} else {
|
|
5468
|
+
this.hideLoading();
|
|
5469
|
+
if (this.debug) {
|
|
5470
|
+
console.log('[NightSessionWidget] No new data, keeping cached data visible');
|
|
5471
|
+
}
|
|
5472
|
+
}
|
|
5473
|
+
} else {
|
|
5474
|
+
const model = new NightSessionModel(message['0']);
|
|
5475
|
+
this.data = model; // Store for caching
|
|
5476
|
+
this.updateWidget(model);
|
|
5397
5477
|
}
|
|
5398
|
-
}
|
|
5399
5478
|
} else {
|
|
5400
|
-
|
|
5401
|
-
|
|
5402
|
-
|
|
5403
|
-
|
|
5404
|
-
|
|
5405
|
-
// No matching symbol - keep cached data if available
|
|
5406
|
-
if (this.debug) {
|
|
5407
|
-
console.log('[NightSessionWidget] No matching symbol in response, keeping cached data');
|
|
5479
|
+
// No matching symbol - keep cached data if available
|
|
5480
|
+
if (this.debug) {
|
|
5481
|
+
console.log('[NightSessionWidget] No matching symbol in response, keeping cached data');
|
|
5482
|
+
}
|
|
5483
|
+
this.hideLoading();
|
|
5408
5484
|
}
|
|
5409
|
-
|
|
5410
|
-
}
|
|
5411
|
-
}
|
|
5485
|
+
} */
|
|
5412
5486
|
if (message._cached) ;
|
|
5413
5487
|
}
|
|
5414
5488
|
updateWidget(data) {
|
|
@@ -39085,7 +39159,7 @@ class IntradayChartWidget extends BaseWidget {
|
|
|
39085
39159
|
let priceData = null;
|
|
39086
39160
|
|
|
39087
39161
|
// Handle array format (standard night session format)
|
|
39088
|
-
if (Array.isArray(message)) {
|
|
39162
|
+
if (Array.isArray(message.data)) {
|
|
39089
39163
|
console.log('[IntradayChartWidget] Processing array format, length:', message.length);
|
|
39090
39164
|
const symbolData = message.find(item => item.Symbol === this.symbol);
|
|
39091
39165
|
console.log('[IntradayChartWidget] Found symbol data:', symbolData);
|
|
@@ -40056,8 +40130,10 @@ class ONBBOLevel2Widget extends BaseWidget {
|
|
|
40056
40130
|
this.styled = options.styled !== undefined ? options.styled : true;
|
|
40057
40131
|
this.maxLevels = options.maxLevels || 10; // Number of levels to display
|
|
40058
40132
|
this.data = null;
|
|
40133
|
+
this.level1Data = null; // Store Level 1 data separately
|
|
40059
40134
|
this.isDestroyed = false;
|
|
40060
|
-
this.
|
|
40135
|
+
this.unsubscribeL2 = null;
|
|
40136
|
+
this.unsubscribeL1 = null;
|
|
40061
40137
|
this.symbolEditor = null;
|
|
40062
40138
|
this.loadingTimeout = null;
|
|
40063
40139
|
|
|
@@ -40158,13 +40234,22 @@ class ONBBOLevel2Widget extends BaseWidget {
|
|
|
40158
40234
|
this.showError(`No data received for ${upperSymbol}. Please try again.`);
|
|
40159
40235
|
}, 10000);
|
|
40160
40236
|
|
|
40161
|
-
// Unsubscribe from old symbol
|
|
40162
|
-
if (this.
|
|
40237
|
+
// Unsubscribe from old symbol's L2 and L1 data
|
|
40238
|
+
if (this.unsubscribeL2) {
|
|
40163
40239
|
if (this.debug) {
|
|
40164
|
-
console.log(`[ONBBOLevel2Widget] Unsubscribing from ${this.symbol}`);
|
|
40240
|
+
console.log(`[ONBBOLevel2Widget] Unsubscribing from ${this.symbol} L2`);
|
|
40165
40241
|
}
|
|
40166
|
-
this.
|
|
40167
|
-
this.
|
|
40242
|
+
this.wsManager.sendUnsubscribe('queryonbbol2', this.symbol);
|
|
40243
|
+
this.unsubscribeL2();
|
|
40244
|
+
this.unsubscribeL2 = null;
|
|
40245
|
+
}
|
|
40246
|
+
if (this.unsubscribeL1) {
|
|
40247
|
+
if (this.debug) {
|
|
40248
|
+
console.log(`[ONBBOLevel2Widget] Unsubscribing from ${this.symbol} L1`);
|
|
40249
|
+
}
|
|
40250
|
+
this.wsManager.sendUnsubscribe('queryonbbol1', this.symbol);
|
|
40251
|
+
this.unsubscribeL1();
|
|
40252
|
+
this.unsubscribeL1 = null;
|
|
40168
40253
|
}
|
|
40169
40254
|
|
|
40170
40255
|
// Update internal symbol
|
|
@@ -40234,10 +40319,51 @@ class ONBBOLevel2Widget extends BaseWidget {
|
|
|
40234
40319
|
}
|
|
40235
40320
|
}
|
|
40236
40321
|
subscribeToData() {
|
|
40237
|
-
// Subscribe to ONBBO Level 2 data
|
|
40238
|
-
|
|
40239
|
-
|
|
40240
|
-
|
|
40322
|
+
// Subscribe to ONBBO Level 2 data (order book)
|
|
40323
|
+
// Use separate widget IDs to avoid "already active" duplicate detection
|
|
40324
|
+
this.unsubscribeL2 = this.wsManager.subscribe(`${this.widgetId}-l2`, ['queryonbbol2'], messageWrapper => {
|
|
40325
|
+
const {
|
|
40326
|
+
event,
|
|
40327
|
+
data
|
|
40328
|
+
} = messageWrapper;
|
|
40329
|
+
|
|
40330
|
+
// Handle connection events
|
|
40331
|
+
if (event === 'connection') {
|
|
40332
|
+
this.handleConnectionStatus(data);
|
|
40333
|
+
return;
|
|
40334
|
+
}
|
|
40335
|
+
|
|
40336
|
+
// For data events, add type context
|
|
40337
|
+
if (event === 'data') {
|
|
40338
|
+
data._dataType = 'level2';
|
|
40339
|
+
this.handleMessage({
|
|
40340
|
+
event,
|
|
40341
|
+
data
|
|
40342
|
+
});
|
|
40343
|
+
}
|
|
40344
|
+
}, this.symbol);
|
|
40345
|
+
|
|
40346
|
+
// Subscribe to ONBBO Level 1 data (statistics: LastPx, LowPx, HighPx, Volume)
|
|
40347
|
+
this.unsubscribeL1 = this.wsManager.subscribe(`${this.widgetId}-l1`, ['queryonbbol1'], messageWrapper => {
|
|
40348
|
+
const {
|
|
40349
|
+
event,
|
|
40350
|
+
data
|
|
40351
|
+
} = messageWrapper;
|
|
40352
|
+
|
|
40353
|
+
// Connection already handled by L2 subscription
|
|
40354
|
+
if (event === 'connection') {
|
|
40355
|
+
return;
|
|
40356
|
+
}
|
|
40357
|
+
|
|
40358
|
+
// For data events, add type context
|
|
40359
|
+
if (event === 'data') {
|
|
40360
|
+
data._dataType = 'level1';
|
|
40361
|
+
this.handleMessage({
|
|
40362
|
+
event,
|
|
40363
|
+
data
|
|
40364
|
+
});
|
|
40365
|
+
}
|
|
40366
|
+
}, this.symbol);
|
|
40241
40367
|
}
|
|
40242
40368
|
handleData(message) {
|
|
40243
40369
|
if (this.loadingTimeout) {
|
|
@@ -40245,8 +40371,14 @@ class ONBBOLevel2Widget extends BaseWidget {
|
|
|
40245
40371
|
this.loadingTimeout = null;
|
|
40246
40372
|
}
|
|
40247
40373
|
|
|
40374
|
+
// Extract data type from metadata (added by subscription callback)
|
|
40375
|
+
const dataType = message._dataType;
|
|
40376
|
+
if (this.debug) {
|
|
40377
|
+
console.log(`[ONBBOLevel2Widget] handleData called with type: ${dataType}`, message);
|
|
40378
|
+
}
|
|
40379
|
+
|
|
40248
40380
|
// Handle error messages
|
|
40249
|
-
if (message.type === 'error') {
|
|
40381
|
+
if (message.type === 'error' || message.error == true) {
|
|
40250
40382
|
const errorMsg = message.message || 'Server error';
|
|
40251
40383
|
if (this.debug) {
|
|
40252
40384
|
console.log('[ONBBOLevel2Widget] Error:', errorMsg);
|
|
@@ -40255,16 +40387,54 @@ class ONBBOLevel2Widget extends BaseWidget {
|
|
|
40255
40387
|
return;
|
|
40256
40388
|
}
|
|
40257
40389
|
|
|
40390
|
+
// Handle Level 1 data (statistics: LastPx, LowPx, HighPx, Volume)
|
|
40391
|
+
if (message.type === 'queryonbbol1') {
|
|
40392
|
+
if (this.debug) {
|
|
40393
|
+
console.log('[ONBBOLevel2Widget] Processing Level 1 data:', message);
|
|
40394
|
+
}
|
|
40395
|
+
|
|
40396
|
+
// Handle array format (new format with Data wrapper)
|
|
40397
|
+
if (message.data && Array.isArray(message.data)) {
|
|
40398
|
+
const l1Data = message.data.find(d => d.Symbol === this.symbol);
|
|
40399
|
+
if (l1Data) {
|
|
40400
|
+
this.level1Data = {
|
|
40401
|
+
lastPx: l1Data.LastPx || 0,
|
|
40402
|
+
lowPx: l1Data.LowPx || 0,
|
|
40403
|
+
highPx: l1Data.HighPx || 0,
|
|
40404
|
+
volume: l1Data.Volume || 0
|
|
40405
|
+
};
|
|
40406
|
+
this.updateLevel1Display();
|
|
40407
|
+
}
|
|
40408
|
+
}
|
|
40409
|
+
// Handle direct array format (standard format)
|
|
40410
|
+
else if (Array.isArray(message)) {
|
|
40411
|
+
const l1Data = message.find(d => d.Symbol === this.symbol);
|
|
40412
|
+
if (l1Data) {
|
|
40413
|
+
this.level1Data = {
|
|
40414
|
+
lastPx: l1Data.LastPx || 0,
|
|
40415
|
+
lowPx: l1Data.LowPx || 0,
|
|
40416
|
+
highPx: l1Data.HighPx || 0,
|
|
40417
|
+
volume: l1Data.Volume || 0
|
|
40418
|
+
};
|
|
40419
|
+
this.updateLevel1Display();
|
|
40420
|
+
}
|
|
40421
|
+
}
|
|
40422
|
+
|
|
40423
|
+
// Clean up metadata
|
|
40424
|
+
delete message._dataType;
|
|
40425
|
+
return;
|
|
40426
|
+
}
|
|
40427
|
+
|
|
40258
40428
|
// Handle Level 2 data - Array of MMID quotes
|
|
40259
|
-
if (Array.isArray(message)) {
|
|
40429
|
+
if (Array.isArray(message.data)) {
|
|
40260
40430
|
// Check if it's an array of MMID objects (ONBBO format)
|
|
40261
|
-
if (message.length > 0 && message[0].MMID) {
|
|
40431
|
+
if (message.data.length > 0 && message.data[0].MMID) {
|
|
40262
40432
|
if (this.debug) {
|
|
40263
40433
|
console.log('[ONBBOLevel2Widget] Received MMID array:', message);
|
|
40264
40434
|
}
|
|
40265
40435
|
|
|
40266
40436
|
// Create model from MMID array
|
|
40267
|
-
const model = new ONBBOLevel2Model(message);
|
|
40437
|
+
const model = new ONBBOLevel2Model(message.data);
|
|
40268
40438
|
model.symbol = this.symbol; // Set symbol from widget
|
|
40269
40439
|
this.data = model;
|
|
40270
40440
|
this.updateWidget(model);
|
|
@@ -40272,7 +40442,7 @@ class ONBBOLevel2Widget extends BaseWidget {
|
|
|
40272
40442
|
}
|
|
40273
40443
|
|
|
40274
40444
|
// Try to find symbol in array (alternative format)
|
|
40275
|
-
const symbolData = message.find(item => item.Symbol === this.symbol);
|
|
40445
|
+
const symbolData = message.data.find(item => item.Symbol === this.symbol);
|
|
40276
40446
|
if (symbolData) {
|
|
40277
40447
|
if (symbolData.NotFound === true) {
|
|
40278
40448
|
this.showError(`No Level 2 data available for ${this.symbol}`);
|
|
@@ -40286,32 +40456,31 @@ class ONBBOLevel2Widget extends BaseWidget {
|
|
|
40286
40456
|
this.showError(`No Level 2 data available for ${this.symbol}`);
|
|
40287
40457
|
}
|
|
40288
40458
|
// Handle wrapped format
|
|
40289
|
-
else if (message.type === 'queryonbbol2') {
|
|
40290
|
-
|
|
40291
|
-
|
|
40292
|
-
|
|
40293
|
-
|
|
40459
|
+
/* else if (message.type === 'queryonbbol2') {
|
|
40460
|
+
// Check if wrapped data contains MMID array
|
|
40461
|
+
if (message['0'] && Array.isArray(message['0'])) {
|
|
40462
|
+
if (this.debug) {
|
|
40463
|
+
console.log('[ONBBOLevel2Widget] Received wrapped MMID array:', message['0']);
|
|
40464
|
+
}
|
|
40465
|
+
const model = new ONBBOLevel2Model(message['0']);
|
|
40466
|
+
model.symbol = this.symbol;
|
|
40467
|
+
this.data = model;
|
|
40468
|
+
this.updateWidget(model);
|
|
40469
|
+
return;
|
|
40294
40470
|
}
|
|
40295
|
-
|
|
40296
|
-
|
|
40297
|
-
|
|
40298
|
-
|
|
40299
|
-
|
|
40300
|
-
|
|
40301
|
-
|
|
40302
|
-
|
|
40303
|
-
|
|
40304
|
-
if (message['0'].NotFound === true) {
|
|
40305
|
-
this.showError(`No Level 2 data available for ${this.symbol}`);
|
|
40471
|
+
// Check for symbol match in wrapped format
|
|
40472
|
+
if (message['0']?.Symbol === this.symbol) {
|
|
40473
|
+
if (message['0'].NotFound === true) {
|
|
40474
|
+
this.showError(`No Level 2 data available for ${this.symbol}`);
|
|
40475
|
+
} else {
|
|
40476
|
+
const model = new ONBBOLevel2Model(message['0']);
|
|
40477
|
+
this.data = model;
|
|
40478
|
+
this.updateWidget(model);
|
|
40479
|
+
}
|
|
40306
40480
|
} else {
|
|
40307
|
-
|
|
40308
|
-
this.data = model;
|
|
40309
|
-
this.updateWidget(model);
|
|
40481
|
+
this.showError(`No Level 2 data available for ${this.symbol}`);
|
|
40310
40482
|
}
|
|
40311
|
-
|
|
40312
|
-
this.showError(`No Level 2 data available for ${this.symbol}`);
|
|
40313
|
-
}
|
|
40314
|
-
}
|
|
40483
|
+
} */
|
|
40315
40484
|
}
|
|
40316
40485
|
updateWidget(data) {
|
|
40317
40486
|
if (this.isDestroyed) return;
|
|
@@ -40409,6 +40578,43 @@ class ONBBOLevel2Widget extends BaseWidget {
|
|
|
40409
40578
|
askBody.appendChild(row);
|
|
40410
40579
|
});
|
|
40411
40580
|
}
|
|
40581
|
+
updateLevel1Display() {
|
|
40582
|
+
if (!this.level1Data) return;
|
|
40583
|
+
const formatPrice = price => {
|
|
40584
|
+
return price ? price.toFixed(2) : '--';
|
|
40585
|
+
};
|
|
40586
|
+
const formatVolume = volume => {
|
|
40587
|
+
if (!volume) return '--';
|
|
40588
|
+
return volume.toLocaleString();
|
|
40589
|
+
};
|
|
40590
|
+
|
|
40591
|
+
// Update Last Price
|
|
40592
|
+
const lastPxElement = this.container.querySelector('.l1-last-px');
|
|
40593
|
+
if (lastPxElement) {
|
|
40594
|
+
lastPxElement.textContent = formatPrice(this.level1Data.lastPx);
|
|
40595
|
+
}
|
|
40596
|
+
|
|
40597
|
+
// Update Low Price
|
|
40598
|
+
const lowPxElement = this.container.querySelector('.l1-low-px');
|
|
40599
|
+
if (lowPxElement) {
|
|
40600
|
+
lowPxElement.textContent = formatPrice(this.level1Data.lowPx);
|
|
40601
|
+
}
|
|
40602
|
+
|
|
40603
|
+
// Update High Price
|
|
40604
|
+
const highPxElement = this.container.querySelector('.l1-high-px');
|
|
40605
|
+
if (highPxElement) {
|
|
40606
|
+
highPxElement.textContent = formatPrice(this.level1Data.highPx);
|
|
40607
|
+
}
|
|
40608
|
+
|
|
40609
|
+
// Update Volume
|
|
40610
|
+
const volumeElement = this.container.querySelector('.l1-volume');
|
|
40611
|
+
if (volumeElement) {
|
|
40612
|
+
volumeElement.textContent = formatVolume(this.level1Data.volume);
|
|
40613
|
+
}
|
|
40614
|
+
if (this.debug) {
|
|
40615
|
+
console.log('[ONBBOLevel2Widget] Updated Level 1 display:', this.level1Data);
|
|
40616
|
+
}
|
|
40617
|
+
}
|
|
40412
40618
|
showLoading() {
|
|
40413
40619
|
const loadingOverlay = this.container.querySelector('.widget-loading-overlay');
|
|
40414
40620
|
if (loadingOverlay) {
|
|
@@ -40455,9 +40661,17 @@ class ONBBOLevel2Widget extends BaseWidget {
|
|
|
40455
40661
|
this.clearTimeout(this.loadingTimeout);
|
|
40456
40662
|
this.loadingTimeout = null;
|
|
40457
40663
|
}
|
|
40458
|
-
|
|
40459
|
-
|
|
40460
|
-
|
|
40664
|
+
|
|
40665
|
+
// Unsubscribe from L2 data
|
|
40666
|
+
if (this.unsubscribeL2) {
|
|
40667
|
+
this.unsubscribeL2();
|
|
40668
|
+
this.unsubscribeL2 = null;
|
|
40669
|
+
}
|
|
40670
|
+
|
|
40671
|
+
// Unsubscribe from L1 data
|
|
40672
|
+
if (this.unsubscribeL1) {
|
|
40673
|
+
this.unsubscribeL1();
|
|
40674
|
+
this.unsubscribeL1 = null;
|
|
40461
40675
|
}
|
|
40462
40676
|
|
|
40463
40677
|
// Destroy the symbol editor
|
|
@@ -41583,6 +41797,7 @@ class WebSocketManager {
|
|
|
41583
41797
|
}
|
|
41584
41798
|
}
|
|
41585
41799
|
handleMessage(event) {
|
|
41800
|
+
//console.log('EVENT', event)
|
|
41586
41801
|
try {
|
|
41587
41802
|
// Update activity tracking - connection is alive!
|
|
41588
41803
|
this.lastMessageReceived = Date.now();
|
|
@@ -41607,22 +41822,20 @@ class WebSocketManager {
|
|
|
41607
41822
|
return;
|
|
41608
41823
|
}
|
|
41609
41824
|
|
|
41610
|
-
// Determine
|
|
41611
|
-
const
|
|
41825
|
+
// Determine type based on error content, default to 'error'
|
|
41826
|
+
const errorType = this._getTargetTypeFromErrorMessage(textMessage) || 'error';
|
|
41612
41827
|
if (textMessage.toLowerCase().includes('no night session') || textMessage.toLowerCase().includes('no data')) {
|
|
41613
41828
|
message = {
|
|
41614
|
-
type:
|
|
41829
|
+
type: errorType,
|
|
41615
41830
|
message: textMessage,
|
|
41616
|
-
error:
|
|
41617
|
-
noData: true
|
|
41618
|
-
targetType: targetType // Will be 'querynightsession' for night session errors
|
|
41831
|
+
error: true,
|
|
41832
|
+
noData: true
|
|
41619
41833
|
};
|
|
41620
41834
|
} else {
|
|
41621
41835
|
message = {
|
|
41622
|
-
type:
|
|
41836
|
+
type: errorType,
|
|
41623
41837
|
message: textMessage,
|
|
41624
|
-
error:
|
|
41625
|
-
targetType: targetType // Could be null for general errors
|
|
41838
|
+
error: true
|
|
41626
41839
|
};
|
|
41627
41840
|
}
|
|
41628
41841
|
}
|
|
@@ -41630,9 +41843,16 @@ class WebSocketManager {
|
|
|
41630
41843
|
console.log('[WebSocketManager] Processed message:', message);
|
|
41631
41844
|
}
|
|
41632
41845
|
|
|
41633
|
-
//
|
|
41634
|
-
|
|
41635
|
-
|
|
41846
|
+
// Extract data field for night session messages to avoid nested structure
|
|
41847
|
+
// Night session format: { type: 'queryonbbol1', error: false, data: [...] }
|
|
41848
|
+
// We want to send just the data array to widgets
|
|
41849
|
+
let dataToRoute = message;
|
|
41850
|
+
/* if (message.data !== undefined && message.type !== undefined) {
|
|
41851
|
+
// This is night session format - extract the data
|
|
41852
|
+
dataToRoute = message.data;
|
|
41853
|
+
} */
|
|
41854
|
+
|
|
41855
|
+
this._routeMessage(dataToRoute);
|
|
41636
41856
|
} catch (error) {
|
|
41637
41857
|
console.error('[WebSocketManager] Error handling message:', error);
|
|
41638
41858
|
this._notifyWidgets('error', {
|
|
@@ -41771,7 +41991,31 @@ class WebSocketManager {
|
|
|
41771
41991
|
}
|
|
41772
41992
|
} else {
|
|
41773
41993
|
if (this.config.debug) {
|
|
41774
|
-
console.log(`[WebSocketManager] Subscription ${subscriptionKey} already active, skipping`);
|
|
41994
|
+
console.log(`[WebSocketManager] Subscription ${subscriptionKey} already active, skipping server subscription`);
|
|
41995
|
+
}
|
|
41996
|
+
|
|
41997
|
+
// Subscription already active, but send cached data to newly subscribing widgets
|
|
41998
|
+
const cachedMessage = this.lastMessageCache.get(subscriptionKey);
|
|
41999
|
+
console.log('LAST', this.lastMessageCache);
|
|
42000
|
+
if (cachedMessage) {
|
|
42001
|
+
if (this.config.debug) {
|
|
42002
|
+
console.log(`[WebSocketManager] Sending cached data to newly subscribing widgets for ${subscriptionKey}`);
|
|
42003
|
+
}
|
|
42004
|
+
|
|
42005
|
+
// Find all widgets subscribed to this type:symbol combination
|
|
42006
|
+
this.subscriptions.forEach((subscription, widgetId) => {
|
|
42007
|
+
if (subscription.types.has(type) && subscription.symbol === symbol) {
|
|
42008
|
+
try {
|
|
42009
|
+
subscription.callback({
|
|
42010
|
+
event: 'data',
|
|
42011
|
+
data: cachedMessage,
|
|
42012
|
+
widgetId
|
|
42013
|
+
});
|
|
42014
|
+
} catch (error) {
|
|
42015
|
+
console.error(`[WebSocketManager] Error sending cached data to widget ${widgetId}:`, error);
|
|
42016
|
+
}
|
|
42017
|
+
}
|
|
42018
|
+
});
|
|
41775
42019
|
}
|
|
41776
42020
|
}
|
|
41777
42021
|
});
|
|
@@ -41823,11 +42067,6 @@ class WebSocketManager {
|
|
|
41823
42067
|
* The data field structure varies based on the type
|
|
41824
42068
|
*/
|
|
41825
42069
|
_normalizeMessage(message) {
|
|
41826
|
-
// If message already has targetType (error messages), return as is
|
|
41827
|
-
if (message.targetType) {
|
|
41828
|
-
return message;
|
|
41829
|
-
}
|
|
41830
|
-
|
|
41831
42070
|
// Check for error field (case-insensitive)
|
|
41832
42071
|
const errorField = message.error || message.Error;
|
|
41833
42072
|
const typeField = message.type || message.Type;
|
|
@@ -41838,13 +42077,12 @@ class WebSocketManager {
|
|
|
41838
42077
|
if (this.config.debug) {
|
|
41839
42078
|
console.log(`[WebSocketManager] Detected error message with type: ${typeField}`);
|
|
41840
42079
|
}
|
|
41841
|
-
|
|
41842
|
-
// Set targetType for routing to specific widget types
|
|
41843
42080
|
return {
|
|
41844
42081
|
...message,
|
|
41845
|
-
|
|
41846
|
-
type
|
|
41847
|
-
|
|
42082
|
+
// Only add type if message doesn't already have one
|
|
42083
|
+
...(!message.type && !message.Type && typeField ? {
|
|
42084
|
+
type: typeField
|
|
42085
|
+
} : {})
|
|
41848
42086
|
};
|
|
41849
42087
|
}
|
|
41850
42088
|
|
|
@@ -41862,10 +42100,11 @@ class WebSocketManager {
|
|
|
41862
42100
|
// Treat as error and route based on type
|
|
41863
42101
|
return {
|
|
41864
42102
|
...message,
|
|
41865
|
-
|
|
41866
|
-
type
|
|
41867
|
-
|
|
41868
|
-
|
|
42103
|
+
// Only add type if message doesn't already have one
|
|
42104
|
+
...(!message.type && !message.Type && typeField ? {
|
|
42105
|
+
type: typeField
|
|
42106
|
+
} : {}),
|
|
42107
|
+
error: true // Mark as error since it was detected as implicit error
|
|
41869
42108
|
};
|
|
41870
42109
|
}
|
|
41871
42110
|
}
|
|
@@ -41899,8 +42138,8 @@ class WebSocketManager {
|
|
|
41899
42138
|
};
|
|
41900
42139
|
}
|
|
41901
42140
|
|
|
41902
|
-
//
|
|
41903
|
-
if (typeof normalizedData === 'object' && !normalizedData.type) {
|
|
42141
|
+
// Only add type field if the normalized data doesn't already have one
|
|
42142
|
+
if (typeof normalizedData === 'object' && !normalizedData.type && !normalizedData.Type) {
|
|
41904
42143
|
normalizedData.type = typeField;
|
|
41905
42144
|
}
|
|
41906
42145
|
return normalizedData;
|
|
@@ -41922,32 +42161,7 @@ class WebSocketManager {
|
|
|
41922
42161
|
// Cache the message for later use by new subscribers
|
|
41923
42162
|
this._cacheMessage(message);
|
|
41924
42163
|
|
|
41925
|
-
//
|
|
41926
|
-
if (message.targetType) {
|
|
41927
|
-
const targetWidgets = this.typeSubscriptions.get(message.targetType);
|
|
41928
|
-
if (targetWidgets && targetWidgets.size > 0) {
|
|
41929
|
-
if (this.config.debug) {
|
|
41930
|
-
console.log(`[WebSocketManager] Routing ${message.targetType} error to specific widgets:`, [...targetWidgets]);
|
|
41931
|
-
}
|
|
41932
|
-
targetWidgets.forEach(widgetId => {
|
|
41933
|
-
const subscription = this.subscriptions.get(widgetId);
|
|
41934
|
-
if (subscription) {
|
|
41935
|
-
try {
|
|
41936
|
-
subscription.callback({
|
|
41937
|
-
event: 'data',
|
|
41938
|
-
data: message,
|
|
41939
|
-
widgetId
|
|
41940
|
-
});
|
|
41941
|
-
} catch (error) {
|
|
41942
|
-
console.error(`[WebSocketManager] Error in widget ${widgetId} callback:`, error);
|
|
41943
|
-
}
|
|
41944
|
-
}
|
|
41945
|
-
});
|
|
41946
|
-
return; // Don't fall through to broadcast
|
|
41947
|
-
}
|
|
41948
|
-
}
|
|
41949
|
-
|
|
41950
|
-
//console.log('here');
|
|
42164
|
+
// Get relevant widgets based on message type and symbol
|
|
41951
42165
|
const relevantWidgets = this._getRelevantWidgets(message);
|
|
41952
42166
|
if (this.config.debug && relevantWidgets.size > 0) {
|
|
41953
42167
|
console.log(`[WebSocketManager] Routing message to ${relevantWidgets.size} relevant widgets`);
|
|
@@ -41990,42 +42204,49 @@ class WebSocketManager {
|
|
|
41990
42204
|
_cacheMessage(message) {
|
|
41991
42205
|
try {
|
|
41992
42206
|
// Extract symbol and message type to create cache key
|
|
41993
|
-
|
|
41994
|
-
|
|
42207
|
+
// This allows new widgets to get instant data when subscribing
|
|
42208
|
+
// check in message.data or message.Data
|
|
42209
|
+
let data;
|
|
42210
|
+
if (message.data) {
|
|
42211
|
+
data = message.data;
|
|
42212
|
+
} else if (message.Data) {
|
|
42213
|
+
data = message.Data;
|
|
42214
|
+
} else {
|
|
42215
|
+
data = message;
|
|
42216
|
+
}
|
|
42217
|
+
const symbol = this._extractSymbol(data);
|
|
42218
|
+
const messageType = message.type;
|
|
42219
|
+
if (this.config.debug) {
|
|
42220
|
+
console.log(`[WebSocketManager] _cacheMessage - extracted symbol: "${symbol}", messageType: "${messageType}"`);
|
|
42221
|
+
}
|
|
42222
|
+
|
|
42223
|
+
// Cache by type:symbol combination
|
|
41995
42224
|
if (messageType && symbol) {
|
|
41996
42225
|
const cacheKey = `${messageType}:${symbol}`;
|
|
41997
42226
|
this.lastMessageCache.set(cacheKey, message);
|
|
41998
42227
|
if (this.config.debug) {
|
|
41999
42228
|
console.log(`[WebSocketManager] Cached message for ${cacheKey}`);
|
|
42000
42229
|
}
|
|
42001
|
-
}
|
|
42002
|
-
|
|
42003
|
-
|
|
42004
|
-
|
|
42005
|
-
const firstItem = message[0];
|
|
42006
|
-
const symbol = firstItem.Symbol;
|
|
42007
|
-
const messageType = this._extractMessageType(message);
|
|
42008
|
-
if (messageType && symbol) {
|
|
42009
|
-
const cacheKey = `${messageType}:${symbol}`;
|
|
42010
|
-
this.lastMessageCache.set(cacheKey, message);
|
|
42230
|
+
} else {
|
|
42231
|
+
// If we can't extract symbol from message, try to cache by type only
|
|
42232
|
+
// This helps with data like ONBBO L2 which doesn't have symbol in the message
|
|
42233
|
+
if (messageType) {
|
|
42011
42234
|
if (this.config.debug) {
|
|
42012
|
-
console.log(`[WebSocketManager]
|
|
42235
|
+
console.log(`[WebSocketManager] No symbol found in message, attempting to infer from subscriptions for type: ${messageType}`);
|
|
42013
42236
|
}
|
|
42014
|
-
}
|
|
42015
|
-
}
|
|
42016
42237
|
|
|
42017
|
-
|
|
42018
|
-
|
|
42019
|
-
|
|
42020
|
-
|
|
42021
|
-
|
|
42022
|
-
|
|
42023
|
-
|
|
42024
|
-
|
|
42025
|
-
|
|
42238
|
+
// Find active subscriptions for this message type and cache for each
|
|
42239
|
+
this.activeSubscriptions.forEach(activeKey => {
|
|
42240
|
+
const [type, sym] = activeKey.split(':');
|
|
42241
|
+
if (type === messageType && sym) {
|
|
42242
|
+
const cacheKey = activeKey;
|
|
42243
|
+
this.lastMessageCache.set(cacheKey, message);
|
|
42244
|
+
if (this.config.debug) {
|
|
42245
|
+
console.log(`[WebSocketManager] Cached message for ${cacheKey} (inferred from active subscription)`);
|
|
42246
|
+
}
|
|
42026
42247
|
}
|
|
42027
|
-
}
|
|
42028
|
-
}
|
|
42248
|
+
});
|
|
42249
|
+
}
|
|
42029
42250
|
}
|
|
42030
42251
|
} catch (error) {
|
|
42031
42252
|
console.error('[WebSocketManager] Error caching message:', error);
|
|
@@ -42192,7 +42413,7 @@ class WebSocketManager {
|
|
|
42192
42413
|
_extractSymbol(item) {
|
|
42193
42414
|
// Handle new format where symbol might be in nested data structure
|
|
42194
42415
|
// Check if this is an array with data that has _messageType (normalized new format)
|
|
42195
|
-
if (Array.isArray(item)
|
|
42416
|
+
if (Array.isArray(item)) {
|
|
42196
42417
|
// The data is an array, check first item for symbol
|
|
42197
42418
|
if (item.length > 0 && item[0]) {
|
|
42198
42419
|
return this._extractSymbolFromItem(item[0]);
|