acttrader-charts 1.3.0-beta.13 → 1.3.0-beta.15
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 +193 -30
- 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 +193 -30
- 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
|
@@ -16837,7 +16837,7 @@ var IndicatorSettingsDialog = class {
|
|
|
16837
16837
|
input.max = String(field.max);
|
|
16838
16838
|
input.step = String(field.step);
|
|
16839
16839
|
input.value = String(currentVal);
|
|
16840
|
-
input.enterKeyHint = "
|
|
16840
|
+
input.enterKeyHint = "go";
|
|
16841
16841
|
Object.assign(input.style, {
|
|
16842
16842
|
width: "80px",
|
|
16843
16843
|
background: this.theme.background,
|
|
@@ -18424,7 +18424,7 @@ var DrawingStylePopover = class {
|
|
|
18424
18424
|
input.step = "0.001";
|
|
18425
18425
|
input.value = current;
|
|
18426
18426
|
input.title = "Level ratio \u2014 press Enter to apply";
|
|
18427
|
-
input.enterKeyHint = "
|
|
18427
|
+
input.enterKeyHint = "go";
|
|
18428
18428
|
Object.assign(input.style, {
|
|
18429
18429
|
width: "58px",
|
|
18430
18430
|
padding: "2px 4px",
|
|
@@ -18686,7 +18686,7 @@ var DraftQtyFlyout = class {
|
|
|
18686
18686
|
makeInput() {
|
|
18687
18687
|
const input = document.createElement("input");
|
|
18688
18688
|
input.type = "number";
|
|
18689
|
-
input.enterKeyHint = "
|
|
18689
|
+
input.enterKeyHint = "go";
|
|
18690
18690
|
Object.assign(input.style, {
|
|
18691
18691
|
width: "64px",
|
|
18692
18692
|
background: "transparent",
|
|
@@ -19788,6 +19788,101 @@ var OrderLineTimeDragHandler = class _OrderLineTimeDragHandler {
|
|
|
19788
19788
|
}
|
|
19789
19789
|
};
|
|
19790
19790
|
|
|
19791
|
+
// src/interaction/OrderLineAnchorStore.ts
|
|
19792
|
+
var ORDER_LINE_ANCHORS_LS_KEY = "finchart.orderLineTimeAnchors";
|
|
19793
|
+
var ORDER_LINE_ANCHORS_MAX_ENTRIES = 500;
|
|
19794
|
+
var OrderLineAnchorStore = class {
|
|
19795
|
+
constructor(_storage, _key = ORDER_LINE_ANCHORS_LS_KEY, _maxEntries = ORDER_LINE_ANCHORS_MAX_ENTRIES) {
|
|
19796
|
+
this._storage = _storage;
|
|
19797
|
+
this._key = _key;
|
|
19798
|
+
this._maxEntries = _maxEntries;
|
|
19799
|
+
this._entries = /* @__PURE__ */ new Map();
|
|
19800
|
+
this._load();
|
|
19801
|
+
}
|
|
19802
|
+
/** The page's `localStorage`, or `null` when it is absent or access throws. */
|
|
19803
|
+
static browserStorage() {
|
|
19804
|
+
try {
|
|
19805
|
+
if (typeof localStorage === "undefined") return null;
|
|
19806
|
+
return localStorage;
|
|
19807
|
+
} catch {
|
|
19808
|
+
return null;
|
|
19809
|
+
}
|
|
19810
|
+
}
|
|
19811
|
+
/** Persisted unix-ms anchor for `label`, or `undefined` when none was saved. */
|
|
19812
|
+
get(label) {
|
|
19813
|
+
return this._entries.get(label)?.ts;
|
|
19814
|
+
}
|
|
19815
|
+
has(label) {
|
|
19816
|
+
return this._entries.has(label);
|
|
19817
|
+
}
|
|
19818
|
+
/** Number of persisted anchors. */
|
|
19819
|
+
get size() {
|
|
19820
|
+
return this._entries.size;
|
|
19821
|
+
}
|
|
19822
|
+
/**
|
|
19823
|
+
* Records the candle time `label`'s badge was dropped on and writes it through to storage.
|
|
19824
|
+
* Non-finite timestamps are ignored. `now` is the save time used for eviction ordering.
|
|
19825
|
+
*/
|
|
19826
|
+
set(label, ts, now = Date.now()) {
|
|
19827
|
+
if (!label || !Number.isFinite(ts)) return;
|
|
19828
|
+
this._entries.set(label, { ts, at: now });
|
|
19829
|
+
this._evict();
|
|
19830
|
+
this._save();
|
|
19831
|
+
}
|
|
19832
|
+
/** Forgets `label`'s anchor. Returns whether one existed. */
|
|
19833
|
+
delete(label) {
|
|
19834
|
+
const had = this._entries.delete(label);
|
|
19835
|
+
if (had) this._save();
|
|
19836
|
+
return had;
|
|
19837
|
+
}
|
|
19838
|
+
/** Drops every persisted anchor (memory + storage). */
|
|
19839
|
+
clear() {
|
|
19840
|
+
this._entries.clear();
|
|
19841
|
+
try {
|
|
19842
|
+
this._storage?.removeItem(this._key);
|
|
19843
|
+
} catch {
|
|
19844
|
+
}
|
|
19845
|
+
}
|
|
19846
|
+
_evict() {
|
|
19847
|
+
if (this._entries.size <= this._maxEntries) return;
|
|
19848
|
+
const byAge = [...this._entries.entries()].sort((a, b) => a[1].at - b[1].at);
|
|
19849
|
+
const excess = this._entries.size - this._maxEntries;
|
|
19850
|
+
for (let i = 0; i < excess; i++) {
|
|
19851
|
+
const victim = byAge[i];
|
|
19852
|
+
if (victim) this._entries.delete(victim[0]);
|
|
19853
|
+
}
|
|
19854
|
+
}
|
|
19855
|
+
_load() {
|
|
19856
|
+
if (!this._storage) return;
|
|
19857
|
+
try {
|
|
19858
|
+
const raw = this._storage.getItem(this._key);
|
|
19859
|
+
if (!raw) return;
|
|
19860
|
+
const parsed = JSON.parse(raw);
|
|
19861
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return;
|
|
19862
|
+
for (const [label, value] of Object.entries(parsed)) {
|
|
19863
|
+
if (!value || typeof value !== "object") continue;
|
|
19864
|
+
const { ts, at } = value;
|
|
19865
|
+
if (typeof ts !== "number" || !Number.isFinite(ts)) continue;
|
|
19866
|
+
const savedAt = typeof at === "number" && Number.isFinite(at) ? at : 0;
|
|
19867
|
+
this._entries.set(label, { ts, at: savedAt });
|
|
19868
|
+
}
|
|
19869
|
+
this._evict();
|
|
19870
|
+
} catch {
|
|
19871
|
+
}
|
|
19872
|
+
}
|
|
19873
|
+
_save() {
|
|
19874
|
+
if (!this._storage) return;
|
|
19875
|
+
try {
|
|
19876
|
+
if (this._entries.size === 0) {
|
|
19877
|
+
this._storage.removeItem(this._key);
|
|
19878
|
+
return;
|
|
19879
|
+
}
|
|
19880
|
+
this._storage.setItem(this._key, JSON.stringify(Object.fromEntries(this._entries)));
|
|
19881
|
+
} catch {
|
|
19882
|
+
}
|
|
19883
|
+
}
|
|
19884
|
+
};
|
|
19885
|
+
|
|
19791
19886
|
// src/indicators/sourceField.ts
|
|
19792
19887
|
function getSource(bar, source) {
|
|
19793
19888
|
return bar[source];
|
|
@@ -23504,6 +23599,8 @@ var _ChartEngine = class _ChartEngine {
|
|
|
23504
23599
|
/** Last traded price from the most recent tick that carried one ('ltp' source mode). */
|
|
23505
23600
|
this.liveLtp = null;
|
|
23506
23601
|
this.tickClosePriceSource = "bid";
|
|
23602
|
+
/** Re-fetch history through `dataLoader` when the price source changes (`reloadOnPriceSourceChange`). */
|
|
23603
|
+
this._reloadOnPriceSourceChange = true;
|
|
23507
23604
|
/** True while an async data fetch is in-flight; suppresses tick processing to
|
|
23508
23605
|
* prevent stale ticks from corrupting newly-loaded bars. */
|
|
23509
23606
|
this._suppressTicks = false;
|
|
@@ -23550,6 +23647,15 @@ var _ChartEngine = class _ChartEngine {
|
|
|
23550
23647
|
* `timestamp` back via `setLevels` (auto-released on match). Survives PnL-only refreshes.
|
|
23551
23648
|
*/
|
|
23552
23649
|
this._timeAnchorOverride = /* @__PURE__ */ new Map();
|
|
23650
|
+
/**
|
|
23651
|
+
* Time anchors persisted in localStorage (`orderLineAnchorPersistence`), keyed by level
|
|
23652
|
+
* label — the candle each badge was last dropped on. Restored at construction so a
|
|
23653
|
+
* horizontally-dragged order line comes back where the user left it after a reload.
|
|
23654
|
+
* Null when persistence is disabled or time-drag is off.
|
|
23655
|
+
*/
|
|
23656
|
+
this._orderLineAnchorStore = null;
|
|
23657
|
+
/** Where an un-dragged `timeDraggable` badge sits (`orderLineDefaultAnchor`). */
|
|
23658
|
+
this._orderLineDefaultAnchor = "timestamp";
|
|
23553
23659
|
this.tradeDragNewPrice = null;
|
|
23554
23660
|
/** Derived SL preview price during an entry drag in follow-brackets mode. */
|
|
23555
23661
|
this.tradeDragNewSLPrice = null;
|
|
@@ -24786,6 +24892,7 @@ var _ChartEngine = class _ChartEngine {
|
|
|
24786
24892
|
this._targetViewport = { ...this.viewport };
|
|
24787
24893
|
this.maxSubPanes = config.maxSubPanes ?? 3;
|
|
24788
24894
|
this.tickClosePriceSource = config.tickClosePriceSource ?? "bid";
|
|
24895
|
+
this._reloadOnPriceSourceChange = config.reloadOnPriceSourceChange !== false;
|
|
24789
24896
|
this.showLtpPrice = config.showLtpPrice;
|
|
24790
24897
|
this.tradesThresholdForHorizontalLine = config.tradesThresholdForHorizontalLine ?? 2;
|
|
24791
24898
|
if (config.positionRenderStyle === "line" || config.positionRenderStyle === "dot") {
|
|
@@ -24815,6 +24922,12 @@ var _ChartEngine = class _ChartEngine {
|
|
|
24815
24922
|
this._features = config.features;
|
|
24816
24923
|
this.drawingManager.setFreehandEnabled(config.features?.enableForecasting === true);
|
|
24817
24924
|
this._orderLineDragSnap = config.orderLineDragSnap !== false;
|
|
24925
|
+
this._orderLineDefaultAnchor = config.orderLineDefaultAnchor === "center" ? "center" : "timestamp";
|
|
24926
|
+
if (this._orderTimeDragEnabled && config.orderLineAnchorPersistence !== false) {
|
|
24927
|
+
this._orderLineAnchorStore = new OrderLineAnchorStore(
|
|
24928
|
+
OrderLineAnchorStore.browserStorage()
|
|
24929
|
+
);
|
|
24930
|
+
}
|
|
24818
24931
|
this.tradeLevelButtonScale = Math.min(Math.max(config.tradeLevelButtonScale ?? 1, 1), 3);
|
|
24819
24932
|
this._bracketLabel = {
|
|
24820
24933
|
mode: config.bracketLabelMode ?? "price",
|
|
@@ -24994,11 +25107,7 @@ var _ChartEngine = class _ChartEngine {
|
|
|
24994
25107
|
showSnapshotBtn,
|
|
24995
25108
|
config.priceSourceSelector ?? null,
|
|
24996
25109
|
this.tickClosePriceSource,
|
|
24997
|
-
(source) =>
|
|
24998
|
-
this.tickClosePriceSource = source;
|
|
24999
|
-
this.scheduleRender();
|
|
25000
|
-
this.emitter.emit("priceSourceChange", { source });
|
|
25001
|
-
}
|
|
25110
|
+
(source) => this._applyPriceSource(source, true)
|
|
25002
25111
|
);
|
|
25003
25112
|
this.advancedToolbar.setIndicatorOptions(indicatorOptions);
|
|
25004
25113
|
this.wrapper.appendChild(this.advancedToolbar.el);
|
|
@@ -25045,11 +25154,7 @@ var _ChartEngine = class _ChartEngine {
|
|
|
25045
25154
|
resolvedOneClickTradeToggle ?? null,
|
|
25046
25155
|
config.priceSourceSelector ?? null,
|
|
25047
25156
|
this.tickClosePriceSource,
|
|
25048
|
-
(source) =>
|
|
25049
|
-
this.tickClosePriceSource = source;
|
|
25050
|
-
this.scheduleRender();
|
|
25051
|
-
this.emitter.emit("priceSourceChange", { source });
|
|
25052
|
-
}
|
|
25157
|
+
(source) => this._applyPriceSource(source, true)
|
|
25053
25158
|
);
|
|
25054
25159
|
this.topBar.setIndicatorOptions(indicatorOptions);
|
|
25055
25160
|
this.wrapper.appendChild(this.topBar.el);
|
|
@@ -25171,7 +25276,7 @@ var _ChartEngine = class _ChartEngine {
|
|
|
25171
25276
|
this.canvasWrap.appendChild(this.drawCanvas);
|
|
25172
25277
|
this.textInputEl = document.createElement("input");
|
|
25173
25278
|
this.textInputEl.type = "text";
|
|
25174
|
-
this.textInputEl.enterKeyHint = "
|
|
25279
|
+
this.textInputEl.enterKeyHint = "go";
|
|
25175
25280
|
Object.assign(this.textInputEl.style, {
|
|
25176
25281
|
position: "absolute",
|
|
25177
25282
|
display: "none",
|
|
@@ -25870,7 +25975,7 @@ var _ChartEngine = class _ChartEngine {
|
|
|
25870
25975
|
const minBars = this.minInitialBars;
|
|
25871
25976
|
const cap = this.maxLookbackMs;
|
|
25872
25977
|
const attempt = (i, start) => {
|
|
25873
|
-
loader({ start, end, interval }).then((bars) => {
|
|
25978
|
+
loader({ start, end, interval, priceSource: this.tickClosePriceSource }).then((bars) => {
|
|
25874
25979
|
if (gen !== this._loadGeneration) return;
|
|
25875
25980
|
const aggregated = this.maybeAggregate(bars);
|
|
25876
25981
|
const reachedCap = end.getTime() - start.getTime() >= cap;
|
|
@@ -25882,7 +25987,8 @@ var _ChartEngine = class _ChartEngine {
|
|
|
25882
25987
|
timeframe: this.timeframe,
|
|
25883
25988
|
interval,
|
|
25884
25989
|
start,
|
|
25885
|
-
end
|
|
25990
|
+
end,
|
|
25991
|
+
priceSource: this.tickClosePriceSource
|
|
25886
25992
|
});
|
|
25887
25993
|
return;
|
|
25888
25994
|
}
|
|
@@ -25917,7 +26023,7 @@ var _ChartEngine = class _ChartEngine {
|
|
|
25917
26023
|
const minBars = this.minInitialBars;
|
|
25918
26024
|
const cap = this.maxLookbackMs;
|
|
25919
26025
|
const attempt = (i, start) => {
|
|
25920
|
-
loader({ start, end, interval }).then((bars) => {
|
|
26026
|
+
loader({ start, end, interval, priceSource: this.tickClosePriceSource }).then((bars) => {
|
|
25921
26027
|
if (gen !== this._loadGeneration) return;
|
|
25922
26028
|
const aggregated = this.maybeAggregate(bars);
|
|
25923
26029
|
const reachedCap = end.getTime() - start.getTime() >= cap;
|
|
@@ -27096,17 +27202,44 @@ var _ChartEngine = class _ChartEngine {
|
|
|
27096
27202
|
this.streamAdapter = null;
|
|
27097
27203
|
return this;
|
|
27098
27204
|
}
|
|
27099
|
-
/** Switch which price drives
|
|
27205
|
+
/** Switch which price drives candle close/high/low at runtime
|
|
27100
27206
|
* (`'bid'`, `'ask'` or `'ltp'`). Also syncs the header price-source
|
|
27101
|
-
* dropdown when `priceSourceSelector` is enabled
|
|
27102
|
-
*
|
|
27103
|
-
*
|
|
27207
|
+
* dropdown when `priceSourceSelector` is enabled, and — unless
|
|
27208
|
+
* `reloadOnPriceSourceChange` is `false` — re-runs `dataLoader` with the
|
|
27209
|
+
* new `params.priceSource` so the loaded history is rebuilt from that
|
|
27210
|
+
* price too. Programmatic calls do not emit `priceSourceChange` — that
|
|
27211
|
+
* event is reserved for user picks from the dropdown. */
|
|
27104
27212
|
setTickClosePriceSource(source) {
|
|
27213
|
+
this._applyPriceSource(source, false);
|
|
27214
|
+
return this;
|
|
27215
|
+
}
|
|
27216
|
+
/**
|
|
27217
|
+
* Applies a new candle price source. Shared by the header dropdown pick and
|
|
27218
|
+
* `setTickClosePriceSource()`.
|
|
27219
|
+
*
|
|
27220
|
+
* Switching the field alone only changes how the NEXT live ticks extend the
|
|
27221
|
+
* last candle; every bar already on screen was fetched with the previous
|
|
27222
|
+
* source, so the chart kept showing e.g. bid history under an "LTP" label.
|
|
27223
|
+
* When the source actually changes and a `dataLoader` is configured, the
|
|
27224
|
+
* whole window is therefore re-fetched (`triggerLoad('priceSource')`) — the
|
|
27225
|
+
* loader receives the source as `params.priceSource` to forward to its API.
|
|
27226
|
+
* The visible time window is restored after the reload so the user does not
|
|
27227
|
+
* lose their scroll/zoom position.
|
|
27228
|
+
*/
|
|
27229
|
+
_applyPriceSource(source, fromUserPick) {
|
|
27230
|
+
const changed = source !== this.tickClosePriceSource;
|
|
27105
27231
|
this.tickClosePriceSource = source;
|
|
27106
27232
|
this.topBar?.setPriceSource(source);
|
|
27107
27233
|
this.advancedToolbar?.setPriceSource(source);
|
|
27108
27234
|
this.scheduleRender();
|
|
27109
|
-
|
|
27235
|
+
if (changed && this._reloadOnPriceSourceChange && this.dataLoader && !this._isDestroyed) {
|
|
27236
|
+
const viewport = this.getViewportTimestamps();
|
|
27237
|
+
if (viewport) {
|
|
27238
|
+
this._pendingViewportRestore = { ...this._pendingViewportRestore ?? {}, viewport };
|
|
27239
|
+
}
|
|
27240
|
+
this.triggerLoad("priceSource");
|
|
27241
|
+
}
|
|
27242
|
+
if (fromUserPick) this.emitter.emit("priceSourceChange", { source });
|
|
27110
27243
|
}
|
|
27111
27244
|
/** Show/hide the LTP (last traded price) marker — dashed line + axis tag.
|
|
27112
27245
|
* `true` always shows it when the feed supplies an LTP, `false` hides it
|
|
@@ -27271,7 +27404,7 @@ var _ChartEngine = class _ChartEngine {
|
|
|
27271
27404
|
}
|
|
27272
27405
|
const incomingTs = lvl.timestamp;
|
|
27273
27406
|
const overrideTs = this._timeAnchorOverride.get(label);
|
|
27274
|
-
if (incomingTs !== void 0 && overrideTs !== void 0 && Math.round(this.timestampToBarIndex(incomingTs)) === Math.round(this.timestampToBarIndex(overrideTs))) {
|
|
27407
|
+
if (this._honorsLevelTimestamp(lvl) && incomingTs !== void 0 && overrideTs !== void 0 && Math.round(this.timestampToBarIndex(incomingTs)) === Math.round(this.timestampToBarIndex(overrideTs))) {
|
|
27275
27408
|
this._timeAnchorOverride.delete(label);
|
|
27276
27409
|
}
|
|
27277
27410
|
}
|
|
@@ -28289,8 +28422,7 @@ var _ChartEngine = class _ChartEngine {
|
|
|
28289
28422
|
* Resolves the horizontal badge center X (canvas px) for a level during render, or `null`
|
|
28290
28423
|
* to keep the legacy chart-centered placement. Priority:
|
|
28291
28424
|
* 1. the live drag bar index, for the level currently being time-dragged;
|
|
28292
|
-
* 2.
|
|
28293
|
-
* 3. the level's own `timestamp`.
|
|
28425
|
+
* 2. the resolved time anchor — see `_resolvedTimeAnchor`.
|
|
28294
28426
|
* Returns `null` when time-drag is disabled or the level has no time anchor.
|
|
28295
28427
|
*/
|
|
28296
28428
|
_orderLineAnchorX(level, chartW) {
|
|
@@ -28298,10 +28430,34 @@ var _ChartEngine = class _ChartEngine {
|
|
|
28298
28430
|
if (this.orderTimeDragHandler?.active && this.orderTimeDragHandler.dragLabel === level.label && this.tradeDragNewBarIndex !== null) {
|
|
28299
28431
|
return this.scaleManager.xToPixel(this.tradeDragNewBarIndex, this.viewport, chartW);
|
|
28300
28432
|
}
|
|
28301
|
-
const ts = this.
|
|
28433
|
+
const ts = this._resolvedTimeAnchor(level);
|
|
28302
28434
|
if (ts === void 0) return null;
|
|
28303
28435
|
return this.scaleManager.xToPixel(this.timestampToBarIndex(ts), this.viewport, chartW);
|
|
28304
28436
|
}
|
|
28437
|
+
/**
|
|
28438
|
+
* The unix-ms time anchor a level's badge should sit at (ignoring any live drag), or
|
|
28439
|
+
* `undefined` for the legacy chart-centered placement. Priority:
|
|
28440
|
+
* 1. a drop override staged this session (set on the last drag release);
|
|
28441
|
+
* 2. the anchor persisted in localStorage from an earlier session
|
|
28442
|
+
* (`orderLineAnchorPersistence`);
|
|
28443
|
+
* 3. the level's own `timestamp` — unless `orderLineDefaultAnchor: 'center'` and the
|
|
28444
|
+
* level is `timeDraggable`, in which case an un-dragged badge stays centered.
|
|
28445
|
+
*/
|
|
28446
|
+
_resolvedTimeAnchor(level) {
|
|
28447
|
+
const override = this._timeAnchorOverride.get(level.label);
|
|
28448
|
+
if (override !== void 0) return override;
|
|
28449
|
+
const persisted = this._orderLineAnchorStore?.get(level.label);
|
|
28450
|
+
if (persisted !== void 0) return persisted;
|
|
28451
|
+
return this._honorsLevelTimestamp(level) ? level.timestamp : void 0;
|
|
28452
|
+
}
|
|
28453
|
+
/**
|
|
28454
|
+
* Whether a level's own `timestamp` positions its badge. False only for `timeDraggable`
|
|
28455
|
+
* levels under `orderLineDefaultAnchor: 'center'`, whose un-dragged badge is centered
|
|
28456
|
+
* regardless of `timestamp` (a dragged one is positioned by its override / persisted anchor).
|
|
28457
|
+
*/
|
|
28458
|
+
_honorsLevelTimestamp(level) {
|
|
28459
|
+
return !(this._orderLineDefaultAnchor === "center" && level.timeDraggable === true);
|
|
28460
|
+
}
|
|
28305
28461
|
/** Returns the effective entry price for a level, preferring any staged main drag. */
|
|
28306
28462
|
_effectiveEntryPrice(label, fallback) {
|
|
28307
28463
|
const changes = this.pendingLevelDrags.get(label);
|
|
@@ -28888,7 +29044,8 @@ var _ChartEngine = class _ChartEngine {
|
|
|
28888
29044
|
const params = {
|
|
28889
29045
|
start: new Date(allBars[0].time),
|
|
28890
29046
|
end: new Date(allBars[allBars.length - 1].time),
|
|
28891
|
-
interval: this.timeframe
|
|
29047
|
+
interval: this.timeframe,
|
|
29048
|
+
priceSource: this.tickClosePriceSource
|
|
28892
29049
|
};
|
|
28893
29050
|
if (this.compareManager.isActive()) {
|
|
28894
29051
|
void this.compareManager.refetchAll(params).then(() => {
|
|
@@ -29850,7 +30007,7 @@ var _ChartEngine = class _ChartEngine {
|
|
|
29850
30007
|
const rawAnchorX = this._orderLineAnchorX(level, chartW) ?? chartW / 2;
|
|
29851
30008
|
const anchorX = Math.max(dragArea.x, Math.min(dragArea.x + dragArea.w, rawAnchorX));
|
|
29852
30009
|
const startBarIndex = this.scaleManager.pixelToBarIndex(anchorX, this.viewport, chartW);
|
|
29853
|
-
const startTimestamp = this.
|
|
30010
|
+
const startTimestamp = this._resolvedTimeAnchor(level) ?? this.barIndexToTimestamp(startBarIndex) ?? 0;
|
|
29854
30011
|
this.orderTimeDragHandler.start(level, hitX ?? anchorX, anchorX, startBarIndex, startTimestamp);
|
|
29855
30012
|
this.drawCanvas.style.cursor = "grabbing";
|
|
29856
30013
|
this.emitter.emit("orderLineMoveStart", {
|
|
@@ -29953,6 +30110,7 @@ var _ChartEngine = class _ChartEngine {
|
|
|
29953
30110
|
const fromBarIndex = Math.round(res.startBarIndex);
|
|
29954
30111
|
if (toTs !== void 0 && res.newBarIndex !== fromBarIndex) {
|
|
29955
30112
|
this._timeAnchorOverride.set(res.label, toTs);
|
|
30113
|
+
this._orderLineAnchorStore?.set(res.label, toTs);
|
|
29956
30114
|
this.emitter.emit("orderLineMoved", {
|
|
29957
30115
|
label: res.label,
|
|
29958
30116
|
fromTimestamp: res.startTimestamp,
|
|
@@ -30076,7 +30234,12 @@ var _ChartEngine = class _ChartEngine {
|
|
|
30076
30234
|
if (!this.dataLoader) return;
|
|
30077
30235
|
if (this.isFetching) return;
|
|
30078
30236
|
const interval = this.timeframeToInterval(this.getBaseInterval());
|
|
30079
|
-
this.dataLoader({
|
|
30237
|
+
this.dataLoader({
|
|
30238
|
+
start: new Date(fromTime),
|
|
30239
|
+
end: new Date(toTime),
|
|
30240
|
+
interval,
|
|
30241
|
+
priceSource: this.tickClosePriceSource
|
|
30242
|
+
}).then((rawBars) => {
|
|
30080
30243
|
const bars = this.maybeAggregate(rawBars);
|
|
30081
30244
|
if (bars.length === 0) return;
|
|
30082
30245
|
this.backfillDrawingTimestamps();
|
|
@@ -30115,7 +30278,7 @@ var _ChartEngine = class _ChartEngine {
|
|
|
30115
30278
|
const start = new Date(barTime);
|
|
30116
30279
|
const end = new Date(barTime + intervalMs * 3);
|
|
30117
30280
|
const interval = this.timeframeToInterval(this.getBaseInterval());
|
|
30118
|
-
this.dataLoader({ start, end, interval }).then((rawBars) => {
|
|
30281
|
+
this.dataLoader({ start, end, interval, priceSource: this.tickClosePriceSource }).then((rawBars) => {
|
|
30119
30282
|
const bars = this.maybeAggregate(rawBars);
|
|
30120
30283
|
if (bars.length === 0) return;
|
|
30121
30284
|
const all = this.dataStore.all;
|