react-klinecharts-ui 0.3.0 → 0.5.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 +317 -8
- package/dist/{chunk-U325AHHX.js → chunk-DTBNTO4M.js} +8 -19
- package/dist/chunk-DTBNTO4M.js.map +1 -0
- package/dist/{chunk-PIFLJKYF.cjs → chunk-UJNJH3BS.cjs} +8 -19
- package/dist/chunk-UJNJH3BS.cjs.map +1 -0
- package/dist/extensions.cjs +6 -6
- package/dist/extensions.js +1 -1
- package/dist/index.cjs +476 -273
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +198 -33
- package/dist/index.d.ts +198 -33
- package/dist/index.js +432 -229
- package/dist/index.js.map +1 -1
- package/package.json +4 -3
- package/dist/chunk-PIFLJKYF.cjs.map +0 -1
- package/dist/chunk-U325AHHX.js.map +0 -1
package/README.md
CHANGED
|
@@ -41,6 +41,9 @@ 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)
|
|
44
47
|
6. [Utilities](#utilities)
|
|
45
48
|
- [createDataLoader](#createdataloader)
|
|
46
49
|
- [TA (Technical Analysis)](#ta-technical-analysis)
|
|
@@ -49,7 +52,8 @@ Many features in this library — including 11 TradingView-style indicators, 9 d
|
|
|
49
52
|
9. [Drawing Overlays](#drawing-overlays)
|
|
50
53
|
10. [Extensions](#extensions)
|
|
51
54
|
11. [State Callbacks](#state-callbacks)
|
|
52
|
-
12. [
|
|
55
|
+
12. [Backend Signals & Notifications](#backend-signals--notifications)
|
|
56
|
+
13. [Full Export List](#full-export-list)
|
|
53
57
|
|
|
54
58
|
---
|
|
55
59
|
|
|
@@ -206,6 +210,11 @@ interface KlinechartsUIState {
|
|
|
206
210
|
periods: TerminalPeriod[]; // List of available timeframes
|
|
207
211
|
mainIndicators: string[]; // Active main chart indicators
|
|
208
212
|
subIndicators: Record<string, string>; // Active sub-indicators: { name → paneId }
|
|
213
|
+
indicatorAxes: Record<string, string>; // Custom Y-axis bindings: { indicatorId → yAxisId }
|
|
214
|
+
indicatorVisibility: Record<string, boolean>; // Visibility overrides: { indicatorId → false } (sparse)
|
|
215
|
+
alerts: Alert[]; // Price alerts (useAlerts) — shared across all consumers
|
|
216
|
+
measure: MeasureState; // Measure-tool state (useMeasure): { isActive, fromPoint, result }
|
|
217
|
+
replay: ReplayState; // Replay control state (useReplay): { isReplaying, isPaused, speed, barIndex, totalBars }
|
|
209
218
|
styles: DeepPartial<Styles> | undefined; // Custom klinecharts styles
|
|
210
219
|
screenshotUrl: string | null; // URL of the last screenshot
|
|
211
220
|
}
|
|
@@ -225,6 +234,11 @@ type KlinechartsUIAction =
|
|
|
225
234
|
| { type: "SET_LOADING"; isLoading: boolean }
|
|
226
235
|
| { type: "SET_MAIN_INDICATORS"; indicators: string[] }
|
|
227
236
|
| { type: "SET_SUB_INDICATORS"; indicators: Record<string, string> }
|
|
237
|
+
| { type: "SET_INDICATOR_AXES"; axes: Record<string, string> }
|
|
238
|
+
| { type: "SET_INDICATOR_VISIBILITY"; visibility: Record<string, boolean> }
|
|
239
|
+
| { type: "SET_ALERTS"; alerts: Alert[] }
|
|
240
|
+
| { type: "SET_MEASURE"; measure: Partial<MeasureState> }
|
|
241
|
+
| { type: "SET_REPLAY"; replay: Partial<ReplayState> }
|
|
228
242
|
| { type: "SET_STYLES"; styles: DeepPartial<Styles> | undefined }
|
|
229
243
|
| { type: "SET_LOCALE"; locale: string }
|
|
230
244
|
| { type: "SET_SCREENSHOT_URL"; url: string | null };
|
|
@@ -455,10 +469,15 @@ const {
|
|
|
455
469
|
moveToMain,
|
|
456
470
|
moveToSub,
|
|
457
471
|
setIndicatorVisible,
|
|
472
|
+
isIndicatorVisible,
|
|
458
473
|
updateIndicatorParams,
|
|
459
474
|
getIndicatorParams,
|
|
460
475
|
isMainIndicatorActive,
|
|
461
476
|
isSubIndicatorActive,
|
|
477
|
+
indicatorAxes,
|
|
478
|
+
getIndicatorAxis,
|
|
479
|
+
indicatorVisibility,
|
|
480
|
+
bindIndicatorToNewAxis,
|
|
462
481
|
} = useIndicators();
|
|
463
482
|
```
|
|
464
483
|
|
|
@@ -466,17 +485,20 @@ const {
|
|
|
466
485
|
|
|
467
486
|
| Field | Type | Description |
|
|
468
487
|
| ------------------------- | ------------------------ | ------------------------------------------ |
|
|
469
|
-
| `mainIndicators` | `IndicatorInfo[]` | All main indicators with `isActive`
|
|
470
|
-
| `subIndicators` | `IndicatorInfo[]` | All sub-indicators with `isActive`
|
|
488
|
+
| `mainIndicators` | `IndicatorInfo[]` | All main indicators with `isActive` + `visible` flags |
|
|
489
|
+
| `subIndicators` | `IndicatorInfo[]` | All sub-indicators with `isActive` + `visible` flags |
|
|
471
490
|
| `activeMainIndicators` | `string[]` | Active main indicator names only |
|
|
472
491
|
| `activeSubIndicators` | `Record<string, string>` | Active sub-indicators: `{ name → paneId }` |
|
|
473
492
|
| `availableMainIndicators` | `string[]` | Full list from `MAIN_INDICATORS` |
|
|
474
493
|
| `availableSubIndicators` | `string[]` | Full list from `SUB_INDICATORS` |
|
|
494
|
+
| `indicatorAxes` | `Record<string, string>` | Custom Y-axis bindings: `{ indicatorId → yAxisId }` |
|
|
495
|
+
| `indicatorVisibility` | `Record<string, boolean>`| Visibility overrides: `{ indicatorId → false }` (sparse — only hidden indicators; absent means visible) |
|
|
475
496
|
|
|
476
497
|
```typescript
|
|
477
498
|
interface IndicatorInfo {
|
|
478
499
|
name: string; // "MA", "MACD", "RSI", etc.
|
|
479
500
|
isActive: boolean; // Whether it is currently on the chart
|
|
501
|
+
visible: boolean; // Whether it is currently shown (vs hidden); true when inactive
|
|
480
502
|
}
|
|
481
503
|
```
|
|
482
504
|
|
|
@@ -484,19 +506,46 @@ interface IndicatorInfo {
|
|
|
484
506
|
|
|
485
507
|
| Method | Description |
|
|
486
508
|
| --------------------------------------------- | ------------------------------------------------------------- |
|
|
487
|
-
| `addMainIndicator(name)`
|
|
509
|
+
| `addMainIndicator(name, options?)` | Creates the indicator on `candle_pane` with id `main_${name}`. Pass `{ yAxis }` to bind it to a secondary axis (see below) |
|
|
488
510
|
| `removeMainIndicator(name)` | Removes the indicator and updates state |
|
|
489
|
-
| `addSubIndicator(name)`
|
|
511
|
+
| `addSubIndicator(name, options?)` | Creates the indicator on a new sub-pane with id `sub_${name}`. Also accepts `{ yAxis }` |
|
|
490
512
|
| `removeSubIndicator(name)` | Removes the sub-indicator and its pane |
|
|
491
513
|
| `toggleMainIndicator(name)` | `add` if inactive, `remove` if active |
|
|
492
514
|
| `toggleSubIndicator(name)` | Same for sub-indicators |
|
|
493
515
|
| `moveToMain(name)` | Moves from sub-pane to `candle_pane` |
|
|
494
516
|
| `moveToSub(name)` | Moves from `candle_pane` to a new sub-pane |
|
|
495
|
-
| `setIndicatorVisible(name, isMain, visible)` | Show/hide indicator via `chart.overrideIndicator`
|
|
517
|
+
| `setIndicatorVisible(name, isMain, visible)` | Show/hide indicator via `chart.overrideIndicator`; mirrors the flag into `indicatorVisibility` |
|
|
518
|
+
| `isIndicatorVisible(name, isMain)` | Reactive read counterpart to `setIndicatorVisible`; returns `true` for the default/inactive state |
|
|
496
519
|
| `updateIndicatorParams(name, paneId, params)` | Update `calcParams` via `chart.overrideIndicator` |
|
|
497
520
|
| `getIndicatorParams(name)` | Returns `[{ label, defaultValue }]` or `[]` if no parameters |
|
|
498
521
|
| `isMainIndicatorActive(name)` | Quick active check |
|
|
499
522
|
| `isSubIndicatorActive(name)` | Quick active check |
|
|
523
|
+
| `getIndicatorAxis(name, isMain)` | Returns the custom `yAxisId` an indicator is bound to, or `undefined` for the default axis |
|
|
524
|
+
| `bindIndicatorToNewAxis(name, isMain, yAxis?)`| Rebinds an existing indicator to a different Y-axis (omit `yAxis` to return it to the default axis) |
|
|
525
|
+
|
|
526
|
+
#### Secondary Y-axis binding (multiple Y-axes)
|
|
527
|
+
|
|
528
|
+
klinecharts v10 supports several independent Y-axes on one pane, so an indicator whose value range differs sharply from price (RSI 0–100, volume, …) can get its own scale instead of distorting the shared price axis or being forced into a separate sub-pane.
|
|
529
|
+
|
|
530
|
+
```typescript
|
|
531
|
+
// Add RSI on the main pane, on its own left axis (price scale stays intact)
|
|
532
|
+
addMainIndicator("RSI", { yAxis: { id: "rsi_axis", position: "left" } });
|
|
533
|
+
|
|
534
|
+
// Later: move it back to the shared price axis
|
|
535
|
+
bindIndicatorToNewAxis("RSI", true);
|
|
536
|
+
|
|
537
|
+
// Or move an indicator already on the chart onto a dedicated right axis
|
|
538
|
+
bindIndicatorToNewAxis("VOL", true, { id: "vol_axis", position: "right" });
|
|
539
|
+
```
|
|
540
|
+
|
|
541
|
+
`yAxis` is a klinecharts `YAxisOverride`; the key field is **`id`** — indicators sharing the same `id` share one axis. Useful extras: `position` (`"left" | "right"`), `name` (scale type: `"normal" | "percentage" | "log"`), `inside`, and `needWidget` (set `false` for an invisible axis — own scale, no labels).
|
|
542
|
+
|
|
543
|
+
This binding is a **persistent property, not a one-shot action**. It is tracked in provider state (`indicatorAxes`, keyed by indicator id) and preserved across:
|
|
544
|
+
|
|
545
|
+
- **undo/redo** — toggling an indicator off and back on (`useUndoRedo`) restores it on the same axis, not the price axis;
|
|
546
|
+
- **layout presets** — `useLayoutManager` save/load reproduces each indicator's axis 1:1.
|
|
547
|
+
|
|
548
|
+
> Note: `bindIndicatorToNewAxis` removes and recreates the indicator (v10 `overrideIndicator` cannot rebind an axis), preserving calc params, styles and visibility. The rebind action itself is not pushed onto the undo stack.
|
|
500
549
|
|
|
501
550
|
#### Available indicators
|
|
502
551
|
|
|
@@ -991,6 +1040,8 @@ const {
|
|
|
991
1040
|
|
|
992
1041
|
Measure price changes, percentage swings, bar count, and time intervals between two points on the chart.
|
|
993
1042
|
|
|
1043
|
+
> **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.
|
|
1044
|
+
|
|
994
1045
|
```typescript
|
|
995
1046
|
import { useMeasure } from "react-klinecharts-ui";
|
|
996
1047
|
|
|
@@ -1064,6 +1115,8 @@ const {
|
|
|
1064
1115
|
|
|
1065
1116
|
Replay historical candles at various speeds with play/pause/step controls and progress tracking.
|
|
1066
1117
|
|
|
1118
|
+
> **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.
|
|
1119
|
+
|
|
1067
1120
|
```typescript
|
|
1068
1121
|
import { useReplay } from "react-klinecharts-ui";
|
|
1069
1122
|
|
|
@@ -1096,6 +1149,128 @@ const {
|
|
|
1096
1149
|
|
|
1097
1150
|
---
|
|
1098
1151
|
|
|
1152
|
+
### useAlerts
|
|
1153
|
+
|
|
1154
|
+
Client-side price alerts. Draws a locked horizontal 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)).
|
|
1155
|
+
|
|
1156
|
+
> **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.
|
|
1157
|
+
|
|
1158
|
+
```typescript
|
|
1159
|
+
import { useAlerts } from "react-klinecharts-ui";
|
|
1160
|
+
|
|
1161
|
+
const {
|
|
1162
|
+
alerts,
|
|
1163
|
+
addAlert,
|
|
1164
|
+
removeAlert,
|
|
1165
|
+
clearAlerts,
|
|
1166
|
+
onAlertTriggered,
|
|
1167
|
+
} = useAlerts();
|
|
1168
|
+
|
|
1169
|
+
const id = addAlert(65000, "crossing_up", "BTC broke 65k");
|
|
1170
|
+
|
|
1171
|
+
onAlertTriggered((alert) => {
|
|
1172
|
+
console.log("Alert fired:", alert.message, alert.price);
|
|
1173
|
+
});
|
|
1174
|
+
```
|
|
1175
|
+
|
|
1176
|
+
#### Return type: `UseAlertsReturn`
|
|
1177
|
+
|
|
1178
|
+
| Property | Type | Description |
|
|
1179
|
+
|----------|------|-------------|
|
|
1180
|
+
| `alerts` | `Alert[]` | Current alerts (active and triggered) |
|
|
1181
|
+
| `addAlert` | `(price: number, condition: AlertCondition, message?: string) => string` | Create an alert at a price level; returns its id |
|
|
1182
|
+
| `removeAlert` | `(id: string) => void` | Remove a single alert and its chart line |
|
|
1183
|
+
| `clearAlerts` | `() => void` | Remove all alerts |
|
|
1184
|
+
| `onAlertTriggered` | `(callback: (alert: Alert) => void) => void` | Register a callback fired once when an alert's condition is met |
|
|
1185
|
+
|
|
1186
|
+
#### Types
|
|
1187
|
+
|
|
1188
|
+
```typescript
|
|
1189
|
+
type AlertCondition = "crossing_up" | "crossing_down" | "crossing";
|
|
1190
|
+
|
|
1191
|
+
interface Alert {
|
|
1192
|
+
id: string;
|
|
1193
|
+
price: number;
|
|
1194
|
+
condition: AlertCondition;
|
|
1195
|
+
message?: string;
|
|
1196
|
+
triggered: boolean;
|
|
1197
|
+
}
|
|
1198
|
+
```
|
|
1199
|
+
|
|
1200
|
+
| Condition | Fires when |
|
|
1201
|
+
|-----------|------------|
|
|
1202
|
+
| `crossing_up` | Previous close `<` price **and** current close `>=` price |
|
|
1203
|
+
| `crossing_down` | Previous close `>` price **and** current close `<=` price |
|
|
1204
|
+
| `crossing` | Either direction |
|
|
1205
|
+
|
|
1206
|
+
> 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.
|
|
1207
|
+
|
|
1208
|
+
---
|
|
1209
|
+
|
|
1210
|
+
### useCrosshair
|
|
1211
|
+
|
|
1212
|
+
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.
|
|
1213
|
+
|
|
1214
|
+
```typescript
|
|
1215
|
+
import { useCrosshair } from "react-klinecharts-ui";
|
|
1216
|
+
|
|
1217
|
+
const { barData } = useCrosshair();
|
|
1218
|
+
|
|
1219
|
+
// barData is null until the cursor is over a candle
|
|
1220
|
+
if (barData) {
|
|
1221
|
+
console.log(barData.close, barData.changePercent);
|
|
1222
|
+
}
|
|
1223
|
+
```
|
|
1224
|
+
|
|
1225
|
+
#### Return type: `UseCrosshairReturn`
|
|
1226
|
+
|
|
1227
|
+
| Property | Type | Description |
|
|
1228
|
+
|----------|------|-------------|
|
|
1229
|
+
| `barData` | `CrosshairBarData \| null` | OHLCV of the hovered bar, or `null` when off-chart |
|
|
1230
|
+
|
|
1231
|
+
#### CrosshairBarData
|
|
1232
|
+
|
|
1233
|
+
| Property | Type | Description |
|
|
1234
|
+
|----------|------|-------------|
|
|
1235
|
+
| `open` | `number` | Open price |
|
|
1236
|
+
| `high` | `number` | High price |
|
|
1237
|
+
| `low` | `number` | Low price |
|
|
1238
|
+
| `close` | `number` | Close price |
|
|
1239
|
+
| `volume` | `number` | Volume |
|
|
1240
|
+
| `timestamp` | `number` | Bar timestamp (ms) |
|
|
1241
|
+
| `change` | `number` | `close - open`, rounded to the symbol's price precision |
|
|
1242
|
+
| `changePercent` | `number` | Percent change relative to open, 2 decimals |
|
|
1243
|
+
|
|
1244
|
+
---
|
|
1245
|
+
|
|
1246
|
+
### useDataExport
|
|
1247
|
+
|
|
1248
|
+
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>`.
|
|
1249
|
+
|
|
1250
|
+
```typescript
|
|
1251
|
+
import { useDataExport } from "react-klinecharts-ui";
|
|
1252
|
+
|
|
1253
|
+
const { exportAll, exportVisible } = useDataExport();
|
|
1254
|
+
|
|
1255
|
+
exportAll("csv"); // every loaded bar
|
|
1256
|
+
exportVisible("json"); // only the currently visible range
|
|
1257
|
+
```
|
|
1258
|
+
|
|
1259
|
+
#### Return type: `UseDataExportReturn`
|
|
1260
|
+
|
|
1261
|
+
| Property | Type | Description |
|
|
1262
|
+
|----------|------|-------------|
|
|
1263
|
+
| `exportAll` | `(format: ExportFormat) => void` | Download all loaded candles |
|
|
1264
|
+
| `exportVisible` | `(format: ExportFormat) => void` | Download only the visible range (falls back to all bars if the range is unavailable) |
|
|
1265
|
+
|
|
1266
|
+
```typescript
|
|
1267
|
+
type ExportFormat = "csv" | "json";
|
|
1268
|
+
```
|
|
1269
|
+
|
|
1270
|
+
> No-op when the chart is not ready or holds no data.
|
|
1271
|
+
|
|
1272
|
+
---
|
|
1273
|
+
|
|
1099
1274
|
## Utilities
|
|
1100
1275
|
|
|
1101
1276
|
### createDataLoader
|
|
@@ -1240,6 +1415,29 @@ const PRICE_AXIS_TYPES = ["normal", "percentage", "log"] as const;
|
|
|
1240
1415
|
type PriceAxisType = "normal" | "percentage" | "log";
|
|
1241
1416
|
```
|
|
1242
1417
|
|
|
1418
|
+
### YAXIS_POSITIONS
|
|
1419
|
+
|
|
1420
|
+
```typescript
|
|
1421
|
+
const YAXIS_POSITIONS = ["left", "right"] as const;
|
|
1422
|
+
type YAxisPosition = "left" | "right";
|
|
1423
|
+
```
|
|
1424
|
+
|
|
1425
|
+
### COMPARE_RULES
|
|
1426
|
+
|
|
1427
|
+
Baseline rule used when overlaying compared symbols (see [useCompare](#usecompare)).
|
|
1428
|
+
|
|
1429
|
+
```typescript
|
|
1430
|
+
const COMPARE_RULES = ["current_open", "prev_close"] as const;
|
|
1431
|
+
type CompareRule = "current_open" | "prev_close";
|
|
1432
|
+
```
|
|
1433
|
+
|
|
1434
|
+
### TOOLTIP_SHOW_RULES
|
|
1435
|
+
|
|
1436
|
+
```typescript
|
|
1437
|
+
const TOOLTIP_SHOW_RULES = ["always", "follow_cross", "none"] as const;
|
|
1438
|
+
type TooltipShowRule = "always" | "follow_cross" | "none";
|
|
1439
|
+
```
|
|
1440
|
+
|
|
1243
1441
|
---
|
|
1244
1442
|
|
|
1245
1443
|
## Custom Indicator Templates
|
|
@@ -1508,6 +1706,97 @@ const savedTheme = localStorage.getItem('theme') ?? 'dark';
|
|
|
1508
1706
|
|
|
1509
1707
|
---
|
|
1510
1708
|
|
|
1709
|
+
## Backend Signals & Notifications
|
|
1710
|
+
|
|
1711
|
+
A common question: **how do front-end indicators connect to a backend for buy/sell signals or push notifications?**
|
|
1712
|
+
|
|
1713
|
+
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.
|
|
1714
|
+
|
|
1715
|
+
There are two directions to wire up.
|
|
1716
|
+
|
|
1717
|
+
### Backend → chart (display server signals)
|
|
1718
|
+
|
|
1719
|
+
Push signals computed on your backend into the chart through the `Datafeed` and overlay hooks:
|
|
1720
|
+
|
|
1721
|
+
- **`Datafeed.subscribe`** — your real-time channel (WebSocket/SSE). Stream live candles, and alongside them any backend-computed signal payloads.
|
|
1722
|
+
- **[`useOrderLines`](#useorderlines)** — render entry/SL/TP levels as draggable horizontal lines; `onPriceChange` reports the new price when a user drags one.
|
|
1723
|
+
- **[`useAnnotations`](#useannotations)** — drop markers/notes on the chart at the bars where signals fired.
|
|
1724
|
+
|
|
1725
|
+
```tsx
|
|
1726
|
+
// A WebSocket carrying both candles and backend signals
|
|
1727
|
+
const datafeed: Datafeed = {
|
|
1728
|
+
// ...searchSymbols / getHistoryKLineData
|
|
1729
|
+
subscribe(symbol, period, callback) {
|
|
1730
|
+
const ws = new WebSocket(`wss://api.example.com/stream/${symbol.ticker}`);
|
|
1731
|
+
ws.onmessage = (e) => {
|
|
1732
|
+
const msg = JSON.parse(e.data);
|
|
1733
|
+
if (msg.type === "kline") callback(msg.candle);
|
|
1734
|
+
if (msg.type === "signal") signalBus.emit(msg); // hand off to your UI
|
|
1735
|
+
};
|
|
1736
|
+
sockets.set(symbol.ticker, ws);
|
|
1737
|
+
},
|
|
1738
|
+
unsubscribe(symbol) {
|
|
1739
|
+
sockets.get(symbol.ticker)?.close();
|
|
1740
|
+
sockets.delete(symbol.ticker);
|
|
1741
|
+
},
|
|
1742
|
+
};
|
|
1743
|
+
```
|
|
1744
|
+
|
|
1745
|
+
```tsx
|
|
1746
|
+
// Render a backend signal as an order line + annotation
|
|
1747
|
+
function SignalLayer() {
|
|
1748
|
+
const { createOrderLine } = useOrderLines();
|
|
1749
|
+
const { addAnnotation } = useAnnotations();
|
|
1750
|
+
|
|
1751
|
+
useEffect(() => {
|
|
1752
|
+
return signalBus.on("signal", (s) => {
|
|
1753
|
+
createOrderLine({ price: s.entry, text: `${s.side} @ ${s.entry}` });
|
|
1754
|
+
addAnnotation(s.side === "buy" ? "▲" : "▼", s.entry, s.timestamp);
|
|
1755
|
+
});
|
|
1756
|
+
}, [createOrderLine, addAnnotation]);
|
|
1757
|
+
|
|
1758
|
+
return null;
|
|
1759
|
+
}
|
|
1760
|
+
```
|
|
1761
|
+
|
|
1762
|
+
### Chart → backend (react to price events)
|
|
1763
|
+
|
|
1764
|
+
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:
|
|
1765
|
+
|
|
1766
|
+
```tsx
|
|
1767
|
+
function PriceAlertBridge() {
|
|
1768
|
+
const { addAlert, onAlertTriggered } = useAlerts();
|
|
1769
|
+
|
|
1770
|
+
useEffect(() => {
|
|
1771
|
+
addAlert(65000, "crossing_up", "BTC > 65k");
|
|
1772
|
+
|
|
1773
|
+
onAlertTriggered(async (alert) => {
|
|
1774
|
+
// 1. Notify your backend (e.g. to place/adjust an order)
|
|
1775
|
+
await fetch("https://api.example.com/signals", {
|
|
1776
|
+
method: "POST",
|
|
1777
|
+
headers: { "Content-Type": "application/json" },
|
|
1778
|
+
body: JSON.stringify({ price: alert.price, condition: alert.condition }),
|
|
1779
|
+
});
|
|
1780
|
+
|
|
1781
|
+
// 2. Browser push notification
|
|
1782
|
+
if (Notification.permission === "granted") {
|
|
1783
|
+
new Notification("Price alert", { body: alert.message });
|
|
1784
|
+
}
|
|
1785
|
+
});
|
|
1786
|
+
}, [addAlert, onAlertTriggered]);
|
|
1787
|
+
|
|
1788
|
+
return null;
|
|
1789
|
+
}
|
|
1790
|
+
```
|
|
1791
|
+
|
|
1792
|
+
> 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.
|
|
1793
|
+
|
|
1794
|
+
### Observing state
|
|
1795
|
+
|
|
1796
|
+
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.
|
|
1797
|
+
|
|
1798
|
+
---
|
|
1799
|
+
|
|
1511
1800
|
## Full Export List
|
|
1512
1801
|
|
|
1513
1802
|
```typescript
|
|
@@ -1534,7 +1823,12 @@ export { useKlinechartsUILoading, type UseKlinechartsUILoadingReturn };
|
|
|
1534
1823
|
export { usePeriods, type UsePeriodsReturn };
|
|
1535
1824
|
export { useTimezone, type UseTimezoneReturn, type TimezoneItem };
|
|
1536
1825
|
export { useSymbolSearch, type UseSymbolSearchReturn };
|
|
1537
|
-
export {
|
|
1826
|
+
export {
|
|
1827
|
+
useIndicators,
|
|
1828
|
+
type UseIndicatorsReturn,
|
|
1829
|
+
type IndicatorInfo,
|
|
1830
|
+
type AddIndicatorOptions,
|
|
1831
|
+
};
|
|
1538
1832
|
export {
|
|
1539
1833
|
useDrawingTools,
|
|
1540
1834
|
type UseDrawingToolsReturn,
|
|
@@ -1567,6 +1861,19 @@ export {
|
|
|
1567
1861
|
type UseScriptEditorReturn,
|
|
1568
1862
|
type ScriptPlacement,
|
|
1569
1863
|
};
|
|
1864
|
+
export { useCrosshair, type UseCrosshairReturn, type CrosshairBarData };
|
|
1865
|
+
export { useAlerts, type UseAlertsReturn, type Alert, type AlertCondition };
|
|
1866
|
+
export { useDataExport, type UseDataExportReturn, type ExportFormat };
|
|
1867
|
+
export { useWatchlist, type UseWatchlistReturn, type WatchlistItem };
|
|
1868
|
+
export { useReplay, type UseReplayReturn, type ReplaySpeed };
|
|
1869
|
+
export { useCompare, type UseCompareReturn, type CompareSymbol };
|
|
1870
|
+
export {
|
|
1871
|
+
useMeasure,
|
|
1872
|
+
type UseMeasureReturn,
|
|
1873
|
+
type MeasureResult,
|
|
1874
|
+
type MeasurePoint,
|
|
1875
|
+
};
|
|
1876
|
+
export { useAnnotations, type UseAnnotationsReturn, type Annotation };
|
|
1570
1877
|
|
|
1571
1878
|
// Data
|
|
1572
1879
|
export { DEFAULT_PERIODS, type TerminalPeriod };
|
|
@@ -1619,7 +1926,7 @@ export {
|
|
|
1619
1926
|
export * from "./indicators";
|
|
1620
1927
|
|
|
1621
1928
|
// Extensions
|
|
1622
|
-
export { registerExtensions, overlays, indicators, orderLine };
|
|
1929
|
+
export { registerExtensions, overlays, indicators, orderLine, depthOverlay };
|
|
1623
1930
|
export type {
|
|
1624
1931
|
OrderLineExtendData,
|
|
1625
1932
|
OrderLineLineStyle,
|
|
@@ -1627,5 +1934,7 @@ export type {
|
|
|
1627
1934
|
OrderLineLabelStyle,
|
|
1628
1935
|
OrderLineFontStyle,
|
|
1629
1936
|
OrderLinePadding,
|
|
1937
|
+
DepthOverlayExtendData,
|
|
1938
|
+
DepthOverlayRow,
|
|
1630
1939
|
};
|
|
1631
1940
|
```
|
|
@@ -929,18 +929,14 @@ var ray = {
|
|
|
929
929
|
needDefaultYAxisFigure: true,
|
|
930
930
|
createPointFigures: ({ coordinates, bounding }) => {
|
|
931
931
|
if (coordinates.length > 1) {
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
coordinate = { x: coordinates[0].x, y: bounding.height };
|
|
936
|
-
} else {
|
|
937
|
-
coordinate = { x: coordinates[0].x, y: 0 };
|
|
932
|
+
const coordinate = (() => {
|
|
933
|
+
if (coordinates[0].x === coordinates[1].x && coordinates[0].y !== coordinates[1].y) {
|
|
934
|
+
return coordinates[0].y < coordinates[1].y ? { x: coordinates[0].x, y: bounding.height } : { x: coordinates[0].x, y: 0 };
|
|
938
935
|
}
|
|
939
|
-
} else {
|
|
940
936
|
const x = coordinates[0].x < coordinates[1].x ? bounding.width : 0;
|
|
941
937
|
const y = (coordinates[1].y - coordinates[0].y) / (coordinates[1].x - coordinates[0].x) * (x - coordinates[0].x) + coordinates[0].y;
|
|
942
|
-
|
|
943
|
-
}
|
|
938
|
+
return { x, y };
|
|
939
|
+
})();
|
|
944
940
|
return [
|
|
945
941
|
{
|
|
946
942
|
type: "line",
|
|
@@ -1950,14 +1946,7 @@ var macdTv = {
|
|
|
1950
1946
|
styles: (data) => {
|
|
1951
1947
|
const current = data.current?.histogram ?? 0;
|
|
1952
1948
|
const pre = data.prev?.histogram ?? 0;
|
|
1953
|
-
|
|
1954
|
-
if (current > 0) {
|
|
1955
|
-
color = current > pre ? "#26A69A" : "#B2DFDB";
|
|
1956
|
-
} else if (current < 0) {
|
|
1957
|
-
color = current < pre ? "#FF5252" : "#FFCDD2";
|
|
1958
|
-
} else {
|
|
1959
|
-
color = "#B2DFDB";
|
|
1960
|
-
}
|
|
1949
|
+
const color = current > 0 ? current > pre ? "#26A69A" : "#B2DFDB" : current < 0 ? current < pre ? "#FF5252" : "#FFCDD2" : "#B2DFDB";
|
|
1961
1950
|
return { color };
|
|
1962
1951
|
}
|
|
1963
1952
|
},
|
|
@@ -2464,5 +2453,5 @@ function registerExtensions() {
|
|
|
2464
2453
|
}
|
|
2465
2454
|
|
|
2466
2455
|
export { TA_default, abcd_default, anyWaves_default, arrow_default, bollTv_default, brush_default, cci_default, circle_default, depthOverlay_default, eightWaves_default, elliottWave_default, fibRetracement_default, fibonacciCircle_default, fibonacciExtension_default, fibonacciSegment_default, fibonacciSpeedResistanceFan_default, fibonacciSpiral_default, fiveWaves_default, gannBox_default, gannFan_default, hma_default, ichimoku_default, indicators, longPosition_default, maRibbon_default, macdTv_default, measure_default, orderLine_default, overlays, parallelChannel_default, parallelogram_default, pivotPoints_default, ray_default, rect_default, registerExtensions, rsiTv_default, shortPosition_default, stochastic_default, superTrend_default, threeWaves_default, triangle_default, vwap_default, xabcd_default };
|
|
2467
|
-
//# sourceMappingURL=chunk-
|
|
2468
|
-
//# sourceMappingURL=chunk-
|
|
2456
|
+
//# sourceMappingURL=chunk-DTBNTO4M.js.map
|
|
2457
|
+
//# sourceMappingURL=chunk-DTBNTO4M.js.map
|