acttrader-charts 1.2.0-beta.4 → 1.2.0-beta.6

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
@@ -312,6 +312,34 @@ When the on-canvas ✓/✗ buttons are hidden (mobile native UI), the chart adap
312
312
 
313
313
  When `enableTrading` is on and live BID/ASK data is streaming, hovering / activating the trade crosshair button while the cursor price is inside the spread shows **"Buy Market"** and **"Sell Market"** rows instead of the standard Limit/Stop rows. Tapping either row calls `showMarketDraft()` internally and emits `draftInitiated` with `orderType: 'market'`.
314
314
 
315
+ ### Horizontal (time-axis) order-line dragging
316
+
317
+ Opt-in via `features.orderLineTimeDrag` (off by default; enable it per broker from the host app — e.g. only for Hankotrade users). When enabled, any level flagged `timeDraggable: true` can have its **info-box badge** dragged left/right to re-anchor the order to a different candle. The **price line stays locked** — only the time anchor moves. Grab the badge for horizontal drag (`grab` / `grabbing` cursor); the price line itself still drags vertically as before.
318
+
319
+ ```ts
320
+ const chart = new ChartEngine({
321
+ container,
322
+ features: { orderLineTimeDrag: true }, // host enables this only for the gated broker
323
+ orderLineDragSnap: true, // snap to nearest candle on release (default)
324
+ });
325
+
326
+ chart.setLevels(
327
+ [{ id: 'A1', price: 1.21013, side: 'buy', orderType: 'limit', lots: 0.08,
328
+ timestamp: 1718000000000, timeDraggable: true }],
329
+ 'id', 'price', 'pending',
330
+ );
331
+
332
+ chart.on('orderLineMoved', ({ label, fromTimestamp, toTimestamp, data }) => {
333
+ // Persist the move, then echo `timestamp: toTimestamp` in your next setLevels().
334
+ });
335
+ ```
336
+
337
+ - **Bounds:** the badge is clamped to the visible viewport — it can't be dragged past the left/right edge.
338
+ - **Snap:** controlled by `orderLineDragSnap` (default `true`); set `false` to keep the exact released time.
339
+ - **Escape / touch-cancel:** reverts the badge to its starting candle without emitting `orderLineMoved`.
340
+ - **Stays put after release:** the chart holds the dropped position across `setLevels` refreshes until you echo the new `timestamp` back (auto-released on match).
341
+ - A level **without** `timestamp` renders exactly as before (badge centered), so existing consumers are unaffected.
342
+
315
343
  ---
316
344
 
317
345
  ## Default Configuration
@@ -368,6 +396,8 @@ When `enableTrading` is on and live BID/ASK data is streaming, hovering / activa
368
396
  | `showTradeLevelsAlways` | | `false` | Always render SL/TP bracket lines + price pills, even when the parent level is not hovered or selected. The close (×) button stays hover-only so the chart isn't cluttered. Toggleable from the Settings dialog (Trading tab). Persisted in `localStorage`. |
369
397
  | `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)` |
370
398
  | `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 |
399
+ | `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 |
400
+ | `orderLineDragSnap` | | `true` | When horizontal dragging is enabled, snap the badge to the nearest candle on release. Set `false` to keep the exact released time |
371
401
  | `levelClusteringEnabled` | | `true` | Enable trade-level fan-out clustering; overlapping levels group into expandable badges |
372
402
  | `clusterThresholdDistance` | | `20` | Pixel proximity threshold for clustering (only when `levelClusteringEnabled` is `true`) |
373
403
  | `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 |
@@ -450,6 +480,16 @@ new ChartEngine({
450
480
  });
451
481
  ```
452
482
 
483
+ > **Fonts & the host document.** Canvas-drawn UI text (axes, crosshair, indicator pills)
484
+ > uses the `*FontFamily` values above. The DOM overlays — the **symbol name**, the
485
+ > **O/H/L/C strip**, and the toolbar — use `font-family: inherit`, so they resolve to the
486
+ > **host document's `body` font**. When you mount the chart on a normal web page this lets
487
+ > the chart pick up your site's font automatically. When you embed it in a bare host (e.g.
488
+ > a native WebView whose page sets no font), give the host `<body>` a `font-family` — the
489
+ > bundled WebView template (`wrappers/webview/src/template.html`) now ships one
490
+ > (`'Inter', system-ui, -apple-system, …`) so these elements fall back to the platform
491
+ > system font instead of the WebView's default serif.
492
+
453
493
  You can also import individual section defaults:
454
494
 
