mdas-jsview-sdk 1.0.11-uat.0 → 1.0.13-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 +373 -87
- package/dist/mdas-sdk.esm.js.map +1 -1
- package/dist/mdas-sdk.js +373 -87
- 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.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">
|
|
@@ -1205,13 +1275,12 @@
|
|
|
1205
1275
|
<div class="company-market-info">
|
|
1206
1276
|
<span class="night-company-name"></span>
|
|
1207
1277
|
<span class="market-name"></span>
|
|
1208
|
-
<span class="market-mic"></span>
|
|
1209
1278
|
</div>
|
|
1210
1279
|
<h1 class="symbol editable-symbol"
|
|
1211
1280
|
title="Double-click to edit symbol"
|
|
1212
1281
|
data-original-symbol="">
|
|
1213
1282
|
</h1>
|
|
1214
|
-
|
|
1283
|
+
|
|
1215
1284
|
</div>
|
|
1216
1285
|
<div class="price-section">
|
|
1217
1286
|
<div class="current-price"></div>
|
|
@@ -4421,13 +4490,6 @@
|
|
|
4421
4490
|
marketNameElement.textContent = this.exchangeName || data.exchangeName || '';
|
|
4422
4491
|
}
|
|
4423
4492
|
|
|
4424
|
-
// Update MIC (Market Identifier Code)
|
|
4425
|
-
const marketMicElement = this.container.querySelector('.market-mic');
|
|
4426
|
-
if (marketMicElement) {
|
|
4427
|
-
const micValue = this.mic || data.mic || '';
|
|
4428
|
-
marketMicElement.textContent = micValue;
|
|
4429
|
-
}
|
|
4430
|
-
|
|
4431
4493
|
// Update price
|
|
4432
4494
|
const currentPriceElement = this.container.querySelector('.current-price');
|
|
4433
4495
|
if (currentPriceElement) {
|
|
@@ -7925,73 +7987,6 @@ ${SharedStyles}
|
|
|
7925
7987
|
}
|
|
7926
7988
|
}
|
|
7927
7989
|
|
|
7928
|
-
const IntradayChartTemplate = `
|
|
7929
|
-
<div class="intraday-chart-widget">
|
|
7930
|
-
<div class="chart-header">
|
|
7931
|
-
<div class="chart-title-section">
|
|
7932
|
-
<div class="company-market-info">
|
|
7933
|
-
<span class="intraday-company-name"></span>
|
|
7934
|
-
</div>
|
|
7935
|
-
<h3 class="intraday-chart-symbol editable-symbol"
|
|
7936
|
-
title="Double-click to edit symbol"
|
|
7937
|
-
data-original-symbol="">AAPL</h3>
|
|
7938
|
-
</div>
|
|
7939
|
-
<div class="chart-change positive">+0.00 (+0.00%)</div>
|
|
7940
|
-
</div>
|
|
7941
|
-
|
|
7942
|
-
<div class="chart-controls">
|
|
7943
|
-
<div class="chart-range-selector">
|
|
7944
|
-
<button class="range-btn active" data-range="0">1D</button>
|
|
7945
|
-
<button class="range-btn" data-range="5">5D</button>
|
|
7946
|
-
</div>
|
|
7947
|
-
<div class="chart-type-selector">
|
|
7948
|
-
<button class="type-btn active" data-type="line" title="Line Chart">Line</button>
|
|
7949
|
-
<button class="type-btn" data-type="area" title="Area Chart">Mountain</button>
|
|
7950
|
-
<button class="type-btn" data-type="candlestick" title="Candlestick Chart">Candles</button>
|
|
7951
|
-
</div>
|
|
7952
|
-
<button class="zoom-reset-btn" title="Reset Zoom">
|
|
7953
|
-
<svg width="16" height="16" viewBox="0 0 16 16" fill="none">
|
|
7954
|
-
<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"/>
|
|
7955
|
-
<path d="M5 8h6M8 5v6" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/>
|
|
7956
|
-
</svg>
|
|
7957
|
-
Reset Zoom
|
|
7958
|
-
</button>
|
|
7959
|
-
</div>
|
|
7960
|
-
|
|
7961
|
-
<div class="chart-container">
|
|
7962
|
-
<canvas id="intradayChart"></canvas>
|
|
7963
|
-
</div>
|
|
7964
|
-
|
|
7965
|
-
<div class="chart-stats">
|
|
7966
|
-
<div class="stat-item stat-open">
|
|
7967
|
-
<span class="stat-label">Open</span>
|
|
7968
|
-
<span class="stat-value">$0.00</span>
|
|
7969
|
-
</div>
|
|
7970
|
-
<div class="stat-item stat-high">
|
|
7971
|
-
<span class="stat-label">High</span>
|
|
7972
|
-
<span class="stat-value">$0.00</span>
|
|
7973
|
-
</div>
|
|
7974
|
-
<div class="stat-item stat-low">
|
|
7975
|
-
<span class="stat-label">Low</span>
|
|
7976
|
-
<span class="stat-value">$0.00</span>
|
|
7977
|
-
</div>
|
|
7978
|
-
<div class="stat-item stat-close">
|
|
7979
|
-
<span class="stat-label">Close</span>
|
|
7980
|
-
<span class="stat-value">$0.00</span>
|
|
7981
|
-
</div>
|
|
7982
|
-
<div class="stat-item stat-volume">
|
|
7983
|
-
<span class="stat-label">Volume</span>
|
|
7984
|
-
<span class="stat-value">0</span>
|
|
7985
|
-
</div>
|
|
7986
|
-
</div>
|
|
7987
|
-
|
|
7988
|
-
<div class="widget-loading-overlay hidden">
|
|
7989
|
-
<div class="loading-spinner"></div>
|
|
7990
|
-
<div class="loading-text">Loading chart data...</div>
|
|
7991
|
-
</div>
|
|
7992
|
-
</div>
|
|
7993
|
-
`;
|
|
7994
|
-
|
|
7995
7990
|
const IntradayChartStyles = `
|
|
7996
7991
|
.intraday-chart-widget {
|
|
7997
7992
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Arial, sans-serif;
|
|
@@ -8176,14 +8171,28 @@ ${SharedStyles}
|
|
|
8176
8171
|
}
|
|
8177
8172
|
|
|
8178
8173
|
.chart-stats {
|
|
8179
|
-
display: grid;
|
|
8180
|
-
grid-template-columns: repeat(5, 1fr);
|
|
8181
|
-
gap: 15px;
|
|
8182
8174
|
padding: 15px;
|
|
8183
8175
|
background: #f9fafb;
|
|
8184
8176
|
border-radius: 8px;
|
|
8185
8177
|
}
|
|
8186
8178
|
|
|
8179
|
+
.stats-header {
|
|
8180
|
+
font-size: 0.875em;
|
|
8181
|
+
font-weight: 700;
|
|
8182
|
+
color: #374151;
|
|
8183
|
+
text-transform: uppercase;
|
|
8184
|
+
letter-spacing: 0.5px;
|
|
8185
|
+
margin-bottom: 12px;
|
|
8186
|
+
padding-bottom: 8px;
|
|
8187
|
+
border-bottom: 2px solid #e5e7eb;
|
|
8188
|
+
}
|
|
8189
|
+
|
|
8190
|
+
.stats-grid {
|
|
8191
|
+
display: grid;
|
|
8192
|
+
grid-template-columns: repeat(5, 1fr);
|
|
8193
|
+
gap: 15px;
|
|
8194
|
+
}
|
|
8195
|
+
|
|
8187
8196
|
.stat-item {
|
|
8188
8197
|
display: flex;
|
|
8189
8198
|
flex-direction: column;
|
|
@@ -8252,11 +8261,16 @@ ${SharedStyles}
|
|
|
8252
8261
|
padding: 15px;
|
|
8253
8262
|
}
|
|
8254
8263
|
|
|
8255
|
-
.
|
|
8264
|
+
.stats-grid {
|
|
8256
8265
|
grid-template-columns: repeat(3, 1fr);
|
|
8257
8266
|
gap: 10px;
|
|
8258
8267
|
}
|
|
8259
8268
|
|
|
8269
|
+
.stats-header {
|
|
8270
|
+
font-size: 0.8em;
|
|
8271
|
+
margin-bottom: 10px;
|
|
8272
|
+
}
|
|
8273
|
+
|
|
8260
8274
|
.chart-container {
|
|
8261
8275
|
height: 350px;
|
|
8262
8276
|
}
|
|
@@ -37506,6 +37520,11 @@ ${SharedStyles}
|
|
|
37506
37520
|
|
|
37507
37521
|
// Symbol editor
|
|
37508
37522
|
this.symbolEditor = null;
|
|
37523
|
+
|
|
37524
|
+
// Lazy loading cache for chart data
|
|
37525
|
+
this.cached1DData = null;
|
|
37526
|
+
this.cached5DData = null;
|
|
37527
|
+
this.is5DDataLoading = false;
|
|
37509
37528
|
this.createWidgetStructure();
|
|
37510
37529
|
this.setupSymbolEditor();
|
|
37511
37530
|
this.initialize();
|
|
@@ -37607,6 +37626,11 @@ ${SharedStyles}
|
|
|
37607
37626
|
this.chartData = null;
|
|
37608
37627
|
this.livePrice = null;
|
|
37609
37628
|
|
|
37629
|
+
// Clear all cached data for old symbol
|
|
37630
|
+
this.cached1DData = null;
|
|
37631
|
+
this.cached5DData = null;
|
|
37632
|
+
this.is5DDataLoading = false;
|
|
37633
|
+
|
|
37610
37634
|
// Update internal symbol
|
|
37611
37635
|
this.symbol = upperSymbol;
|
|
37612
37636
|
|
|
@@ -37721,7 +37745,7 @@ ${SharedStyles}
|
|
|
37721
37745
|
// Update chart type and re-render
|
|
37722
37746
|
this.chartType = type;
|
|
37723
37747
|
this.renderChart();
|
|
37724
|
-
|
|
37748
|
+
// Stats are managed by WebSocket updates only
|
|
37725
37749
|
});
|
|
37726
37750
|
});
|
|
37727
37751
|
}
|
|
@@ -37757,7 +37781,31 @@ ${SharedStyles}
|
|
|
37757
37781
|
throw new Error('API service not available');
|
|
37758
37782
|
}
|
|
37759
37783
|
|
|
37760
|
-
//
|
|
37784
|
+
// For 5D chart: Load data from multiple days (rangeback 0-6)
|
|
37785
|
+
if (this.rangeBack === 5) {
|
|
37786
|
+
await this.load5DayChartData(apiService);
|
|
37787
|
+
return;
|
|
37788
|
+
}
|
|
37789
|
+
|
|
37790
|
+
// For 1D chart: Check if we have cached data first
|
|
37791
|
+
if (this.rangeBack === 0 && this.cached1DData) {
|
|
37792
|
+
if (this.debug) {
|
|
37793
|
+
console.log('[IntradayChartWidget] Using cached 1D data');
|
|
37794
|
+
}
|
|
37795
|
+
|
|
37796
|
+
// Use cached data
|
|
37797
|
+
this.chartData = this.cached1DData;
|
|
37798
|
+
this.renderChart();
|
|
37799
|
+
// Skip updateStats() - stats will be updated from WebSocket data only
|
|
37800
|
+
this.hideLoading();
|
|
37801
|
+
|
|
37802
|
+
// Restart auto-refresh and live price subscription
|
|
37803
|
+
await this.startAutoRefresh();
|
|
37804
|
+
this.subscribeToLivePrice();
|
|
37805
|
+
return;
|
|
37806
|
+
}
|
|
37807
|
+
|
|
37808
|
+
// FALLBACK LOGIC: Try to find most recent available data (for 1D)
|
|
37761
37809
|
const MAX_LOOKBACK_DAYS = 7;
|
|
37762
37810
|
let attemptRangeBack = this.rangeBack;
|
|
37763
37811
|
let dataFound = false;
|
|
@@ -37832,8 +37880,16 @@ ${SharedStyles}
|
|
|
37832
37880
|
console.error('[IntradayChartWidget] Model has no data points after processing');
|
|
37833
37881
|
throw new Error(`No valid data points for ${this.symbol}`);
|
|
37834
37882
|
}
|
|
37883
|
+
|
|
37884
|
+
// Cache 1D data for instant switching
|
|
37885
|
+
if (this.rangeBack === 0) {
|
|
37886
|
+
this.cached1DData = this.chartData;
|
|
37887
|
+
if (this.debug) {
|
|
37888
|
+
console.log('[IntradayChartWidget] Cached 1D data for instant switching');
|
|
37889
|
+
}
|
|
37890
|
+
}
|
|
37835
37891
|
this.renderChart();
|
|
37836
|
-
|
|
37892
|
+
// Skip updateStats() - stats will be updated from WebSocket data only
|
|
37837
37893
|
this.hideLoading();
|
|
37838
37894
|
if (this.debug) {
|
|
37839
37895
|
console.log(`[IntradayChartWidget] Loaded ${dataArray.length} data points`);
|
|
@@ -37846,6 +37902,9 @@ ${SharedStyles}
|
|
|
37846
37902
|
await this.startAutoRefresh();
|
|
37847
37903
|
// Subscribe to live price updates
|
|
37848
37904
|
this.subscribeToLivePrice();
|
|
37905
|
+
|
|
37906
|
+
// LAZY LOADING: Preload 5D data in the background after 1D loads
|
|
37907
|
+
this.preload5DDataInBackground();
|
|
37849
37908
|
} else {
|
|
37850
37909
|
// Historical data or fallback - don't refresh
|
|
37851
37910
|
this.stopAutoRefresh();
|
|
@@ -37873,6 +37932,165 @@ ${SharedStyles}
|
|
|
37873
37932
|
this.showError(errorMessage);
|
|
37874
37933
|
}
|
|
37875
37934
|
}
|
|
37935
|
+
async load5DayChartData(apiService) {
|
|
37936
|
+
try {
|
|
37937
|
+
// Check if we have cached 5D data
|
|
37938
|
+
if (this.cached5DData) {
|
|
37939
|
+
if (this.debug) {
|
|
37940
|
+
console.log('[IntradayChartWidget] Using cached 5D data');
|
|
37941
|
+
}
|
|
37942
|
+
|
|
37943
|
+
// Use cached data
|
|
37944
|
+
this.chartData = this.cached5DData;
|
|
37945
|
+
this.renderChart();
|
|
37946
|
+
// Skip updateStats() - stats will be updated from WebSocket data only
|
|
37947
|
+
this.hideLoading();
|
|
37948
|
+
|
|
37949
|
+
// Subscribe to live price for stats updates (WebSocket only)
|
|
37950
|
+
this.subscribeToLivePrice();
|
|
37951
|
+
|
|
37952
|
+
// Don't auto-refresh for 5D chart
|
|
37953
|
+
this.stopAutoRefresh();
|
|
37954
|
+
return;
|
|
37955
|
+
}
|
|
37956
|
+
|
|
37957
|
+
// No cached data, load it now
|
|
37958
|
+
const combinedData = await this.fetch5DayData(apiService);
|
|
37959
|
+
|
|
37960
|
+
// Process the combined data
|
|
37961
|
+
this.chartData = new IntradayChartModel(combinedData);
|
|
37962
|
+
if (this.chartData.dataPoints.length === 0) {
|
|
37963
|
+
throw new Error(`No valid data points for ${this.symbol}`);
|
|
37964
|
+
}
|
|
37965
|
+
|
|
37966
|
+
// Cache the processed data
|
|
37967
|
+
this.cached5DData = this.chartData;
|
|
37968
|
+
this.renderChart();
|
|
37969
|
+
// Skip updateStats() - stats will be updated from WebSocket data only
|
|
37970
|
+
this.hideLoading();
|
|
37971
|
+
if (this.debug) {
|
|
37972
|
+
console.log(`[IntradayChartWidget] 5D chart loaded with ${this.chartData.dataPoints.length} data points`);
|
|
37973
|
+
}
|
|
37974
|
+
|
|
37975
|
+
// Subscribe to live price for stats updates (WebSocket only)
|
|
37976
|
+
this.subscribeToLivePrice();
|
|
37977
|
+
|
|
37978
|
+
// Don't auto-refresh for 5D chart
|
|
37979
|
+
this.stopAutoRefresh();
|
|
37980
|
+
} catch (error) {
|
|
37981
|
+
console.error('[IntradayChartWidget] Error loading 5D chart data:', error);
|
|
37982
|
+
throw error; // Re-throw to be caught by parent loadChartData
|
|
37983
|
+
}
|
|
37984
|
+
}
|
|
37985
|
+
async fetch5DayData(apiService) {
|
|
37986
|
+
const DAYS_TO_COLLECT = 5;
|
|
37987
|
+
const MAX_RANGEBACK_ATTEMPTS = 7; // API limit: maximum 7 rangeback
|
|
37988
|
+
|
|
37989
|
+
if (this.debug) {
|
|
37990
|
+
console.log('[IntradayChartWidget] Fetching 5D chart data with parallel requests (API limit: rangeback 0-6)');
|
|
37991
|
+
}
|
|
37992
|
+
|
|
37993
|
+
// OPTIMIZATION: Query all rangeback values in parallel (0-6)
|
|
37994
|
+
const rangebackPromises = [];
|
|
37995
|
+
for (let rb = 0; rb < MAX_RANGEBACK_ATTEMPTS; rb++) {
|
|
37996
|
+
rangebackPromises.push(apiService.getIntradayChart(this.source, this.symbol, rb).then(response => {
|
|
37997
|
+
// Extract data array from response
|
|
37998
|
+
let dataArray = response;
|
|
37999
|
+
if (response && response.data && Array.isArray(response.data)) {
|
|
38000
|
+
dataArray = response.data;
|
|
38001
|
+
}
|
|
38002
|
+
return {
|
|
38003
|
+
rangeBack: rb,
|
|
38004
|
+
data: dataArray
|
|
38005
|
+
};
|
|
38006
|
+
}).catch(error => {
|
|
38007
|
+
// If a request fails, return null so we can filter it out
|
|
38008
|
+
if (this.debug) {
|
|
38009
|
+
console.warn(`[IntradayChartWidget] Request failed for rangeback ${rb}:`, error);
|
|
38010
|
+
}
|
|
38011
|
+
return {
|
|
38012
|
+
rangeBack: rb,
|
|
38013
|
+
data: null
|
|
38014
|
+
};
|
|
38015
|
+
}));
|
|
38016
|
+
}
|
|
38017
|
+
|
|
38018
|
+
// Wait for all parallel requests to complete
|
|
38019
|
+
const results = await Promise.all(rangebackPromises);
|
|
38020
|
+
if (this.debug) {
|
|
38021
|
+
console.log('[IntradayChartWidget] All parallel requests completed');
|
|
38022
|
+
}
|
|
38023
|
+
|
|
38024
|
+
// Filter out empty/null responses and collect valid days
|
|
38025
|
+
const collectedDays = results.filter(result => {
|
|
38026
|
+
const isValid = result.data && Array.isArray(result.data) && result.data.length > 0;
|
|
38027
|
+
if (this.debug) {
|
|
38028
|
+
if (isValid) {
|
|
38029
|
+
console.log(`[IntradayChartWidget] Rangeback ${result.rangeBack}: ${result.data.length} data points`);
|
|
38030
|
+
} else {
|
|
38031
|
+
console.log(`[IntradayChartWidget] Rangeback ${result.rangeBack}: No data (skipped)`);
|
|
38032
|
+
}
|
|
38033
|
+
}
|
|
38034
|
+
return isValid;
|
|
38035
|
+
}).slice(0, DAYS_TO_COLLECT); // Take only the first 5 days with data
|
|
38036
|
+
|
|
38037
|
+
if (collectedDays.length === 0) {
|
|
38038
|
+
throw new Error(`No intraday data available for ${this.symbol} in the past ${MAX_RANGEBACK_ATTEMPTS} days`);
|
|
38039
|
+
}
|
|
38040
|
+
if (this.debug) {
|
|
38041
|
+
console.log(`[IntradayChartWidget] Collected ${collectedDays.length}/${DAYS_TO_COLLECT} days of data`);
|
|
38042
|
+
if (collectedDays.length < DAYS_TO_COLLECT) {
|
|
38043
|
+
console.log(`[IntradayChartWidget] Note: Only ${collectedDays.length} days available within API limit (rangeback 0-6)`);
|
|
38044
|
+
}
|
|
38045
|
+
}
|
|
38046
|
+
|
|
38047
|
+
// Combine all collected days into a single array (oldest to newest)
|
|
38048
|
+
const combinedData = [];
|
|
38049
|
+
for (let i = collectedDays.length - 1; i >= 0; i--) {
|
|
38050
|
+
combinedData.push(...collectedDays[i].data);
|
|
38051
|
+
}
|
|
38052
|
+
if (this.debug) {
|
|
38053
|
+
console.log(`[IntradayChartWidget] Combined ${combinedData.length} total data points from ${collectedDays.length} days`);
|
|
38054
|
+
}
|
|
38055
|
+
return combinedData;
|
|
38056
|
+
}
|
|
38057
|
+
preload5DDataInBackground() {
|
|
38058
|
+
// Prevent multiple simultaneous preloads
|
|
38059
|
+
if (this.is5DDataLoading || this.cached5DData) {
|
|
38060
|
+
return;
|
|
38061
|
+
}
|
|
38062
|
+
this.is5DDataLoading = true;
|
|
38063
|
+
if (this.debug) {
|
|
38064
|
+
console.log('[IntradayChartWidget] Starting background preload of 5D data...');
|
|
38065
|
+
}
|
|
38066
|
+
|
|
38067
|
+
// Run in background without blocking
|
|
38068
|
+
setTimeout(async () => {
|
|
38069
|
+
try {
|
|
38070
|
+
const apiService = this.wsManager.getApiService();
|
|
38071
|
+
if (!apiService) {
|
|
38072
|
+
if (this.debug) {
|
|
38073
|
+
console.log('[IntradayChartWidget] API service not available for preload');
|
|
38074
|
+
}
|
|
38075
|
+
return;
|
|
38076
|
+
}
|
|
38077
|
+
const combinedData = await this.fetch5DayData(apiService);
|
|
38078
|
+
|
|
38079
|
+
// Create and cache the model
|
|
38080
|
+
const chartData = new IntradayChartModel(combinedData);
|
|
38081
|
+
this.cached5DData = chartData;
|
|
38082
|
+
if (this.debug) {
|
|
38083
|
+
console.log(`[IntradayChartWidget] ✓ Background preload complete: ${chartData.dataPoints.length} data points cached`);
|
|
38084
|
+
}
|
|
38085
|
+
} catch (error) {
|
|
38086
|
+
if (this.debug) {
|
|
38087
|
+
console.warn('[IntradayChartWidget] Background preload failed:', error);
|
|
38088
|
+
}
|
|
38089
|
+
} finally {
|
|
38090
|
+
this.is5DDataLoading = false;
|
|
38091
|
+
}
|
|
38092
|
+
}, 1000); // Wait 1 second after 1D loads before starting preload
|
|
38093
|
+
}
|
|
37876
38094
|
subscribeToLivePrice() {
|
|
37877
38095
|
// Unsubscribe from previous subscription if any
|
|
37878
38096
|
if (this.unsubscribe) {
|
|
@@ -37957,6 +38175,64 @@ ${SharedStyles}
|
|
|
37957
38175
|
} else {
|
|
37958
38176
|
console.log('[IntradayChartWidget] Invalid price, not updating:', price);
|
|
37959
38177
|
}
|
|
38178
|
+
|
|
38179
|
+
// Update chart stats with live WebSocket data for both 1D and 5D charts
|
|
38180
|
+
// This shows the current day's stats from live data
|
|
38181
|
+
this.updateStatsFromLiveData(priceData);
|
|
38182
|
+
}
|
|
38183
|
+
updateStatsFromLiveData(data) {
|
|
38184
|
+
if (!data) return;
|
|
38185
|
+
|
|
38186
|
+
// Extract stats from WebSocket data
|
|
38187
|
+
const stats = {
|
|
38188
|
+
high: data.HighPx !== undefined && data.HighPx !== null ? parseFloat(data.HighPx) : null,
|
|
38189
|
+
low: data.LowPx !== undefined && data.LowPx !== null ? parseFloat(data.LowPx) : null,
|
|
38190
|
+
open: data.OpenPx !== undefined && data.OpenPx !== null ? parseFloat(data.OpenPx) : null,
|
|
38191
|
+
close: data.LastPx !== undefined && data.LastPx !== null ? parseFloat(data.LastPx) : data.TradePx !== undefined && data.TradePx !== null ? parseFloat(data.TradePx) : null,
|
|
38192
|
+
volume: data.Volume !== undefined && data.Volume !== null ? parseInt(data.Volume) : null,
|
|
38193
|
+
change: data.Change !== undefined && data.Change !== null ? parseFloat(data.Change) : null,
|
|
38194
|
+
changePercent: data.ChangePercent !== undefined && data.ChangePercent !== null ? parseFloat(data.ChangePercent) * 100 : null
|
|
38195
|
+
};
|
|
38196
|
+
if (this.debug) {
|
|
38197
|
+
console.log('[IntradayChartWidget] Updating stats from live data:', stats);
|
|
38198
|
+
}
|
|
38199
|
+
|
|
38200
|
+
// Update stats display
|
|
38201
|
+
const highElement = this.container.querySelector('.stat-high .stat-value');
|
|
38202
|
+
const lowElement = this.container.querySelector('.stat-low .stat-value');
|
|
38203
|
+
const openElement = this.container.querySelector('.stat-open .stat-value');
|
|
38204
|
+
const closeElement = this.container.querySelector('.stat-close .stat-value');
|
|
38205
|
+
const volumeElement = this.container.querySelector('.stat-volume .stat-value');
|
|
38206
|
+
const changeElement = this.container.querySelector('.chart-change');
|
|
38207
|
+
if (highElement && stats.high !== null) {
|
|
38208
|
+
highElement.textContent = `$${stats.high.toFixed(2)}`;
|
|
38209
|
+
}
|
|
38210
|
+
if (lowElement && stats.low !== null) {
|
|
38211
|
+
lowElement.textContent = `$${stats.low.toFixed(2)}`;
|
|
38212
|
+
}
|
|
38213
|
+
if (openElement && stats.open !== null) {
|
|
38214
|
+
openElement.textContent = `$${stats.open.toFixed(2)}`;
|
|
38215
|
+
}
|
|
38216
|
+
if (closeElement && stats.close !== null) {
|
|
38217
|
+
closeElement.textContent = `$${stats.close.toFixed(2)}`;
|
|
38218
|
+
}
|
|
38219
|
+
if (volumeElement && stats.volume !== null) {
|
|
38220
|
+
volumeElement.textContent = this.formatVolume(stats.volume);
|
|
38221
|
+
}
|
|
38222
|
+
if (changeElement && stats.change !== null && stats.changePercent !== null) {
|
|
38223
|
+
const changeClass = stats.change >= 0 ? 'positive' : 'negative';
|
|
38224
|
+
changeElement.className = `chart-change ${changeClass}`;
|
|
38225
|
+
const sign = stats.change >= 0 ? '+' : '';
|
|
38226
|
+
changeElement.textContent = `${sign}${stats.change.toFixed(2)} (${sign}${stats.changePercent.toFixed(2)}%)`;
|
|
38227
|
+
}
|
|
38228
|
+
}
|
|
38229
|
+
formatVolume(volume) {
|
|
38230
|
+
if (volume >= 1000000) {
|
|
38231
|
+
return (volume / 1000000).toFixed(2) + 'M';
|
|
38232
|
+
} else if (volume >= 1000) {
|
|
38233
|
+
return (volume / 1000).toFixed(2) + 'K';
|
|
38234
|
+
}
|
|
38235
|
+
return volume.toString();
|
|
37960
38236
|
}
|
|
37961
38237
|
updateLivePriceLine() {
|
|
37962
38238
|
if (!this.chartInstance || !this.livePrice) {
|
|
@@ -38115,7 +38391,8 @@ ${SharedStyles}
|
|
|
38115
38391
|
if (response && Array.isArray(response)) {
|
|
38116
38392
|
this.chartData = new IntradayChartModel(response);
|
|
38117
38393
|
this.renderChart();
|
|
38118
|
-
|
|
38394
|
+
// Stats are managed by WebSocket updates only
|
|
38395
|
+
|
|
38119
38396
|
if (this.debug) {
|
|
38120
38397
|
console.log(`[IntradayChartWidget] Auto-refresh complete - ${response.length} data points`);
|
|
38121
38398
|
}
|
|
@@ -38421,10 +38698,12 @@ ${SharedStyles}
|
|
|
38421
38698
|
autoSkip: true,
|
|
38422
38699
|
maxRotation: 0,
|
|
38423
38700
|
minRotation: 0,
|
|
38424
|
-
callback: (value, index) => {
|
|
38701
|
+
callback: (value, index, ticks) => {
|
|
38425
38702
|
if (this.rangeBack > 0) {
|
|
38426
|
-
// For multi-day charts with linear scale
|
|
38427
|
-
|
|
38703
|
+
// For multi-day charts with linear scale
|
|
38704
|
+
// value is the x-value (index in data array), not the tick index
|
|
38705
|
+
const dataIndex = Math.round(value);
|
|
38706
|
+
const point = validDataPoints[dataIndex];
|
|
38428
38707
|
if (point) {
|
|
38429
38708
|
const date = new Date(point.time);
|
|
38430
38709
|
return date.toLocaleString('en-US', {
|
|
@@ -38565,6 +38844,13 @@ ${SharedStyles}
|
|
|
38565
38844
|
});
|
|
38566
38845
|
}
|
|
38567
38846
|
}
|
|
38847
|
+
|
|
38848
|
+
/**
|
|
38849
|
+
* DEPRECATED: This method is no longer used. Stats are now exclusively
|
|
38850
|
+
* updated from WebSocket data via updateStatsFromLiveData() to ensure
|
|
38851
|
+
* consistency between 1D and 5D charts (both showing today's stats only).
|
|
38852
|
+
* Kept for reference only.
|
|
38853
|
+
*/
|
|
38568
38854
|
updateStats() {
|
|
38569
38855
|
if (!this.chartData) return;
|
|
38570
38856
|
const stats = this.chartData.getStats();
|