@dwlf/charting 1.0.0 → 1.1.1

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.
Files changed (50) hide show
  1. package/README.md +225 -19
  2. package/dist/charting/__tests__/chartSpec.test.d.ts +1 -0
  3. package/dist/charting/scales.d.ts +14 -0
  4. package/dist/charting/types.d.ts +454 -0
  5. package/dist/charting.css +1 -1
  6. package/dist/components/DWLFChart.d.ts +119 -0
  7. package/dist/components/index.d.ts +2 -0
  8. package/dist/components/overlays/AlertLineAnnotationView.d.ts +14 -0
  9. package/dist/components/overlays/AnnotationLayer.d.ts +55 -0
  10. package/dist/components/overlays/ArrowAnnotationView.d.ts +24 -0
  11. package/dist/components/overlays/BosLineAnnotationView.d.ts +22 -0
  12. package/dist/components/overlays/BrushAnnotationView.d.ts +20 -0
  13. package/dist/components/overlays/ChannelAnnotationView.d.ts +23 -0
  14. package/dist/components/overlays/CrossLineAnnotationView.d.ts +29 -0
  15. package/dist/components/overlays/DiagonalLineOverlay.d.ts +31 -0
  16. package/dist/components/overlays/EmojiAnnotationView.d.ts +22 -0
  17. package/dist/components/overlays/FairValueGapAnnotationView.d.ts +23 -0
  18. package/dist/components/overlays/FibExtensionAnnotationView.d.ts +19 -0
  19. package/dist/components/overlays/FibRetracementAnnotationView.d.ts +19 -0
  20. package/dist/components/overlays/HLineAnnotationView.d.ts +15 -0
  21. package/dist/components/overlays/HorizontalLineOverlay.d.ts +23 -0
  22. package/dist/components/overlays/MarkerOverlay.d.ts +66 -0
  23. package/dist/components/overlays/MeasureAnnotationView.d.ts +25 -0
  24. package/dist/components/overlays/MessageBubbleOverlay.d.ts +55 -0
  25. package/dist/components/overlays/OrderBlockAnnotationView.d.ts +23 -0
  26. package/dist/components/overlays/PitchforkAnnotationView.d.ts +19 -0
  27. package/dist/components/overlays/PositionOverlay.d.ts +52 -0
  28. package/dist/components/overlays/RayAnnotationView.d.ts +30 -0
  29. package/dist/components/overlays/RectangleAnnotationView.d.ts +23 -0
  30. package/dist/components/overlays/SMAOverlay.d.ts +20 -0
  31. package/dist/components/overlays/TextAnnotationView.d.ts +24 -0
  32. package/dist/components/overlays/TimeRangeAnnotationView.d.ts +22 -0
  33. package/dist/components/overlays/TrendLineAnnotationView.d.ts +23 -0
  34. package/dist/components/overlays/VLineAnnotationView.d.ts +26 -0
  35. package/dist/components/overlays/annotationConstants.d.ts +21 -0
  36. package/dist/components/overlays/annotationUtils.d.ts +13 -0
  37. package/dist/components/overlays/useAnnotationDrag.d.ts +18 -0
  38. package/dist/components/overlays/usePointAnnotationDrag.d.ts +23 -0
  39. package/dist/hooks/useCandlestickChart.d.ts +18 -0
  40. package/dist/hooks/useChartAnimations.d.ts +49 -0
  41. package/dist/hooks/useChartLayout.d.ts +12 -0
  42. package/dist/hooks/useChartPanZoom.d.ts +7 -0
  43. package/dist/hooks/useChartPanZoomVirtual.d.ts +24 -0
  44. package/dist/hooks/useContainerSize.d.ts +4 -0
  45. package/dist/hooks/useOverlayToggles.d.ts +19 -0
  46. package/dist/index.cjs +1 -1
  47. package/dist/index.d.ts +56 -0
  48. package/dist/index.js +13 -13
  49. package/dist/utils/indicators.d.ts +40 -0
  50. package/package.json +4 -1
