react-klinecharts-ui 0.4.0 → 0.6.0

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
@@ -41,6 +41,11 @@ Many features in this library — including 11 TradingView-style indicators, 9 d
41
41
  - [useMeasure](#usemeasure)
42
42
  - [useAnnotations](#useannotations)
43
43
  - [useReplay](#usereplay)
44
+ - [useAlerts](#usealerts)
45
+ - [useCrosshair](#usecrosshair)
46
+ - [useDataExport](#usedataexport)
47
+ - [useHotkeys](#usehotkeys)
48
+ - [useChartAxes](#usechartaxes)
44
49
  6. [Utilities](#utilities)
45
50
  - [createDataLoader](#createdataloader)
46
51
  - [TA (Technical Analysis)](#ta-technical-analysis)
@@ -49,7 +54,8 @@ Many features in this library — including 11 TradingView-style indicators, 9 d
49
54
  9. [Drawing Overlays](#drawing-overlays)
50
55
  10. [Extensions](#extensions)
51
56
  11. [State Callbacks](#state-callbacks)
52
- 12. [Full Export List](#full-export-list)
57
+ 12. [Backend Signals & Notifications](#backend-signals--notifications)
58
+ 13. [Full Export List](#full-export-list)
53
59
 
54
60
  ---
55
61
 
@@ -207,6 +213,10 @@ interface KlinechartsUIState {
207
213
  mainIndicators: string[]; // Active main chart indicators
208
214
  subIndicators: Record<string, string>; // Active sub-indicators: { name → paneId }
209
215
  indicatorAxes: Record<string, string>; // Custom Y-axis bindings: { indicatorId → yAxisId }
216
+ indicatorVisibility: Record<string, boolean>; // Visibility overrides: { indicatorId → false } (sparse)
217
+ alerts: Alert[]; // Price alerts (useAlerts) — shared across all consumers
218
+ measure: MeasureState; // Measure-tool state (useMeasure): { isActive, fromPoint, result }
219
+ replay: ReplayState; // Replay control state (useReplay): { isReplaying, isPaused, speed, barIndex, totalBars }
210
220
  styles: DeepPartial<Styles> | undefined; // Custom klinecharts styles
211
221
  screenshotUrl: string | null; // URL of the last screenshot
212
222
  }
@@ -227,6 +237,10 @@ type KlinechartsUIAction =
227
237
  | { type: "SET_MAIN_INDICATORS"; indicators: string[] }
228
238
  | { type: "SET_SUB_INDICATORS"; indicators: Record<string, string> }
229
239
  | { type: "SET_INDICATOR_AXES"; axes: Record<string, string> }
240
+ | { type: "SET_INDICATOR_VISIBILITY"; visibility: Record<string, boolean> }
241
+ | { type: "SET_ALERTS"; alerts: Alert[] }
242
+ | { type: "SET_MEASURE"; measure: Partial<MeasureState> }
243
+ | { type: "SET_REPLAY"; replay: Partial<ReplayState> }
230
244
  | { type: "SET_STYLES"; styles: DeepPartial<Styles> | undefined }
231
245
  | { type: "SET_LOCALE"; locale: string }
232
246
  | { type: "SET_SCREENSHOT_URL"; url: string | null };
@@ -457,12 +471,14 @@ const {
457
471
  moveToMain,
458
472
  moveToSub,
459
473
  setIndicatorVisible,
474
+ isIndicatorVisible,
460
475
  updateIndicatorParams,
461
476
  getIndicatorParams,
462
477
  isMainIndicatorActive,
463
478
  isSubIndicatorActive,
464
479
  indicatorAxes,
465
480
  getIndicatorAxis,
481
+ indicatorVisibility,
466
482
  bindIndicatorToNewAxis,
467
483
  } = useIndicators();
468
484
  ```
@@ -471,17 +487,20 @@ const {
471
487
 
472
488
  | Field | Type | Description |
473
489
  | ------------------------- | ------------------------ | ------------------------------------------ |
474
- | `mainIndicators` | `IndicatorInfo[]` | All main indicators with `isActive` flag |
475
- | `subIndicators` | `IndicatorInfo[]` | All sub-indicators with `isActive` flag |
490
+ | `mainIndicators` | `IndicatorInfo[]` | All main indicators with `isActive` + `visible` flags |
491
+ | `subIndicators` | `IndicatorInfo[]` | All sub-indicators with `isActive` + `visible` flags |
476
492
  | `activeMainIndicators` | `string[]` | Active main indicator names only |
477
493
  | `activeSubIndicators` | `Record<string, string>` | Active sub-indicators: `{ name → paneId }` |
478
494
  | `availableMainIndicators` | `string[]` | Full list from `MAIN_INDICATORS` |
479
495
  | `availableSubIndicators` | `string[]` | Full list from `SUB_INDICATORS` |
496
+ | `indicatorAxes` | `Record<string, string>` | Custom Y-axis bindings: `{ indicatorId → yAxisId }` |
497
+ | `indicatorVisibility` | `Record<string, boolean>`| Visibility overrides: `{ indicatorId → false }` (sparse — only hidden indicators; absent means visible) |
480
498
 
481
499
  ```typescript
482
500
  interface IndicatorInfo {
483
501
  name: string; // "MA", "MACD", "RSI", etc.
484
502
  isActive: boolean; // Whether it is currently on the chart
503
+ visible: boolean; // Whether it is currently shown (vs hidden); true when inactive
485
504
  }
486
505
  ```
487
506
 
@@ -497,11 +516,16 @@ interface IndicatorInfo {
497
516
  | `toggleSubIndicator(name)` | Same for sub-indicators |
498
517
  | `moveToMain(name)` | Moves from sub-pane to `candle_pane` |
499
518
  | `moveToSub(name)` | Moves from `candle_pane` to a new sub-pane |
500
- | `setIndicatorVisible(name, isMain, visible)` | Show/hide indicator via `chart.overrideIndicator` |
519
+ | `setIndicatorVisible(name, isMain, visible)` | Show/hide indicator via `chart.overrideIndicator`; mirrors the flag into `indicatorVisibility` |
520
+ | `isIndicatorVisible(name, isMain)` | Reactive read counterpart to `setIndicatorVisible`; returns `true` for the default/inactive state |
501
521
  | `updateIndicatorParams(name, paneId, params)` | Update `calcParams` via `chart.overrideIndicator` |
502
522
  | `getIndicatorParams(name)` | Returns `[{ label, defaultValue }]` or `[]` if no parameters |
503
523
  | `isMainIndicatorActive(name)` | Quick active check |
504
524
  | `isSubIndicatorActive(name)` | Quick active check |
525
+ | `collapseSubIndicator(name)` | Collapse a sub-indicator pane to minimal height (30px) |
526
+ | `expandSubIndicator(name)` | Expand a previously collapsed sub-indicator pane |
527
+ | `isSubIndicatorCollapsed(name)` | Whether the given sub-indicator pane is currently collapsed |
528
+ | `reorderSubIndicator(name, direction)` | Reorder a sub-indicator pane `"up"` or `"down"` |
505
529
  | `getIndicatorAxis(name, isMain)` | Returns the custom `yAxisId` an indicator is bound to, or `undefined` for the default axis |
506
530
  | `bindIndicatorToNewAxis(name, isMain, yAxis?)`| Rebinds an existing indicator to a different Y-axis (omit `yAxis` to return it to the default axis) |
507
531
 
@@ -550,12 +574,14 @@ const {
550
574
  magnetMode,
551
575
  isLocked,
552
576
  isVisible,
577
+ autoRetrigger,
553
578
  selectTool,
554
579
  clearActiveTool,
555
580
  setMagnetMode,
556
581
  toggleLock,
557
582
  toggleVisibility,
558
583
  removeAllDrawings,
584
+ setAutoRetrigger,
559
585
  } = useDrawingTools();
560
586
  ```
561
587
 
@@ -566,12 +592,14 @@ const {
566
592
  | `magnetMode` | `"normal" \| "weak" \| "strong"` | Snap-to-OHLC mode |
567
593
  | `isLocked` | `boolean` | Whether all drawings are locked |
568
594
  | `isVisible` | `boolean` | Whether all drawings are visible |
595
+ | `autoRetrigger` | `boolean` | Re-arm the tool after finishing a shape (default `true`) |
569
596
  | `selectTool(name)` | — | Start drawing via `chart.createOverlay` |
570
597
  | `clearActiveTool()` | — | Deselect tool (local state only) |
571
598
  | `setMagnetMode(mode)` | — | Change magnet mode for all existing and future drawings |
572
599
  | `toggleLock()` | — | Toggle lock on all drawings |
573
600
  | `toggleVisibility()` | — | Show/hide all drawings |
574
601
  | `removeAllDrawings()` | — | Remove all drawings in the `drawing_tools` group |
602
+ | `setAutoRetrigger(enabled)` | — | Enable/disable auto re-arming |
575
603
 
576
604
  ```typescript
577
605
  interface DrawingToolItem {
@@ -594,6 +622,9 @@ interface DrawingCategoryItem {
594
622
  | `polygon` | circle, rect, parallelogram, triangle |
595
623
  | `fibonacci` | fibonacciLine, fibonacciSegment, fibonacciCircle, fibonacciSpiral, fibonacciSpeedResistanceFan, fibonacciExtension, gannBox |
596
624
  | `wave` | xabcd, abcd, threeWaves, fiveWaves, eightWaves, anyWaves |
625
+ | `annotation` | brush |
626
+
627
+ > **Freehand drawing.** The `brush` tool (category `annotation`) uses klinecharts' continuous (freehand) drawing mode — hold and drag to sketch. It is a built-in overlay added in **klinecharts 10.0.0-beta3**, so it requires beta3+ to render.
597
628
 
598
629
  ---
599
630
 
@@ -609,20 +640,25 @@ const settings = useKlinechartsUISettings();
609
640
 
610
641
  | Field | Type | Default | Description |
611
642
  | ------------------------ | --------------- | ---------------- | ------------------------- |
612
- | `candleType` | `string` | `"candle_solid"` | Candle display type |
613
- | `candleUpColor` | `string` | `"#2DC08E"` | Bullish candle color |
614
- | `candleDownColor` | `string` | `"#F92855"` | Bearish candle color |
615
- | `showLastPrice` | `boolean` | `true` | Last price mark on Y-axis |
616
- | `showHighPrice` | `boolean` | `true` | High price mark |
617
- | `showLowPrice` | `boolean` | `true` | Low price mark |
618
- | `showIndicatorLastValue` | `boolean` | `true` | Indicator last value mark |
619
- | `priceAxisType` | `PriceAxisType` | `"normal"` | Y-axis scale type |
620
- | `reverseCoordinate` | `boolean` | `false` | Invert Y-axis |
621
- | `showTimeAxis` | `boolean` | `true` | Show X-axis |
622
- | `showGrid` | `boolean` | `true` | Show grid |
623
- | `showCrosshair` | `boolean` | `true` | Show crosshair |
624
- | `showCandleTooltip` | `boolean` | `true` | OHLCV tooltip |
625
- | `showIndicatorTooltip` | `boolean` | `true` | Indicator tooltip |
643
+ | `candleType` | `string` | `"candle_solid"` | Candle display type |
644
+ | `candleUpColor` | `string` | `"#2DC08E"` | Bullish candle color |
645
+ | `candleDownColor` | `string` | `"#F92855"` | Bearish candle color |
646
+ | `compareRule` | `CompareRule` | `"current_open"` | Baseline rule for compared symbols |
647
+ | `showLastPrice` | `boolean` | `true` | Last price mark on Y-axis |
648
+ | `showLastPriceLine` | `boolean` | `true` | Last price horizontal line |
649
+ | `showHighPrice` | `boolean` | `true` | High price mark |
650
+ | `showLowPrice` | `boolean` | `true` | Low price mark |
651
+ | `showIndicatorLastValue` | `boolean` | `true` | Indicator last value mark |
652
+ | `priceAxisType` | `PriceAxisType` | `"normal"` | Y-axis scale type |
653
+ | `yAxisPosition` | `YAxisPosition` | `"right"` | Y-axis side (`"left" \| "right"`) |
654
+ | `yAxisInside` | `boolean` | `false` | Draw the Y-axis inside the pane |
655
+ | `reverseCoordinate` | `boolean` | `false` | Invert Y-axis |
656
+ | `showTimeAxis` | `boolean` | `true` | Show X-axis |
657
+ | `showGrid` | `boolean` | `true` | Show grid |
658
+ | `showCrosshair` | `boolean` | `true` | Show crosshair |
659
+ | `showCandleTooltip` | `boolean` | `true` | OHLCV tooltip |
660
+ | `showIndicatorTooltip` | `boolean` | `true` | Indicator tooltip |
661
+ | `tooltipShowRule` | `TooltipShowRule`| `"always"` | When to show tooltips |
626
662
 
627
663
  **Candle types:** `candle_solid`, `candle_stroke`, `candle_up_stroke`, `candle_down_stroke`, `ohlc`, `area`
628
664
 
@@ -630,14 +666,17 @@ const settings = useKlinechartsUISettings();
630
666
 
631
667
  #### Extra fields
632
668
 
633
- | Field | Type | Description |
634
- | ---------------- | --------------------------------------------- | ----------------------------------------------------- |
635
- | `candleTypes` | `CandleTypeItem[]` | List of `{ key, localeKey }` for rendering a selector |
636
- | `priceAxisTypes` | `{ key: PriceAxisType; localeKey: string }[]` | List for rendering a selector |
669
+ | Field | Type | Description |
670
+ | ------------------ | ----------------------------------------------- | ----------------------------------------------------- |
671
+ | `candleTypes` | `CandleTypeItem[]` | List of `{ key, localeKey }` for rendering a selector |
672
+ | `priceAxisTypes` | `{ key: PriceAxisType; localeKey: string }[]` | List for rendering a selector |
673
+ | `yAxisPositions` | `{ key: YAxisPosition; localeKey: string }[]` | List for rendering a selector |
674
+ | `compareRules` | `{ key: CompareRule; localeKey: string }[]` | List for rendering a selector |
675
+ | `tooltipShowRules` | `{ key: TooltipShowRule; localeKey: string }[]` | List for rendering a selector |
637
676
 
638
677
  #### Setters
639
678
 
640
- Each field has a corresponding setter: `setCandleType`, `setCandleUpColor`, `setCandleDownColor`, `setShowLastPrice`, `setShowHighPrice`, `setShowLowPrice`, `setShowIndicatorLastValue`, `setPriceAxisType`, `setReverseCoordinate`, `setShowTimeAxis`, `setShowGrid`, `setShowCrosshair`, `setShowCandleTooltip`, `setShowIndicatorTooltip`.
679
+ Each field has a corresponding setter: `setCandleType`, `setCandleUpColor`, `setCandleDownColor`, `setCompareRule`, `setShowLastPrice`, `setShowLastPriceLine`, `setShowHighPrice`, `setShowLowPrice`, `setShowIndicatorLastValue`, `setPriceAxisType`, `setYAxisPosition`, `setYAxisInside`, `setReverseCoordinate`, `setShowTimeAxis`, `setShowGrid`, `setShowCrosshair`, `setShowCandleTooltip`, `setShowIndicatorTooltip`, `setTooltipShowRule`.
641
680
 
642
681
  All setters immediately apply changes via `chart.setStyles(...)`.
643
682
 
@@ -718,7 +757,7 @@ const { containerRef, toggle, isFullscreen } = useFullscreen();
718
757
 
719
758
  Create and manage horizontal price level lines (order lines).
720
759
 
721
- > **Requirement:** The `orderLine` overlay must be registered via `overlays={[orderLine]}` on the provider.
760
+ > **No setup required.** The `orderLine` overlay is registered automatically by `registerExtensions()` (enabled by default). Passing `overlays={[orderLine]}` to the provider still works and is harmless, but is no longer necessary.
722
761
 
723
762
  ```typescript
724
763
  const {
@@ -1003,7 +1042,7 @@ const {
1003
1042
  | Property | Type | Description |
1004
1043
  |----------|------|-------------|
1005
1044
  | `symbols` | `CompareSymbol[]` | Array of comparison symbols with metadata |
1006
- | `addSymbol` | `(ticker: string) => void` | Add a symbol to compare |
1045
+ | `addSymbol` | `(ticker: string, color?: string) => Promise<void>` | Add a symbol to compare (optional line color) |
1007
1046
  | `removeSymbol` | `(ticker: string) => void` | Remove a comparison symbol |
1008
1047
  | `toggleSymbol` | `(ticker: string) => void` | Toggle visibility of a symbol |
1009
1048
  | `clearAll` | `() => void` | Remove all comparison symbols |
@@ -1022,6 +1061,8 @@ const {
1022
1061
 
1023
1062
  Measure price changes, percentage swings, bar count, and time intervals between two points on the chart.
1024
1063
 
1064
+ > **Multi-instance safe.** State lives in the shared provider store (`state.measure`), so calling `useMeasure()` in several components (e.g. a toolbar toggle and a separate result panel) keeps them in sync — no need to hoist a single instance.
1065
+
1025
1066
  ```typescript
1026
1067
  import { useMeasure } from "react-klinecharts-ui";
1027
1068
 
@@ -1030,6 +1071,8 @@ const {
1030
1071
  startMeasure,
1031
1072
  cancelMeasure,
1032
1073
  result,
1074
+ clearResult,
1075
+ fromPoint,
1033
1076
  } = useMeasure();
1034
1077
  ```
1035
1078
 
@@ -1041,6 +1084,8 @@ const {
1041
1084
  | `startMeasure` | `() => void` | Enter measurement mode (click two points) |
1042
1085
  | `cancelMeasure` | `() => void` | Exit measurement mode |
1043
1086
  | `result` | `MeasureResult \| null` | Measurement data (null if not measured yet) |
1087
+ | `clearResult` | `() => void` | Clear the current measurement result |
1088
+ | `fromPoint` | `MeasurePoint \| null` | The first picked point while measuring (null when inactive) |
1044
1089
 
1045
1090
  #### MeasureResult
1046
1091
 
@@ -1095,18 +1140,23 @@ const {
1095
1140
 
1096
1141
  Replay historical candles at various speeds with play/pause/step controls and progress tracking.
1097
1142
 
1143
+ > **Multi-instance safe.** Control state lives in the shared store (`state.replay`) and the playback timer + data buffers are owned by the provider, so there is exactly one replay session no matter how many `useReplay()` instances are mounted — start in one component and step in another, and they drive the same session.
1144
+
1098
1145
  ```typescript
1099
1146
  import { useReplay } from "react-klinecharts-ui";
1100
1147
 
1101
1148
  const {
1102
- isPlaying,
1149
+ isReplaying,
1150
+ isPaused,
1103
1151
  speed,
1104
- currentIndex,
1152
+ barIndex,
1105
1153
  totalBars,
1106
- play,
1107
- pause,
1108
- stop,
1109
- step,
1154
+ startReplay,
1155
+ stopReplay,
1156
+ togglePause,
1157
+ stepForward,
1158
+ stepBackward,
1159
+ seekTo,
1110
1160
  setSpeed,
1111
1161
  } = useReplay();
1112
1162
  ```
@@ -1115,15 +1165,245 @@ const {
1115
1165
 
1116
1166
  | Property | Type | Description |
1117
1167
  |----------|------|-------------|
1118
- | `isPlaying` | `boolean` | Whether replay is running |
1119
- | `speed` | `number` | Current playback speed (0.25, 0.5, 1, 2, 4) |
1120
- | `currentIndex` | `number` | Current bar index being displayed |
1121
- | `totalBars` | `number` | Total bars in the dataset |
1122
- | `play` | `() => void` | Start replay from current position |
1123
- | `pause` | `() => void` | Pause replay (can resume with play) |
1124
- | `stop` | `() => void` | Stop replay and reset to start |
1125
- | `step` | `() => void` | Advance one bar when paused |
1126
- | `setSpeed` | `(speed: number) => void` | Set playback speed multiplier |
1168
+ | `isReplaying` | `boolean` | Whether a replay session is active |
1169
+ | `isPaused` | `boolean` | Whether the replay is currently paused |
1170
+ | `speed` | `ReplaySpeed` | Current playback speed multiplier (`1 \| 2 \| 5 \| 10`) |
1171
+ | `barIndex` | `number` | Current bar index in the replay |
1172
+ | `totalBars` | `number` | Total bars in the saved dataset |
1173
+ | `startReplay` | `() => void` | Start replaying from the beginning |
1174
+ | `stopReplay` | `() => void` | Stop replay and restore the original data |
1175
+ | `togglePause` | `() => void` | Toggle play/pause |
1176
+ | `stepForward` | `() => void` | Advance one bar while paused |
1177
+ | `stepBackward` | `() => void` | Go back one bar while paused |
1178
+ | `seekTo` | `(index: number) => void` | Seek to a specific bar index (pauses playback) |
1179
+ | `setSpeed` | `(speed: ReplaySpeed) => void` | Change the playback speed |
1180
+
1181
+ ---
1182
+
1183
+ ### useAlerts
1184
+
1185
+ Client-side price alerts. Draws a **labelled** locked horizontal line (price tag on the Y-axis + a bell-marked caption above the line) on the chart for each alert and polls the latest candle once per second, firing a callback when the close price crosses the alert level. This is the primary hook for reacting to price events — e.g. forwarding a buy/sell signal to your backend or triggering a push notification (see [Backend Signals & Notifications](#backend-signals--notifications)).
1186
+
1187
+ > **Multi-instance safe.** The alert list lives in the shared store (`state.alerts`) and the crossing poller is owned by the provider (one poller, active only while alerts exist), so multiple `useAlerts()` instances share one list. Note: `onAlertTriggered` registers a **single** listener — the last registration wins.
1188
+
1189
+ > **No manual overlay registration.** The `alertLine` overlay template the hook draws with is registered automatically (both by `registerExtensions()` and lazily inside `useAlerts` before the first overlay is created) — you don't need to pass it through the provider's `overlays` prop.
1190
+
1191
+ ```typescript
1192
+ import { useAlerts } from "react-klinecharts-ui";
1193
+
1194
+ const {
1195
+ alerts,
1196
+ addAlert,
1197
+ removeAlert,
1198
+ clearAlerts,
1199
+ onAlertTriggered,
1200
+ } = useAlerts();
1201
+
1202
+ // Default: orange dashed line, bell + price/message caption.
1203
+ const id = addAlert(65000, "crossing_up", "BTC broke 65k");
1204
+
1205
+ // Customize the look via the optional 4th argument (AlertLineExtendData).
1206
+ addAlert(70000, "crossing_up", "Take profit", {
1207
+ color: "#e91e63",
1208
+ showBell: true,
1209
+ });
1210
+
1211
+ onAlertTriggered((alert) => {
1212
+ console.log("Alert fired:", alert.message, alert.price);
1213
+ });
1214
+ ```
1215
+
1216
+ #### Return type: `UseAlertsReturn`
1217
+
1218
+ | Property | Type | Description |
1219
+ |----------|------|-------------|
1220
+ | `alerts` | `Alert[]` | Current alerts (active and triggered) |
1221
+ | `addAlert` | `(price: number, condition: AlertCondition, message?: string, extendData?: AlertLineExtendData) => string` | Create an alert at a price level; returns its id. The optional `extendData` customizes the line/label look |
1222
+ | `removeAlert` | `(id: string) => void` | Remove a single alert and its chart line |
1223
+ | `clearAlerts` | `() => void` | Remove all alerts |
1224
+ | `onAlertTriggered` | `(callback: (alert: Alert) => void) => void` | Register a callback fired once when an alert's condition is met |
1225
+
1226
+ #### Types
1227
+
1228
+ ```typescript
1229
+ type AlertCondition = "crossing_up" | "crossing_down" | "crossing";
1230
+
1231
+ interface Alert {
1232
+ id: string;
1233
+ price: number;
1234
+ condition: AlertCondition;
1235
+ message?: string;
1236
+ triggered: boolean;
1237
+ /** Visual style of the alert line; persisted so it survives undo/redo & layout presets. */
1238
+ extendData?: AlertLineExtendData;
1239
+ }
1240
+
1241
+ interface AlertLineExtendData {
1242
+ /** Primary color for the line, the Y-axis mark bg, and label fallback. Default: "#ff9800" */
1243
+ color?: string;
1244
+ /** Caption above the line. Defaults to `message ?? formatted price` (symbol precision). */
1245
+ text?: string;
1246
+ /** Line style overrides (style / width / dashedValue). Default: dashed. */
1247
+ line?: OrderLineLineStyle;
1248
+ /** Y-axis price mark style overrides. */
1249
+ mark?: OrderLineMarkStyle;
1250
+ /** Caption text style overrides. */
1251
+ label?: OrderLineLabelStyle;
1252
+ /** Show a 🔔 marker before the caption. Default: true */
1253
+ showBell?: boolean;
1254
+ }
1255
+ ```
1256
+
1257
+ The `line` / `mark` / `label` style types are shared with [`useOrderLines`](#useorderlines) (`OrderLineLineStyle`, `OrderLineMarkStyle`, `OrderLineLabelStyle`).
1258
+
1259
+ | Condition | Fires when |
1260
+ |-----------|------------|
1261
+ | `crossing_up` | Previous close `<` price **and** current close `>=` price |
1262
+ | `crossing_down` | Previous close `>` price **and** current close `<=` price |
1263
+ | `crossing` | Either direction |
1264
+
1265
+ > Detection is based on the **latest candle's close**, polled every second from `chart.getDataList()`. An alert fires at most once (its `triggered` flag flips to `true`); recreate it to re-arm.
1266
+
1267
+ ---
1268
+
1269
+ ### useCrosshair
1270
+
1271
+ Tracks the OHLCV data of the bar currently under the crosshair. Returns `null` when the cursor is off-chart. Updates are throttled with `requestAnimationFrame`, making it suitable for driving a live data panel / legend that follows the cursor.
1272
+
1273
+ ```typescript
1274
+ import { useCrosshair } from "react-klinecharts-ui";
1275
+
1276
+ const { barData } = useCrosshair();
1277
+
1278
+ // barData is null until the cursor is over a candle
1279
+ if (barData) {
1280
+ console.log(barData.close, barData.changePercent);
1281
+ }
1282
+ ```
1283
+
1284
+ #### Return type: `UseCrosshairReturn`
1285
+
1286
+ | Property | Type | Description |
1287
+ |----------|------|-------------|
1288
+ | `barData` | `CrosshairBarData \| null` | OHLCV of the hovered bar, or `null` when off-chart |
1289
+
1290
+ #### CrosshairBarData
1291
+
1292
+ | Property | Type | Description |
1293
+ |----------|------|-------------|
1294
+ | `open` | `number` | Open price |
1295
+ | `high` | `number` | High price |
1296
+ | `low` | `number` | Low price |
1297
+ | `close` | `number` | Close price |
1298
+ | `volume` | `number` | Volume |
1299
+ | `timestamp` | `number` | Bar timestamp (ms) |
1300
+ | `change` | `number` | `close - open`, rounded to the symbol's price precision |
1301
+ | `changePercent` | `number` | Percent change relative to open, 2 decimals |
1302
+
1303
+ ---
1304
+
1305
+ ### useDataExport
1306
+
1307
+ Export chart candle data to a downloaded file in CSV or JSON format. Columns: `Date` (ISO), `Open`, `High`, `Low`, `Close`, `Volume`. The file is named `<ticker>_<YYYY-MM-DD>.<format>`.
1308
+
1309
+ ```typescript
1310
+ import { useDataExport } from "react-klinecharts-ui";
1311
+
1312
+ const { exportAll, exportVisible } = useDataExport();
1313
+
1314
+ exportAll("csv"); // every loaded bar
1315
+ exportVisible("json"); // only the currently visible range
1316
+ ```
1317
+
1318
+ #### Return type: `UseDataExportReturn`
1319
+
1320
+ | Property | Type | Description |
1321
+ |----------|------|-------------|
1322
+ | `exportAll` | `(format: ExportFormat) => void` | Download all loaded candles |
1323
+ | `exportVisible` | `(format: ExportFormat) => void` | Download only the visible range (falls back to all bars if the range is unavailable) |
1324
+
1325
+ ```typescript
1326
+ type ExportFormat = "csv" | "json";
1327
+ ```
1328
+
1329
+ > No-op when the chart is not ready or holds no data.
1330
+
1331
+ ---
1332
+
1333
+ ### useHotkeys
1334
+
1335
+ Keyboard shortcuts (klinecharts v10, requires **klinecharts 10.0.0-beta3+**). Register custom hotkeys globally and toggle hotkey handling per chart. The `action` callback receives the chart instance, the keyboard event, the matched key, and the hotkey template.
1336
+
1337
+ ```typescript
1338
+ import { useHotkeys } from "react-klinecharts-ui";
1339
+
1340
+ const { registerHotkey, setHotkeysEnabled, supportedHotkeys } = useHotkeys();
1341
+
1342
+ // Register a custom shortcut — Ctrl/Cmd+L removes all overlays.
1343
+ registerHotkey({
1344
+ name: "remove-all-overlays",
1345
+ keys: ["ctrl+l", "meta+l"],
1346
+ preventDefault: true,
1347
+ action: ({ chart }) => chart.removeOverlay(),
1348
+ });
1349
+
1350
+ // Disable all built-in shortcuts except undo/redo.
1351
+ setHotkeysEnabled(true, ["undo", "redo"]);
1352
+ ```
1353
+
1354
+ #### Return type: `UseHotkeysReturn`
1355
+
1356
+ | Property | Type | Description |
1357
+ |----------|------|-------------|
1358
+ | `registerHotkey` | `(template: HotkeyTemplate) => void` | Register a custom hotkey globally (idempotent per `name`) |
1359
+ | `getHotkey` | `(name: string) => HotkeyTemplate \| null` | Look up a registered hotkey by name |
1360
+ | `supportedHotkeys` | `string[]` | Names of every registered hotkey (built-in + custom) |
1361
+ | `setHotkeysEnabled` | `(enabled: boolean, exclude?: string[]) => void` | Enable/disable hotkey handling for the chart; optionally exclude names |
1362
+ | `getHotkeysConfig` | `() => Hotkey \| null` | Current `{ enabled, exclude }` config for the chart |
1363
+
1364
+ ```typescript
1365
+ interface HotkeyTemplate {
1366
+ name: string;
1367
+ keys: string | string[];
1368
+ preventDefault?: boolean;
1369
+ stopPropagation?: boolean;
1370
+ check?: (params: HotkeyActionParams) => boolean;
1371
+ action: (params: HotkeyActionParams) => void;
1372
+ extendData?: unknown;
1373
+ }
1374
+
1375
+ interface Hotkey {
1376
+ enabled: boolean;
1377
+ exclude: string[];
1378
+ }
1379
+ ```
1380
+
1381
+ > Custom hotkeys register **globally** (shared by every chart on the page); the enable/exclude switches are per-chart. klinecharts exposes no removal API, so a registered hotkey lives for the page session.
1382
+
1383
+ ---
1384
+
1385
+ ### useChartAxes
1386
+
1387
+ Override the chart's built-in X (time) and Y (value) axes (klinecharts v10 `overrideXAxis` / `overrideYAxis`, added in **beta2**). For binding indicators to additional secondary Y-axes, use [useIndicators](#useindicators) instead.
1388
+
1389
+ ```typescript
1390
+ import { useChartAxes } from "react-klinecharts-ui";
1391
+
1392
+ const { overrideXAxis, overrideYAxis } = useChartAxes();
1393
+
1394
+ overrideYAxis({ reverse: true }); // flip the price scale
1395
+ overrideYAxis({ inside: true }); // draw price labels inside the pane
1396
+ overrideXAxis({ scrollZoomEnabled: false }); // lock time-axis zoom
1397
+ ```
1398
+
1399
+ #### Return type: `UseChartAxesReturn`
1400
+
1401
+ | Property | Type | Description |
1402
+ |----------|------|-------------|
1403
+ | `overrideXAxis` | `(override: XAxisOverride) => void` | Override the main X (time) axis (`name`, `scrollZoomEnabled`, `createTicks`) |
1404
+ | `overrideYAxis` | `(override: YAxisOverride) => void` | Override a Y (value) axis (`reverse`, `inside`, `position`, `scrollZoomEnabled`, `createRange`, `createTicks`, `id`/`paneId` to target one) |
1405
+
1406
+ > klinecharts beta3 ships these two methods with their parameter types **crossed** in its published typings; this hook shields you behind semantically-correct signatures, so `overrideYAxis` takes `YAxisOverride` and `overrideXAxis` takes `XAxisOverride` as expected.
1127
1407
 
1128
1408
  ---
1129
1409
 
@@ -1271,6 +1551,29 @@ const PRICE_AXIS_TYPES = ["normal", "percentage", "log"] as const;
1271
1551
  type PriceAxisType = "normal" | "percentage" | "log";
1272
1552
  ```
1273
1553
 
1554
+ ### YAXIS_POSITIONS
1555
+
1556
+ ```typescript
1557
+ const YAXIS_POSITIONS = ["left", "right"] as const;
1558
+ type YAxisPosition = "left" | "right";
1559
+ ```
1560
+
1561
+ ### COMPARE_RULES
1562
+
1563
+ Baseline rule used when overlaying compared symbols (see [useCompare](#usecompare)).
1564
+
1565
+ ```typescript
1566
+ const COMPARE_RULES = ["current_open", "prev_close"] as const;
1567
+ type CompareRule = "current_open" | "prev_close";
1568
+ ```
1569
+
1570
+ ### TOOLTIP_SHOW_RULES
1571
+
1572
+ ```typescript
1573
+ const TOOLTIP_SHOW_RULES = ["always", "follow_cross", "none"] as const;
1574
+ type TooltipShowRule = "always" | "follow_cross" | "none";
1575
+ ```
1576
+
1274
1577
  ---
1275
1578
 
1276
1579
  ## Custom Indicator Templates
@@ -1346,7 +1649,7 @@ import { indicators } from "react-klinecharts-ui";
1346
1649
 
1347
1650
  ### registerExtensions
1348
1651
 
1349
- Registers all built-in drawing overlays via `registerOverlay`. Called automatically by the provider when `registerExtensions: true`.
1652
+ Registers all built-in drawing overlays plus the feature overlays (`orderLine`, `alertLine`, `depthOverlay`) via `registerOverlay`. Called automatically by the provider when `registerExtensions: true`.
1350
1653
 
1351
1654
  ```typescript
1352
1655
  import { registerExtensions } from "react-klinecharts-ui";
@@ -1355,12 +1658,11 @@ registerExtensions(); // Idempotent — repeated calls are ignored
1355
1658
 
1356
1659
  ### orderLine
1357
1660
 
1358
- Overlay template for horizontal price level lines. **Not registered automatically** must be passed explicitly to the provider.
1661
+ Overlay template for horizontal price level lines. **Registered automatically** by `registerExtensions()` (default), so `useOrderLines` works out of the box. Passing it through `overlays={[orderLine]}` is optional.
1359
1662
 
1360
1663
  ```typescript
1361
- import { orderLine, KlinechartsUIProvider } from "react-klinecharts-ui";
1362
-
1363
- <KlinechartsUIProvider overlays={[orderLine]}>...</KlinechartsUIProvider>;
1664
+ import { orderLine } from "react-klinecharts-ui";
1665
+ // No provider wiring needed — registered automatically.
1364
1666
  ```
1365
1667
 
1366
1668
  **Implementation details:**
@@ -1426,14 +1728,24 @@ interface OrderLinePadding {
1426
1728
 
1427
1729
  All sub-interfaces (`OrderLineLineStyle`, `OrderLineMarkStyle`, `OrderLineLabelStyle`, `OrderLineFontStyle`, `OrderLinePadding`) are exported as named types from both the main and `extensions` entry points.
1428
1730
 
1429
- ### depthOverlay
1731
+ ### alertLine
1430
1732
 
1431
- Overlay template for visualizing order book depth as horizontal liquidity bars at each price level. Shows cumulative buy/sell volume at price levels, useful for understanding support/resistance zones.
1733
+ Overlay template drawn by [`useAlerts`](#usealerts) for price alerts: a locked horizontal line with a Y-axis price mark and a bell-marked caption above the line. **Registered automatically** by `registerExtensions()` and lazily by `useAlerts` itself, so no provider wiring is required.
1432
1734
 
1433
1735
  ```typescript
1434
- import { depthOverlay, KlinechartsUIProvider } from "react-klinecharts-ui/extensions";
1736
+ import { alertLine } from "react-klinecharts-ui";
1737
+ // Used internally by useAlerts; exported for advanced/manual overlay use.
1738
+ ```
1435
1739
 
1436
- <KlinechartsUIProvider overlays={[depthOverlay]}>...</KlinechartsUIProvider>;
1740
+ Its `extendData` shape is [`AlertLineExtendData`](#types) — it reuses the `OrderLineLineStyle` / `OrderLineMarkStyle` / `OrderLineLabelStyle` sub-types from `orderLine` and adds `showBell?: boolean` (default `true`). When no `text` is supplied the caption falls back to the formatted price (using `chart.getSymbol()?.pricePrecision`).
1741
+
1742
+ ### depthOverlay
1743
+
1744
+ Overlay template for visualizing order book depth as horizontal liquidity bars at each price level. Shows cumulative buy/sell volume at price levels, useful for understanding support/resistance zones. **Registered automatically** by `registerExtensions()` (default); explicit `overlays={[depthOverlay]}` wiring is optional.
1745
+
1746
+ ```typescript
1747
+ import { depthOverlay } from "react-klinecharts-ui/extensions";
1748
+ // No provider wiring needed — registered automatically.
1437
1749
  ```
1438
1750
 
1439
1751
  **Implementation details:**
@@ -1539,6 +1851,97 @@ const savedTheme = localStorage.getItem('theme') ?? 'dark';
1539
1851
 
1540
1852
  ---
1541
1853
 
1854
+ ## Backend Signals & Notifications
1855
+
1856
+ A common question: **how do front-end indicators connect to a backend for buy/sell signals or push notifications?**
1857
+
1858
+ This library is **headless by design** — it owns chart state, datafeed wiring, and overlay management, but it deliberately does **not** generate trading signals, execute orders, or send notifications. Those belong to your application/backend layer. What the library provides is the full set of extension points to connect the two. Backend-driven signals are **not** a built-in feature and are not planned as one, because they fall outside the headless UI scope.
1859
+
1860
+ There are two directions to wire up.
1861
+
1862
+ ### Backend → chart (display server signals)
1863
+
1864
+ Push signals computed on your backend into the chart through the `Datafeed` and overlay hooks:
1865
+
1866
+ - **`Datafeed.subscribe`** — your real-time channel (WebSocket/SSE). Stream live candles, and alongside them any backend-computed signal payloads.
1867
+ - **[`useOrderLines`](#useorderlines)** — render entry/SL/TP levels as draggable horizontal lines; `onPriceChange` reports the new price when a user drags one.
1868
+ - **[`useAnnotations`](#useannotations)** — drop markers/notes on the chart at the bars where signals fired.
1869
+
1870
+ ```tsx
1871
+ // A WebSocket carrying both candles and backend signals
1872
+ const datafeed: Datafeed = {
1873
+ // ...searchSymbols / getHistoryKLineData
1874
+ subscribe(symbol, period, callback) {
1875
+ const ws = new WebSocket(`wss://api.example.com/stream/${symbol.ticker}`);
1876
+ ws.onmessage = (e) => {
1877
+ const msg = JSON.parse(e.data);
1878
+ if (msg.type === "kline") callback(msg.candle);
1879
+ if (msg.type === "signal") signalBus.emit(msg); // hand off to your UI
1880
+ };
1881
+ sockets.set(symbol.ticker, ws);
1882
+ },
1883
+ unsubscribe(symbol) {
1884
+ sockets.get(symbol.ticker)?.close();
1885
+ sockets.delete(symbol.ticker);
1886
+ },
1887
+ };
1888
+ ```
1889
+
1890
+ ```tsx
1891
+ // Render a backend signal as an order line + annotation
1892
+ function SignalLayer() {
1893
+ const { createOrderLine } = useOrderLines();
1894
+ const { addAnnotation } = useAnnotations();
1895
+
1896
+ useEffect(() => {
1897
+ return signalBus.on("signal", (s) => {
1898
+ createOrderLine({ price: s.entry, text: `${s.side} @ ${s.entry}` });
1899
+ addAnnotation(s.side === "buy" ? "▲" : "▼", s.entry, s.timestamp);
1900
+ });
1901
+ }, [createOrderLine, addAnnotation]);
1902
+
1903
+ return null;
1904
+ }
1905
+ ```
1906
+
1907
+ ### Chart → backend (react to price events)
1908
+
1909
+ Detect a price event on the client and forward it to your backend (webhook, order placement) or fire a push notification — all inside the [`useAlerts`](#usealerts) callback:
1910
+
1911
+ ```tsx
1912
+ function PriceAlertBridge() {
1913
+ const { addAlert, onAlertTriggered } = useAlerts();
1914
+
1915
+ useEffect(() => {
1916
+ addAlert(65000, "crossing_up", "BTC > 65k");
1917
+
1918
+ onAlertTriggered(async (alert) => {
1919
+ // 1. Notify your backend (e.g. to place/adjust an order)
1920
+ await fetch("https://api.example.com/signals", {
1921
+ method: "POST",
1922
+ headers: { "Content-Type": "application/json" },
1923
+ body: JSON.stringify({ price: alert.price, condition: alert.condition }),
1924
+ });
1925
+
1926
+ // 2. Browser push notification
1927
+ if (Notification.permission === "granted") {
1928
+ new Notification("Price alert", { body: alert.message });
1929
+ }
1930
+ });
1931
+ }, [addAlert, onAlertTriggered]);
1932
+
1933
+ return null;
1934
+ }
1935
+ ```
1936
+
1937
+ > The chart-side `useAlerts` detection is a convenience based on the latest candle close (polled once per second) — it is **not** a substitute for authoritative server-side alerting. For guaranteed delivery, run the alert/signal logic on your backend and use the **Backend → chart** path above to visualize it.
1938
+
1939
+ ### Observing state
1940
+
1941
+ Use **[State Callbacks](#state-callbacks)** (`onStateChange`, `onSymbolChange`, `onSubIndicatorsChange`, …) to forward symbol/period/indicator changes to your backend — for example, to subscribe the right server-side signal stream for whatever the user is currently viewing.
1942
+
1943
+ ---
1944
+
1542
1945
  ## Full Export List
1543
1946
 
1544
1947
  ```typescript
@@ -1565,7 +1968,12 @@ export { useKlinechartsUILoading, type UseKlinechartsUILoadingReturn };
1565
1968
  export { usePeriods, type UsePeriodsReturn };
1566
1969
  export { useTimezone, type UseTimezoneReturn, type TimezoneItem };
1567
1970
  export { useSymbolSearch, type UseSymbolSearchReturn };
1568
- export { useIndicators, type UseIndicatorsReturn, type IndicatorInfo };
1971
+ export {
1972
+ useIndicators,
1973
+ type UseIndicatorsReturn,
1974
+ type IndicatorInfo,
1975
+ type AddIndicatorOptions,
1976
+ };
1569
1977
  export {
1570
1978
  useDrawingTools,
1571
1979
  type UseDrawingToolsReturn,
@@ -1598,6 +2006,19 @@ export {
1598
2006
  type UseScriptEditorReturn,
1599
2007
  type ScriptPlacement,
1600
2008
  };
2009
+ export { useCrosshair, type UseCrosshairReturn, type CrosshairBarData };
2010
+ export { useAlerts, type UseAlertsReturn, type Alert, type AlertCondition };
2011
+ export { useDataExport, type UseDataExportReturn, type ExportFormat };
2012
+ export { useWatchlist, type UseWatchlistReturn, type WatchlistItem };
2013
+ export { useReplay, type UseReplayReturn, type ReplaySpeed };
2014
+ export { useCompare, type UseCompareReturn, type CompareSymbol };
2015
+ export {
2016
+ useMeasure,
2017
+ type UseMeasureReturn,
2018
+ type MeasureResult,
2019
+ type MeasurePoint,
2020
+ };
2021
+ export { useAnnotations, type UseAnnotationsReturn, type Annotation };
1601
2022
 
1602
2023
  // Data
1603
2024
  export { DEFAULT_PERIODS, type TerminalPeriod };
@@ -1650,7 +2071,7 @@ export {
1650
2071
  export * from "./indicators";
1651
2072
 
1652
2073
  // Extensions
1653
- export { registerExtensions, overlays, indicators, orderLine };
2074
+ export { registerExtensions, overlays, indicators, orderLine, alertLine, depthOverlay };
1654
2075
  export type {
1655
2076
  OrderLineExtendData,
1656
2077
  OrderLineLineStyle,
@@ -1658,5 +2079,8 @@ export type {
1658
2079
  OrderLineLabelStyle,
1659
2080
  OrderLineFontStyle,
1660
2081
  OrderLinePadding,
2082
+ AlertLineExtendData,
2083
+ DepthOverlayExtendData,
2084
+ DepthOverlayRow,
1661
2085
  };
1662
2086
  ```