@christtrade/depth 0.19.0 → 0.20.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 +175 -96
- package/depth.cjs +56 -56
- package/depth.css +1 -1
- package/depth.mjs +56 -56
- package/depth.nopreflight.css +1 -1
- package/package.json +1 -1
- package/types/components/ui/resizable.d.ts +1 -1
- package/types/core/BarStore.d.ts +69 -0
- package/types/core/DataEngine.d.ts +15 -2
- package/types/core/DepthChart.d.ts +1 -1
- package/types/core/ExecutionEngine.d.ts +3 -2
- package/types/core/RenderEngine.d.ts +2 -9
- package/types/core/TypedEventBus.d.ts +10 -9
- package/types/core/index.d.ts +1 -0
- package/types/hooks/useChartData.d.ts +11 -9
- package/types/hooks/useChartHandlers.d.ts +5 -4
- package/types/hooks/useChartInteraction.d.ts +5 -4
- package/types/hooks/useChartSettings.d.ts +5 -4
- package/types/hooks/useChartSubscriptions.d.ts +5 -4
- package/types/hooks/useChartView.d.ts +5 -4
- package/types/interfaces/plugins/IChartPlugin.d.ts +13 -2
- package/types/interfaces/plugins/IDrawingPlugin.d.ts +2 -2
- package/types/lib/matchingEngine.d.ts +3 -2
- package/types/lib/renderers/renderer.d.ts +5 -28
package/README.md
CHANGED
|
@@ -1,25 +1,17 @@
|
|
|
1
1
|
<h1>ChristTrade Depth</h1>
|
|
2
2
|
|
|
3
|
-
A
|
|
4
|
-
|
|
3
|
+
A trading chart for React: canvas rendering, a plugin and scripting runtime,
|
|
4
|
+
a strategy backtester, and a local L3 matching engine. It's the chart behind
|
|
5
|
+
[ChristTrade](https://christtrade.com).
|
|
5
6
|
|
|
6
|
-
Depth
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
settings. You give it a data adapter and a container with a height, and you have
|
|
10
|
-
a trading terminal.
|
|
7
|
+
Depth ships the whole terminal, not drawing primitives: toolbar, symbol
|
|
8
|
+
switcher, drawing tools, indicators, order ticket, playback and settings. You
|
|
9
|
+
pass it an `IDataAdapter` and a container with a height.
|
|
11
10
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
lightweight plotting library. If you want 45 KB that draws a line, Depth is the
|
|
17
|
-
wrong tool and [Lightweight Charts](https://github.com/tradingview/lightweight-charts)
|
|
18
|
-
is a good one. If you want the thing your users already know how to use, keep
|
|
19
|
-
reading.
|
|
20
|
-
|
|
21
|
-
React 18 or 19 is the only runtime dependency you install. Everything else -
|
|
22
|
-
Radix, Lucide, Luxon, the workers, the fonts - is compiled in.
|
|
11
|
+
`depth.mjs` is ~1.2 MB minified. React 18 or 19 is the only peer dependency;
|
|
12
|
+
Radix, Lucide, Luxon, the workers and the fonts are bundled. If you need a 45 KB
|
|
13
|
+
line plotter, use [Lightweight Charts](https://github.com/tradingview/lightweight-charts)
|
|
14
|
+
instead.
|
|
23
15
|
|
|
24
16
|
## Install
|
|
25
17
|
|
|
@@ -30,8 +22,8 @@ npm i react react-dom # if you don't already have them
|
|
|
30
22
|
|
|
31
23
|
## Quick start
|
|
32
24
|
|
|
33
|
-
`SimulatedMarketAdapter` generates synthetic
|
|
34
|
-
|
|
25
|
+
`SimulatedMarketAdapter` generates synthetic data, so this runs without a data
|
|
26
|
+
source:
|
|
35
27
|
|
|
36
28
|
```jsx
|
|
37
29
|
import { useDepthChart, SimulatedMarketAdapter } from '@christtrade/depth';
|
|
@@ -48,110 +40,197 @@ export default function MyChart() {
|
|
|
48
40
|
start: Date.now() - 1000 * 60 * 60 * 24,
|
|
49
41
|
end: Date.now(),
|
|
50
42
|
},
|
|
51
|
-
// additional options...
|
|
52
43
|
});
|
|
53
44
|
|
|
54
45
|
return <div style={{ width: '100%', height: '100%' }}>{element}</div>;
|
|
55
46
|
}
|
|
56
47
|
```
|
|
57
48
|
|
|
58
|
-
`element` is the chart. `chart` is the controller
|
|
59
|
-
drawings, plugins,
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
-
|
|
65
|
-
|
|
66
|
-
-
|
|
67
|
-
|
|
68
|
-
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
-
|
|
85
|
-
|
|
86
|
-
- **Multi-pane and multi-chart layouts**, with synced crosshairs.
|
|
87
|
-
- **Playback** - scrub, step, and replay historical sessions bar by bar.
|
|
88
|
-
- **Trading** - order ticket, quick-trade buttons, position and P&L rendering,
|
|
49
|
+
`element` is the chart. `chart` is the controller: timeframes, symbols,
|
|
50
|
+
drawings, plugins, `serialize()` / `restore()`. Types ship with the package.
|
|
51
|
+
|
|
52
|
+
### Setup gotchas
|
|
53
|
+
|
|
54
|
+
- The chart fills its container. `height: auto` collapses it to 0.
|
|
55
|
+
- Dark mode is a `dark` class on any ancestor or on `<html>`. Without it you
|
|
56
|
+
get the light theme.
|
|
57
|
+
- `depth.css` includes Tailwind preflight (a CSS reset). If it fights your
|
|
58
|
+
styles, import `@christtrade/depth/depth.nopreflight.css` instead.
|
|
59
|
+
- Workers are embedded as blob URLs, so a strict CSP needs `worker-src blob:`.
|
|
60
|
+
- From `npm create vite`: add `class="dark"` to `<html>` and drop
|
|
61
|
+
`import './index.css'` from `main.jsx`. The template centres and pads
|
|
62
|
+
`#root`.
|
|
63
|
+
|
|
64
|
+
## Features
|
|
65
|
+
|
|
66
|
+
- Chart types: candles, hollow candles, Heikin-Ashi, bars, line, area, step,
|
|
67
|
+
baseline, and footprint on L3 data. Plugins can register more.
|
|
68
|
+
- Drawing tools: trend line, ray, extended line, horizontal and vertical
|
|
69
|
+
lines and rays, cross line, info line, trend angle, parallel channel, Fib
|
|
70
|
+
retracement, rectangle, triangle, text, long/short position and fixed
|
|
71
|
+
volume profile.
|
|
72
|
+
- 21 built-in indicators, written against the same plugin API third parties
|
|
73
|
+
get.
|
|
74
|
+
- Multi-pane and multi-chart layouts with synced crosshairs.
|
|
75
|
+
- Playback: scrub, step and replay sessions bar by bar.
|
|
76
|
+
- Trading: order ticket, quick-trade buttons, positions and P&L on the chart,
|
|
89
77
|
and a local L3 matching engine with real fee schedules for simulated fills.
|
|
90
|
-
-
|
|
91
|
-
|
|
92
|
-
|
|
78
|
+
- Sessions: trading hours, holidays and subsessions. Closed time is cut out
|
|
79
|
+
of the x axis.
|
|
80
|
+
- Themes: built-in dark and light themes, or register your own.
|
|
93
81
|
|
|
94
|
-
##
|
|
82
|
+
## Architecture
|
|
95
83
|
|
|
96
|
-
|
|
84
|
+
### Data
|
|
97
85
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
86
|
+
An `IDataAdapter` implements `resolveSymbol`, `searchSymbols` and
|
|
87
|
+
`fetchBars`, plus optional `subscribeRealtime` and `getCapabilities`. Each
|
|
88
|
+
adapter declares the data level it serves:
|
|
89
|
+
|
|
90
|
+
| Level | Data | Also serves |
|
|
91
|
+
| --- | --- | --- |
|
|
92
|
+
| `l3` | MBO events | `tick`, `ohlcv`, `l2` |
|
|
93
|
+
| `tick` | trades | `ohlcv` |
|
|
94
|
+
| `ohlcv` | bars | |
|
|
95
|
+
| `l2` | book snapshots | |
|
|
96
|
+
|
|
97
|
+
A plugin or feature declares the level it needs, and on a symbol that can't
|
|
98
|
+
serve it, it's refused with a reason instead of breaking. The chunk processors
|
|
99
|
+
(`processOhlcvChunk`, `processTickChunk`, `processL2Chunk`, `processL3Chunk`)
|
|
100
|
+
are exported, so an adapter doesn't reimplement aggregation. Plugins can add
|
|
101
|
+
data sources at runtime with `registerDataSource`, which is how
|
|
102
|
+
bring-your-own-API-key providers work.
|
|
103
|
+
|
|
104
|
+
The `DataEngine` keeps one store per symbol and pages history in as you pan.
|
|
105
|
+
Every chart on that symbol reads the same store.
|
|
106
|
+
|
|
107
|
+
### Storage
|
|
108
|
+
|
|
109
|
+
OHLCV lives in a `BarStore`: six `Float64Array` columns (`time`, `open`,
|
|
110
|
+
`high`, `low`, `close`, `volume`, plus bid/ask once a bar has them), sorted by
|
|
111
|
+
`time`.
|
|
112
|
+
|
|
113
|
+
- 48 bytes a bar. A `{ time, open, high, low, close, volume }` object is ~176,
|
|
114
|
+
and each one is something for the GC to walk.
|
|
115
|
+
- Capacity doubles on growth, and the spare room is split between both ends,
|
|
116
|
+
so append and prepend are amortized O(bars added). Paging history in never
|
|
117
|
+
copies what's loaded.
|
|
118
|
+
- `lowerBound` / `upperBound` binary search on `time`.
|
|
119
|
+
- When a chart's timeframe is the resolution the data came in at, the chart
|
|
120
|
+
draws from the engine's store directly. Other timeframes get one
|
|
121
|
+
aggregated copy.
|
|
122
|
+
|
|
123
|
+
The column views are replaced when the store grows. Read `bars.close` off the
|
|
124
|
+
store each time, and key caches on `bars.version`, which bumps on every
|
|
125
|
+
mutation.
|
|
126
|
+
|
|
127
|
+
L3 events are packed into 20 bytes each in a `CompactBuffer` (BigInt64
|
|
128
|
+
timestamp, int32 price, uint32 size, uint24 order id, packed action/side), so
|
|
129
|
+
30M events take ~600 MB instead of ~5 GB as objects.
|
|
130
|
+
|
|
131
|
+
### Rendering
|
|
132
|
+
|
|
133
|
+
Four stacked canvases: `background`, `base` (candles, grid, indicators),
|
|
134
|
+
`drawings` and `ui` (crosshair, axis labels, price pills). One rAF loop paints
|
|
135
|
+
only the layers marked dirty, so an idle chart costs close to nothing.
|
|
136
|
+
|
|
137
|
+
Time is BigInt nanoseconds. `SessionMapper` maps real time to "market time",
|
|
138
|
+
with closed sessions taken out, and the transformer maps that to pixels.
|
|
139
|
+
|
|
140
|
+
Per frame, drawing is O(visible bars), and lookups by time (status line,
|
|
141
|
+
magnet snap, y-axis autofit) are O(log n) in loaded bars.
|
|
142
|
+
|
|
143
|
+
### Workers
|
|
101
144
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
145
|
+
- `script.worker`: user scripts and strategies, off the main thread.
|
|
146
|
+
- `slice.worker`: decodes L3 ranges and merges history pages.
|
|
147
|
+
- `heatmap.worker`: builds book snapshots and renders the depth heatmap to an
|
|
148
|
+
`OffscreenCanvas`.
|
|
149
|
+
- An indicator worker for heavy indicator math.
|
|
107
150
|
|
|
108
|
-
|
|
109
|
-
|
|
151
|
+
## Performance
|
|
152
|
+
|
|
153
|
+
Ryzen 5 7500F, Chrome, 1m bars.
|
|
154
|
+
|
|
155
|
+
- 1M bars loaded, ~300 on screen: panning holds 240fps. Draw, status line,
|
|
156
|
+
autofit and snap cost the same as with 20k loaded (see the perf guard
|
|
157
|
+
below).
|
|
158
|
+
- Heap with 1M bars loaded, in ChristTrade: ~480 MB.
|
|
159
|
+
- Backtest over 2M bars (~4 years of BTC 1m) through the script worker:
|
|
160
|
+
207-265ms. Stats are running (Welford) and the equity curve is capped, so
|
|
161
|
+
it holds ~1.1 MB at 2M bars.
|
|
162
|
+
- `processL3Chunk`: ~1.5M MBO events/sec on synthetic data.
|
|
163
|
+
|
|
164
|
+
### Perf guard
|
|
165
|
+
|
|
166
|
+
`npm run perf:guard` runs in CI. It bundles the draw, status line, autofit,
|
|
167
|
+
snap and prepend paths with esbuild, times each at 20k and at 1M loaded bars
|
|
168
|
+
with ~300 on screen, drawing to a no-op canvas, and fails if any is 5x slower
|
|
169
|
+
at 1M, or if a `BarStore` paged in to 1M bars takes more than 72 bytes a bar
|
|
170
|
+
including spare capacity:
|
|
171
|
+
|
|
172
|
+
```
|
|
173
|
+
ok draw candles 118.0µs -> 85.4µs 0.7x
|
|
174
|
+
ok status line 0.8µs -> 0.9µs 1.1x
|
|
175
|
+
ok autofit 2.0µs -> 1.9µs 1.0x
|
|
176
|
+
ok magnet snap 1.0µs -> 0.9µs 0.9x
|
|
177
|
+
ok page prepend 0.96ms -> 1.04ms 1.1x
|
|
178
|
+
ok bytes/bar 66.7 at 1M, spare room included (max 72)
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
Left column is 20k bars, right is 1M.
|
|
110
182
|
|
|
111
183
|
## Plugins
|
|
112
184
|
|
|
113
|
-
Plugins are
|
|
114
|
-
[christtrade.com](https://christtrade.com)
|
|
115
|
-
|
|
116
|
-
and
|
|
185
|
+
Plugins are JavaScript modules, or scripts written in the built-in editor on
|
|
186
|
+
[christtrade.com](https://christtrade.com). They can add indicators, chart
|
|
187
|
+
types, drawing tools, panels, toolbar items, data sources and render overlays,
|
|
188
|
+
and can offload heavy math to WebAssembly.
|
|
117
189
|
|
|
118
|
-
A plugin declares the capabilities and network origins it needs, and `ctx`
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
plugins run in your app.
|
|
190
|
+
A plugin declares the capabilities and network origins it needs, and `ctx`
|
|
191
|
+
only exposes those, so you can show a user what a plugin wants before it
|
|
192
|
+
runs. It isn't a sandbox: plugin code runs in your page. Read
|
|
193
|
+
[SECURITY.md](SECURITY.md) before running other people's plugins.
|
|
123
194
|
|
|
124
|
-
|
|
125
|
-
|
|
195
|
+
Strategies run in the script worker. `StrategyEngine` does intrabar fills,
|
|
196
|
+
parameter sweeps and walk-forward analysis.
|
|
197
|
+
|
|
198
|
+
Full docs: [docs.christtrade.com/depth](https://docs.christtrade.com/depth).
|
|
199
|
+
|
|
200
|
+
## Development
|
|
201
|
+
|
|
202
|
+
```bash
|
|
203
|
+
npm test # node:test via tsx
|
|
204
|
+
npm run perf:guard
|
|
205
|
+
npx tsc -p tsconfig.json --noEmit
|
|
206
|
+
npm run dist # build dist/, smoke test it
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
CI runs tests, typecheck and the perf guard on Node 20 and 22.
|
|
126
210
|
|
|
127
211
|
## Status
|
|
128
212
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
library becomes usable.
|
|
213
|
+
Pre-1.0. It runs in production at ChristTrade, but the public API still
|
|
214
|
+
moves and minor versions can break it. 1.0 is the API freeze. Breaking changes
|
|
215
|
+
are marked in [CHANGELOG.md](CHANGELOG.md).
|
|
133
216
|
|
|
134
217
|
## Contributing
|
|
135
218
|
|
|
136
|
-
|
|
137
|
-
all help, and I read them.
|
|
219
|
+
Issues are welcome: bug reports, reproductions, API questions.
|
|
138
220
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
221
|
+
Pull requests are by invitation. Depth is a single-author library. If you
|
|
222
|
+
found something broken, open an issue, and if a PR is the right fix I'll ask
|
|
223
|
+
for one. Unsolicited PRs usually get closed and reopened as issues, which
|
|
224
|
+
isn't a comment on the code.
|
|
143
225
|
|
|
144
226
|
## Attribution
|
|
145
227
|
|
|
146
|
-
Depth draws a small ChristTrade mark in the corner of the chart.
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
otherwise - you can remove it and you'll be within your rights. I'm asking you
|
|
150
|
-
not to. The mark is the only thing this library asks in return for being free,
|
|
151
|
-
and it's how people find it.
|
|
228
|
+
Depth draws a small ChristTrade mark in the corner of the chart. Apache-2.0
|
|
229
|
+
doesn't require you to keep it, and you can remove it. I'm asking you not to:
|
|
230
|
+
it's the only thing the library asks for, and it's how people find it.
|
|
152
231
|
|
|
153
|
-
The name is
|
|
154
|
-
|
|
232
|
+
The name is separate. Apache-2.0 grants no trademark rights (section 6), so
|
|
233
|
+
you can fork Depth but can't ship it as "ChristTrade Depth". See
|
|
155
234
|
[NOTICE](NOTICE).
|
|
156
235
|
|
|
157
236
|
## License
|