package/README.md CHANGED
@@ -22,17 +22,14 @@ import type { ChartSpec } from '@dwlf/charting';
22
22
  const spec: ChartSpec = {
23
23
  panes: [
24
24
  {
25
- height: 300,
25
+ id: 'price',
26
+ heightRatio: 3,
27
+ yScale: { mode: 'auto' },
26
28
  series: [
27
29
  {
30
+ key: 'candles',
28
31
  type: 'ohlc',
29
- data: candles.map(c => ({
30
- x: new Date(c.t * 1000).toISOString(),
31
- open: c.o,
32
- high: c.h,
33
- low: c.l,
34
- close: c.c,
35
- })),
32
+ data: candles, // array of { t, o, h, l, c }
36
33
  },
37
34
  ],
38
35
  },
@@ -40,22 +37,201 @@ const spec: ChartSpec = {
40
37
  };
41
38
 
42
39
  function MyChart() {
43
- return <DWLFChart spec={spec} />;
40
+ return <DWLFChart spec={spec} darkMode={true} enablePanZoom={true} />;
44
41
  }
45
42
  ```
46
43
 
44
+ ## Dark Mode
45
+
46
+ Dark mode is supported via the `darkMode` prop (defaults to `true`):
47
+
48
+ ```tsx
49
+ <DWLFChart spec={spec} darkMode={true} />
50
+ ```
51
+
52
+ This controls the background, text, grid, crosshair, tooltip, and candle colors automatically.
53
+
54
+ For further customisation, use `axisColors`:
55
+
56
+ ```tsx
57
+ <DWLFChart
58
+ spec={spec}
59
+ darkMode={true}
60
+ axisColors={{ dark: '#8b949e', light: '#57606a' }}
61
+ />
62
+ ```
63
+
64
+ ## Timestamps
65
+
66
+ **Important:** The charting library expects timestamps in **milliseconds** (Unix epoch in ms). If your data uses seconds (common in crypto APIs), multiply by 1000:
67
+
68
+ ```tsx
69
+ const chartData = candles.map(c => ({
70
+ t: c.t * 1000, // seconds → milliseconds
71
+ o: c.o,
72
+ h: c.h,
73
+ l: c.l,
74
+ c: c.c,
75
+ }));
76
+ ```
77
+
78
+ When pairing with `@dwlf/indicators`, note that indicator output uses the same timestamp format as input. If your source data uses seconds, the indicator output will too — convert when passing to the chart.
79
+
80
+ ## Series Configuration
81
+
82
+ Each pane contains an array of series. Every series needs a `key` (unique identifier), `type`, and `data`.
83
+
84
+ ### Series Types
85
+
86
+ | Type | Description | Data format |
87
+ |------|-------------|-------------|
88
+ | `ohlc` | Candlestick chart | `{ t, o, h, l, c }[]` |
89
+ | `line` | Line chart | `{ t, v }[]` |
90
+ | `hist` | Histogram bars | `{ t, v }[]` |
91
+ | `area` | Filled area | `{ t, v }[]` |
92
+ | `marker` | Point markers | `{ t, price, text?, tooltip?, shape? }[]` |
93
+ | `position` | Trade positions | `{ t, price, type, stopLoss?, takeProfit? }[]` |
94
+
95
+ ### Series Colors
96
+
97
+ Set colors with the `color` shorthand or `style.color` (both work):
98
+
99
+ ```tsx
100
+ // Shorthand
101
+ { key: 'ema8', type: 'line', data: ema8, color: '#58a6ff' }
102
+
103
+ // Full style object (takes precedence)
104
+ { key: 'ema8', type: 'line', data: ema8, style: { color: '#58a6ff', lineWidth: 2, dashed: true } }
105
+ ```
106
+
107
+ ### Style Options
108
+
109
+ ```tsx
110
+ interface SeriesStyle {
111
+ color?: string; // Series color
112
+ lineWidth?: number; // Line thickness (default: 1.5)
113
+ dashed?: boolean; // Dashed line
114
+ opacity?: number; // Opacity (0-1)
115
+ markerShape?: 'arrow-up' | 'arrow-down' | 'circle';
116
+ markerSize?: number;
117
+ }
118
+ ```
119
+
120
+ ## Multi-Pane Layout
121
+
122
+ Use `heightRatio` to control pane proportions:
123
+
124
+ ```tsx
125
+ const spec: ChartSpec = {
126
+ panes: [
127
+ {
128
+ id: 'price',
129
+ heightRatio: 3, // 75% of height
130
+ yScale: { mode: 'auto' },
131
+ series: [{ key: 'candles', type: 'ohlc', data: candles }],
132
+ },
133
+ {
134
+ id: 'dss',
135
+ heightRatio: 1, // 25% of height
136
+ yScale: { mode: 'fixed', min: 0, max: 100 },
137
+ series: [
138
+ { key: 'dss', type: 'line', data: dssData, color: '#22c55e' },
139
+ { key: 'signal', type: 'line', data: signalData, color: '#ef4444' },
140
+ ],
141
+ guides: [
142
+ { y: 80, dashed: true, label: 'OB', color: '#ef4444' },
143
+ { y: 20, dashed: true, label: 'OS', color: '#22c55e' },
144
+ ],
145
+ },
146
+ ],
147
+ };
148
+ ```
149
+
150
+ ## DWLFChart Props
151
+
152
+ | Prop | Type | Default | Description |
153
+ |------|------|---------|-------------|
154
+ | `spec` | `ChartSpec` | — | Chart specification (panes, series, guides) |
155
+ | `darkMode` | `boolean` | `true` | Dark/light theme |
156
+ | `enablePanZoom` | `boolean` | `false` | Enable scroll-to-zoom and drag-to-pan |
157
+ | `timeframe` | `string` | `'daily'` | Affects X-axis date formatting (`'daily'`, `'weekly'`, `'4h'`, `'1h'`) |
158
+ | `initialVisibleCount` | `number` | — | Number of candles visible initially (controls default zoom) |
159
+ | `extraRightSlots` | `number` | — | Extra padding on the right edge |
160
+ | `compressGaps` | `boolean` | `false` | Remove weekend/holiday gaps |
161
+ | `crosshairSnapMode` | `'series' \| 'pointer'` | `'series'` | `'pointer'` follows mouse freely, `'series'` snaps to nearest candle |
162
+ | `showCrosshairPriceLabel` | `boolean` | — | Show price label on crosshair |
163
+ | `axisColors` | `{ light?: string; dark?: string }` | — | Custom axis/crosshair colors |
164
+ | `annotations` | `Annotation[]` | — | Chart annotations (lines, text, fib, etc.) |
165
+ | `className` | `string` | — | CSS class on container |
166
+ | `style` | `CSSProperties` | — | Inline styles on container |
167
+ | `animationState` | `ChartAnimationState` | — | Control entry animations |
168
+
169
+ ## Crosshair Modes
170
+
171
+ By default the crosshair snaps to the nearest candle (`'series'` mode). Most traders prefer the crosshair to follow the mouse freely — use `'pointer'` mode:
172
+
173
+ ```tsx
174
+ <DWLFChart spec={spec} crosshairSnapMode="pointer" />
175
+ ```
176
+
177
+ | Mode | Behaviour |
178
+ |------|-----------|
179
+ | `'series'` (default) | Snaps to nearest candle — good for precise OHLC readouts |
180
+ | `'pointer'` | Follows mouse position freely — feels more natural for interactive use |
181
+
182
+ ## Pan & Zoom
183
+
184
+ Set `enablePanZoom={true}` to enable scroll-to-zoom and drag-to-pan. **This is off by default**, so the chart won't capture mouse scroll events unless you opt in.
185
+
186
+ ```tsx
187
+ <DWLFChart spec={spec} enablePanZoom={true} />
188
+ ```
189
+
190
+ If the chart is embedded in a scrollable page, be aware that `enablePanZoom` will capture scroll events over the chart area for zooming. You may want to place the chart in a fixed-height container so page scrolling still works outside the chart.
191
+
192
+ Use `initialVisibleCount` to control how many candles are visible on first render (the default shows all data):
193
+
194
+ ```tsx
195
+ <DWLFChart spec={spec} enablePanZoom={true} initialVisibleCount={100} />
196
+ ```
197
+
198
+ ## Right-Side Buffer
199
+
200
+ By default the chart fits data edge-to-edge. To add empty space on the right (useful for seeing the latest candle clearly or leaving room for annotations), use `extraRightSlots`:
201
+
202
+ ```tsx
203
+ <DWLFChart spec={spec} extraRightSlots={5} />
204
+ ```
205
+
206
+ This adds 5 candle-widths of empty space to the right of the last data point.
207
+
208
+ Alternatively, you can append placeholder candles to your data with the same timestamp spacing but no visible data — the chart will render the empty space naturally.
209
+
47
210
  ## Annotations
48
211
 
49
- 20+ built-in annotation types with drag-to-create and interactive editing:
212
+ 20+ built-in annotation types with creation helpers:
50
213
 
51
214
  ```tsx
52
- import { DWLFChart, AnnotationLayer, createHLineAnnotation } from '@dwlf/charting';
215
+ import {
216
+ DWLFChart,
217
+ AnnotationLayer,
218
+ createHLineAnnotation,
219
+ createTrendLineAnnotation,
220
+ createFibRetracementAnnotation,
221
+ } from '@dwlf/charting';
53
222
 
54
223
  const annotations = [
55
- createHLineAnnotation({ price: 150, label: 'Support' }),
56
- createTrendLineAnnotation({ time1, price1, time2, price2 }),
224
+ createHLineAnnotation({ price: 42000, label: 'Support', color: '#22c55e' }),
225
+ createTrendLineAnnotation({ time1, price1, time2, price2, color: '#3b82f6' }),
57
226
  createFibRetracementAnnotation({ time1, price1, time2, price2 }),
58
227
  ];
228
+
229
+ <DWLFChart
230
+ spec={spec}
231
+ annotations={annotations}
232
+ onAnnotationSelect={(id) => console.log('selected', id)}
233
+ onAnnotationMove={(id, update) => console.log('moved', id, update)}
234
+ />
59
235
  ```
60
236
 
61
237
  **Available annotations:** Horizontal Line, Vertical Line, Text, Trend Line, Ray, Cross Line, Rectangle, Channel, Fibonacci Retracement, Fibonacci Extension, Measure, Pitchfork, Arrow, Time Range, Alert Line, Brush, Emoji, Order Block, Fair Value Gap, BOS Line.
@@ -64,17 +240,47 @@ const annotations = [
64
240
 
65
241
  ```tsx
66
242
  import {
67
- useCandlestickChart,
68
- useChartPanZoom,
69
- useChartLayout,
70
- useContainerSize,
71
- useChartAnimations,
243
+ useCandlestickChart, // D3 scales and layout for candlestick data
244
+ useChartPanZoom, // Pan and zoom state management
245
+ useChartLayout, // Chart dimension calculations
246
+ useContainerSize, // Responsive container sizing
247
+ useChartAnimations, // Entry animation orchestration
248
+ useOverlayToggles, // Overlay visibility management
72
249
  } from '@dwlf/charting';
73
250
  ```
74
251
 
252
+ ## Using with @dwlf/indicators
253
+
254
+ Fetch candles from your data source, compute indicators, render:
255
+
256
+ ```tsx
257
+ import { EMA, Bollinger, DSS } from '@dwlf/indicators';
258
+ import { DWLFChart } from '@dwlf/charting';
259
+ import '@dwlf/charting/styles';
260
+
261
+ // Compute indicators (timestamps must match your candle timestamps)
262
+ const ema8 = EMA.computeEMA(candles, 8);
263
+ const bb = Bollinger.computeBollingerBands(candles, { length: 20 });
264
+
265
+ // Build chart spec — remember to convert timestamps to milliseconds
266
+ const spec = {
267
+ panes: [{
268
+ id: 'price',
269
+ heightRatio: 1,
270
+ yScale: { mode: 'auto' },
271
+ series: [
272
+ { key: 'candles', type: 'ohlc', data: candles.map(c => ({ ...c, t: c.t * 1000 })) },
273
+ { key: 'ema8', type: 'line', data: ema8.ema.map(p => ({ t: p.t * 1000, v: p.v })), color: '#58a6ff' },
274
+ { key: 'bb-upper', type: 'line', data: bb.upper.map(p => ({ t: p.t * 1000, v: p.v })), color: '#8b949e', style: { dashed: true } },
275
+ { key: 'bb-lower', type: 'line', data: bb.lower.map(p => ({ t: p.t * 1000, v: p.v })), color: '#8b949e', style: { dashed: true } },
276
+ ],
277
+ }],
278
+ };
279
+ ```
280
+
75
281
  ## Used By
76
282
 
77
- This is the same charting engine that powers [DWLF](https://dwlf.co.uk) — a market intelligence platform for traders. The strategy builders, backtesting UI, and analytics dashboards that sit on top of this library are available via the DWLF platform.
283
+ This is the same charting engine that powers [DWLF](https://dwlf.co.uk) — a market intelligence platform for AI agents and traders.
78
284
 
79
285
  ## License
80
286
 
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,14 @@
1
+ import { ChartSpec, LinePoint, OhlcPoint, PaneComputedScale, PaneSpec, SeriesSpec } from './types';
2
+ export type ResolvePaneDomainOptions = {
3
+ includeOverlaysInAutoScale?: boolean;
4
+ };
5
+ export declare const resolvePaneDomain: (pane: PaneSpec, options?: ResolvePaneDomainOptions) => [number, number];
6
+ export declare const createPaneScale: (domain: [number, number], height: number) => PaneComputedScale;
7
+ export type BuildPaneScalesOptions = {
8
+ includeOverlaysInAutoScale?: boolean;
9
+ };
10
+ export declare const buildPaneScales: (spec: ChartSpec, paneHeights: Record<string, number>, options?: BuildPaneScalesOptions) => Record<string, PaneComputedScale>;
11
+ export declare const collectPaneTimes: (pane: PaneSpec) => number[];
12
+ export declare const collectSpecTimes: (spec: ChartSpec) => number[];
13
+ export declare const findClosestTime: (times: number[], value: number) => number;
14
+ export type { LinePoint, OhlcPoint, PaneSpec, SeriesSpec };