mdas-jsview-sdk 1.0.12-uat.0 → 1.0.14-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.js CHANGED
@@ -1195,6 +1195,76 @@
1195
1195
  </div>
1196
1196
  `;
1197
1197
 
1198
+ const IntradayChartTemplate = `
1199
+ <div class="intraday-chart-widget">
1200
+ <div class="chart-header">
1201
+ <div class="chart-title-section">
1202
+ <div class="company-market-info">
1203
+ <span class="intraday-company-name"></span>
1204
+ </div>
1205
+ <h3 class="intraday-chart-symbol editable-symbol"
1206
+ title="Double-click to edit symbol"
1207
+ data-original-symbol="">AAPL</h3>
1208
+ </div>
1209
+ <div class="chart-change positive">+0.00 (+0.00%)</div>
1210
+ </div>
1211
+
1212
+ <div class="chart-controls">
1213
+ <div class="chart-range-selector">
1214
+ <button class="range-btn active" data-range="0">1D</button>
1215
+ <button class="range-btn" data-range="5">5D</button>
1216
+ </div>
1217
+ <div class="chart-type-selector">
1218
+ <button class="type-btn active" data-type="line" title="Line Chart">Line</button>
1219
+ <button class="type-btn" data-type="area" title="Area Chart">Mountain</button>
1220
+ <button class="type-btn" data-type="candlestick" title="Candlestick Chart">Candles</button>
1221
+ </div>
1222
+ <button class="zoom-reset-btn" title="Reset Zoom">
1223
+ <svg width="16" height="16" viewBox="0 0 16 16" fill="none">
1224
+ <path d="M2 8a6 6 0 1 1 12 0A6 6 0 0 1 2 8zm6-7a7 7 0 1 0 0 14A7 7 0 0 0 8 1z" fill="currentColor"/>
1225
+ <path d="M5 8h6M8 5v6" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/>
1226
+ </svg>
1227
+ Reset Zoom
1228
+ </button>
1229
+ </div>
1230
+
1231
+ <div class="chart-container">
1232
+ <canvas id="intradayChart"></canvas>
1233
+ </div>
1234
+
1235
+ <div class="chart-stats">
1236
+ <div class="stats-header">Daily Stats</div>
1237
+ <div class="stats-grid">
1238
+ <div class="stat-item stat-open">
1239
+ <span class="stat-label">Open</span>
1240
+ <span class="stat-value">$0.00</span>
1241
+ </div>
1242
+ <div class="stat-item stat-high">
1243
+ <span class="stat-label">High</span>
1244
+ <span class="stat-value">$0.00</span>
1245
+ </div>
1246
+ <div class="stat-item stat-low">
1247
+ <span class="stat-label">Low</span>
1248
+ <span class="stat-value">$0.00</span>
1249
+ </div>
1250
+ <div class="stat-item stat-close">
1251
+ <span class="stat-label">Close</span>
1252
+ <span class="stat-value">$0.00</span>
1253
+ </div>
1254
+ <div class="stat-item stat-volume">
1255
+ <span class="stat-label">Volume</span>
1256
+ <span class="stat-value">0</span>
1257
+ </div>
1258
+ </div>
1259
+ </div>
1260
+
1261
+ <div class="widget-loading-overlay hidden">
1262
+ <div class="loading-spinner"></div>
1263
+ <div class="loading-text">Loading chart data...</div>
1264
+ </div>
1265
+ </div>
1266
+ `;
1267
+
1198
1268
  // Widget HTML Templates
1199
1269
  const NightSessionTemplate = `
1200
1270
  <div class="night-session-widget widget">
@@ -3973,9 +4043,11 @@
3973
4043
  } else {
3974
4044
  return 'BlueOcean 20 mins delayed';
3975
4045
  }
