acttrader-charts 1.0.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 +676 -0
- package/dist/MACD-BmvUIYwI.d.cts +1128 -0
- package/dist/MACD-BmvUIYwI.d.ts +1128 -0
- package/dist/chunk-X6OSI4P2.js +2523 -0
- package/dist/chunk-X6OSI4P2.js.map +1 -0
- package/dist/index.cjs +20264 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +1351 -0
- package/dist/index.d.ts +1351 -0
- package/dist/index.js +17651 -0
- package/dist/index.js.map +1 -0
- package/dist/indicators/index.cjs +2555 -0
- package/dist/indicators/index.cjs.map +1 -0
- package/dist/indicators/index.d.cts +288 -0
- package/dist/indicators/index.d.ts +288 -0
- package/dist/indicators/index.js +3 -0
- package/dist/indicators/index.js.map +1 -0
- package/package.json +54 -0
package/README.md
ADDED
|
@@ -0,0 +1,676 @@
|
|
|
1
|
+
# @acttrader/stockchart
|
|
2
|
+
|
|
3
|
+
A performant, zero-dependency stock charting library built on Canvas 2D.
|
|
4
|
+
Dual ESM/CJS output, TypeScript-first.
|
|
5
|
+
|
|
6
|
+
**Features:** 13 chart series types · 30+ indicators (overlay + sub-pane) · 80+ drawing tools · Trade-From-Chart (TFC) with drag-to-modify levels · Real-time WebSocket streaming · Dark & Light themes · Fully configurable labels for i18n · Fullscreen support
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## Installation
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
npm install @acttrader/stockchart
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
## Basic Usage
|
|
19
|
+
|
|
20
|
+
```ts
|
|
21
|
+
import { ChartEngine } from '@acttrader/stockchart';
|
|
22
|
+
|
|
23
|
+
const chart = new ChartEngine({
|
|
24
|
+
container: document.getElementById('chart')!,
|
|
25
|
+
theme: 'dark',
|
|
26
|
+
series: 'candlestick',
|
|
27
|
+
symbol: 'XAUUSD',
|
|
28
|
+
timeframe: '1D',
|
|
29
|
+
duration: '1Y',
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
chart.loadData(ohlcvBars); // OHLCVBar[]
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Load OHLCV data and the chart is ready. All UI (top bar, bottom bar, drawing toolbar) is rendered automatically unless `showUI: false`.
|
|
36
|
+
|
|
37
|
+
### Respond to duration / timeframe changes
|
|
38
|
+
|
|
39
|
+
```ts
|
|
40
|
+
chart.on('durationChange', ({ duration, timeframe }) => {
|
|
41
|
+
fetchBars(timeframe, duration).then(bars => chart.loadData(bars));
|
|
42
|
+
});
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### Programmatic data loading via `dataLoader`
|
|
46
|
+
|
|
47
|
+
```ts
|
|
48
|
+
const chart = new ChartEngine({
|
|
49
|
+
container,
|
|
50
|
+
dataLoader: async ({ start, end, interval }) => {
|
|
51
|
+
const res = await fetch(`/api/bars?from=${start.getTime()}&to=${end.getTime()}&tf=${interval}`);
|
|
52
|
+
return res.json(); // OHLCVBar[]
|
|
53
|
+
},
|
|
54
|
+
});
|
|
55
|
+
// No manual loadData() needed — the engine calls dataLoader on start and on timeframe/duration changes.
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
---
|
|
59
|
+
|
|
60
|
+
## Advanced Usage
|
|
61
|
+
|
|
62
|
+
### Adding Indicators
|
|
63
|
+
|
|
64
|
+
```ts
|
|
65
|
+
import { SMA, EMA, RSI } from '@acttrader/stockchart';
|
|
66
|
+
|
|
67
|
+
chart.addIndicator(new SMA(20, '#f59e0b')); // overlay
|
|
68
|
+
chart.addIndicator(new RSI(14, '#818cf8')); // sub-pane
|
|
69
|
+
chart.removeIndicator('SMA');
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Indicator pills appear inline above the chart (up to 2 visible; beyond that collapses into a dropdown).
|
|
73
|
+
|
|
74
|
+
### Drawing Tools
|
|
75
|
+
|
|
76
|
+
```ts
|
|
77
|
+
chart.setDrawingTool('trendLine'); // activate
|
|
78
|
+
chart.setDrawingTool(null); // back to pointer mode
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
Keyboard shortcuts: `Escape` cancel / deselect · `Delete`/`Backspace` remove selected · `Ctrl+Z` undo · `Ctrl+Y` redo
|
|
82
|
+
|
|
83
|
+
### Real-time Streaming
|
|
84
|
+
|
|
85
|
+
```ts
|
|
86
|
+
import { WebSocketAdapter } from '@acttrader/stockchart';
|
|
87
|
+
|
|
88
|
+
const adapter = new WebSocketAdapter(
|
|
89
|
+
'wss://feed.example.com/ticks',
|
|
90
|
+
(msg) => ({ time: msg.t, bid: msg.p, ask: msg.p, volume: msg.v }),
|
|
91
|
+
);
|
|
92
|
+
|
|
93
|
+
chart.connectStream(adapter);
|
|
94
|
+
// chart.disconnectStream();
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
Auto-reconnects with exponential backoff (2 s → 30 s). Stream status is reflected in the top-bar dot and emitted via `streamStatus`.
|
|
98
|
+
|
|
99
|
+
To push ticks directly without an adapter (e.g. from your own WebSocket handler):
|
|
100
|
+
|
|
101
|
+
```ts
|
|
102
|
+
chart.pushTick({ time: Date.now(), bid: 1.2055, ask: 1.2057, volume: 120 });
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
### Trade From Chart (TFC) — `setLevels`
|
|
106
|
+
|
|
107
|
+
TFC renders draggable price levels for open positions and pending orders.
|
|
108
|
+
The library is broker-agnostic: it draws the lines and emits typed events after the user confirms; your app owns the API calls.
|
|
109
|
+
|
|
110
|
+
**Pending order** (dashed line, draggable with optional SL/TP brackets):
|
|
111
|
+
|
|
112
|
+
```ts
|
|
113
|
+
chart.setLevels(
|
|
114
|
+
[{
|
|
115
|
+
label: 'ORD-1',
|
|
116
|
+
price: 1.2050,
|
|
117
|
+
side: 'buy',
|
|
118
|
+
orderType: 'limit',
|
|
119
|
+
lots: 1.0,
|
|
120
|
+
stopLossPrice: 1.1980,
|
|
121
|
+
takeProfitPrice: 1.2150,
|
|
122
|
+
text: 'Buy Limit',
|
|
123
|
+
}],
|
|
124
|
+
'label', // unique key field
|
|
125
|
+
'price', // price field
|
|
126
|
+
'pending', // level type
|
|
127
|
+
);
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
**Open position** (solid line + live P&L + optional SL/TP brackets):
|
|
131
|
+
|
|
132
|
+
```ts
|
|
133
|
+
chart.setLevels(
|
|
134
|
+
[{
|
|
135
|
+
label: 'POS-1',
|
|
136
|
+
price: 1.2010,
|
|
137
|
+
pnl: 42.5,
|
|
138
|
+
pnlText: '+$42.50',
|
|
139
|
+
side: 'buy',
|
|
140
|
+
stopLossPrice: 1.1960,
|
|
141
|
+
takeProfitPrice: 1.2120,
|
|
142
|
+
}],
|
|
143
|
+
'label', 'price', 'position',
|
|
144
|
+
);
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
**Bracket orders via `ToClose`** — link a separate SL/TP pending order to a parent level:
|
|
148
|
+
|
|
149
|
+
```ts
|
|
150
|
+
chart.setLevels([
|
|
151
|
+
{ label: 'POS-1', price: 1.2010, side: 'buy', type: 'position' },
|
|
152
|
+
{ label: 'ORD-SL', price: 1.1960, side: 'sell', orderType: 'stop', ToClose: 'POS-1' },
|
|
153
|
+
], 'label', 'price', 'pending');
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
**Remove levels:**
|
|
157
|
+
|
|
158
|
+
```ts
|
|
159
|
+
chart.removeLevelByLabel('ORD-1');
|
|
160
|
+
chart.setLevels([], 'label', 'price', 'pending'); // clear all of one type
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
**TFC events:**
|
|
164
|
+
|
|
165
|
+
```ts
|
|
166
|
+
// Confirmed drag of a pending order entry
|
|
167
|
+
chart.on('tradeLevelEdit', ({ label, type, changes }) => {
|
|
168
|
+
for (const c of changes) {
|
|
169
|
+
if (c.field === 'MAIN') myApi.modifyOrder(label, { price: c.newPrice });
|
|
170
|
+
if (c.field === 'SL') myApi.modifyOrder(label, { stopLoss: c.newPrice });
|
|
171
|
+
if (c.field === 'TP') myApi.modifyOrder(label, { takeProfit: c.newPrice });
|
|
172
|
+
}
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
// User clicked × on a level
|
|
176
|
+
chart.on('tradeLevelClose', ({ label, type, action }) => {
|
|
177
|
+
if (type === 'pending') myApi.cancelOrder(label);
|
|
178
|
+
if (type === 'position') myApi.closePosition(label);
|
|
179
|
+
});
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
**Drag constraints (enforced live):**
|
|
183
|
+
|
|
184
|
+
| Order side | Stop Loss | Take Profit |
|
|
185
|
+
|---|---|---|
|
|
186
|
+
| `buy` | must stay ≤ order price | must stay ≥ order price |
|
|
187
|
+
| `sell` | must stay ≥ order price | must stay ≤ order price |
|
|
188
|
+
|
|
189
|
+
---
|
|
190
|
+
|
|
191
|
+
## Default Configuration
|
|
192
|
+
|
|
193
|
+
### `ChartConfig`
|
|
194
|
+
|
|
195
|
+
| Property | Required | Default | Description |
|
|
196
|
+
|---|:---:|---|---|
|
|
197
|
+
| `container` | ✓ | — | Host `HTMLElement` |
|
|
198
|
+
| `theme` | | `"dark"` | `"dark"` or `"light"` |
|
|
199
|
+
| `series` | | `"candlestick"` | Initial chart type |
|
|
200
|
+
| `showVolume` | | `true` | Show volume overlay |
|
|
201
|
+
| `showUI` | | `true` | Render top / bottom / left bars |
|
|
202
|
+
| `timeframe` | | `"1D"` | Initial timeframe label |
|
|
203
|
+
| `duration` | | — | Initial active duration button |
|
|
204
|
+
| `symbol` | | — | Symbol name shown in the top bar |
|
|
205
|
+
| `padding` | | `{top:8,right:0,bottom:0,left:0}` | Canvas padding (px) |
|
|
206
|
+
| `minLots` | | `1` | Default lot size in the trade popover |
|
|
207
|
+
| `tickActivityMs` | | `30000` | ms the stream dot stays green after last tick |
|
|
208
|
+
| `maxCandles` | | `200` | Max bars fetched per data-load request |
|
|
209
|
+
| `durationTimeframeMap` | | *(see below)* | Override duration → timeframe pairings |
|
|
210
|
+
| `dataLoader` | | — | `(params) => Promise<OHLCVBar[]>` auto-called on load / change |
|
|
211
|
+
| `uiConfig` | | `DEFAULT_UI_CONFIG` | Deep-partial size / font overrides per component |
|
|
212
|
+
| `labels` | | `DEFAULT_LABELS` | Deep-partial string overrides for i18n/translation |
|
|
213
|
+
| `onOrderSubmit` | | — | Called when user submits a trade via the floating button |
|
|
214
|
+
| `onLevelEdit` | | — | Called when user confirms a TFC level edit |
|
|
215
|
+
| `onLevelDragEnd` | | — | *(deprecated — use `onLevelEdit`)* |
|
|
216
|
+
|
|
217
|
+
### `OHLCVBar`
|
|
218
|
+
|
|
219
|
+
| Field | Required | Type | Description |
|
|
220
|
+
|---|:---:|---|---|
|
|
221
|
+
| `time` | ✓ | `number` | Unix ms timestamp |
|
|
222
|
+
| `open` | ✓ | `number` | Open price |
|
|
223
|
+
| `high` | ✓ | `number` | High price |
|
|
224
|
+
| `low` | ✓ | `number` | Low price |
|
|
225
|
+
| `close` | ✓ | `number` | Close price |
|
|
226
|
+
| `volume` | | `number` | Volume (omit to hide volume overlay) |
|
|
227
|
+
|
|
228
|
+
### Duration → Auto Timeframe Map
|
|
229
|
+
|
|
230
|
+
| Duration | Default timeframe |
|
|
231
|
+
|---|---|
|
|
232
|
+
| `1D` | `5m` |
|
|
233
|
+
| `5D` | `15m` |
|
|
234
|
+
| `1M` | `30m` |
|
|
235
|
+
| `3M` | `1h` |
|
|
236
|
+
| `6M` | `4h` |
|
|
237
|
+
| `1Y` | `1D` |
|
|
238
|
+
| `5Y` | `1W` |
|
|
239
|
+
| `All` | `1M` |
|
|
240
|
+
|
|
241
|
+
Override individual entries via `durationTimeframeMap`:
|
|
242
|
+
|
|
243
|
+
```ts
|
|
244
|
+
new ChartEngine({ ..., durationTimeframeMap: { '1Y': '4h', '5Y': '1D' } });
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
### `UiConfig` — sizes & fonts
|
|
248
|
+
|
|
249
|
+
All values are optional; unset keys fall back to `DEFAULT_UI_CONFIG`.
|
|
250
|
+
|
|
251
|
+
```ts
|
|
252
|
+
import { DEFAULT_UI_CONFIG } from '@acttrader/stockchart';
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
| Component key | Configurable properties |
|
|
256
|
+
|---|---|
|
|
257
|
+
| `drawingToolbar` | `iconBtnSize`, `iconFontSize`, `iconFontFamily`, `flyoutLabelFontSize`, `flyoutLabelFontFamily`, `shortcutFontSize`, `soonBadgeFontSize`, `flyoutHeadingFontSize`, `flyoutHeadingLetterSpacing`, `scrollBtnHeight`, `scrollBtnFontSize`, `barPadding`, `btnGap` |
|
|
258
|
+
| `topBar` | `height`, `dropBtnFontSize`, `dropBtnFontFamily`, `drawBtnSize`, `drawBtnIconFontSize`, `flyoutRowFontSize`, `flyoutRowFontFamily`, `flyoutCategoryFontSize`, `flyoutCategoryLetterSpacing`, `flyoutCheckFontSize`, `streamDotSize` |
|
|
259
|
+
| `bottomBar` | `height`, `btnFontSize`, `btnFontFamily` |
|
|
260
|
+
| `priceAxis` | `fontSize`, `fontFamily` |
|
|
261
|
+
| `timeAxis` | `fontSize`, `fontFamily` |
|
|
262
|
+
| `crosshair` | `labelHeight`, `labelPaddingX`, `fontSize`, `fontFamily` |
|
|
263
|
+
| `indicatorOverlay` | `pillFontSize`, `pillFontFamily`, `dotFontSize`, `pillIconFontSize`, `collapseBtnFontSize`, `collapseBtnFontFamily`, `dropdownRowFontSize`, `dropdownRowFontFamily`, `dropdownIconFontSize` |
|
|
264
|
+
|
|
265
|
+
**Example:**
|
|
266
|
+
|
|
267
|
+
```ts
|
|
268
|
+
import { resolveUiConfig } from '@acttrader/stockchart';
|
|
269
|
+
|
|
270
|
+
new ChartEngine({
|
|
271
|
+
container,
|
|
272
|
+
uiConfig: {
|
|
273
|
+
topBar: { height: '40px', dropBtnFontSize: '13px' },
|
|
274
|
+
priceAxis: { fontSize: '12px', fontFamily: 'Inter, sans-serif' },
|
|
275
|
+
},
|
|
276
|
+
});
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
You can also import individual section defaults:
|
|
280
|
+
|
|
281
|
+
```ts
|
|
282
|
+
import {
|
|
283
|
+
DEFAULT_UI_CONFIG,
|
|
284
|
+
DEFAULT_TOP_BAR_CONFIG,
|
|
285
|
+
DEFAULT_PRICE_AXIS_CONFIG,
|
|
286
|
+
DEFAULT_CROSSHAIR_CONFIG,
|
|
287
|
+
// ...
|
|
288
|
+
} from '@acttrader/stockchart';
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
### `ChartLabels` — i18n / translation
|
|
292
|
+
|
|
293
|
+
All user-visible strings can be overridden for translation. Only keys you supply are replaced; the rest fall back to `DEFAULT_LABELS` (English).
|
|
294
|
+
|
|
295
|
+
```ts
|
|
296
|
+
import { DEFAULT_LABELS, resolveLabels } from '@acttrader/stockchart';
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
Pass overrides directly in `ChartConfig`:
|
|
300
|
+
|
|
301
|
+
```ts
|
|
302
|
+
new ChartEngine({
|
|
303
|
+
container,
|
|
304
|
+
labels: {
|
|
305
|
+
trade: { buy: 'Acheter', sell: 'Vendre', limit: 'Limite', stop: 'Stop' },
|
|
306
|
+
ohlc: { open: 'O', high: 'H', low: 'L', close: 'C', volume: 'V' },
|
|
307
|
+
chart: { loading: 'Chargement…', scrollToLatest: 'Aller à la fin' },
|
|
308
|
+
},
|
|
309
|
+
});
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
| Section | Key | Default | Description |
|
|
313
|
+
|---|---|---|---|
|
|
314
|
+
| `topBar.series` | `candlestick` | `'Candles'` | Series dropdown label |
|
|
315
|
+
| `topBar.series` | `hollow` | `'Hollow'` | |
|
|
316
|
+
| `topBar.series` | `ohlc` | `'OHLC'` | |
|
|
317
|
+
| `topBar.series` | `line` | `'Line'` | |
|
|
318
|
+
| `topBar.series` | `area` | `'Area'` | |
|
|
319
|
+
| `topBar` | `indicatorsBtn` | `'Indicators'` | Indicators button (no active) |
|
|
320
|
+
| `topBar` | `indicatorsBtnActive` | `'Indicators ({count})'` | `{count}` replaced at runtime |
|
|
321
|
+
| `topBar` | `toggleDrawingTitle` | `'Toggle Drawing Tools'` | Toolbar toggle tooltip |
|
|
322
|
+
| `topBar` | `toggleFullscreenTitle` | `'Toggle Fullscreen'` | Fullscreen button tooltip |
|
|
323
|
+
| `topBar` | `exitFullscreenTitle` | `'Exit Fullscreen'` | |
|
|
324
|
+
| `topBar` | `settingsTitle` | `'Settings'` | Settings button tooltip |
|
|
325
|
+
| `topBar.timeframes` | `'1m'`…`'1Y'` | same as key | Timeframe dropdown labels |
|
|
326
|
+
| `bottomBar.durations` | `'1D'`…`'All'` | same as key | Duration button labels |
|
|
327
|
+
| `drawingToolbar.categories` | `trendLines` | `'Trend Lines & Channels'` | Category flyout heading |
|
|
328
|
+
| `drawingToolbar.categories` | `fibonacci` | `'Fibonacci & Gann Tools'` | |
|
|
329
|
+
| `drawingToolbar.categories` | `shapes` | `'Geometric Shapes'` | |
|
|
330
|
+
| `drawingToolbar.categories` | `measurements` | `'Measurement Tools'` | |
|
|
331
|
+
| `drawingToolbar.categories` | `pitchforks` | `'Pitchfork Tools'` | |
|
|
332
|
+
| `drawingToolbar.categories` | `volume` | `'Volume & Statistical Tools'` | |
|
|
333
|
+
| `drawingToolbar.categories` | `annotations` | `'Annotation Tools'` | |
|
|
334
|
+
| `drawingToolbar.categories` | `patterns` | `'Pattern Recognition'` | |
|
|
335
|
+
| `drawingToolbar.categories` | `elliott` | `'Elliott Wave Tools'` | |
|
|
336
|
+
| `drawingToolbar.categories` | `brushes` | `'Brush & Highlighter'` | |
|
|
337
|
+
| `drawingToolbar.categories` | `advanced` | `'Advanced Tools'` | |
|
|
338
|
+
| `drawingToolbar.categories` | `priceProjection` | `'Price Projection Tools'` | |
|
|
339
|
+
| `drawingToolbar.tools` | *(DrawingToolType)* | English name per tool | One entry per `DrawingToolType` |
|
|
340
|
+
| `drawingToolbar.actions` | `undo` | `'Undo (Ctrl+Z)'` | Action button tooltips |
|
|
341
|
+
| `drawingToolbar.actions` | `redo` | `'Redo (Ctrl+Y)'` | |
|
|
342
|
+
| `drawingToolbar.actions` | `deleteSelected` | `'Delete Selected (Del)'` | |
|
|
343
|
+
| `drawingToolbar.actions` | `clearAll` | `'Clear All'` | |
|
|
344
|
+
| `drawingToolbar.actions` | `showAll` | `'Show All'` | |
|
|
345
|
+
| `drawingToolbar.actions` | `hideAll` | `'Hide All'` | |
|
|
346
|
+
| `drawingToolbar.actions` | `lockAll` | `'Lock All'` | |
|
|
347
|
+
| `drawingToolbar.actions` | `unlockAll` | `'Unlock All'` | |
|
|
348
|
+
| `drawingToolbar` | `soonBadge` | `'soon'` | Badge on unimplemented tools |
|
|
349
|
+
| `drawingToolbar` | `scrollUp` | `'Scroll up'` | Scroll indicator tooltip |
|
|
350
|
+
| `drawingToolbar` | `scrollDown` | `'Scroll down'` | |
|
|
351
|
+
| `ohlc` | `open` | `'O'` | OHLC strip label |
|
|
352
|
+
| `ohlc` | `high` | `'H'` | |
|
|
353
|
+
| `ohlc` | `low` | `'L'` | |
|
|
354
|
+
| `ohlc` | `close` | `'C'` | |
|
|
355
|
+
| `ohlc` | `volume` | `'V'` | |
|
|
356
|
+
| `trade` | `buy` | `'Buy'` | Trade popover label |
|
|
357
|
+
| `trade` | `sell` | `'Sell'` | |
|
|
358
|
+
| `trade` | `limit` | `'Limit'` | Order type label |
|
|
359
|
+
| `trade` | `stop` | `'Stop'` | |
|
|
360
|
+
| `trade` | `market` | `'Market'` | |
|
|
361
|
+
| `trade` | `qty` | `'Qty'` | Draft order qty input label |
|
|
362
|
+
| `trade` | `placeOrderTitle` | `'Place order at this price'` | Trade button tooltip |
|
|
363
|
+
| `dialogs.settings` | `title` | `'Chart Settings'` | Dialog title |
|
|
364
|
+
| `dialogs.settings` | `tfcSection` | `'Trade from Charts'` | Section heading |
|
|
365
|
+
| `dialogs.settings` | `showLabel` | `'Show'` | Radio group label |
|
|
366
|
+
| `dialogs.settings` | `positionStyleLabel` | `'Position Style'` | |
|
|
367
|
+
| `dialogs.settings` | `showAll` | `'All'` | Filter option |
|
|
368
|
+
| `dialogs.settings` | `showPositions` | `'Positions Only'` | |
|
|
369
|
+
| `dialogs.settings` | `showOrders` | `'Orders Only'` | |
|
|
370
|
+
| `dialogs.settings` | `styleLine` | `'Full Line'` | Style option |
|
|
371
|
+
| `dialogs.settings` | `styleDot` | `'Dot'` | |
|
|
372
|
+
| `dialogs.indicator` | `titleSuffix` | `'Settings'` | Appended to indicator name in dialog title |
|
|
373
|
+
| `dialogs.indicator` | `noParams` | `'No configurable parameters.'` | Empty-state message |
|
|
374
|
+
| `chart` | `loading` | `'Loading…'` | Loading overlay text |
|
|
375
|
+
| `chart` | `scrollToLatest` | `'Scroll to latest'` | Jump-to-end button tooltip |
|
|
376
|
+
| `chart` | `nIndicators` | `'{count} indicators'` | Collapse button; `{count}` replaced at runtime |
|
|
377
|
+
|
|
378
|
+
### `ChartTheme` — colors
|
|
379
|
+
|
|
380
|
+
```ts
|
|
381
|
+
import { DARK_THEME, LIGHT_THEME } from '@acttrader/stockchart';
|
|
382
|
+
import type { ChartTheme } from '@acttrader/stockchart';
|
|
383
|
+
```
|
|
384
|
+
|
|
385
|
+
Pass a full or partial theme object to customize colors:
|
|
386
|
+
|
|
387
|
+
```ts
|
|
388
|
+
const myTheme: ChartTheme = {
|
|
389
|
+
...DARK_THEME,
|
|
390
|
+
background: '#0a0a0a',
|
|
391
|
+
candle: { up: '#00c853', down: '#ff1744', wickUp: '#00c853', wickDown: '#ff1744' },
|
|
392
|
+
};
|
|
393
|
+
|
|
394
|
+
new ChartEngine({ container, theme: 'dark' });
|
|
395
|
+
// Theme override is applied via setTheme() after construction:
|
|
396
|
+
chart.setTheme('light');
|
|
397
|
+
```
|
|
398
|
+
|
|
399
|
+
| Top-level key | Type | Description |
|
|
400
|
+
|---|---|---|
|
|
401
|
+
| `background` | `string` | Canvas background color |
|
|
402
|
+
| `grid` | `string` | Grid line color |
|
|
403
|
+
| `axisText` | `string` | Axis tick label color |
|
|
404
|
+
| `axisBorder` | `string` | Axis border / separator color |
|
|
405
|
+
| `crosshair` | `string` | Crosshair line color |
|
|
406
|
+
| `tooltip` | `{background, text, border}` | Floating label colors |
|
|
407
|
+
| `candle` | `{up, down, wickUp, wickDown}` | Candlestick colors |
|
|
408
|
+
| `volume` | `{up, down}` | Volume bar colors |
|
|
409
|
+
| `ui` | `ChartThemeUi` | Accent and interactive-state colors |
|
|
410
|
+
| `drawingToolbar` | `DrawingToolbarColors` | Icon and flyout colors |
|
|
411
|
+
| `topBar` | `TopBarColors` | Top bar button and flyout colors |
|
|
412
|
+
| `bottomBar` | `BottomBarColors` | Duration button colors |
|
|
413
|
+
| `indicatorOverlay` | `IndicatorOverlayColors` | Pill and dropdown colors |
|
|
414
|
+
| `tradeLevels` | `TradeLevelColors` | Level line and info box colors |
|
|
415
|
+
| `tradePanel` | `TradePanelColors` | Trade panel side-drawer colors |
|
|
416
|
+
|
|
417
|
+
---
|
|
418
|
+
|
|
419
|
+
## API Reference
|
|
420
|
+
|
|
421
|
+
### Data
|
|
422
|
+
|
|
423
|
+
```ts
|
|
424
|
+
chart.loadData(bars: OHLCVBar[]): this
|
|
425
|
+
chart.prependData(bars: OHLCVBar[]): this // prepend historical bars (infinite scroll back)
|
|
426
|
+
chart.correctBar(barTime: number, bar: OHLCVBar): void // replace a bar with authoritative data after close
|
|
427
|
+
chart.setLoading(loading: boolean): this
|
|
428
|
+
```
|
|
429
|
+
|
|
430
|
+
### Series & Appearance
|
|
431
|
+
|
|
432
|
+
```ts
|
|
433
|
+
chart.setSeries(series: SeriesType): this
|
|
434
|
+
chart.setTheme('dark' | 'light'): this
|
|
435
|
+
chart.setVolume(show: boolean): this
|
|
436
|
+
```
|
|
437
|
+
|
|
438
|
+
`SeriesType` values: `candlestick` · `hollow` · `line` · `area` · `ohlc` · `heikinashi` · `volumecandles` · `linemarkers` · `step` · `hlcarea` · `baseline` · `columns` · `highlow`
|
|
439
|
+
|
|
440
|
+
### Indicators
|
|
441
|
+
|
|
442
|
+
```ts
|
|
443
|
+
chart.addIndicator(indicator: IIndicator): this
|
|
444
|
+
chart.removeIndicator(name: string): this
|
|
445
|
+
```
|
|
446
|
+
|
|
447
|
+
### Drawing Tools
|
|
448
|
+
|
|
449
|
+
```ts
|
|
450
|
+
chart.setDrawingTool(tool: DrawingToolType | null): this
|
|
451
|
+
```
|
|
452
|
+
|
|
453
|
+
### Trade Levels (TFC)
|
|
454
|
+
|
|
455
|
+
```ts
|
|
456
|
+
chart.setLevels(levels, labelField, priceField, type): this
|
|
457
|
+
chart.removeLevelByLabel(label: string): this
|
|
458
|
+
```
|
|
459
|
+
|
|
460
|
+
### Trade Button
|
|
461
|
+
|
|
462
|
+
```ts
|
|
463
|
+
chart.setOrderLots(lots: number): void // update default qty at runtime
|
|
464
|
+
```
|
|
465
|
+
|
|
466
|
+
### Viewport
|
|
467
|
+
|
|
468
|
+
```ts
|
|
469
|
+
chart.isAtLiveEdge(): boolean
|
|
470
|
+
```
|
|
471
|
+
|
|
472
|
+
### Streaming
|
|
473
|
+
|
|
474
|
+
```ts
|
|
475
|
+
chart.connectStream(adapter: IWebSocketAdapter): this
|
|
476
|
+
chart.disconnectStream(): this
|
|
477
|
+
chart.pushTick(tick: { time: number; bid: number; ask: number; volume?: number }): void // push a tick directly without an adapter
|
|
478
|
+
```
|
|
479
|
+
|
|
480
|
+
### State Persistence
|
|
481
|
+
|
|
482
|
+
```ts
|
|
483
|
+
// Capture the full current configuration as a serializable object
|
|
484
|
+
const state: ChartState = chart.getState();
|
|
485
|
+
// → { symbol, timeframe, duration, series, showVolume, theme, indicators[], drawings[] }
|
|
486
|
+
|
|
487
|
+
// Restore a previously saved state (call after construction, before loadData)
|
|
488
|
+
chart.setState(state);
|
|
489
|
+
```
|
|
490
|
+
|
|
491
|
+
Use together with the `stateChange` event to persist chart config per symbol:
|
|
492
|
+
|
|
493
|
+
```ts
|
|
494
|
+
import type { ChartState } from '@acttrader/stockchart';
|
|
495
|
+
|
|
496
|
+
chart.on('stateChange', ({ symbol, state }) => {
|
|
497
|
+
localStorage.setItem(`chart:${symbol}`, JSON.stringify(state));
|
|
498
|
+
});
|
|
499
|
+
|
|
500
|
+
// On init — restore if available
|
|
501
|
+
const saved = localStorage.getItem(`chart:${symbol}`);
|
|
502
|
+
if (saved) chart.setState(JSON.parse(saved) as ChartState);
|
|
503
|
+
```
|
|
504
|
+
|
|
505
|
+
### Lifecycle
|
|
506
|
+
|
|
507
|
+
```ts
|
|
508
|
+
chart.destroy(): void
|
|
509
|
+
```
|
|
510
|
+
|
|
511
|
+
---
|
|
512
|
+
|
|
513
|
+
## Built-in Indicators
|
|
514
|
+
|
|
515
|
+
### Trend / Price Overlay
|
|
516
|
+
|
|
517
|
+
| Class | Constructor defaults |
|
|
518
|
+
|---|---|
|
|
519
|
+
| `SMA(period?, color?)` | period 20 |
|
|
520
|
+
| `EMA(period?, color?)` | period 20 |
|
|
521
|
+
| `WMA(period?, color?)` | period 20 |
|
|
522
|
+
| `HMA(period?, color?)` | period 20 — Hull MA |
|
|
523
|
+
| `BollingerBands(period?, mult?, color?)` | 20, 2 |
|
|
524
|
+
| `KeltnerChannels(period?, mult?, color?)` | 20, 2 |
|
|
525
|
+
| `DonchianChannels(period?, color?)` | 20 |
|
|
526
|
+
| `IchimokuCloud(tenkan?, kijun?, senkou?, color?)` | 9, 26, 52 |
|
|
527
|
+
| `ParabolicSAR(step?, max?, color?)` | 0.02, 0.2 |
|
|
528
|
+
| `Supertrend(period?, mult?, color?)` | 10, 3 |
|
|
529
|
+
| `MARibbon(color?)` | 8 EMAs (10–80) |
|
|
530
|
+
| `PivotPoints(color?)` | Standard pivot levels |
|
|
531
|
+
| `FibRetracementIndicator(color?)` | Auto swing high/low |
|
|
532
|
+
| `HeikinAshi(color?)` | Heikin-Ashi candle overlay |
|
|
533
|
+
| `LinearRegression(period?, color?)` | Linear regression line overlay |
|
|
534
|
+
|
|
535
|
+
### Sub-pane Oscillators
|
|
536
|
+
|
|
537
|
+
| Class | Constructor defaults |
|
|
538
|
+
|---|---|
|
|
539
|
+
| `RSI(period?, color?)` | 14 |
|
|
540
|
+
| `MACD(fast?, slow?, signal?, color?)` | 12, 26, 9 |
|
|
541
|
+
| `Stochastic(kPeriod?, dPeriod?, color?)` | 14, 3 |
|
|
542
|
+
| `StochRSI(rsiPeriod?, stochPeriod?, kPeriod?, dPeriod?, color?)` | 14, 14, 3, 3 |
|
|
543
|
+
| `CCI(period?, color?)` | 20 |
|
|
544
|
+
| `WilliamsR(period?, color?)` | 14 |
|
|
545
|
+
| `ROC(period?, color?)` | 12 |
|
|
546
|
+
| `ATR(period?, color?)` | 14 |
|
|
547
|
+
| `ADX(period?, color?)` | 14 — includes +DI / -DI |
|
|
548
|
+
| `OBV(color?)` | On Balance Volume |
|
|
549
|
+
| `VWAP(color?)` | Intra-day weighted average |
|
|
550
|
+
| `AccDistribution(color?)` | Accumulation/Distribution |
|
|
551
|
+
| `MFI(period?, color?)` | 14 — Money Flow Index |
|
|
552
|
+
| `CMF(period?, color?)` | 20 — Chaikin Money Flow |
|
|
553
|
+
| `AwesomeOscillator(color?)` | 5 / 34 SMA difference |
|
|
554
|
+
| `VOL(color?)` | Volume oscillator sub-pane |
|
|
555
|
+
|
|
556
|
+
Sub-pane heights are user-resizable by dragging the separator between panes.
|
|
557
|
+
|
|
558
|
+
---
|
|
559
|
+
|
|
560
|
+
## Drawing Tools
|
|
561
|
+
|
|
562
|
+
### Lines & Channels
|
|
563
|
+
|
|
564
|
+
| Key | Tool | Placement |
|
|
565
|
+
|---|---|---|
|
|
566
|
+
| `horizontalLine` | Horizontal Line | Single click |
|
|
567
|
+
| `verticalLine` | Vertical Line | Single click |
|
|
568
|
+
| `trendLine` | Trend Line | 2 clicks |
|
|
569
|
+
| `trendAngle` | Trend Angle | 2 clicks (shows angle) |
|
|
570
|
+
| `crossLine` | Cross Line | Single click (H+V) |
|
|
571
|
+
| `parallelChannel` | Parallel Channel | 3 clicks |
|
|
572
|
+
| `flatChannel` | Flat Channel | 2 clicks |
|
|
573
|
+
| `disjointChannel` | Disjoint Channel | 3 clicks |
|
|
574
|
+
|
|
575
|
+
### Fibonacci & Gann
|
|
576
|
+
|
|
577
|
+
`fibRetracement` · `fibExtension` · `fibChannel` · `fibTimezone` · `fibCircles` · `fibSpiral` · `fibFan` · `fibProjection` · `gannFan` · `gannSquare` · `gannBox`
|
|
578
|
+
|
|
579
|
+
### Shapes
|
|
580
|
+
|
|
581
|
+
`rectangle` · `rotatedRectangle` · `ellipse` · `triangle` · `circle` · `arc` · `polyline` · `path` · `brush` · `highlighter`
|
|
582
|
+
|
|
583
|
+
### Measurements & Annotations
|
|
584
|
+
|
|
585
|
+
`priceRange` · `dateRange` · `datePriceRange` · `ruler` · `priceLabel` · `priceNote` · `priceProjection` · `projection` · `arrowUp` · `arrowDown` · `arrowMarker` · `text` · `callout` · `anchoredNote` · `flag` · `sineLine` · `regressionTrend` · `ghostFeed`
|
|
586
|
+
|
|
587
|
+
### Volume Profile
|
|
588
|
+
|
|
589
|
+
`volumeProfile` · `anchoredVP` · `fixedRangeVP`
|
|
590
|
+
|
|
591
|
+
### Cyclic & Time
|
|
592
|
+
|
|
593
|
+
`cyclicLines` · `timeCycles`
|
|
594
|
+
|
|
595
|
+
### Harmonic & Elliott Patterns
|
|
596
|
+
|
|
597
|
+
`abcdPattern` · `headShoulders` · `trianglePattern` · `batPattern` · `butterflyPattern` · `crabPattern` · `gartleyPattern` · `cypherPattern` · `sharkPattern` · `threeDrives` · `elliottImpulse` · `elliottCorrective` · `elliottTriangle` · `elliottCombination` · `elliottWxy`
|
|
598
|
+
|
|
599
|
+
### Pitchforks
|
|
600
|
+
|
|
601
|
+
`pitchfork` · `schiffPitchfork` · `modifiedSchiff` · `insidePitchfork`
|
|
602
|
+
|
|
603
|
+
---
|
|
604
|
+
|
|
605
|
+
## Events
|
|
606
|
+
|
|
607
|
+
```ts
|
|
608
|
+
chart.on('crosshair', ({ x, y, barIndex, price, bar }) => {});
|
|
609
|
+
chart.on('click', ({ x, y, barIndex, price, bar }) => {});
|
|
610
|
+
chart.on('zoom', ({ viewport }) => {});
|
|
611
|
+
chart.on('pan', ({ viewport }) => {});
|
|
612
|
+
chart.on('timeframeChange',({ timeframe }) => {});
|
|
613
|
+
chart.on('durationChange', ({ duration, timeframe }) => {});
|
|
614
|
+
chart.on('seriesChange', ({ series }) => {});
|
|
615
|
+
chart.on('streamStatus', ({ status }) => {}); // 'connected' | 'reconnecting' | 'disconnected'
|
|
616
|
+
chart.on('dataLoaded', ({ timeframe, interval, start, end }) => {});
|
|
617
|
+
chart.on('newBar', ({ completedBar, openingBar, intervalMs }) => {});
|
|
618
|
+
chart.on('stateChange', ({ symbol, state }) => {
|
|
619
|
+
// Fires after every user-driven config change (timeframe, series, theme,
|
|
620
|
+
// indicators, drawings, volume). `state` is a full serializable snapshot.
|
|
621
|
+
localStorage.setItem(`chart:${symbol}`, JSON.stringify(state));
|
|
622
|
+
});
|
|
623
|
+
|
|
624
|
+
// TFC events
|
|
625
|
+
chart.on('tradeLevelEdit', ({ label, type, data, changes }) => {});
|
|
626
|
+
chart.on('tradeLevelClose', ({ label, type, action, data }) => {});
|
|
627
|
+
chart.on('tradeLevelDragEnd', ({ label, type, newPrice, data }) => {}); // deprecated
|
|
628
|
+
chart.on('tradeLevelBracketDrag', ({ label, bracketType, newPrice, data }) => {}); // deprecated
|
|
629
|
+
chart.on('tradeLevelEditOpen', ({ label, type, price, side, stopLossPrice, takeProfitPrice, data }) => {});
|
|
630
|
+
chart.on('tradeLevelConfirmed',({ label, type }) => {});
|
|
631
|
+
```
|
|
632
|
+
|
|
633
|
+
---
|
|
634
|
+
|
|
635
|
+
## Custom Indicator
|
|
636
|
+
|
|
637
|
+
Implement `IIndicator` and pass it to `addIndicator()`:
|
|
638
|
+
|
|
639
|
+
```ts
|
|
640
|
+
import type { IIndicator, OHLCVBar, IndicatorResult } from '@acttrader/stockchart';
|
|
641
|
+
|
|
642
|
+
class MyIndicator implements IIndicator {
|
|
643
|
+
name = 'MyInd';
|
|
644
|
+
color = '#e91e63';
|
|
645
|
+
pane = 'sub' as const; // 'main' = overlay, 'sub' = dedicated pane
|
|
646
|
+
paneHeight = 80;
|
|
647
|
+
|
|
648
|
+
compute(data: OHLCVBar[]): IndicatorResult[] {
|
|
649
|
+
return data.map((bar, i) => ({ index: i, value: bar.close }));
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
render(ctx, results, scale, viewport, chartHeight) {
|
|
653
|
+
// draw with ctx (Canvas 2D)
|
|
654
|
+
}
|
|
655
|
+
}
|
|
656
|
+
|
|
657
|
+
chart.addIndicator(new MyIndicator());
|
|
658
|
+
```
|
|
659
|
+
|
|
660
|
+
---
|
|
661
|
+
|
|
662
|
+
## Build & Dev
|
|
663
|
+
|
|
664
|
+
```bash
|
|
665
|
+
npm run dev # Vite dev server with demo chart
|
|
666
|
+
npm run build # ESM + CJS via tsup → dist/
|
|
667
|
+
npm run test # Vitest unit tests
|
|
668
|
+
npm run typecheck # tsc --noEmit
|
|
669
|
+
npm run lint # ESLint
|
|
670
|
+
```
|
|
671
|
+
|
|
672
|
+
---
|
|
673
|
+
|
|
674
|
+
## License
|
|
675
|
+
|
|
676
|
+
MIT
|