acttrader-charts 1.0.16 → 1.0.18

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 CHANGED
@@ -13,6 +13,17 @@ Dual ESM/CJS output, TypeScript-first.
13
13
  npm install acttrader-charts
14
14
  ```
15
15
 
16
+ ### Beta releases
17
+
18
+ Pre-release builds are published under the `beta` dist-tag and use prerelease semver (`X.Y.Z-beta.N`). They never move the default `latest` tag, so existing consumers are unaffected.
19
+
20
+ ```bash
21
+ npm install acttrader-charts@beta # opt in to the latest beta
22
+ npm install acttrader-charts@1.1.0-beta.1 # pin a specific beta
23
+ ```
24
+
25
+ `npm install acttrader-charts` and existing semver ranges (`^1.0.0`, `~1.0.0`) continue to resolve only to stable releases — by spec, semver ranges exclude prerelease versions.
26
+
16
27
  ---
17
28
 
18
29
  ## Basic Usage
@@ -55,6 +66,8 @@ const chart = new ChartEngine({
55
66
  // No manual loadData() needed — the engine calls dataLoader on start and on timeframe/duration changes.
56
67
  ```
57
68
 
69
+ 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`).
70
+
58
71
  ---
59
72
 
60
73
  ## Advanced Usage
@@ -160,6 +173,10 @@ chart.removeLevelByLabel('ORD-1');
160
173
  chart.setLevels([], 'label', 'price', 'pending'); // clear all of one type
161
174
  ```
162
175
 
176
+ **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.
177
+
178
+ **Brackets follow entry on drag:** when the entry line of a pending order, draft order, or an open position with `entryPriceEditable: true` is dragged, any existing `stopLossPrice` / `takeProfitPrice` brackets translate along with it by the same price delta. The distance between entry and each bracket is whatever the user currently sees — if they manually drag SL or TP to a new price, that new distance becomes the anchor for the next entry drag. Missing brackets aren't auto-created. On confirm, `tradeLevelEdit` carries all translated fields together in one `changes[]` array; on mobile (`hideLevelConfirmCancel`) the three changes are applied as one atomic event.
179
+
163
180
  **TFC events:**
164
181
 
165
182
  ```ts
@@ -236,6 +253,8 @@ When `enableTrading` is on and live BID/ASK data is streaming, hovering / activa
236
253
  | `minLots` | | `1` | Default lot size in the trade popover |
237
254
  | `tickActivityMs` | | `30000` | ms the stream dot stays green after last tick |
238
255
  | `maxCandles` | | `200` | Max bars fetched per data-load request |
256
+ | `minInitialBars` | | `10` | If `dataLoader` returns fewer bars, the fetch window auto-widens and retries (handles weekends, market closures, and sparse symbols) |
257
+ | `maxLookbackMs` | | `31_536_000_000` | Hard ceiling on auto-widening lookback (ms). Retries stop once the window reaches this. Default: 365 days |
239
258
  | `prefetchThreshold` | | `80` | Bars from start of data at which historical fetch triggers (min 20) |
240
259
  | `mobileBarDivisor` | | `2` | Divide desktop visible bar count on touch devices (`2`, `3`, or `4`) |
241
260
  | `momentumScrollEnabled` | | `true` | Enable momentum (kinetic) scrolling — chart coasts after a fast flick |
@@ -257,6 +276,7 @@ When `enableTrading` is on and live BID/ASK data is streaming, hovering / activa
257
276
  | `tradeDisplayFilter` | | `"all"` | Which TFC levels are visible: `"all"` · `"positions"` · `"orders"` · `"none"` |
258
277
  | `positionRenderStyle` | | auto | Force position render style: `"line"` or `"dot"` |
259
278
  | `hideLevelConfirmCancel` | | `false` | Hide on-canvas ✓/✗ confirm-cancel buttons for TFC level edits |
279
+ | `tradeLevelButtonScale` | | `1` | Multiplier for trade-level Confirm/Cancel/Edit/Close button radii and gaps. Scales visuals **and** hit/drag areas together — raise it on touch devices for larger tap targets. Clamped to `[1, 3]`. Also settable at runtime via `chart.setTradeLevelButtonScale(scale)` |
260
280
  | `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 |