3976
- } else if (this.source.toLowerCase().includes('bruce') || this.source.toLowerCase().includes('blueocean')) {
4046
+ } else if (this.source.toLowerCase().includes('bruce') || this.source.toLowerCase().includes('blueocean') || this.source.toLowerCase().includes('onbbo')) {
3977
4047
  if (this.source.toLowerCase() === 'bruce') {
3978
4048
  return 'Bruce Real-time';
4049
+ } else if (this.source.toLowerCase() === 'onbbo') {
4050
+ return 'ONBBO Real-time';
3979
4051
  } else {
3980
4052
  return 'BlueOcean Real-time';
3981
4053
  }
@@ -4011,8 +4083,8 @@
4011
4083
  if (!options.wsManager) {
4012
4084
  throw new Error('WebSocketManager is required for NightSessionWidget');
4013
4085
  }
4014
- if (!options.source || options.source.toLowerCase() !== 'blueocean' && options.source.toLowerCase() !== 'bruce') {
4015
- throw new Error('Source should be either "blueocean" or "bruce"');
4086
+ if (!options.source || options.source.toLowerCase() !== 'blueocean' && options.source.toLowerCase() !== 'bruce' && options.source.toLowerCase() !== 'onbbo') {
4087
+ throw new Error('Source should be either "blueocean", "bruce", or "onbbo"');
4016
4088
  }
4017
4089
  this.type = 'nightsession ' + options.source;
4018
4090
 
@@ -4232,7 +4304,14 @@
4232
4304
  }
4233
4305
  }
4234
4306
  subscribeToData() {
4235
- const subscriptionType = this.source === 'bruce' ? 'querybrucel1' : 'queryblueoceanl1';
4307
+ let subscriptionType;
4308
+ if (this.source === 'bruce') {
4309
+ subscriptionType = 'querybrucel1';
4310
+ } else if (this.source === 'onbbo') {
4311
+ subscriptionType = 'queryonbbol1';
4312
+ } else {
4313
+ subscriptionType = 'queryblueoceanl1';
4314
+ }
4236
4315
 
4237
4316
  // Subscribe with symbol for routing
4238
4317
  this.unsubscribe = this.wsManager.subscribe(this.widgetId, [subscriptionType], this.handleMessage.bind(this), this.symbol // Pass symbol for routing
@@ -4346,9 +4425,12 @@
4346
4425
  }
4347
4426
  }
4348
4427
  // Handle wrapped format
