acttrader-charts 1.3.0-beta.14 → 1.3.0-beta.16
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 +20 -8
- package/dist/{MACD-C42nYzfa.d.cts → MACD-lXwCQ5We.d.cts} +42 -1
- package/dist/{MACD-C42nYzfa.d.ts → MACD-lXwCQ5We.d.ts} +42 -1
- package/dist/index.cjs +205 -36
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +50 -8
- package/dist/index.d.ts +50 -8
- package/dist/index.js +205 -36
- 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 +5 -5
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -58,12 +58,15 @@ chart.on('durationChange', ({ duration, timeframe }) => {
|
|
|
58
58
|
```ts
|
|
59
59
|
const chart = new ChartEngine({
|
|
60
60
|
container,
|
|
61
|
-
dataLoader: async ({ start, end, interval }) => {
|
|
62
|
-
|
|
61
|
+
dataLoader: async ({ start, end, interval, priceSource }) => {
|
|
62
|
+
// `priceSource` ('bid' | 'ask' | 'ltp') is the candle source the chart is showing —
|
|
63
|
+
// pass it to your history API so the bars match (dealing feeds: LTP vs BID candles).
|
|
64
|
+
const res = await fetch(`/api/bars?from=${start.getTime()}&to=${end.getTime()}&tf=${interval}&source=${priceSource}`);
|
|
63
65
|
return res.json(); // OHLCVBar[]
|
|
64
66
|
},
|
|
65
67
|
});
|
|
66
|
-
// No manual loadData() needed — the engine calls dataLoader on start
|
|
68
|
+
// No manual loadData() needed — the engine calls dataLoader on start, on timeframe/duration
|
|
69
|
+
// changes, and (unless `reloadOnPriceSourceChange: false`) whenever the price source changes.
|
|
67
70
|
```
|
|
68
71
|
|
|
69
72
|
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`).
|
|
@@ -171,6 +174,8 @@ dealingChart.setTickClosePriceSource('bid');
|
|
|
171
174
|
dealingChart.on('priceSourceChange', ({ source }) => saveTradeSetting(source));
|
|
172
175
|
```
|
|
173
176
|
|
|
177
|
+
**History follows the source.** Switching the source (dropdown pick or `setTickClosePriceSource()`) does not just change how live ticks extend the last candle — the engine re-runs your `dataLoader` with `params.priceSource` set to the new value and replaces the loaded bars, keeping the visible time window. Forward `priceSource` to your charting API (e.g. as a query parameter) so it returns LTP-built or BID-built candles accordingly; without it the API keeps serving the old source and the chart cannot change. Set `reloadOnPriceSourceChange: false` to opt out of the re-fetch.
|
|
178
|
+
|
|
174
179
|
### Compare symbols
|
|
175
180
|
|
|
176
181
|
Overlay one or more comparison instruments on the main chart, normalized to
|
|
@@ -348,6 +353,8 @@ const chart = new ChartEngine({
|
|
|
348
353
|
container,
|
|
349
354
|
features: { orderLineTimeDrag: true }, // host enables this only for the gated broker
|
|
350
355
|
orderLineDragSnap: true, // snap to nearest candle on release (default)
|
|
356
|
+
orderLineAnchorPersistence: true, // remember dropped positions in localStorage (default)
|
|
357
|
+
orderLineDefaultAnchor: 'center', // un-dragged badges start mid-chart (default: 'timestamp')
|
|
351
358
|
});
|
|
352
359
|
|
|
353
360
|
chart.setLevels(
|
|
@@ -365,6 +372,8 @@ chart.on('orderLineMoved', ({ label, fromTimestamp, toTimestamp, data }) => {
|
|
|
365
372
|
- **Snap:** controlled by `orderLineDragSnap` (default `true`); set `false` to keep the exact released time.
|
|
366
373
|
- **Escape / touch-cancel:** reverts the badge to its starting candle without emitting `orderLineMoved`.
|
|
367
374
|
- **Stays put after release:** the chart holds the dropped position across `setLevels` refreshes until you echo the new `timestamp` back (auto-released on match).
|
|
375
|
+
- **Survives reloads:** with `orderLineAnchorPersistence` (default `true`) the dropped candle time is saved in `localStorage` under `finchart.orderLineTimeAnchors`, keyed by the level's label. After a page reload the badge returns to that candle even if your `setLevels()` payload still carries the order's original `timestamp` — the persisted anchor wins until the badge is dragged again. Capped at the 500 most recently dragged labels; set `false` if you persist anchors server-side instead.
|
|
376
|
+
- **New orders at the center:** with `orderLineDefaultAnchor: 'center'` a `timeDraggable` level that has never been dragged ignores its `timestamp` and renders mid-chart — so a freshly filled market order arrives in the middle of the chart rather than pinned to the latest candle at the right edge. Levels that are not `timeDraggable` still honor `timestamp`. Default `'timestamp'` keeps the previous behavior.
|
|
368
377
|
- A level **without** `timestamp` renders exactly as before (badge centered), so existing consumers are unaffected.
|
|
369
378
|
|
|
370
379
|
---
|
|
@@ -405,7 +414,7 @@ chart.on('orderLineMoved', ({ label, fromTimestamp, toTimestamp, data }) => {
|
|
|
405
414
|
| `momentumMaxVelocity` | | `6.0` | Max launch velocity (px/ms) — caps hard-flick speed |
|
|
406
415
|
| `targetCandleWidth` | | `10` | Target px width per candle for auto-calculating initial bar count |
|
|
407
416
|
| `durationTimeframeMap` | | *(see below)* | Override duration → timeframe pairings |
|
|
408
|
-
| `dataLoader` | | — | `(
|
|
417
|
+
| `dataLoader` | | — | `({ start, end, interval, priceSource }) => Promise<OHLCVBar[]>` auto-called on load, timeframe/duration change, and price-source change. `priceSource` is the candle source to fetch (`'bid'`, `'ask'` or `'ltp'`) |
|
|
409
418
|
| `compareDataLoader` | | — | `({ symbol, start, end, interval }) => Promise<OHLCVBar[]>` — fetches bars for a compare symbol. Set this to enable the library-owned Compare flow. |
|
|
410
419
|
| `initialCompares` | | — | Symbols to auto-add as compares once the initial primary range is loaded |
|
|
411
420
|
| `maxCompares` | | `8` | Maximum concurrent compare symbols. Adding beyond emits `compareError` |
|
|
@@ -414,7 +423,8 @@ chart.on('orderLineMoved', ({ label, fromTimestamp, toTimestamp, data }) => {
|
|
|
414
423
|
| `labels` | | `DEFAULT_LABELS` | Deep-partial string overrides for i18n/translation |
|
|
415
424
|
| `tickClosePriceSource` | | `"bid"` | Which price drives live tick close/high/low: `"bid"`, `"ask"`, or `"ltp"` (build candles from the last traded price — exchange/dealing feeds; ticks without a valid LTP fall back to the bid) |
|
|
416
425
|
| `showLtpPrice` | | unset | Show the LTP marker (dashed price line + axis tag). Unset: shown only in `"ltp"` mode. `true`: always shown when the feed supplies an LTP. `false`: hidden even in `"ltp"` mode (candles still build from the LTP). Toggle at runtime with `chart.setShowLtpPrice(show)` |
|
|
417
|
-
| `priceSourceSelector` | | unset | Show a price-source dropdown in the chart header listing the given sources, e.g. `["ltp", "bid"]` (dealing feeds). A user pick switches the
|
|
426
|
+
| `priceSourceSelector` | | unset | Show a price-source dropdown in the chart header listing the given sources, e.g. `["ltp", "bid"]` (dealing feeds). A user pick switches the candle source, re-fetches history via `dataLoader` (see `reloadOnPriceSourceChange`) and emits `priceSourceChange`; sync it programmatically with `chart.setTickClosePriceSource(source)`. Hidden when unset/empty. Default header layout only |
|
|
427
|
+
| `reloadOnPriceSourceChange` | | `true` | Re-run `dataLoader` with the new `params.priceSource` whenever the candle price source changes, so historical candles are rebuilt from the selected price (LTP vs BID) and not only the live one. The visible time window is preserved. Set `false` to keep only live ticks following the new source |
|
|
418
428
|
| `showBidAskLines` | | `false` | **Deprecated** — show both bid and ask as dashed lines during a live stream. Prefer the per-line checks `showAskLine` / `showBidLine`, which override it when set |
|
|
419
429
|
| `showAskLine` | | unset | Show the Ask price line (dashed line + axis tag) independently. Unset: legacy `showBidAskLines` behavior. Toggle at runtime with `chart.setShowAskLine(show)` |
|
|
420
430
|
| `showBidLine` | | unset | Show the Bid price line (dashed line + axis tag) independently. Unset: legacy `showBidAskLines` behavior. Toggle at runtime with `chart.setShowBidLine(show)` |
|
|
@@ -432,6 +442,8 @@ chart.on('orderLineMoved', ({ label, fromTimestamp, toTimestamp, data }) => {
|
|
|
432
442
|
| `tfcEnabled` | | `true` | Enable the TFC toggle button in the top bar. When `false`, TFC is completely disabled — the toggle button is hidden and all trade levels, draft orders, and the floating trade button are suppressed |
|
|
433
443
|
| `features.orderLineTimeDrag` | | `false` | Enable **horizontal (time-axis) order-line dragging**. A level with `timeDraggable: true` can have its info-box badge dragged left/right to re-anchor the order to a different candle — **price stays locked**. Emits `orderLineMoved` on release. Off by default; intended to be enabled per broker (e.g. Hankotrade) by the host app |
|
|
434
444
|
| `orderLineDragSnap` | | `true` | When horizontal dragging is enabled, snap the badge to the nearest candle on release. Set `false` to keep the exact released time |
|
|
445
|
+
| `orderLineAnchorPersistence` | | `true` | When horizontal dragging is enabled, remember where each badge was dropped in `localStorage` (key `finchart.orderLineTimeAnchors`, keyed by level label) so it comes back to the same candle after a reload. A persisted anchor overrides the level's `timestamp` until the badge is dragged again. Set `false` to persist anchors yourself |
|
|
446
|
+
| `orderLineDefaultAnchor` | | `'timestamp'` | Where an un-dragged `timeDraggable` badge sits: `'timestamp'` = over the candle at the level's `timestamp`; `'center'` = the chart's horizontal center (ignores `timestamp`), so a new market order lands mid-chart. Non-draggable levels always honor `timestamp` |
|
|
435
447
|
| `levelClusteringEnabled` | | `true` | Enable trade-level fan-out clustering; overlapping levels group into expandable badges |
|
|
436
448
|
| `clusterThresholdDistance` | | `20` | Pixel proximity threshold for clustering (only when `levelClusteringEnabled` is `true`) |
|
|
437
449
|
| `hideSymbolAndTick` | | `false` | Hide the symbol name and tick-activity (streaming) dot in the top-left overlay. Does **not** affect the OHLC(V) strip — use `hideOHLCV` for that |
|
|
@@ -1181,7 +1193,7 @@ chart.on('durationChange', ({ duration, timeframe }) => {});
|
|
|
1181
1193
|
chart.on('seriesChange', ({ series }) => {});
|
|
1182
1194
|
chart.on('priceSourceChange', ({ source }) => {}); // header BID/ASK/LTP dropdown pick
|
|
1183
1195
|
chart.on('streamStatus', ({ status }) => {}); // 'connected' | 'reconnecting' | 'disconnected'
|
|
1184
|
-
chart.on('dataLoaded', ({ timeframe, interval, start, end }) => {});
|
|
1196
|
+
chart.on('dataLoaded', ({ timeframe, interval, start, end, priceSource }) => {});
|
|
1185
1197
|
chart.on('newBar', ({ completedBar, openingBar, intervalMs }) => {});
|
|
1186
1198
|
chart.on('indicatorAdded', ({ instanceId, shortName, params }) => {}); // a study instance was added — keep instanceId to remove it later
|
|
1187
1199
|
chart.on('indicatorRemoved', ({ instanceId, shortName }) => {});
|
|
@@ -1212,8 +1224,8 @@ chart.on('tradeLevelBracketDrag', ({ label, bracketType, newPrice, data }) => {}
|
|
|
1212
1224
|
chart.on('orderLineMoveStart', ({ label, fromTimestamp, fromBarIndex, isFullscreen }) => {});
|
|
1213
1225
|
chart.on('orderLineMoving', ({ label, toTimestamp, toBarIndex, isFullscreen }) => {}); // fires on every move
|
|
1214
1226
|
chart.on('orderLineMoved', ({ label, fromTimestamp, toTimestamp, fromBarIndex, toBarIndex, data, isFullscreen }) => {
|
|
1215
|
-
//
|
|
1216
|
-
//
|
|
1227
|
+
// The chart already remembers the drop in localStorage (orderLineAnchorPersistence, default on).
|
|
1228
|
+
// Hook here only if you also want to persist the new time anchor server-side.
|
|
1217
1229
|
});
|
|
1218
1230
|
|
|
1219
1231
|
// Fires after addLevelBracket() auto-places a bracket, delivering the computed price back to the caller
|
|
@@ -603,6 +603,15 @@ interface DataLoaderParams {
|
|
|
603
603
|
start: Date;
|
|
604
604
|
end: Date;
|
|
605
605
|
interval: string;
|
|
606
|
+
/**
|
|
607
|
+
* Which price the chart is currently building candles from
|
|
608
|
+
* (`tickClosePriceSource`: `'bid'`, `'ask'` or `'ltp'`). Forward it to your
|
|
609
|
+
* history API (e.g. as a query parameter) so the fetched bars match the
|
|
610
|
+
* source the user picked in the header dropdown — the engine re-runs the
|
|
611
|
+
* loader with the new value whenever the source changes. Always set by the
|
|
612
|
+
* engine; optional only so callers that build params by hand keep compiling.
|
|
613
|
+
*/
|
|
614
|
+
priceSource?: 'bid' | 'ask' | 'ltp';
|
|
606
615
|
}
|
|
607
616
|
/**
|
|
608
617
|
* Params passed to `compareDataLoader`. Mirrors `DataLoaderParams` but also
|
|
@@ -920,6 +929,14 @@ interface ChartConfig {
|
|
|
920
929
|
* Rendered by the default header layout.
|
|
921
930
|
*/
|
|
922
931
|
priceSourceSelector?: Array<'bid' | 'ask' | 'ltp'>;
|
|
932
|
+
/**
|
|
933
|
+
* Re-run `dataLoader` whenever the candle price source changes (a header
|
|
934
|
+
* dropdown pick or `setTickClosePriceSource()`), passing the new source as
|
|
935
|
+
* `params.priceSource`, so the historical candles are rebuilt from the
|
|
936
|
+
* selected price and not just the live one. Set `false` to keep the old
|
|
937
|
+
* behavior where only live ticks follow the new source. Default: `true`.
|
|
938
|
+
*/
|
|
939
|
+
reloadOnPriceSourceChange?: boolean;
|
|
923
940
|
/**
|
|
924
941
|
* When the combined count of open positions and pending orders exceeds this
|
|
925
942
|
* number, the position render style auto-defaults to `'dot'` (compact).
|
|
@@ -1295,6 +1312,26 @@ interface ChartConfig {
|
|
|
1295
1312
|
* keeps the exact (interpolated) time it was released at. Default: `true`.
|
|
1296
1313
|
*/
|
|
1297
1314
|
orderLineDragSnap?: boolean;
|
|
1315
|
+
/**
|
|
1316
|
+
* Remember where each horizontally-dragged order-line badge was dropped in
|
|
1317
|
+
* `localStorage` (keyed by the level's label, i.e. your order/trade id) so it comes back
|
|
1318
|
+
* to the same candle after a page reload — even when the next `setLevels()` payload
|
|
1319
|
+
* carries the order's original `timestamp`. A persisted anchor takes precedence over
|
|
1320
|
+
* the level's `timestamp` until the label is dragged again. Bounded to the 500 most
|
|
1321
|
+
* recently dragged labels. Only relevant when `features.orderLineTimeDrag` is enabled.
|
|
1322
|
+
* Default: `true`.
|
|
1323
|
+
*/
|
|
1324
|
+
orderLineAnchorPersistence?: boolean;
|
|
1325
|
+
/**
|
|
1326
|
+
* Where a `timeDraggable` level's badge sits before the user has dragged it:
|
|
1327
|
+
* - `'timestamp'` (default): over the candle at the level's `timestamp`, as before.
|
|
1328
|
+
* - `'center'`: at the chart's horizontal center, ignoring the level's `timestamp`, so a
|
|
1329
|
+
* freshly placed market order arrives mid-chart instead of pinned to the latest candle.
|
|
1330
|
+
* Once the user drags the badge it is anchored to (and persisted at) the dropped candle.
|
|
1331
|
+
* Levels that are not `timeDraggable` always honor their `timestamp`.
|
|
1332
|
+
* Only relevant when `features.orderLineTimeDrag` is enabled.
|
|
1333
|
+
*/
|
|
1334
|
+
orderLineDefaultAnchor?: 'timestamp' | 'center';
|
|
1298
1335
|
}
|
|
1299
1336
|
interface IndicatorResult {
|
|
1300
1337
|
index: number;
|
|
@@ -1569,7 +1606,9 @@ type ChartEventMap = {
|
|
|
1569
1606
|
};
|
|
1570
1607
|
/** Emitted when the user picks a price source (BID / ASK / LTP) from the
|
|
1571
1608
|
* header dropdown (`priceSourceSelector`). Not emitted for programmatic
|
|
1572
|
-
* `setTickClosePriceSource()` calls.
|
|
1609
|
+
* `setTickClosePriceSource()` calls. By the time this fires the engine has
|
|
1610
|
+
* already switched the live source and (unless `reloadOnPriceSourceChange`
|
|
1611
|
+
* is `false`) started re-fetching history via `dataLoader`. */
|
|
1573
1612
|
priceSourceChange: {
|
|
1574
1613
|
source: 'bid' | 'ask' | 'ltp';
|
|
1575
1614
|
};
|
|
@@ -1583,6 +1622,8 @@ type ChartEventMap = {
|
|
|
1583
1622
|
interval: string;
|
|
1584
1623
|
start: Date;
|
|
1585
1624
|
end: Date;
|
|
1625
|
+
/** Candle price source the bars were requested with (see `DataLoaderParams.priceSource`). */
|
|
1626
|
+
priceSource: 'bid' | 'ask' | 'ltp';
|
|
1586
1627
|
};
|
|
1587
1628
|
/** Emitted when the user clicks the × button on a trade, position, or bracket (SL/TP) level. */
|
|
1588
1629
|
tradeLevelClose: {
|
|
@@ -603,6 +603,15 @@ interface DataLoaderParams {
|
|
|
603
603
|
start: Date;
|
|
604
604
|
end: Date;
|
|
605
605
|
interval: string;
|
|
606
|
+
/**
|
|
607
|
+
* Which price the chart is currently building candles from
|
|
608
|
+
* (`tickClosePriceSource`: `'bid'`, `'ask'` or `'ltp'`). Forward it to your
|
|
609
|
+
* history API (e.g. as a query parameter) so the fetched bars match the
|
|
610
|
+
* source the user picked in the header dropdown — the engine re-runs the
|
|
611
|
+
* loader with the new value whenever the source changes. Always set by the
|
|
612
|
+
* engine; optional only so callers that build params by hand keep compiling.
|
|
613
|
+
*/
|
|
614
|
+
priceSource?: 'bid' | 'ask' | 'ltp';
|
|
606
615
|
}
|
|
607
616
|
/**
|
|
608
617
|
* Params passed to `compareDataLoader`. Mirrors `DataLoaderParams` but also
|
|
@@ -920,6 +929,14 @@ interface ChartConfig {
|
|
|
920
929
|
* Rendered by the default header layout.
|
|
921
930
|
*/
|
|
922
931
|
priceSourceSelector?: Array<'bid' | 'ask' | 'ltp'>;
|
|
932
|
+
/**
|
|
933
|
+
* Re-run `dataLoader` whenever the candle price source changes (a header
|
|
934
|
+
* dropdown pick or `setTickClosePriceSource()`), passing the new source as
|
|
935
|
+
* `params.priceSource`, so the historical candles are rebuilt from the
|
|
936
|
+
* selected price and not just the live one. Set `false` to keep the old
|
|
937
|
+
* behavior where only live ticks follow the new source. Default: `true`.
|
|
938
|
+
*/
|
|
939
|
+
reloadOnPriceSourceChange?: boolean;
|
|
923
940
|
/**
|
|
924
941
|
* When the combined count of open positions and pending orders exceeds this
|
|
925
942
|
* number, the position render style auto-defaults to `'dot'` (compact).
|
|
@@ -1295,6 +1312,26 @@ interface ChartConfig {
|
|
|
1295
1312
|
* keeps the exact (interpolated) time it was released at. Default: `true`.
|
|
1296
1313
|
*/
|
|
1297
1314
|
orderLineDragSnap?: boolean;
|
|
1315
|
+
/**
|
|
1316
|
+
* Remember where each horizontally-dragged order-line badge was dropped in
|
|
1317
|
+
* `localStorage` (keyed by the level's label, i.e. your order/trade id) so it comes back
|
|
1318
|
+
* to the same candle after a page reload — even when the next `setLevels()` payload
|
|
1319
|
+
* carries the order's original `timestamp`. A persisted anchor takes precedence over
|
|
1320
|
+
* the level's `timestamp` until the label is dragged again. Bounded to the 500 most
|
|
1321
|
+
* recently dragged labels. Only relevant when `features.orderLineTimeDrag` is enabled.
|
|
1322
|
+
* Default: `true`.
|
|
1323
|
+
*/
|
|
1324
|
+
orderLineAnchorPersistence?: boolean;
|
|
1325
|
+
/**
|
|
1326
|
+
* Where a `timeDraggable` level's badge sits before the user has dragged it:
|
|
1327
|
+
* - `'timestamp'` (default): over the candle at the level's `timestamp`, as before.
|
|
1328
|
+
* - `'center'`: at the chart's horizontal center, ignoring the level's `timestamp`, so a
|
|
1329
|
+
* freshly placed market order arrives mid-chart instead of pinned to the latest candle.
|
|
1330
|
+
* Once the user drags the badge it is anchored to (and persisted at) the dropped candle.
|
|
1331
|
+
* Levels that are not `timeDraggable` always honor their `timestamp`.
|
|
1332
|
+
* Only relevant when `features.orderLineTimeDrag` is enabled.
|
|
1333
|
+
*/
|
|
1334
|
+
orderLineDefaultAnchor?: 'timestamp' | 'center';
|
|
1298
1335
|
}
|
|
1299
1336
|
interface IndicatorResult {
|
|
1300
1337
|
index: number;
|
|
@@ -1569,7 +1606,9 @@ type ChartEventMap = {
|
|
|
1569
1606
|
};
|
|
1570
1607
|
/** Emitted when the user picks a price source (BID / ASK / LTP) from the
|
|
1571
1608
|
* header dropdown (`priceSourceSelector`). Not emitted for programmatic
|
|
1572
|
-
* `setTickClosePriceSource()` calls.
|
|
1609
|
+
* `setTickClosePriceSource()` calls. By the time this fires the engine has
|
|
1610
|
+
* already switched the live source and (unless `reloadOnPriceSourceChange`
|
|
1611
|
+
* is `false`) started re-fetching history via `dataLoader`. */
|
|
1573
1612
|
priceSourceChange: {
|
|
1574
1613
|
source: 'bid' | 'ask' | 'ltp';
|
|
1575
1614
|
};
|
|
@@ -1583,6 +1622,8 @@ type ChartEventMap = {
|
|
|
1583
1622
|
interval: string;
|
|
1584
1623
|
start: Date;
|
|
1585
1624
|
end: Date;
|
|
1625
|
+
/** Candle price source the bars were requested with (see `DataLoaderParams.priceSource`). */
|
|
1626
|
+
priceSource: 'bid' | 'ask' | 'ltp';
|
|
1586
1627
|
};
|
|
1587
1628
|
/** Emitted when the user clicks the × button on a trade, position, or bracket (SL/TP) level. */
|
|
1588
1629
|
tradeLevelClose: {
|
package/dist/index.cjs
CHANGED
|
@@ -18425,6 +18425,7 @@ var DrawingStylePopover = class {
|
|
|
18425
18425
|
input.value = current;
|
|
18426
18426
|
input.title = "Level ratio \u2014 press Enter to apply";
|
|
18427
18427
|
input.enterKeyHint = "go";
|
|
18428
|
+
input.tabIndex = -1;
|
|
18428
18429
|
Object.assign(input.style, {
|
|
18429
18430
|
width: "58px",
|
|
18430
18431
|
padding: "2px 4px",
|
|
@@ -18436,16 +18437,6 @@ var DrawingStylePopover = class {
|
|
|
18436
18437
|
borderRadius: "3px",
|
|
18437
18438
|
outline: "none"
|
|
18438
18439
|
});
|
|
18439
|
-
input.addEventListener("focus", () => {
|
|
18440
|
-
input.style.borderColor = this.theme.ui.accent;
|
|
18441
|
-
});
|
|
18442
|
-
input.addEventListener("blur", () => {
|
|
18443
|
-
input.style.borderColor = this.theme.axisBorder;
|
|
18444
|
-
});
|
|
18445
|
-
input.addEventListener("keydown", (e) => {
|
|
18446
|
-
e.stopPropagation();
|
|
18447
|
-
if (e.key === "Enter") input.blur();
|
|
18448
|
-
});
|
|
18449
18440
|
const commit = () => {
|
|
18450
18441
|
const raw = Number(input.value);
|
|
18451
18442
|
const next = Number.isFinite(raw) ? levelKey(raw) : null;
|
|
@@ -18461,6 +18452,17 @@ var DrawingStylePopover = class {
|
|
|
18461
18452
|
input.value = next;
|
|
18462
18453
|
onCommit(next);
|
|
18463
18454
|
};
|
|
18455
|
+
input.addEventListener("focus", () => {
|
|
18456
|
+
input.style.borderColor = this.theme.ui.accent;
|
|
18457
|
+
});
|
|
18458
|
+
input.addEventListener("blur", () => {
|
|
18459
|
+
input.style.borderColor = this.theme.axisBorder;
|
|
18460
|
+
commit();
|
|
18461
|
+
});
|
|
18462
|
+
input.addEventListener("keydown", (e) => {
|
|
18463
|
+
e.stopPropagation();
|
|
18464
|
+
if (e.key === "Enter") input.blur();
|
|
18465
|
+
});
|
|
18464
18466
|
input.addEventListener("change", commit);
|
|
18465
18467
|
return input;
|
|
18466
18468
|
}
|
|
@@ -18503,6 +18505,10 @@ var DrawingStylePopover = class {
|
|
|
18503
18505
|
cb.addEventListener("change", () => {
|
|
18504
18506
|
this.emit({ levels: { [key]: { visible: cb.checked, color } } });
|
|
18505
18507
|
});
|
|
18508
|
+
cb.tabIndex = -1;
|
|
18509
|
+
swatch.querySelectorAll("input").forEach((control) => {
|
|
18510
|
+
control.tabIndex = -1;
|
|
18511
|
+
});
|
|
18506
18512
|
panel.append(cb, editable ? this.buildLevelRatioInput(
|
|
18507
18513
|
k,
|
|
18508
18514
|
taken,
|
|
@@ -19788,6 +19794,101 @@ var OrderLineTimeDragHandler = class _OrderLineTimeDragHandler {
|
|
|
19788
19794
|
}
|
|
19789
19795
|
};
|
|
19790
19796
|
|
|
19797
|
+
// src/interaction/OrderLineAnchorStore.ts
|
|
19798
|
+
var ORDER_LINE_ANCHORS_LS_KEY = "finchart.orderLineTimeAnchors";
|
|
19799
|
+
var ORDER_LINE_ANCHORS_MAX_ENTRIES = 500;
|
|
19800
|
+
var OrderLineAnchorStore = class {
|
|
19801
|
+
constructor(_storage, _key = ORDER_LINE_ANCHORS_LS_KEY, _maxEntries = ORDER_LINE_ANCHORS_MAX_ENTRIES) {
|
|
19802
|
+
this._storage = _storage;
|
|
19803
|
+
this._key = _key;
|
|
19804
|
+
this._maxEntries = _maxEntries;
|
|
19805
|
+
this._entries = /* @__PURE__ */ new Map();
|
|
19806
|
+
this._load();
|
|
19807
|
+
}
|
|
19808
|
+
/** The page's `localStorage`, or `null` when it is absent or access throws. */
|
|
19809
|
+
static browserStorage() {
|
|
19810
|
+
try {
|
|
19811
|
+
if (typeof localStorage === "undefined") return null;
|
|
19812
|
+
return localStorage;
|
|
19813
|
+
} catch {
|
|
19814
|
+
return null;
|
|
19815
|
+
}
|
|
19816
|
+
}
|
|
19817
|
+
/** Persisted unix-ms anchor for `label`, or `undefined` when none was saved. */
|
|
19818
|
+
get(label) {
|
|
19819
|
+
return this._entries.get(label)?.ts;
|
|
19820
|
+
}
|
|
19821
|
+
has(label) {
|
|
19822
|
+
return this._entries.has(label);
|
|
19823
|
+
}
|
|
19824
|
+
/** Number of persisted anchors. */
|
|
19825
|
+
get size() {
|
|
19826
|
+
return this._entries.size;
|
|
19827
|
+
}
|
|
19828
|
+
/**
|
|
19829
|
+
* Records the candle time `label`'s badge was dropped on and writes it through to storage.
|
|
19830
|
+
* Non-finite timestamps are ignored. `now` is the save time used for eviction ordering.
|
|
19831
|
+
*/
|
|
19832
|
+
set(label, ts, now = Date.now()) {
|
|
19833
|
+
if (!label || !Number.isFinite(ts)) return;
|
|
19834
|
+
this._entries.set(label, { ts, at: now });
|
|
19835
|
+
this._evict();
|
|
19836
|
+
this._save();
|
|
19837
|
+
}
|
|
19838
|
+
/** Forgets `label`'s anchor. Returns whether one existed. */
|
|
19839
|
+
delete(label) {
|
|
19840
|
+
const had = this._entries.delete(label);
|
|
19841
|
+
if (had) this._save();
|
|
19842
|
+
return had;
|
|
19843
|
+
}
|
|
19844
|
+
/** Drops every persisted anchor (memory + storage). */
|
|
19845
|
+
clear() {
|
|
19846
|
+
this._entries.clear();
|
|
19847
|
+
try {
|
|
19848
|
+
this._storage?.removeItem(this._key);
|
|
19849
|
+
} catch {
|
|
19850
|
+
}
|
|
19851
|
+
}
|
|
19852
|
+
_evict() {
|
|
19853
|
+
if (this._entries.size <= this._maxEntries) return;
|
|
19854
|
+
const byAge = [...this._entries.entries()].sort((a, b) => a[1].at - b[1].at);
|
|
19855
|
+
const excess = this._entries.size - this._maxEntries;
|
|
19856
|
+
for (let i = 0; i < excess; i++) {
|
|
19857
|
+
const victim = byAge[i];
|
|
19858
|
+
if (victim) this._entries.delete(victim[0]);
|
|
19859
|
+
}
|
|
19860
|
+
}
|
|
19861
|
+
_load() {
|
|
19862
|
+
if (!this._storage) return;
|
|
19863
|
+
try {
|
|
19864
|
+
const raw = this._storage.getItem(this._key);
|
|
19865
|
+
if (!raw) return;
|
|
19866
|
+
const parsed = JSON.parse(raw);
|
|
19867
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return;
|
|
19868
|
+
for (const [label, value] of Object.entries(parsed)) {
|
|
19869
|
+
if (!value || typeof value !== "object") continue;
|
|
19870
|
+
const { ts, at } = value;
|
|
19871
|
+
if (typeof ts !== "number" || !Number.isFinite(ts)) continue;
|
|
19872
|
+
const savedAt = typeof at === "number" && Number.isFinite(at) ? at : 0;
|
|
19873
|
+
this._entries.set(label, { ts, at: savedAt });
|
|
19874
|
+
}
|
|
19875
|
+
this._evict();
|
|
19876
|
+
} catch {
|
|
19877
|
+
}
|
|
19878
|
+
}
|
|
19879
|
+
_save() {
|
|
19880
|
+
if (!this._storage) return;
|
|
19881
|
+
try {
|
|
19882
|
+
if (this._entries.size === 0) {
|
|
19883
|
+
this._storage.removeItem(this._key);
|
|
19884
|
+
return;
|
|
19885
|
+
}
|
|
19886
|
+
this._storage.setItem(this._key, JSON.stringify(Object.fromEntries(this._entries)));
|
|
19887
|
+
} catch {
|
|
19888
|
+
}
|
|
19889
|
+
}
|
|
19890
|
+
};
|
|
19891
|
+
|
|
19791
19892
|
// src/indicators/sourceField.ts
|
|
19792
19893
|
function getSource(bar, source) {
|
|
19793
19894
|
return bar[source];
|
|
@@ -23504,6 +23605,8 @@ var _ChartEngine = class _ChartEngine {
|
|
|
23504
23605
|
/** Last traded price from the most recent tick that carried one ('ltp' source mode). */
|
|
23505
23606
|
this.liveLtp = null;
|
|
23506
23607
|
this.tickClosePriceSource = "bid";
|
|
23608
|
+
/** Re-fetch history through `dataLoader` when the price source changes (`reloadOnPriceSourceChange`). */
|
|
23609
|
+
this._reloadOnPriceSourceChange = true;
|
|
23507
23610
|
/** True while an async data fetch is in-flight; suppresses tick processing to
|
|
23508
23611
|
* prevent stale ticks from corrupting newly-loaded bars. */
|
|
23509
23612
|
this._suppressTicks = false;
|
|
@@ -23550,6 +23653,15 @@ var _ChartEngine = class _ChartEngine {
|
|
|
23550
23653
|
* `timestamp` back via `setLevels` (auto-released on match). Survives PnL-only refreshes.
|
|
23551
23654
|
*/
|
|
23552
23655
|
this._timeAnchorOverride = /* @__PURE__ */ new Map();
|
|
23656
|
+
/**
|
|
23657
|
+
* Time anchors persisted in localStorage (`orderLineAnchorPersistence`), keyed by level
|
|
23658
|
+
* label — the candle each badge was last dropped on. Restored at construction so a
|
|
23659
|
+
* horizontally-dragged order line comes back where the user left it after a reload.
|
|
23660
|
+
* Null when persistence is disabled or time-drag is off.
|
|
23661
|
+
*/
|
|
23662
|
+
this._orderLineAnchorStore = null;
|
|
23663
|
+
/** Where an un-dragged `timeDraggable` badge sits (`orderLineDefaultAnchor`). */
|
|
23664
|
+
this._orderLineDefaultAnchor = "timestamp";
|
|
23553
23665
|
this.tradeDragNewPrice = null;
|
|
23554
23666
|
/** Derived SL preview price during an entry drag in follow-brackets mode. */
|
|
23555
23667
|
this.tradeDragNewSLPrice = null;
|
|
@@ -24786,6 +24898,7 @@ var _ChartEngine = class _ChartEngine {
|
|
|
24786
24898
|
this._targetViewport = { ...this.viewport };
|
|
24787
24899
|
this.maxSubPanes = config.maxSubPanes ?? 3;
|
|
24788
24900
|
this.tickClosePriceSource = config.tickClosePriceSource ?? "bid";
|
|
24901
|
+
this._reloadOnPriceSourceChange = config.reloadOnPriceSourceChange !== false;
|
|
24789
24902
|
this.showLtpPrice = config.showLtpPrice;
|
|
24790
24903
|
this.tradesThresholdForHorizontalLine = config.tradesThresholdForHorizontalLine ?? 2;
|
|
24791
24904
|
if (config.positionRenderStyle === "line" || config.positionRenderStyle === "dot") {
|
|
@@ -24815,6 +24928,12 @@ var _ChartEngine = class _ChartEngine {
|
|
|
24815
24928
|
this._features = config.features;
|
|
24816
24929
|
this.drawingManager.setFreehandEnabled(config.features?.enableForecasting === true);
|
|
24817
24930
|
this._orderLineDragSnap = config.orderLineDragSnap !== false;
|
|
24931
|
+
this._orderLineDefaultAnchor = config.orderLineDefaultAnchor === "center" ? "center" : "timestamp";
|
|
24932
|
+
if (this._orderTimeDragEnabled && config.orderLineAnchorPersistence !== false) {
|
|
24933
|
+
this._orderLineAnchorStore = new OrderLineAnchorStore(
|
|
24934
|
+
OrderLineAnchorStore.browserStorage()
|
|
24935
|
+
);
|
|
24936
|
+
}
|
|
24818
24937
|
this.tradeLevelButtonScale = Math.min(Math.max(config.tradeLevelButtonScale ?? 1, 1), 3);
|
|
24819
24938
|
this._bracketLabel = {
|
|
24820
24939
|
mode: config.bracketLabelMode ?? "price",
|
|
@@ -24994,11 +25113,7 @@ var _ChartEngine = class _ChartEngine {
|
|
|
24994
25113
|
showSnapshotBtn,
|
|
24995
25114
|
config.priceSourceSelector ?? null,
|
|
24996
25115
|
this.tickClosePriceSource,
|
|
24997
|
-
(source) =>
|
|
24998
|
-
this.tickClosePriceSource = source;
|
|
24999
|
-
this.scheduleRender();
|
|
25000
|
-
this.emitter.emit("priceSourceChange", { source });
|
|
25001
|
-
}
|
|
25116
|
+
(source) => this._applyPriceSource(source, true)
|
|
25002
25117
|
);
|
|
25003
25118
|
this.advancedToolbar.setIndicatorOptions(indicatorOptions);
|
|
25004
25119
|
this.wrapper.appendChild(this.advancedToolbar.el);
|
|
@@ -25045,11 +25160,7 @@ var _ChartEngine = class _ChartEngine {
|
|
|
25045
25160
|
resolvedOneClickTradeToggle ?? null,
|
|
25046
25161
|
config.priceSourceSelector ?? null,
|
|
25047
25162
|
this.tickClosePriceSource,
|
|
25048
|
-
(source) =>
|
|
25049
|
-
this.tickClosePriceSource = source;
|
|
25050
|
-
this.scheduleRender();
|
|
25051
|
-
this.emitter.emit("priceSourceChange", { source });
|
|
25052
|
-
}
|
|
25163
|
+
(source) => this._applyPriceSource(source, true)
|
|
25053
25164
|
);
|
|
25054
25165
|
this.topBar.setIndicatorOptions(indicatorOptions);
|
|
25055
25166
|
this.wrapper.appendChild(this.topBar.el);
|
|
@@ -25870,7 +25981,7 @@ var _ChartEngine = class _ChartEngine {
|
|
|
25870
25981
|
const minBars = this.minInitialBars;
|
|
25871
25982
|
const cap = this.maxLookbackMs;
|
|
25872
25983
|
const attempt = (i, start) => {
|
|
25873
|
-
loader({ start, end, interval }).then((bars) => {
|
|
25984
|
+
loader({ start, end, interval, priceSource: this.tickClosePriceSource }).then((bars) => {
|
|
25874
25985
|
if (gen !== this._loadGeneration) return;
|
|
25875
25986
|
const aggregated = this.maybeAggregate(bars);
|
|
25876
25987
|
const reachedCap = end.getTime() - start.getTime() >= cap;
|
|
@@ -25882,7 +25993,8 @@ var _ChartEngine = class _ChartEngine {
|
|
|
25882
25993
|
timeframe: this.timeframe,
|
|
25883
25994
|
interval,
|
|
25884
25995
|
start,
|
|
25885
|
-
end
|
|
25996
|
+
end,
|
|
25997
|
+
priceSource: this.tickClosePriceSource
|
|
25886
25998
|
});
|
|
25887
25999
|
return;
|
|
25888
26000
|
}
|
|
@@ -25917,7 +26029,7 @@ var _ChartEngine = class _ChartEngine {
|
|
|
25917
26029
|
const minBars = this.minInitialBars;
|
|
25918
26030
|
const cap = this.maxLookbackMs;
|
|
25919
26031
|
const attempt = (i, start) => {
|
|
25920
|
-
loader({ start, end, interval }).then((bars) => {
|
|
26032
|
+
loader({ start, end, interval, priceSource: this.tickClosePriceSource }).then((bars) => {
|
|
25921
26033
|
if (gen !== this._loadGeneration) return;
|
|
25922
26034
|
const aggregated = this.maybeAggregate(bars);
|
|
25923
26035
|
const reachedCap = end.getTime() - start.getTime() >= cap;
|
|
@@ -27096,17 +27208,44 @@ var _ChartEngine = class _ChartEngine {
|
|
|
27096
27208
|
this.streamAdapter = null;
|
|
27097
27209
|
return this;
|
|
27098
27210
|
}
|
|
27099
|
-
/** Switch which price drives
|
|
27211
|
+
/** Switch which price drives candle close/high/low at runtime
|
|
27100
27212
|
* (`'bid'`, `'ask'` or `'ltp'`). Also syncs the header price-source
|
|
27101
|
-
* dropdown when `priceSourceSelector` is enabled
|
|
27102
|
-
*
|
|
27103
|
-
*
|
|
27213
|
+
* dropdown when `priceSourceSelector` is enabled, and — unless
|
|
27214
|
+
* `reloadOnPriceSourceChange` is `false` — re-runs `dataLoader` with the
|
|
27215
|
+
* new `params.priceSource` so the loaded history is rebuilt from that
|
|
27216
|
+
* price too. Programmatic calls do not emit `priceSourceChange` — that
|
|
27217
|
+
* event is reserved for user picks from the dropdown. */
|
|
27104
27218
|
setTickClosePriceSource(source) {
|
|
27219
|
+
this._applyPriceSource(source, false);
|
|
27220
|
+
return this;
|
|
27221
|
+
}
|
|
27222
|
+
/**
|
|
27223
|
+
* Applies a new candle price source. Shared by the header dropdown pick and
|
|
27224
|
+
* `setTickClosePriceSource()`.
|
|
27225
|
+
*
|
|
27226
|
+
* Switching the field alone only changes how the NEXT live ticks extend the
|
|
27227
|
+
* last candle; every bar already on screen was fetched with the previous
|
|
27228
|
+
* source, so the chart kept showing e.g. bid history under an "LTP" label.
|
|
27229
|
+
* When the source actually changes and a `dataLoader` is configured, the
|
|
27230
|
+
* whole window is therefore re-fetched (`triggerLoad('priceSource')`) — the
|
|
27231
|
+
* loader receives the source as `params.priceSource` to forward to its API.
|
|
27232
|
+
* The visible time window is restored after the reload so the user does not
|
|
27233
|
+
* lose their scroll/zoom position.
|
|
27234
|
+
*/
|
|
27235
|
+
_applyPriceSource(source, fromUserPick) {
|
|
27236
|
+
const changed = source !== this.tickClosePriceSource;
|
|
27105
27237
|
this.tickClosePriceSource = source;
|
|
27106
27238
|
this.topBar?.setPriceSource(source);
|
|
27107
27239
|
this.advancedToolbar?.setPriceSource(source);
|
|
27108
27240
|
this.scheduleRender();
|
|
27109
|
-
|
|
27241
|
+
if (changed && this._reloadOnPriceSourceChange && this.dataLoader && !this._isDestroyed) {
|
|
27242
|
+
const viewport = this.getViewportTimestamps();
|
|
27243
|
+
if (viewport) {
|
|
27244
|
+
this._pendingViewportRestore = { ...this._pendingViewportRestore ?? {}, viewport };
|
|
27245
|
+
}
|
|
27246
|
+
this.triggerLoad("priceSource");
|
|
27247
|
+
}
|
|
27248
|
+
if (fromUserPick) this.emitter.emit("priceSourceChange", { source });
|
|
27110
27249
|
}
|
|
27111
27250
|
/** Show/hide the LTP (last traded price) marker — dashed line + axis tag.
|
|
27112
27251
|
* `true` always shows it when the feed supplies an LTP, `false` hides it
|
|
@@ -27271,7 +27410,7 @@ var _ChartEngine = class _ChartEngine {
|
|
|
27271
27410
|
}
|
|
27272
27411
|
const incomingTs = lvl.timestamp;
|
|
27273
27412
|
const overrideTs = this._timeAnchorOverride.get(label);
|
|
27274
|
-
if (incomingTs !== void 0 && overrideTs !== void 0 && Math.round(this.timestampToBarIndex(incomingTs)) === Math.round(this.timestampToBarIndex(overrideTs))) {
|
|
27413
|
+
if (this._honorsLevelTimestamp(lvl) && incomingTs !== void 0 && overrideTs !== void 0 && Math.round(this.timestampToBarIndex(incomingTs)) === Math.round(this.timestampToBarIndex(overrideTs))) {
|
|
27275
27414
|
this._timeAnchorOverride.delete(label);
|
|
27276
27415
|
}
|
|
27277
27416
|
}
|
|
@@ -28289,8 +28428,7 @@ var _ChartEngine = class _ChartEngine {
|
|
|
28289
28428
|
* Resolves the horizontal badge center X (canvas px) for a level during render, or `null`
|
|
28290
28429
|
* to keep the legacy chart-centered placement. Priority:
|
|
28291
28430
|
* 1. the live drag bar index, for the level currently being time-dragged;
|
|
28292
|
-
* 2.
|
|
28293
|
-
* 3. the level's own `timestamp`.
|
|
28431
|
+
* 2. the resolved time anchor — see `_resolvedTimeAnchor`.
|
|
28294
28432
|
* Returns `null` when time-drag is disabled or the level has no time anchor.
|
|
28295
28433
|
*/
|
|
28296
28434
|
_orderLineAnchorX(level, chartW) {
|
|
@@ -28298,10 +28436,34 @@ var _ChartEngine = class _ChartEngine {
|
|
|
28298
28436
|
if (this.orderTimeDragHandler?.active && this.orderTimeDragHandler.dragLabel === level.label && this.tradeDragNewBarIndex !== null) {
|
|
28299
28437
|
return this.scaleManager.xToPixel(this.tradeDragNewBarIndex, this.viewport, chartW);
|
|
28300
28438
|
}
|
|
28301
|
-
const ts = this.
|
|
28439
|
+
const ts = this._resolvedTimeAnchor(level);
|
|
28302
28440
|
if (ts === void 0) return null;
|
|
28303
28441
|
return this.scaleManager.xToPixel(this.timestampToBarIndex(ts), this.viewport, chartW);
|
|
28304
28442
|
}
|
|
28443
|
+
/**
|
|
28444
|
+
* The unix-ms time anchor a level's badge should sit at (ignoring any live drag), or
|
|
28445
|
+
* `undefined` for the legacy chart-centered placement. Priority:
|
|
28446
|
+
* 1. a drop override staged this session (set on the last drag release);
|
|
28447
|
+
* 2. the anchor persisted in localStorage from an earlier session
|
|
28448
|
+
* (`orderLineAnchorPersistence`);
|
|
28449
|
+
* 3. the level's own `timestamp` — unless `orderLineDefaultAnchor: 'center'` and the
|
|
28450
|
+
* level is `timeDraggable`, in which case an un-dragged badge stays centered.
|
|
28451
|
+
*/
|
|
28452
|
+
_resolvedTimeAnchor(level) {
|
|
28453
|
+
const override = this._timeAnchorOverride.get(level.label);
|
|
28454
|
+
if (override !== void 0) return override;
|
|
28455
|
+
const persisted = this._orderLineAnchorStore?.get(level.label);
|
|
28456
|
+
if (persisted !== void 0) return persisted;
|
|
28457
|
+
return this._honorsLevelTimestamp(level) ? level.timestamp : void 0;
|
|
28458
|
+
}
|
|
28459
|
+
/**
|
|
28460
|
+
* Whether a level's own `timestamp` positions its badge. False only for `timeDraggable`
|
|
28461
|
+
* levels under `orderLineDefaultAnchor: 'center'`, whose un-dragged badge is centered
|
|
28462
|
+
* regardless of `timestamp` (a dragged one is positioned by its override / persisted anchor).
|
|
28463
|
+
*/
|
|
28464
|
+
_honorsLevelTimestamp(level) {
|
|
28465
|
+
return !(this._orderLineDefaultAnchor === "center" && level.timeDraggable === true);
|
|
28466
|
+
}
|
|
28305
28467
|
/** Returns the effective entry price for a level, preferring any staged main drag. */
|
|
28306
28468
|
_effectiveEntryPrice(label, fallback) {
|
|
28307
28469
|
const changes = this.pendingLevelDrags.get(label);
|
|
@@ -28888,7 +29050,8 @@ var _ChartEngine = class _ChartEngine {
|
|
|
28888
29050
|
const params = {
|
|
28889
29051
|
start: new Date(allBars[0].time),
|
|
28890
29052
|
end: new Date(allBars[allBars.length - 1].time),
|
|
28891
|
-
interval: this.timeframe
|
|
29053
|
+
interval: this.timeframe,
|
|
29054
|
+
priceSource: this.tickClosePriceSource
|
|
28892
29055
|
};
|
|
28893
29056
|
if (this.compareManager.isActive()) {
|
|
28894
29057
|
void this.compareManager.refetchAll(params).then(() => {
|
|
@@ -29850,7 +30013,7 @@ var _ChartEngine = class _ChartEngine {
|
|
|
29850
30013
|
const rawAnchorX = this._orderLineAnchorX(level, chartW) ?? chartW / 2;
|
|
29851
30014
|
const anchorX = Math.max(dragArea.x, Math.min(dragArea.x + dragArea.w, rawAnchorX));
|
|
29852
30015
|
const startBarIndex = this.scaleManager.pixelToBarIndex(anchorX, this.viewport, chartW);
|
|
29853
|
-
const startTimestamp = this.
|
|
30016
|
+
const startTimestamp = this._resolvedTimeAnchor(level) ?? this.barIndexToTimestamp(startBarIndex) ?? 0;
|
|
29854
30017
|
this.orderTimeDragHandler.start(level, hitX ?? anchorX, anchorX, startBarIndex, startTimestamp);
|
|
29855
30018
|
this.drawCanvas.style.cursor = "grabbing";
|
|
29856
30019
|
this.emitter.emit("orderLineMoveStart", {
|
|
@@ -29953,6 +30116,7 @@ var _ChartEngine = class _ChartEngine {
|
|
|
29953
30116
|
const fromBarIndex = Math.round(res.startBarIndex);
|
|
29954
30117
|
if (toTs !== void 0 && res.newBarIndex !== fromBarIndex) {
|
|
29955
30118
|
this._timeAnchorOverride.set(res.label, toTs);
|
|
30119
|
+
this._orderLineAnchorStore?.set(res.label, toTs);
|
|
29956
30120
|
this.emitter.emit("orderLineMoved", {
|
|
29957
30121
|
label: res.label,
|
|
29958
30122
|
fromTimestamp: res.startTimestamp,
|
|
@@ -30076,7 +30240,12 @@ var _ChartEngine = class _ChartEngine {
|
|
|
30076
30240
|
if (!this.dataLoader) return;
|
|
30077
30241
|
if (this.isFetching) return;
|
|
30078
30242
|
const interval = this.timeframeToInterval(this.getBaseInterval());
|
|
30079
|
-
this.dataLoader({
|
|
30243
|
+
this.dataLoader({
|
|
30244
|
+
start: new Date(fromTime),
|
|
30245
|
+
end: new Date(toTime),
|
|
30246
|
+
interval,
|
|
30247
|
+
priceSource: this.tickClosePriceSource
|
|
30248
|
+
}).then((rawBars) => {
|
|
30080
30249
|
const bars = this.maybeAggregate(rawBars);
|
|
30081
30250
|
if (bars.length === 0) return;
|
|
30082
30251
|
this.backfillDrawingTimestamps();
|
|
@@ -30115,7 +30284,7 @@ var _ChartEngine = class _ChartEngine {
|
|
|
30115
30284
|
const start = new Date(barTime);
|
|
30116
30285
|
const end = new Date(barTime + intervalMs * 3);
|
|
30117
30286
|
const interval = this.timeframeToInterval(this.getBaseInterval());
|
|
30118
|
-
this.dataLoader({ start, end, interval }).then((rawBars) => {
|
|
30287
|
+
this.dataLoader({ start, end, interval, priceSource: this.tickClosePriceSource }).then((rawBars) => {
|
|
30119
30288
|
const bars = this.maybeAggregate(rawBars);
|
|
30120
30289
|
if (bars.length === 0) return;
|
|
30121
30290
|
const all = this.dataStore.all;
|