455
495
  ```ts
@@ -893,6 +933,15 @@ chart.on('tfcToggle', ({ enabled }) => {}); // TFC toggled on or off via
893
933
  chart.on('tradeLevelDragEnd', ({ label, type, newPrice, data }) => {}); // deprecated — use tradeLevelEdit
894
934
  chart.on('tradeLevelBracketDrag', ({ label, bracketType, newPrice, data }) => {}); // deprecated
895
935
 
936
+ // Horizontal (time-axis) order-line dragging — requires features.orderLineTimeDrag + level.timeDraggable.
937
+ // Price is never changed; only the badge's time anchor moves. `label` is your order id.
938
+ chart.on('orderLineMoveStart', ({ label, fromTimestamp, fromBarIndex, isFullscreen }) => {});
939
+ chart.on('orderLineMoving', ({ label, toTimestamp, toBarIndex, isFullscreen }) => {}); // fires on every move
940
+ chart.on('orderLineMoved', ({ label, fromTimestamp, toTimestamp, fromBarIndex, toBarIndex, data, isFullscreen }) => {
941
+ // Persist the new time anchor for this order. Echo `timestamp: toTimestamp` back in your
942
+ // next setLevels() payload so the badge stays put across refreshes.
943
+ });
944
+
896
945
  // Fires after addLevelBracket() auto-places a bracket, delivering the computed price back to the caller
897
946
  chart.on('tradeLevelBracketActivated', ({ label, bracketType, price, isFullscreen }) => {
898
947
  // Use price to pre-populate the SL/TP input field in your native form
@@ -841,11 +841,13 @@ interface ChartConfig {
841
841
  */
842
842
  targetCandleWidth?: number;
843
843
  /**
844
- * Which side of the quote to use for candle close/high/low during live
845
- * tick updates. Defaults to `'bid'` (forex convention). Set to `'ask'`
846
- * if your broker streams ask-based OHLCV bars.
844
+ * Which price to use for candle close/high/low during live tick updates.
845
+ * Defaults to `'bid'` (forex convention). Set to `'ask'` if your broker
846
+ * streams ask-based OHLCV bars, or `'ltp'` for exchange/dealing feeds
847
+ * that stream a last-traded price — ticks without a valid LTP fall back
848
+ * to the bid.
847
849
  */
848
- tickClosePriceSource?: 'bid' | 'ask';
850
+ tickClosePriceSource?: 'bid' | 'ask' | 'ltp';
849
851
  /**
850
852
  * When the combined count of open positions and pending orders exceeds this
851
853
  * number, the position render style auto-defaults to `'dot'` (compact).
@@ -1020,8 +1022,19 @@ interface ChartConfig {
1020
1022
  *
1021
1023
  * If both `headerLayout` and the deprecated `features.advancedToolbar` are set,
1022
1024
  * `headerLayout` wins.
1025
+ *
1026
+ * - `'mobile'` — Mobile header: a single scrollable action row
1027
+ * (`Tools` button · timeframe pills · `Ask AI` button). Opt-in and fully
1028
+ * isolated; selecting it has no effect on any other white-label. The host
1029
+ * gates it itself, e.g. `headerLayout: isMobile ? 'mobile' : undefined`.
1030
+ * The `Ask AI` button only renders when {@link ChartConfig.onAskAiClick} is set.
1031
+ */
1032
+ headerLayout?: 'simple' | 'advanced' | 'compact' | 'mobile';
1033
+ /**
1034
+ * Called when the user taps the "Ask AI" (✦) button in the `'mobile'` header.
1035
+ * Omit to hide the button entirely. No effect in other header layouts.
1023
1036
  */
1024
- headerLayout?: 'simple' | 'advanced' | 'compact';
1037
+ onAskAiClick?: () => void;
1025
1038
  /**
1026
1039
  * Hide the chart header entirely (simple TopBar / AdvancedToolbar /
1027
1040
  * CompactToolbar — whichever `headerLayout` would have rendered).
@@ -1078,6 +1091,15 @@ interface ChartConfig {
1078
1091
  * removed in a future major version. Currently treated as an alias.
1079
1092
  */
1080
1093
  advancedToolbar?: boolean;
1094
+ /**
1095
+ * Enable horizontal (time-axis) order-line dragging: a level whose `timeDraggable`
1096
+ * is true can have its info-box badge dragged left/right to re-anchor the order to
1097
+ * a different candle (price stays locked), emitting `orderLineMoved` on release.
1098
+ * This is the broker-gating seam — hosts (e.g. the Hankotrade app) enable it only
1099
+ * for their flagged users. When `false` / omitted, behavior is unchanged.
1100
+ * Default: false.
1101
+ */
1102
+ orderLineTimeDrag?: boolean;
1081
1103
  };
1082
1104
  /**
1083
1105
  * Fetches historical OHLC bars for a compare symbol. When provided, the
@@ -1141,6 +1163,12 @@ interface ChartConfig {
1141
1163
  * allowing the user to enable/disable TFC at runtime.
1142
1164
  */
1143
1165
  tfcEnabled?: boolean;
1166
+ /**
1167
+ * Snap a horizontally-dragged order line to the nearest candle on drag release.
1168
+ * Only relevant when `features.orderLineTimeDrag` is enabled. When `false`, the badge
1169
+ * keeps the exact (interpolated) time it was released at. Default: `true`.
1170
+ */
1171
+ orderLineDragSnap?: boolean;
1144
1172
  }
1145
1173
  interface IndicatorResult {
1146
1174
  index: number;
@@ -1229,6 +1257,8 @@ interface Tick {
1229
1257
  bid: number;
1230
1258
  ask: number;
1231
1259
  volume: number;
1260
+ /** Last traded price (exchange/dealing feeds). Absent on pure quote feeds. */
1261
+ ltp?: number;
1232
1262
  }
1233
1263
  interface IWebSocketAdapter {
1234
1264
  connect(): void;
@@ -1543,6 +1573,33 @@ type ChartEventMap = {
1543
1573
  bracketOrderLabel?: string;
1544
1574
  }>;
1545
1575
  };
1576
+ /** Emitted at the instant a horizontal (time-axis) order-line drag begins — before any movement.
1577
+ * Only fires when `features.orderLineTimeDrag` is enabled and the level is `timeDraggable`. */
1578
+ orderLineMoveStart: {
1579
+ label: string;
1580
+ fromTimestamp: number;
1581
+ fromBarIndex: number;
1582
+ isFullscreen: boolean;
1583
+ };
1584
+ /** Emitted on every move during a horizontal order-line drag (before release) for live external sync. */
1585
+ orderLineMoving: {
1586
+ label: string;
1587
+ toTimestamp: number;
1588
+ toBarIndex: number;
1589
+ isFullscreen: boolean;
1590
+ };
1591
+ /** Emitted once when a horizontal order-line drag ends (after snap, if enabled).
1592
+ * `label` is the level's label (i.e. your order id). The price is unchanged — only the
1593
+ * time anchor moved. `data` is the level's original object, returned as-is. */
1594
+ orderLineMoved: {
1595
+ label: string;
1596
+ fromTimestamp: number;
1597
+ toTimestamp: number;
1598
+ fromBarIndex: number;
1599
+ toBarIndex: number;
1600
+ data: unknown;
1601
+ isFullscreen: boolean;
1602
+ };
1546
1603
  /**
1547
1604
  * Emitted when the user picks a preset in the multi-layout popover or toggles
1548
1605
  * a sync option. Fires only when `enableMultipleLayouts: true`. The host
@@ -1677,6 +1734,19 @@ interface PositionLevel {
1677
1734
  orderType?: 'limit' | 'stop';
1678
1735
  /** Lot size for Entry Limit / Entry Stop orders — shown in the info box label. */
1679
1736
  lots?: number;
1737
+ /**
1738
+ * Unix-ms time anchor for the order's badge on the X (time) axis. When set, the info
1739
+ * box is centered horizontally over the candle nearest this time instead of the chart
1740
+ * center. When omitted, the badge renders at the legacy centered X (behavior unchanged).
1741
+ * Only honored when `ChartConfig.features.orderLineTimeDrag` is enabled.
1742
+ */
1743
+ timestamp?: number;
1744
+ /**
1745
+ * When true (and `ChartConfig.features.orderLineTimeDrag` is enabled), the badge can be
1746
+ * dragged horizontally to re-anchor the order to a different candle (price stays locked).
1747
+ * Emits `orderLineMoved` on release. Default: false.
1748
+ */
1749
+ timeDraggable?: boolean;
1680
1750
  /**
1681
1751
  * Your original position object. Returned as-is in the `tradeLevelClose` event.
1682
1752
  * The library never inspects this value.
@@ -1721,6 +1791,19 @@ interface PendingOrderLevel {
1721
1791
  * using the parent's `side` field (buy: price below parent → SL, above → TP; sell: reversed).
1722
1792
  */
1723
1793
  ToClose?: string;
1794
+ /**
1795
+ * Unix-ms time anchor for the order's badge on the X (time) axis. When set, the info
1796
+ * box is centered horizontally over the candle nearest this time instead of the chart
1797
+ * center. When omitted, the badge renders at the legacy centered X (behavior unchanged).
1798
+ * Only honored when `ChartConfig.features.orderLineTimeDrag` is enabled.
1799
+ */
1800
+ timestamp?: number;
1801
+ /**
1802
+ * When true (and `ChartConfig.features.orderLineTimeDrag` is enabled), the badge can be
1803
+ * dragged horizontally to re-anchor the order to a different candle (price stays locked).
1804
+ * Emits `orderLineMoved` on release. Default: false.
1805
+ */
1806
+ timeDraggable?: boolean;
1724
1807
  /** Your original order object. Returned as-is in events. The library never inspects this. */
1725
1808
  data?: unknown;
1726
1809
  }
@@ -841,11 +841,13 @@ interface ChartConfig {
841
841
  */
842
842
  targetCandleWidth?: number;
843
843
  /**
844
- * Which side of the quote to use for candle close/high/low during live
845
- * tick updates. Defaults to `'bid'` (forex convention). Set to `'ask'`
846
- * if your broker streams ask-based OHLCV bars.
844
+ * Which price to use for candle close/high/low during live tick updates.
845
+ * Defaults to `'bid'` (forex convention). Set to `'ask'` if your broker
846
+ * streams ask-based OHLCV bars, or `'ltp'` for exchange/dealing feeds
847
+ * that stream a last-traded price — ticks without a valid LTP fall back
848
+ * to the bid.
847
849
  */
848
- tickClosePriceSource?: 'bid' | 'ask';
850
+ tickClosePriceSource?: 'bid' | 'ask' | 'ltp';
849
851
  /**
850
852
  * When the combined count of open positions and pending orders exceeds this
851
853
  * number, the position render style auto-defaults to `'dot'` (compact).
@@ -1020,8 +1022,19 @@ interface ChartConfig {
1020
1022
  *
1021
1023
  * If both `headerLayout` and the deprecated `features.advancedToolbar` are set,
1022
1024
  * `headerLayout` wins.
1025
+ *
1026
+ * - `'mobile'` — Mobile header: a single scrollable action row
1027
+ * (`Tools` button · timeframe pills · `Ask AI` button). Opt-in and fully
1028
+ * isolated; selecting it has no effect on any other white-label. The host
1029
+ * gates it itself, e.g. `headerLayout: isMobile ? 'mobile' : undefined`.
1030
+ * The `Ask AI` button only renders when {@link ChartConfig.onAskAiClick} is set.
1031
+ */
1032
+ headerLayout?: 'simple' | 'advanced' | 'compact' | 'mobile';
1033
+ /**
1034
+ * Called when the user taps the "Ask AI" (✦) button in the `'mobile'` header.
1035
+ * Omit to hide the button entirely. No effect in other header layouts.
1023
1036
  */
1024
- headerLayout?: 'simple' | 'advanced' | 'compact';
1037
+ onAskAiClick?: () => void;
1025
1038
  /**
1026
1039
  * Hide the chart header entirely (simple TopBar / AdvancedToolbar /
1027
1040
  * CompactToolbar — whichever `headerLayout` would have rendered).
@@ -1078,6 +1091,15 @@ interface ChartConfig {
1078
1091
  * removed in a future major version. Currently treated as an alias.
1079
1092
  */
1080
1093
  advancedToolbar?: boolean;
1094
+ /**
1095
+ * Enable horizontal (time-axis) order-line dragging: a level whose `timeDraggable`
1096
+ * is true can have its info-box badge dragged left/right to re-anchor the order to
1097
+ * a different candle (price stays locked), emitting `orderLineMoved` on release.
1098
+ * This is the broker-gating seam — hosts (e.g. the Hankotrade app) enable it only
1099
+ * for their flagged users. When `false` / omitted, behavior is unchanged.
1100
+ * Default: false.
1101
+ */
1102
+ orderLineTimeDrag?: boolean;
1081
1103
  };
1082
1104
  /**
1083
1105
  * Fetches historical OHLC bars for a compare symbol. When provided, the
@@ -1141,6 +1163,12 @@ interface ChartConfig {
1141
1163
  * allowing the user to enable/disable TFC at runtime.
1142
1164
  */
1143
1165
  tfcEnabled?: boolean;
1166
+ /**
1167
+ * Snap a horizontally-dragged order line to the nearest candle on drag release.
1168
+ * Only relevant when `features.orderLineTimeDrag` is enabled. When `false`, the badge
1169
+ * keeps the exact (interpolated) time it was released at. Default: `true`.
1170
+ */
1171
+ orderLineDragSnap?: boolean;
1144
1172
  }
1145
1173
  interface IndicatorResult {
1146
1174
  index: number;
@@ -1229,6 +1257,8 @@ interface Tick {
1229
1257
  bid: number;
1230
1258
  ask: number;
1231
1259
  volume: number;
1260
+ /** Last traded price (exchange/dealing feeds). Absent on pure quote feeds. */
1261
+ ltp?: number;
1232
1262
  }
1233
1263
  interface IWebSocketAdapter {
1234
1264
  connect(): void;
@@ -1543,6 +1573,33 @@ type ChartEventMap = {
1543
1573
  bracketOrderLabel?: string;
1544
1574
  }>;
1545
1575
  };
1576
+ /** Emitted at the instant a horizontal (time-axis) order-line drag begins — before any movement.
1577
+ * Only fires when `features.orderLineTimeDrag` is enabled and the level is `timeDraggable`. */
1578
+ orderLineMoveStart: {
1579
+ label: string;
1580
+ fromTimestamp: number;
1581
+ fromBarIndex: number;
1582
+ isFullscreen: boolean;
1583
+ };
1584
+ /** Emitted on every move during a horizontal order-line drag (before release) for live external sync. */
1585
+ orderLineMoving: {
1586
+ label: string;
1587
+ toTimestamp: number;
1588
+ toBarIndex: number;
1589
+ isFullscreen: boolean;
1590
+ };
1591
+ /** Emitted once when a horizontal order-line drag ends (after snap, if enabled).
1592
+ * `label` is the level's label (i.e. your order id). The price is unchanged — only the
1593
+ * time anchor moved. `data` is the level's original object, returned as-is. */
1594
+ orderLineMoved: {
1595
+ label: string;
1596
+ fromTimestamp: number;
1597
+ toTimestamp: number;
1598
+ fromBarIndex: number;
1599
+ toBarIndex: number;
1600
+ data: unknown;
1601
+ isFullscreen: boolean;
1602
+ };
1546
1603
  /**
1547
1604
  * Emitted when the user picks a preset in the multi-layout popover or toggles
1548
1605
  * a sync option. Fires only when `enableMultipleLayouts: true`. The host
@@ -1677,6 +1734,19 @@ interface PositionLevel {
1677
1734
  orderType?: 'limit' | 'stop';
1678
1735
  /** Lot size for Entry Limit / Entry Stop orders — shown in the info box label. */
1679
1736
  lots?: number;
1737
+ /**
1738
+ * Unix-ms time anchor for the order's badge on the X (time) axis. When set, the info
1739
+ * box is centered horizontally over the candle nearest this time instead of the chart
1740
+ * center. When omitted, the badge renders at the legacy centered X (behavior unchanged).
1741
+ * Only honored when `ChartConfig.features.orderLineTimeDrag` is enabled.
1742
+ */
1743
+ timestamp?: number;
1744
+ /**
1745
+ * When true (and `ChartConfig.features.orderLineTimeDrag` is enabled), the badge can be
1746
+ * dragged horizontally to re-anchor the order to a different candle (price stays locked).
1747
+ * Emits `orderLineMoved` on release. Default: false.
1748
+ */
1749
+ timeDraggable?: boolean;
1680
1750
  /**
1681
1751
  * Your original position object. Returned as-is in the `tradeLevelClose` event.
1682
1752
  * The library never inspects this value.
@@ -1721,6 +1791,19 @@ interface PendingOrderLevel {
1721
1791
  * using the parent's `side` field (buy: price below parent → SL, above → TP; sell: reversed).
1722
1792
  */
1723
1793
  ToClose?: string;
1794
+ /**
1795
+ * Unix-ms time anchor for the order's badge on the X (time) axis. When set, the info
1796
+ * box is centered horizontally over the candle nearest this time instead of the chart
1797
+ * center. When omitted, the badge renders at the legacy centered X (behavior unchanged).
1798
+ * Only honored when `ChartConfig.features.orderLineTimeDrag` is enabled.
1799
+ */
1800
+ timestamp?: number;
1801
+ /**
1802
+ * When true (and `ChartConfig.features.orderLineTimeDrag` is enabled), the badge can be
1803
+ * dragged horizontally to re-anchor the order to a different candle (price stays locked).
1804
+ * Emits `orderLineMoved` on release. Default: false.
1805
+ */
1806
+ timeDraggable?: boolean;
1724
1807
  /** Your original order object. Returned as-is in events. The library never inspects this. */
1725
1808
  data?: unknown;
1726
1809
  }