261
281
  | `levelClusteringEnabled` | | `true` | Enable trade-level fan-out clustering; overlapping levels group into expandable badges |
262
282
  | `clusterThresholdDistance` | | `20` | Pixel proximity threshold for clustering (only when `levelClusteringEnabled` is `true`) |
@@ -598,6 +618,53 @@ if (saved) chart.setState(JSON.parse(saved) as ChartState);
598
618
  chart.destroy(): void
599
619
  ```
600
620
 
621
+ ### Dismissing open UI
622
+
623
+ Closes any open flyout/modal/dropdown/popover (quantity edit, symbol picker,
624
+ indicator settings, chart settings, trade popover, topbar dropdowns, mobile
625
+ drawing flyout) in a single call. Designed for wiring to the system back
626
+ button / gesture in PWAs, installed web apps, and native wrapper hosts.
627
+
628
+ ```ts
629
+ chart.dismissAllUI(): boolean // true if anything was dismissed, false if nothing was open
630
+ ```
631
+
632
+ Paired with the `uiStateChange` event so you can track whether a back action
633
+ should dismiss chart UI or fall through to your own navigation:
634
+
635
+ ```ts
636
+ chart.on('uiStateChange', ({ hasOpenUI }) => {
637
+ // hasOpenUI === true when at least one flyout/modal/dropdown is open
638
+ });
639
+ ```
640
+
641
+ **PWA — proper History API wiring** (back press dismisses flyout without
642
+ navigating away from the page):
643
+
644
+ ```ts
645
+ let pushedStateForUI = false;
646
+
647
+ chart.on('uiStateChange', ({ hasOpenUI }) => {
648
+ if (hasOpenUI && !pushedStateForUI) {
649
+ history.pushState({ chartUI: true }, '');
650
+ pushedStateForUI = true;
651
+ } else if (!hasOpenUI) {
652
+ pushedStateForUI = false;
653
+ }
654
+ });
655
+
656
+ window.addEventListener('popstate', () => {
657
+ if (chart.dismissAllUI()) pushedStateForUI = false;
658
+ });
659
+ ```
660
+
661
+ **Minimum wiring** (back press closes flyout AND advances browser history —
662
+ fine for single-screen apps without client routing):
663
+
664
+ ```ts
665
+ window.addEventListener('popstate', () => chart.dismissAllUI());
666
+ ```
667
+
601
668
  ---
602
669
 
603
670
  ## Built-in Indicators
@@ -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.
@@ -849,6 +865,14 @@ interface ChartConfig {
849
865
  * Default: `false`.
850
866
  */
851
867
  hideLevelConfirmCancel?: boolean;
868
+ /**
869
+ * Multiplier applied to the Confirm (✓), Cancel (✗), Edit (✎), and Close (×)
870
+ * buttons on trade-level overlays (both main-level and SL/TP bracket boxes).
871
+ * Scales button radii and inter-button gaps so visual size AND hit/drag areas
872
+ * grow together — useful for touch targets.
873
+ * Clamped to `[1, 3]`. Default: `1`.
874
+ */
875
+ tradeLevelButtonScale?: number;
852
876
  /**
853
877
  * When `true`, a theme toggle (Dark / Light) is shown in the Settings dialog.
854
878
  * Default: `false` — the toggle is hidden.
@@ -1077,12 +1101,16 @@ type ChartEventMap = {
1077
1101
  isFullscreen: boolean;
1078
1102
  };
1079
1103
  /** Emitted on every mouse-move while dragging a trade level line (before confirm).
1080
- * `bracketType` is present when dragging an SL/TP bracket line; absent for main entry drag. */
1104
+ * `bracketType` is present when dragging an SL/TP bracket line; absent for main entry drag.
1105
+ * `derivedSLPrice` / `derivedTPPrice` are present during a main-entry drag in follow-brackets mode
1106
+ * so external panels can mirror the SL/TP translation live (keeps validation from flickering). */
1081
1107
  tradeLevelDrag: {
1082
1108
  label: string;
1083
1109
  newPrice: number;
1084
1110
  data: unknown;
1085
1111
  bracketType?: 'stopLoss' | 'takeProfit';
1112
+ derivedSLPrice?: number;
1113
+ derivedTPPrice?: number;
1086
1114
  isFullscreen: boolean;
1087
1115
  };
1088
1116
  /** Emitted at the instant a bracket (SL/TP) drag begins — before any movement.
@@ -1139,6 +1167,12 @@ type ChartEventMap = {
1139
1167
  tfcToggle: {
1140
1168
  enabled: boolean;
1141
1169
  };
1170
+ /** Emitted whenever any dismissible UI (flyout, modal, dropdown, popover) opens or closes.
1171
+ * Hosts (native wrappers, PWAs) listen to track whether a back button / gesture should
1172
+ * dismiss chart UI vs. navigate. Pair with `dismissAllUI()` to wire platform back events. */
1173
+ uiStateChange: {
1174
+ hasOpenUI: boolean;
1175
+ };
1142
1176
  /** Emitted when the user confirms all edits to a level — replaces separate tradeLevelDragEnd / tradeLevelBracketDrag events. */
1143
1177
  tradeLevelEdit: {
1144
1178
  label: string;
@@ -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.
@@ -849,6 +865,14 @@ interface ChartConfig {
849
865
  * Default: `false`.
850
866
  */
851
867
  hideLevelConfirmCancel?: boolean;
868
+ /**
869
+ * Multiplier applied to the Confirm (✓), Cancel (✗), Edit (✎), and Close (×)
870
+ * buttons on trade-level overlays (both main-level and SL/TP bracket boxes).
871
+ * Scales button radii and inter-button gaps so visual size AND hit/drag areas
872
+ * grow together — useful for touch targets.
873
+ * Clamped to `[1, 3]`. Default: `1`.
874
+ */
875
+ tradeLevelButtonScale?: number;
852
876
  /**
853
877
  * When `true`, a theme toggle (Dark / Light) is shown in the Settings dialog.
854
878
  * Default: `false` — the toggle is hidden.
@@ -1077,12 +1101,16 @@ type ChartEventMap = {
1077
1101
  isFullscreen: boolean;
1078
1102
  };
1079
1103
  /** Emitted on every mouse-move while dragging a trade level line (before confirm).
1080
- * `bracketType` is present when dragging an SL/TP bracket line; absent for main entry drag. */
1104
+ * `bracketType` is present when dragging an SL/TP bracket line; absent for main entry drag.
1105
+ * `derivedSLPrice` / `derivedTPPrice` are present during a main-entry drag in follow-brackets mode
1106
+ * so external panels can mirror the SL/TP translation live (keeps validation from flickering). */
1081
1107
  tradeLevelDrag: {
1082
1108
  label: string;
1083
1109
  newPrice: number;
1084
1110
  data: unknown;
1085
1111
  bracketType?: 'stopLoss' | 'takeProfit';
1112
+ derivedSLPrice?: number;
1113
+ derivedTPPrice?: number;
1086
1114
  isFullscreen: boolean;
1087
1115
  };
1088
1116
  /** Emitted at the instant a bracket (SL/TP) drag begins — before any movement.
@@ -1139,6 +1167,12 @@ type ChartEventMap = {
1139
1167
  tfcToggle: {
1140
1168
  enabled: boolean;
1141
1169
  };
1170
+ /** Emitted whenever any dismissible UI (flyout, modal, dropdown, popover) opens or closes.
1171
+ * Hosts (native wrappers, PWAs) listen to track whether a back button / gesture should
1172
+ * dismiss chart UI vs. navigate. Pair with `dismissAllUI()` to wire platform back events. */
1173
+ uiStateChange: {
1174
+ hasOpenUI: boolean;
1175
+ };
1142
1176
  /** Emitted when the user confirms all edits to a level — replaces separate tradeLevelDragEnd / tradeLevelBracketDrag events. */
1143
1177
  tradeLevelEdit: {
1144
1178
  label: string;