4349
- else if (message.type === 'queryblueoceanl1' || message.type === 'querybrucel1') {
4428
+ else if (message.type === 'queryblueoceanl1' || message.type === 'querybrucel1' || message.type === 'queryonbbol1') {
4350
4429
  if (message['0']?.Symbol === this.symbol) {
4351
- if (message['0'].NotFound === true || !message['0'].MarketName || message['0'].MarketName !== 'BLUE') {
4430
+ // For onbbo source, skip MarketName check
4431
+ const isOnbbo = message.type === 'queryonbbol1';
4432
+ const shouldShowNoData = message['0'].NotFound === true || !isOnbbo && (!message['0'].MarketName || message['0'].MarketName !== 'BLUE');
4433
+ if (shouldShowNoData) {
4352
4434
  // Only show no data state if we don't have cached data
4353
4435
  if (!this.data) {
4354
4436
  this.showNoDataState(message['0']);
@@ -7917,73 +7999,6 @@ ${SharedStyles}
7917
7999
  }
7918
8000
  }
7919
8001
 
7920
- const IntradayChartTemplate = `
7921
- <div class="intraday-chart-widget">
7922
- <div class="chart-header">
7923
- <div class="chart-title-section">
7924
- <div class="company-market-info">
7925
- <span class="intraday-company-name"></span>
7926
- </div>
7927
- <h3 class="intraday-chart-symbol editable-symbol"
7928
- title="Double-click to edit symbol"
7929
- data-original-symbol="">AAPL</h3>
7930
- </div>
7931
- <div class="chart-change positive">+0.00 (+0.00%)</div>
7932
- </div>
7933
-
7934
- <div class="chart-controls">
7935
- <div class="chart-range-selector">
7936
- <button class="range-btn active" data-range="0">1D</button>
7937
- <button class="range-btn" data-range="5">5D</button>
7938
- </div>
7939
- <div class="chart-type-selector">
7940
- <button class="type-btn active" data-type="line" title="Line Chart">Line</button>
7941
- <button class="type-btn" data-type="area" title="Area Chart">Mountain</button>
7942
- <button class="type-btn" data-type="candlestick" title="Candlestick Chart">Candles</button>
7943
- </div>
7944
- <button class="zoom-reset-btn" title="Reset Zoom">
7945
- <svg width="16" height="16" viewBox="0 0 16 16" fill="none">
7946
- <path d="M2 8a6 6 0 1 1 12 0A6 6 0 0 1 2 8zm6-7a7 7 0 1 0 0 14A7 7 0 0 0 8 1z" fill="currentColor"/>
7947
- <path d="M5 8h6M8 5v6" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/>
7948
- </svg>
7949
- Reset Zoom
7950
- </button>
7951
- </div>
7952
-
7953
- <div class="chart-container">
7954
- <canvas id="intradayChart"></canvas>
7955
- </div>
7956
-
7957
- <div class="chart-stats">
7958
- <div class="stat-item stat-open">
7959
- <span class="stat-label">Open</span>
7960
- <span class="stat-value">$0.00</span>
7961
- </div>
7962
- <div class="stat-item stat-high">
7963
- <span class="stat-label">High</span>
7964
- <span class="stat-value">$0.00</span>
7965
- </div>
7966
- <div class="stat-item stat-low">
7967
- <span class="stat-label">Low</span>
7968
- <span class="stat-value">$0.00</span>
7969
- </div>
7970
- <div class="stat-item stat-close">
7971
- <span class="stat-label">Close</span>
7972
- <span class="stat-value">$0.00</span>
7973
- </div>
7974
- <div class="stat-item stat-volume">
7975
- <span class="stat-label">Volume</span>
7976
- <span class="stat-value">0</span>
7977
- </div>
7978
- </div>
7979
-
7980
- <div class="widget-loading-overlay hidden">
7981
- <div class="loading-spinner"></div>
7982
- <div class="loading-text">Loading chart data...</div>
7983
- </div>
7984
- </div>
7985
- `;
7986
-
7987
8002
  const IntradayChartStyles = `
7988
8003
  .intraday-chart-widget {
7989
8004
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Arial, sans-serif;
@@ -8168,14 +8183,28 @@ ${SharedStyles}
8168
8183
  }
8169
8184
 
8170
8185
  .chart-stats {
8171
- display: grid;
8172
- grid-template-columns: repeat(5, 1fr);
8173
- gap: 15px;
8174
8186
  padding: 15px;
8175
8187
  background: #f9fafb;
8176
8188
  border-radius: 8px;
8177
8189
  }
8178
8190
 
8191
+ .stats-header {
8192
+ font-size: 0.875em;
8193
+ font-weight: 700;
8194
+ color: #374151;
8195
+ text-transform: uppercase;
8196
+ letter-spacing: 0.5px;
8197
+ margin-bottom: 12px;
8198
+ padding-bottom: 8px;
8199
+ border-bottom: 2px solid #e5e7eb;
8200
+ }
8201
+
8202
+ .stats-grid {
8203
+ display: grid;
8204
+ grid-template-columns: repeat(5, 1fr);
8205
+ gap: 15px;
8206
+ }
8207
+
8179
8208
  .stat-item {
8180
8209
  display: flex;
8181
8210
  flex-direction: column;
@@ -8244,11 +8273,16 @@ ${SharedStyles}
8244
8273
  padding: 15px;
8245
8274
  }
8246
8275
 
8247
- .chart-stats {
8276
+ .stats-grid {
8248
8277
  grid-template-columns: repeat(3, 1fr);
8249
8278
  gap: 10px;
8250
8279
  }
8251
8280
 
8281
+ .stats-header {
8282
+ font-size: 0.8em;
8283
+ margin-bottom: 10px;
8284
+ }
8285
+
8252
8286
  .chart-container {
8253
8287
  height: 350px;
8254
8288
  }
@@ -37499,7 +37533,8 @@ ${SharedStyles}
37499
37533
  // Symbol editor
37500
37534
  this.symbolEditor = null;
37501
37535
 
37502
- // Lazy loading cache for 5D data
37536
+ // Lazy loading cache for chart data
37537
+ this.cached1DData = null;
37503
37538
  this.cached5DData = null;
37504
37539
  this.is5DDataLoading = false;
37505
37540
  this.createWidgetStructure();
@@ -37603,7 +37638,8 @@ ${SharedStyles}
37603
37638
  this.chartData = null;
37604
37639
  this.livePrice = null;
37605
37640
 
37606
- // Clear cached 5D data for old symbol
37641
+ // Clear all cached data for old symbol
37642
+ this.cached1DData = null;
37607
37643
  this.cached5DData = null;
37608
37644
  this.is5DDataLoading = false;
37609
37645
 
@@ -37721,7 +37757,7 @@ ${SharedStyles}
37721
37757
  // Update chart type and re-render
37722
37758
  this.chartType = type;
37723
37759
  this.renderChart();
37724
- this.updateStats();
37760
+ // Stats are managed by WebSocket updates only
37725
37761
  });
37726
37762
  });
37727
37763
  }
@@ -37757,12 +37793,30 @@ ${SharedStyles}
37757
37793
  throw new Error('API service not available');
37758
37794
  }
37759
37795
 
37760
- // For 5D chart: Load data from multiple days (rangeback 0-5)
37796
+ // For 5D chart: Load data from multiple days (rangeback 0-6)
37761
37797
  if (this.rangeBack === 5) {
37762
37798
  await this.load5DayChartData(apiService);
37763
37799
  return;
37764
37800
  }
37765
37801
 
37802
+ // For 1D chart: Check if we have cached data first
37803
+ if (this.rangeBack === 0 && this.cached1DData) {
37804
+ if (this.debug) {
37805
+ console.log('[IntradayChartWidget] Using cached 1D data');
37806
+ }
37807
+
37808
+ // Use cached data
37809
+ this.chartData = this.cached1DData;
37810
+ this.renderChart();
37811
+ // Skip updateStats() - stats will be updated from WebSocket data only
37812
+ this.hideLoading();
37813
+
37814
+ // Restart auto-refresh and live price subscription
37815
+ await this.startAutoRefresh();
37816
+ this.subscribeToLivePrice();
37817
+ return;
37818
+ }
37819
+
37766
37820
  // FALLBACK LOGIC: Try to find most recent available data (for 1D)
37767
37821
  const MAX_LOOKBACK_DAYS = 7;
37768
37822
  let attemptRangeBack = this.rangeBack;
@@ -37838,8 +37892,16 @@ ${SharedStyles}
37838
37892
  console.error('[IntradayChartWidget] Model has no data points after processing');
37839
37893
  throw new Error(`No valid data points for ${this.symbol}`);
37840
37894
  }
37895
+
37896
+ // Cache 1D data for instant switching
37897
+ if (this.rangeBack === 0) {
37898
+ this.cached1DData = this.chartData;
37899
+ if (this.debug) {
37900
+ console.log('[IntradayChartWidget] Cached 1D data for instant switching');
37901
+ }
37902
+ }
37841
37903
  this.renderChart();
37842
- this.updateStats();
37904
+ // Skip updateStats() - stats will be updated from WebSocket data only
37843
37905
  this.hideLoading();
37844
37906
  if (this.debug) {
37845
37907
  console.log(`[IntradayChartWidget] Loaded ${dataArray.length} data points`);
@@ -37893,9 +37955,12 @@ ${SharedStyles}
37893
37955
  // Use cached data
37894
37956
  this.chartData = this.cached5DData;
37895
37957
  this.renderChart();
37896
- this.updateStats();
37958
+ // Skip updateStats() - stats will be updated from WebSocket data only
37897
37959
  this.hideLoading();
37898
37960
 
37961
+ // Subscribe to live price for stats updates (WebSocket only)
37962
+ this.subscribeToLivePrice();
37963
+
37899
37964
  // Don't auto-refresh for 5D chart
37900
37965
  this.stopAutoRefresh();
37901
37966
  return;
@@ -37913,12 +37978,15 @@ ${SharedStyles}
37913
37978
  // Cache the processed data
37914
37979
  this.cached5DData = this.chartData;
37915
37980
  this.renderChart();
37916
- this.updateStats();
37981
+ // Skip updateStats() - stats will be updated from WebSocket data only
37917
37982
  this.hideLoading();
37918
37983
  if (this.debug) {
37919
37984
  console.log(`[IntradayChartWidget] 5D chart loaded with ${this.chartData.dataPoints.length} data points`);
37920
37985
  }
37921
37986
 
37987
+ // Subscribe to live price for stats updates (WebSocket only)
37988
+ this.subscribeToLivePrice();
37989
+
37922
37990
  // Don't auto-refresh for 5D chart
37923
37991
  this.stopAutoRefresh();
37924
37992
  } catch (error) {
@@ -38119,6 +38187,64 @@ ${SharedStyles}
38119
38187
  } else {
38120
38188
  console.log('[IntradayChartWidget] Invalid price, not updating:', price);
38121
38189
  }
38190
+
38191
+ // Update chart stats with live WebSocket data for both 1D and 5D charts
38192
+ // This shows the current day's stats from live data
38193
+ this.updateStatsFromLiveData(priceData);
38194
+ }
38195
+ updateStatsFromLiveData(data) {
38196
+ if (!data) return;
38197
+
38198
+ // Extract stats from WebSocket data
38199
+ const stats = {
38200
+ high: data.HighPx !== undefined && data.HighPx !== null ? parseFloat(data.HighPx) : null,
38201
+ low: data.LowPx !== undefined && data.LowPx !== null ? parseFloat(data.LowPx) : null,
38202
+ open: data.OpenPx !== undefined && data.OpenPx !== null ? parseFloat(data.OpenPx) : null,
38203
+ close: data.LastPx !== undefined && data.LastPx !== null ? parseFloat(data.LastPx) : data.TradePx !== undefined && data.TradePx !== null ? parseFloat(data.TradePx) : null,
38204
+ volume: data.Volume !== undefined && data.Volume !== null ? parseInt(data.Volume) : null,
38205
+ change: data.Change !== undefined && data.Change !== null ? parseFloat(data.Change) : null,
38206
+ changePercent: data.ChangePercent !== undefined && data.ChangePercent !== null ? parseFloat(data.ChangePercent) * 100 : null
38207
+ };
38208
+ if (this.debug) {
38209
+ console.log('[IntradayChartWidget] Updating stats from live data:', stats);
38210
+ }
38211
+
38212
+ // Update stats display
38213
+ const highElement = this.container.querySelector('.stat-high .stat-value');
38214
+ const lowElement = this.container.querySelector('.stat-low .stat-value');
38215
+ const openElement = this.container.querySelector('.stat-open .stat-value');
38216
+ const closeElement = this.container.querySelector('.stat-close .stat-value');
38217
+ const volumeElement = this.container.querySelector('.stat-volume .stat-value');
38218
+ const changeElement = this.container.querySelector('.chart-change');
38219
+ if (highElement && stats.high !== null) {
38220
+ highElement.textContent = `$${stats.high.toFixed(2)}`;
38221
+ }
38222
+ if (lowElement && stats.low !== null) {
38223
+ lowElement.textContent = `$${stats.low.toFixed(2)}`;
38224
+ }
38225
+ if (openElement && stats.open !== null) {
38226
+ openElement.textContent = `$${stats.open.toFixed(2)}`;
38227
+ }
38228
+ if (closeElement && stats.close !== null) {
38229
+ closeElement.textContent = `$${stats.close.toFixed(2)}`;
38230
+ }
38231
+ if (volumeElement && stats.volume !== null) {
38232
+ volumeElement.textContent = this.formatVolume(stats.volume);
38233
+ }
38234
+ if (changeElement && stats.change !== null && stats.changePercent !== null) {
38235
+ const changeClass = stats.change >= 0 ? 'positive' : 'negative';
38236
+ changeElement.className = `chart-change ${changeClass}`;
38237
+ const sign = stats.change >= 0 ? '+' : '';
38238
+ changeElement.textContent = `${sign}${stats.change.toFixed(2)} (${sign}${stats.changePercent.toFixed(2)}%)`;
38239
+ }
38240
+ }
38241
+ formatVolume(volume) {
38242
+ if (volume >= 1000000) {
38243
+ return (volume / 1000000).toFixed(2) + 'M';
38244
+ } else if (volume >= 1000) {
38245
+ return (volume / 1000).toFixed(2) + 'K';
38246
+ }
38247
+ return volume.toString();
38122
38248
  }
38123
38249
  updateLivePriceLine() {
38124
38250
  if (!this.chartInstance || !this.livePrice) {
@@ -38277,7 +38403,8 @@ ${SharedStyles}
38277
38403
  if (response && Array.isArray(response)) {
38278
38404
  this.chartData = new IntradayChartModel(response);
38279
38405
  this.renderChart();
38280
- this.updateStats();
38406
+ // Stats are managed by WebSocket updates only
38407
+
38281
38408
  if (this.debug) {
38282
38409
  console.log(`[IntradayChartWidget] Auto-refresh complete - ${response.length} data points`);
38283
38410
  }
@@ -38729,6 +38856,13 @@ ${SharedStyles}
38729
38856
  });
38730
38857
  }
38731
38858
  }
38859
+
38860
+ /**
38861
+ * DEPRECATED: This method is no longer used. Stats are now exclusively
38862
+ * updated from WebSocket data via updateStatsFromLiveData() to ensure
38863
+ * consistency between 1D and 5D charts (both showing today's stats only).
38864
+ * Kept for reference only.
38865
+ */
38732
38866
  updateStats() {
38733
38867
  if (!this.chartData) return;
38734
38868
  const stats = this.chartData.getStats();