acttrader-charts 1.0.16 → 1.0.17
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/README.md +6 -0
- package/dist/{MACD-ucey7UAq.d.cts → MACD-BbNppL1E.d.cts} +16 -0
- package/dist/{MACD-ucey7UAq.d.ts → MACD-BbNppL1E.d.ts} +16 -0
- package/dist/index.cjs +159 -39
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +7 -2
- package/dist/index.d.ts +7 -2
- package/dist/index.js +159 -39
- package/dist/index.js.map +1 -1
- package/dist/indicators/index.d.cts +2 -2
- package/dist/indicators/index.d.ts +2 -2
- package/dist/webview/chart.html +7 -7
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -55,6 +55,8 @@ const chart = new ChartEngine({
|
|
|
55
55
|
// No manual loadData() needed — the engine calls dataLoader on start and on timeframe/duration changes.
|
|
56
56
|
```
|
|
57
57
|
|
|
58
|
+
If the first fetch returns fewer than `minInitialBars` (default `10`), the engine automatically widens the lookback window and calls `dataLoader` again — up to the `maxLookbackMs` ceiling (default 365 days). This keeps the chart useful on weekends, holidays, or for instruments that just listed. If retries still yield zero bars, the engine shows a **"No data available"** overlay (customise the text via `labels.chart.noData`).
|
|
59
|
+
|
|
58
60
|
---
|
|
59
61
|
|
|
60
62
|
## Advanced Usage
|
|
@@ -160,6 +162,8 @@ chart.removeLevelByLabel('ORD-1');
|
|
|
160
162
|
chart.setLevels([], 'label', 'price', 'pending'); // clear all of one type
|
|
161
163
|
```
|
|
162
164
|
|
|
165
|
+
**Visual differentiation:** pending orders and ES/EL entry working orders render as **dashed** lines tinted by side (`pendingBuyLine` green / `pendingSellLine` red). True open positions render as **solid** lines: green/red when `pnl` is set (sign-colored), otherwise `positionLine` (purple/indigo). The info-box border matches the line color. Each true open position also gets a small colored price tag on the right-side price axis showing the entry price — same visual language as the Bid/Ask tag — so you can read the entry price without hunting for the info box.
|
|
166
|
+
|
|
163
167
|
**TFC events:**
|
|
164
168
|
|
|
165
169
|
```ts
|
|
@@ -236,6 +240,8 @@ When `enableTrading` is on and live BID/ASK data is streaming, hovering / activa
|
|
|
236
240
|
| `minLots` | | `1` | Default lot size in the trade popover |
|
|
237
241
|
| `tickActivityMs` | | `30000` | ms the stream dot stays green after last tick |
|
|
238
242
|
| `maxCandles` | | `200` | Max bars fetched per data-load request |
|
|
243
|
+
| `minInitialBars` | | `10` | If `dataLoader` returns fewer bars, the fetch window auto-widens and retries (handles weekends, market closures, and sparse symbols) |
|
|
244
|
+
| `maxLookbackMs` | | `31_536_000_000` | Hard ceiling on auto-widening lookback (ms). Retries stop once the window reaches this. Default: 365 days |
|
|
239
245
|
| `prefetchThreshold` | | `80` | Bars from start of data at which historical fetch triggers (min 20) |
|
|
240
246
|
| `mobileBarDivisor` | | `2` | Divide desktop visible bar count on touch devices (`2`, `3`, or `4`) |
|
|
241
247
|
| `momentumScrollEnabled` | | `true` | Enable momentum (kinetic) scrolling — chart coasts after a fast flick |
|
|
@@ -300,6 +300,8 @@ interface DialogLabels {
|
|
|
300
300
|
interface ChartMiscLabels {
|
|
301
301
|
/** Overlay text shown while data is being fetched. */
|
|
302
302
|
loading: string;
|
|
303
|
+
/** Overlay text shown when a completed fetch returned zero bars. */
|
|
304
|
+
noData: string;
|
|
303
305
|
/** Tooltip on the "jump to live edge" button. */
|
|
304
306
|
scrollToLatest: string;
|
|
305
307
|
/** Collapse button text in the indicator overlay when more than 2 indicators
|
|
@@ -679,6 +681,20 @@ interface ChartConfig {
|
|
|
679
681
|
* of bars. Default: 200.
|
|
680
682
|
*/
|
|
681
683
|
maxCandles?: number;
|
|
684
|
+
/**
|
|
685
|
+
* Minimum bars expected from the initial fetch before giving up. If the
|
|
686
|
+
* `dataLoader` returns fewer bars than this, ChartEngine automatically
|
|
687
|
+
* widens the lookback window and retries — this keeps charts useful after
|
|
688
|
+
* weekends, holidays, or for instruments with sparse recent history.
|
|
689
|
+
* Default: 10.
|
|
690
|
+
*/
|
|
691
|
+
minInitialBars?: number;
|
|
692
|
+
/**
|
|
693
|
+
* Hard ceiling (in milliseconds) on how far back auto-widening retries
|
|
694
|
+
* can reach when chasing enough bars. Retries stop once the window meets
|
|
695
|
+
* or exceeds this value. Default: 365 days.
|
|
696
|
+
*/
|
|
697
|
+
maxLookbackMs?: number;
|
|
682
698
|
/**
|
|
683
699
|
* How close (in bars) the viewport must be to the start of loaded data
|
|
684
700
|
* before a historical fetch is triggered. Higher values prefetch earlier.
|
|
@@ -300,6 +300,8 @@ interface DialogLabels {
|
|
|
300
300
|
interface ChartMiscLabels {
|
|
301
301
|
/** Overlay text shown while data is being fetched. */
|
|
302
302
|
loading: string;
|
|
303
|
+
/** Overlay text shown when a completed fetch returned zero bars. */
|
|
304
|
+
noData: string;
|
|
303
305
|
/** Tooltip on the "jump to live edge" button. */
|
|
304
306
|
scrollToLatest: string;
|
|
305
307
|
/** Collapse button text in the indicator overlay when more than 2 indicators
|
|
@@ -679,6 +681,20 @@ interface ChartConfig {
|
|
|
679
681
|
* of bars. Default: 200.
|
|
680
682
|
*/
|
|
681
683
|
maxCandles?: number;
|
|
684
|
+
/**
|
|
685
|
+
* Minimum bars expected from the initial fetch before giving up. If the
|
|
686
|
+
* `dataLoader` returns fewer bars than this, ChartEngine automatically
|
|
687
|
+
* widens the lookback window and retries — this keeps charts useful after
|
|
688
|
+
* weekends, holidays, or for instruments with sparse recent history.
|
|
689
|
+
* Default: 10.
|
|
690
|
+
*/
|
|
691
|
+
minInitialBars?: number;
|
|
692
|
+
/**
|
|
693
|
+
* Hard ceiling (in milliseconds) on how far back auto-widening retries
|
|
694
|
+
* can reach when chasing enough bars. Retries stop once the window meets
|
|
695
|
+
* or exceeds this value. Default: 365 days.
|
|
696
|
+
*/
|
|
697
|
+
maxLookbackMs?: number;
|
|
682
698
|
/**
|
|
683
699
|
* How close (in bars) the viewport must be to the start of loaded data
|
|
684
700
|
* before a historical fetch is triggered. Higher values prefetch earlier.
|
package/dist/index.cjs
CHANGED
|
@@ -722,6 +722,7 @@ var DEFAULT_LABELS = {
|
|
|
722
722
|
chart: {
|
|
723
723
|
loading: "Loading\u2026",
|
|
724
724
|
// 'Loading…'
|
|
725
|
+
noData: "No data available",
|
|
725
726
|
scrollToLatest: "Scroll to latest",
|
|
726
727
|
nIndicators: "{count} indicators"
|
|
727
728
|
}
|
|
@@ -1826,6 +1827,10 @@ function monoBoxBg(theme, active) {
|
|
|
1826
1827
|
}
|
|
1827
1828
|
function levelColor(level, colors, theme) {
|
|
1828
1829
|
if (level.type === "position") {
|
|
1830
|
+
const pos = level;
|
|
1831
|
+
if (pos.entryPriceEditable && pos.side) {
|
|
1832
|
+
return pos.side === "buy" ? colors.pendingBuyLine : colors.pendingSellLine;
|
|
1833
|
+
}
|
|
1829
1834
|
const pnl = level.pnl;
|
|
1830
1835
|
if (pnl !== void 0) return pnl >= 0 ? theme.candle.up : theme.candle.down;
|
|
1831
1836
|
return colors.positionLine;
|
|
@@ -2356,11 +2361,12 @@ function drawLevel(ctx, level, layout, chartW, colors, theme, precision, hovered
|
|
|
2356
2361
|
}
|
|
2357
2362
|
}
|
|
2358
2363
|
if (isMarketDraft) return;
|
|
2364
|
+
const isEntryOrderPos = level.type === "position" && level.entryPriceEditable === true;
|
|
2359
2365
|
ctx.save();
|
|
2360
|
-
ctx.strokeStyle =
|
|
2366
|
+
ctx.strokeStyle = color;
|
|
2361
2367
|
ctx.lineWidth = LINE_WIDTH;
|
|
2362
|
-
ctx.globalAlpha = active ?
|
|
2363
|
-
if (isPending) {
|
|
2368
|
+
ctx.globalAlpha = active ? 1 : 0.85;
|
|
2369
|
+
if (isPending || isEntryOrderPos) {
|
|
2364
2370
|
ctx.setLineDash([5, 4]);
|
|
2365
2371
|
}
|
|
2366
2372
|
ctx.beginPath();
|
|
@@ -2373,15 +2379,14 @@ function drawLevel(ctx, level, layout, chartW, colors, theme, precision, hovered
|
|
|
2373
2379
|
const midY = boxY + boxH / 2;
|
|
2374
2380
|
ctx.save();
|
|
2375
2381
|
ctx.fillStyle = monoBoxBg(theme, active);
|
|
2376
|
-
ctx.strokeStyle =
|
|
2382
|
+
ctx.strokeStyle = color;
|
|
2377
2383
|
ctx.lineWidth = 1;
|
|
2378
2384
|
roundRect(ctx, boxX, boxY, boxW, boxH, BOX_RADIUS);
|
|
2379
2385
|
ctx.fill();
|
|
2380
2386
|
ctx.stroke();
|
|
2381
2387
|
let textX = boxX + BOX_PAD_X;
|
|
2382
2388
|
const isDraftLevel = level.data?._isDraft === true;
|
|
2383
|
-
const
|
|
2384
|
-
const supportsQtyField = level.type === "pending" || isEntryOrderPosition;
|
|
2389
|
+
const supportsQtyField = level.type === "pending" || isEntryOrderPos;
|
|
2385
2390
|
const levelLots = level.lots;
|
|
2386
2391
|
if (showQuantityField && (isDraftLevel || selected || hasPendingChanges) && supportsQtyField && levelLots !== void 0) {
|
|
2387
2392
|
const qtyText = String(levelLots);
|
|
@@ -2787,6 +2792,43 @@ function hitTestTradeLevelDrag(x, y, dragAreas) {
|
|
|
2787
2792
|
function hitTestTradeLevelAddBracket(x, y, areas) {
|
|
2788
2793
|
return areas.find((a) => x >= a.x && x <= a.x + a.w && y >= a.y && y <= a.y + a.h) ?? null;
|
|
2789
2794
|
}
|
|
2795
|
+
function renderPositionAxisTags(ctx, levels, scale, priceRange, theme, chartW, priceH, precision) {
|
|
2796
|
+
const tagH = 16;
|
|
2797
|
+
const items = [];
|
|
2798
|
+
for (const level of levels) {
|
|
2799
|
+
if (level.type !== "position") continue;
|
|
2800
|
+
const pos = level;
|
|
2801
|
+
if (pos.entryPriceEditable) continue;
|
|
2802
|
+
const y = scale.yToPixel(pos.price, priceRange, priceH);
|
|
2803
|
+
if (y < -tagH || y > priceH + tagH) continue;
|
|
2804
|
+
items.push({
|
|
2805
|
+
y,
|
|
2806
|
+
label: pos.price.toFixed(precision),
|
|
2807
|
+
color: levelColor(level, theme.tradeLevels, theme)
|
|
2808
|
+
});
|
|
2809
|
+
}
|
|
2810
|
+
if (items.length === 0) return;
|
|
2811
|
+
items.sort((a, b) => a.y - b.y);
|
|
2812
|
+
let lastBottom = -Infinity;
|
|
2813
|
+
for (const it of items) {
|
|
2814
|
+
if (it.y - tagH / 2 < lastBottom) {
|
|
2815
|
+
it.y = lastBottom + tagH / 2;
|
|
2816
|
+
}
|
|
2817
|
+
lastBottom = it.y + tagH / 2 + 1;
|
|
2818
|
+
}
|
|
2819
|
+
ctx.save();
|
|
2820
|
+
ctx.font = "10px 'Inter', system-ui, sans-serif";
|
|
2821
|
+
ctx.textAlign = "left";
|
|
2822
|
+
ctx.textBaseline = "middle";
|
|
2823
|
+
for (const it of items) {
|
|
2824
|
+
const tw = ctx.measureText(it.label).width;
|
|
2825
|
+
ctx.fillStyle = it.color;
|
|
2826
|
+
ctx.fillRect(chartW, it.y - tagH / 2, tw + 12, tagH);
|
|
2827
|
+
ctx.fillStyle = "#ffffff";
|
|
2828
|
+
ctx.fillText(it.label, chartW + 4, it.y);
|
|
2829
|
+
}
|
|
2830
|
+
ctx.restore();
|
|
2831
|
+
}
|
|
2790
2832
|
|
|
2791
2833
|
// src/overlays/OffViewportLevelIndicator.ts
|
|
2792
2834
|
function collectOffViewportMarkers(levels, priceRange, draggingLabel) {
|
|
@@ -17333,6 +17375,8 @@ var _ChartEngine = class _ChartEngine {
|
|
|
17333
17375
|
this.noMoreData = false;
|
|
17334
17376
|
this._loadGeneration = 0;
|
|
17335
17377
|
this.maxCandles = 200;
|
|
17378
|
+
this.minInitialBars = 10;
|
|
17379
|
+
this.maxLookbackMs = 365 * 24 * 60 * 60 * 1e3;
|
|
17336
17380
|
this.prefetchThreshold = 80;
|
|
17337
17381
|
this.defaultVisibleBars = DEFAULT_VISIBLE_BARS;
|
|
17338
17382
|
this.defaultMobileVisibleBars = void 0;
|
|
@@ -17344,6 +17388,7 @@ var _ChartEngine = class _ChartEngine {
|
|
|
17344
17388
|
this.maxSubPanes = 3;
|
|
17345
17389
|
this.showCandleCountdown = true;
|
|
17346
17390
|
this.loadingOverlayEl = null;
|
|
17391
|
+
this.noDataOverlayEl = null;
|
|
17347
17392
|
// Watermark
|
|
17348
17393
|
this.logoImage = null;
|
|
17349
17394
|
// ── State persistence ─────────────────────────────────────────────────────
|
|
@@ -18338,6 +18383,8 @@ var _ChartEngine = class _ChartEngine {
|
|
|
18338
18383
|
this.labels = resolveLabels(labels);
|
|
18339
18384
|
this.tickActivityMs = tickActivityMs;
|
|
18340
18385
|
this.maxCandles = config.maxCandles ?? 200;
|
|
18386
|
+
this.minInitialBars = Math.max(0, config.minInitialBars ?? 10);
|
|
18387
|
+
this.maxLookbackMs = Math.max(0, config.maxLookbackMs ?? 365 * 24 * 60 * 60 * 1e3);
|
|
18341
18388
|
this.prefetchThreshold = config.prefetchThreshold ?? 80;
|
|
18342
18389
|
this.defaultVisibleBars = config.defaultVisibleBars ?? DEFAULT_VISIBLE_BARS;
|
|
18343
18390
|
this.defaultMobileVisibleBars = config.defaultMobileVisibleBars;
|
|
@@ -18608,6 +18655,30 @@ var _ChartEngine = class _ChartEngine {
|
|
|
18608
18655
|
});
|
|
18609
18656
|
this.loadingOverlayEl.appendChild(loadingLabel);
|
|
18610
18657
|
this.canvasWrap.appendChild(this.loadingOverlayEl);
|
|
18658
|
+
this.noDataOverlayEl = document.createElement("div");
|
|
18659
|
+
Object.assign(this.noDataOverlayEl.style, {
|
|
18660
|
+
display: "none",
|
|
18661
|
+
position: "absolute",
|
|
18662
|
+
top: "0",
|
|
18663
|
+
left: "0",
|
|
18664
|
+
width: "100%",
|
|
18665
|
+
height: "100%",
|
|
18666
|
+
alignItems: "center",
|
|
18667
|
+
justifyContent: "center",
|
|
18668
|
+
pointerEvents: "none",
|
|
18669
|
+
zIndex: "19"
|
|
18670
|
+
});
|
|
18671
|
+
const noDataLabel = document.createElement("span");
|
|
18672
|
+
noDataLabel.textContent = this.labels.chart.noData;
|
|
18673
|
+
Object.assign(noDataLabel.style, {
|
|
18674
|
+
color: "rgba(200,200,200,0.9)",
|
|
18675
|
+
fontSize: "13px",
|
|
18676
|
+
background: "rgba(0,0,0,0.45)",
|
|
18677
|
+
padding: "4px 12px",
|
|
18678
|
+
borderRadius: "4px"
|
|
18679
|
+
});
|
|
18680
|
+
this.noDataOverlayEl.appendChild(noDataLabel);
|
|
18681
|
+
this.canvasWrap.appendChild(this.noDataOverlayEl);
|
|
18611
18682
|
}
|
|
18612
18683
|
if (showUI && !hideSymbolAndTick) {
|
|
18613
18684
|
this.siEl = document.createElement("div");
|
|
@@ -18948,6 +19019,7 @@ var _ChartEngine = class _ChartEngine {
|
|
|
18948
19019
|
resetData() {
|
|
18949
19020
|
++this._loadGeneration;
|
|
18950
19021
|
this.setLoading(false);
|
|
19022
|
+
this.setNoData(false);
|
|
18951
19023
|
this.drawingManager.clearAll();
|
|
18952
19024
|
this.levels = [];
|
|
18953
19025
|
this._draftQtyPillArea = void 0;
|
|
@@ -18958,6 +19030,7 @@ var _ChartEngine = class _ChartEngine {
|
|
|
18958
19030
|
this.isFetching = false;
|
|
18959
19031
|
this.noMoreData = false;
|
|
18960
19032
|
this._suppressTicks = false;
|
|
19033
|
+
if (bars.length > 0) this.setNoData(false);
|
|
18961
19034
|
this.liveBidAsk = null;
|
|
18962
19035
|
this.pricePanOffset = 0;
|
|
18963
19036
|
this.priceScaleFactor = 1;
|
|
@@ -19037,6 +19110,14 @@ var _ChartEngine = class _ChartEngine {
|
|
|
19037
19110
|
if (this.loadingOverlayEl) {
|
|
19038
19111
|
this.loadingOverlayEl.style.display = loading ? "flex" : "none";
|
|
19039
19112
|
}
|
|
19113
|
+
if (loading) this.setNoData(false);
|
|
19114
|
+
return this;
|
|
19115
|
+
}
|
|
19116
|
+
/** Shows or hides the "No data available" overlay. */
|
|
19117
|
+
setNoData(show) {
|
|
19118
|
+
if (this.noDataOverlayEl) {
|
|
19119
|
+
this.noDataOverlayEl.style.display = show ? "flex" : "none";
|
|
19120
|
+
}
|
|
19040
19121
|
return this;
|
|
19041
19122
|
}
|
|
19042
19123
|
// ── Data loading helpers ──────────────────────────────────────────────────
|
|
@@ -19109,28 +19190,43 @@ var _ChartEngine = class _ChartEngine {
|
|
|
19109
19190
|
this.isFetching = true;
|
|
19110
19191
|
this.noMoreData = false;
|
|
19111
19192
|
const end = /* @__PURE__ */ new Date();
|
|
19112
|
-
const
|
|
19113
|
-
|
|
19114
|
-
);
|
|
19115
|
-
const durationStart = this.duration ? new Date(end.getTime() - this.durationToMs(this.duration)) : maxCandleStart;
|
|
19116
|
-
const start = new Date(Math.max(durationStart.getTime(), maxCandleStart.getTime()));
|
|
19193
|
+
const maxCandleMs = this.maxCandles * this.timeframeToMs(this.timeframe);
|
|
19194
|
+
const durationMs = this.duration ? this.durationToMs(this.duration) : maxCandleMs;
|
|
19195
|
+
const baseWindowMs = Math.min(durationMs, maxCandleMs);
|
|
19117
19196
|
const interval = this.timeframeToInterval(this.getBaseInterval());
|
|
19118
19197
|
this.setLoading(true);
|
|
19119
|
-
|
|
19120
|
-
|
|
19121
|
-
|
|
19122
|
-
|
|
19123
|
-
|
|
19124
|
-
|
|
19125
|
-
|
|
19126
|
-
|
|
19127
|
-
end
|
|
19198
|
+
const loader = this.dataLoader;
|
|
19199
|
+
const expansionFactors = [1, 5, 25, 125];
|
|
19200
|
+
const minBars = this.minInitialBars;
|
|
19201
|
+
const cap = this.maxLookbackMs;
|
|
19202
|
+
const attempt = (i, start) => {
|
|
19203
|
+
loader({ start, end, interval }).then((bars) => {
|
|
19204
|
+
if (gen !== this._loadGeneration) return;
|
|
19205
|
+
const aggregated = this.maybeAggregate(bars);
|
|
19206
|
+
const reachedCap = end.getTime() - start.getTime() >= cap;
|
|
19207
|
+
if (aggregated.length >= minBars || i + 1 >= expansionFactors.length || reachedCap) {
|
|
19208
|
+
this.loadData(aggregated, reason === "duration");
|
|
19209
|
+
this.setLoading(false);
|
|
19210
|
+
if (aggregated.length === 0) this.setNoData(true);
|
|
19211
|
+
this.emitter.emit("dataLoaded", {
|
|
19212
|
+
timeframe: this.timeframe,
|
|
19213
|
+
interval,
|
|
19214
|
+
start,
|
|
19215
|
+
end
|
|
19216
|
+
});
|
|
19217
|
+
return;
|
|
19218
|
+
}
|
|
19219
|
+
const nextWindowMs = Math.min(baseWindowMs * expansionFactors[i + 1], cap);
|
|
19220
|
+
const nextStart = new Date(end.getTime() - nextWindowMs);
|
|
19221
|
+
attempt(i + 1, nextStart);
|
|
19222
|
+
}).catch(() => {
|
|
19223
|
+
if (gen !== this._loadGeneration) return;
|
|
19224
|
+
this.isFetching = false;
|
|
19225
|
+
this.setLoading(false);
|
|
19128
19226
|
});
|
|
19129
|
-
}
|
|
19130
|
-
|
|
19131
|
-
|
|
19132
|
-
this.setLoading(false);
|
|
19133
|
-
});
|
|
19227
|
+
};
|
|
19228
|
+
const firstWindowMs = Math.min(baseWindowMs * expansionFactors[0], cap);
|
|
19229
|
+
attempt(0, new Date(end.getTime() - firstWindowMs));
|
|
19134
19230
|
}
|
|
19135
19231
|
checkNeedMoreData() {
|
|
19136
19232
|
if (!this.dataLoader || this.isFetching || this.noMoreData) return;
|
|
@@ -19141,22 +19237,36 @@ var _ChartEngine = class _ChartEngine {
|
|
|
19141
19237
|
this.isFetching = true;
|
|
19142
19238
|
const before = this.dataStore.all[0].time;
|
|
19143
19239
|
const end = new Date(before - 1);
|
|
19144
|
-
const
|
|
19145
|
-
|
|
19146
|
-
);
|
|
19147
|
-
const durationStart = this.duration ? new Date(before - this.durationToMs(this.duration)) : maxCandleStart;
|
|
19148
|
-
const start = new Date(Math.max(durationStart.getTime(), maxCandleStart.getTime()));
|
|
19240
|
+
const maxCandleMs = this.maxCandles * this.timeframeToMs(this.timeframe);
|
|
19241
|
+
const durationMs = this.duration ? this.durationToMs(this.duration) : maxCandleMs;
|
|
19242
|
+
const baseWindowMs = Math.min(durationMs, maxCandleMs);
|
|
19149
19243
|
const interval = this.timeframeToInterval(this.getBaseInterval());
|
|
19150
19244
|
this.setLoading(true);
|
|
19151
|
-
|
|
19152
|
-
|
|
19153
|
-
|
|
19154
|
-
|
|
19155
|
-
|
|
19156
|
-
|
|
19157
|
-
|
|
19158
|
-
|
|
19159
|
-
|
|
19245
|
+
const loader = this.dataLoader;
|
|
19246
|
+
const expansionFactors = [1, 5, 25, 125];
|
|
19247
|
+
const minBars = this.minInitialBars;
|
|
19248
|
+
const cap = this.maxLookbackMs;
|
|
19249
|
+
const attempt = (i, start) => {
|
|
19250
|
+
loader({ start, end, interval }).then((bars) => {
|
|
19251
|
+
if (gen !== this._loadGeneration) return;
|
|
19252
|
+
const aggregated = this.maybeAggregate(bars);
|
|
19253
|
+
const reachedCap = end.getTime() - start.getTime() >= cap;
|
|
19254
|
+
if (aggregated.length >= minBars || i + 1 >= expansionFactors.length || reachedCap) {
|
|
19255
|
+
this.prependData(aggregated);
|
|
19256
|
+
this.setLoading(false);
|
|
19257
|
+
return;
|
|
19258
|
+
}
|
|
19259
|
+
const nextWindowMs = Math.min(baseWindowMs * expansionFactors[i + 1], cap);
|
|
19260
|
+
const nextStart = new Date(end.getTime() - nextWindowMs);
|
|
19261
|
+
attempt(i + 1, nextStart);
|
|
19262
|
+
}).catch(() => {
|
|
19263
|
+
if (gen !== this._loadGeneration) return;
|
|
19264
|
+
this.isFetching = false;
|
|
19265
|
+
this.setLoading(false);
|
|
19266
|
+
});
|
|
19267
|
+
};
|
|
19268
|
+
const firstWindowMs = Math.min(baseWindowMs * expansionFactors[0], cap);
|
|
19269
|
+
attempt(0, new Date(end.getTime() - firstWindowMs));
|
|
19160
19270
|
}
|
|
19161
19271
|
addIndicator(indicator) {
|
|
19162
19272
|
if (indicator.pane === "sub") {
|
|
@@ -20675,6 +20785,16 @@ var _ChartEngine = class _ChartEngine {
|
|
|
20675
20785
|
this.selectedTradeLabel
|
|
20676
20786
|
);
|
|
20677
20787
|
this.offViewportHitAreas = offVpResult.hitAreas;
|
|
20788
|
+
renderPositionAxisTags(
|
|
20789
|
+
ctx,
|
|
20790
|
+
filteredLevels,
|
|
20791
|
+
this.scaleManager,
|
|
20792
|
+
priceRange,
|
|
20793
|
+
theme,
|
|
20794
|
+
chartW,
|
|
20795
|
+
priceH,
|
|
20796
|
+
this.dataStore.getPricePrecision()
|
|
20797
|
+
);
|
|
20678
20798
|
ctx.restore();
|
|
20679
20799
|
this.tradeLevelHitAreas = result.hitAreas;
|
|
20680
20800
|
this.tradeLevelEditAreas = result.editAreas;
|