openalgo-charts 1.0.13 → 1.0.14
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/dist/draw/index.d.ts +27 -1841
- package/dist/index.d.ts +2 -2
- package/dist/openalgo-charts.draw.mjs.map +1 -1
- package/dist/openalgo-charts.mjs +1 -1
- package/dist/openalgo-charts.standalone.js +1 -1
- package/dist/profile/index.d.ts +2 -332
- package/dist/trade/index.d.ts +2 -347
- package/package.json +4 -3
package/dist/draw/index.d.ts
CHANGED
|
@@ -1,360 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
from: number;
|
|
3
|
-
to: number;
|
|
4
|
-
}
|
|
5
|
-
interface TimeScaleOptions {
|
|
6
|
-
barSpacing: number;
|
|
7
|
-
minBarSpacing: number;
|
|
8
|
-
maxBarSpacing: number;
|
|
9
|
-
/** Empty bars of space kept to the right of the latest bar. */
|
|
10
|
-
rightOffset: number;
|
|
11
|
-
}
|
|
12
|
-
declare class TimeScale {
|
|
13
|
-
private _barSpacing;
|
|
14
|
-
private _rightOffset;
|
|
15
|
-
private readonly _minBarSpacing;
|
|
16
|
-
private readonly _maxBarSpacing;
|
|
17
|
-
private _width;
|
|
18
|
-
private _baseIndex;
|
|
19
|
-
constructor(options?: Partial<TimeScaleOptions>);
|
|
20
|
-
setWidth(width: number): void;
|
|
21
|
-
get width(): number;
|
|
22
|
-
get barSpacing(): number;
|
|
23
|
-
setBarSpacing(value: number): void;
|
|
24
|
-
get rightOffset(): number;
|
|
25
|
-
setRightOffset(value: number): void;
|
|
26
|
-
/** Logical index of the latest bar; the right edge anchors to baseIndex+rightOffset. */
|
|
27
|
-
setBaseIndex(index: number): void;
|
|
28
|
-
private _rightEdgeIndex;
|
|
29
|
-
/** Logical index → x (media px), bar center. */
|
|
30
|
-
indexToX(index: number): number;
|
|
31
|
-
/** x (media px) → fractional logical index. */
|
|
32
|
-
xToIndex(x: number): number;
|
|
33
|
-
/** Currently visible logical index range (fractional, unclamped to data). */
|
|
34
|
-
visibleRange(): LogicalRange;
|
|
35
|
-
/** Alias of `visibleRange()` for naming parity with common charting APIs. */
|
|
36
|
-
getVisibleLogicalRange(): LogicalRange;
|
|
37
|
-
/**
|
|
38
|
-
* Set the visible logical range (best effort): pick a bar spacing so the span
|
|
39
|
-
* fills the width and anchor the right edge at `range.to`. Bar spacing is
|
|
40
|
-
* clamped to [min,max], so an extreme span lands at the nearest zoom. Fires the
|
|
41
|
-
* change handler so a host that mutates the scale directly still repaints.
|
|
42
|
-
*/
|
|
43
|
-
setVisibleLogicalRange(range: LogicalRange): void;
|
|
44
|
-
/** Repaint hook injected by the host chart, fired after `setVisibleLogicalRange`. */
|
|
45
|
-
setChangeHandler(fn: (() => void) | null): void;
|
|
46
|
-
private _onChange;
|
|
47
|
-
/**
|
|
48
|
-
* Pan by a pixel delta. Positive `dx` drags chart content to the right
|
|
49
|
-
* (revealing older bars), matching a natural left-button drag.
|
|
50
|
-
*/
|
|
51
|
-
scrollByPixels(dx: number): void;
|
|
52
|
-
/**
|
|
53
|
-
* Zoom around an anchor x (the cursor): change bar spacing by `factor`
|
|
54
|
-
* while keeping whatever logical index sits under `focusX` pinned there.
|
|
55
|
-
* `factor` > 1 zooms in (wider bars).
|
|
56
|
-
*/
|
|
57
|
-
zoomAtX(focusX: number, factor: number): void;
|
|
58
|
-
/** Choose bar spacing so `barCount` bars fit the width, anchored at the right edge. */
|
|
59
|
-
fitContent(barCount: number): void;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
interface PriceRange {
|
|
63
|
-
min: number;
|
|
64
|
-
max: number;
|
|
65
|
-
}
|
|
66
|
-
/**
|
|
67
|
-
* Price-scale mode. `linear` and `logarithmic` are full coordinate transforms;
|
|
68
|
-
* `percentage`/`indexed-to-100` (rebase to a baseline) and overlay scales are
|
|
69
|
-
* not yet implemented (see the README known limitations).
|
|
70
|
-
*/
|
|
71
|
-
type PriceScaleMode = 'linear' | 'logarithmic';
|
|
72
|
-
interface PriceScaleOptions {
|
|
73
|
-
/** Fraction of pane height kept empty at top/bottom (default 0.1 each). */
|
|
74
|
-
marginTop: number;
|
|
75
|
-
marginBottom: number;
|
|
76
|
-
/** Instrument tick size (minMove), e.g. 0.05. 0 → infer from range. */
|
|
77
|
-
minMove: number;
|
|
78
|
-
/** Linear or logarithmic price↔y mapping. */
|
|
79
|
-
mode: PriceScaleMode;
|
|
80
|
-
/** Flip the axis (price increases downward) — for spread/short views. */
|
|
81
|
-
inverted: boolean;
|
|
82
|
-
}
|
|
83
|
-
declare class PriceScale {
|
|
84
|
-
private _options;
|
|
85
|
-
private _height;
|
|
86
|
-
private _min;
|
|
87
|
-
private _max;
|
|
88
|
-
private _autoScale;
|
|
89
|
-
/**
|
|
90
|
-
* True once a real range has been applied. The default 0..1 is a placeholder,
|
|
91
|
-
* not a measurement — anything converting y↔price before that would answer
|
|
92
|
-
* confidently with nonsense.
|
|
93
|
-
*/
|
|
94
|
-
private _scaled;
|
|
95
|
-
private _priceFormatter;
|
|
96
|
-
constructor(options?: Partial<PriceScaleOptions>);
|
|
97
|
-
get options(): PriceScaleOptions;
|
|
98
|
-
/** Merge partial options (minMove, mode, inverted, margins) at runtime. */
|
|
99
|
-
setOptions(opts: Partial<PriceScaleOptions>): void;
|
|
100
|
-
setHeight(height: number): void;
|
|
101
|
-
get height(): number;
|
|
102
|
-
setPriceRange(range: PriceRange): void;
|
|
103
|
-
/** Whether a real price range has been applied (see `_scaled`). */
|
|
104
|
-
get scaled(): boolean;
|
|
105
|
-
priceRange(): PriceRange;
|
|
106
|
-
/** Whether the range tracks the data (true) or has been set manually (false). */
|
|
107
|
-
get autoScale(): boolean;
|
|
108
|
-
setAutoScale(on: boolean): void;
|
|
109
|
-
/**
|
|
110
|
-
* Manually scale the visible range around its centre. `factor` > 1 widens the
|
|
111
|
-
* range (compress / zoom out), < 1 narrows it (expand / zoom in). Switches the
|
|
112
|
-
* scale to manual mode so autoscale stops overriding it.
|
|
113
|
-
*/
|
|
114
|
-
scaleAroundCenter(factor: number): void;
|
|
115
|
-
/**
|
|
116
|
-
* Pan the visible range vertically by `dy` media px (dragging the plot up/down).
|
|
117
|
-
* Works in transformed space so it's correct for log scales, and respects
|
|
118
|
-
* `inverted`. Switches to manual mode so autoscale stops overriding it.
|
|
119
|
-
*/
|
|
120
|
-
panByPixels(dy: number): void;
|
|
121
|
-
/** Recompute the visible range from data extremes + configured margins. */
|
|
122
|
-
autoscale(low: number, high: number): void;
|
|
123
|
-
/** Coordinate transform for the active mode (identity for linear, log10 for log). */
|
|
124
|
-
private _t;
|
|
125
|
-
private _tInv;
|
|
126
|
-
/** Price → y (media px). Higher price → smaller y (top of pane), unless inverted. */
|
|
127
|
-
priceToY(price: number): number;
|
|
128
|
-
/** y (media px) → price. */
|
|
129
|
-
yToPrice(y: number): number;
|
|
130
|
-
/** Decimal precision implied by minMove (or the visible range if unset). */
|
|
131
|
-
precision(): number;
|
|
132
|
-
/** Snap a price to the instrument tick size (no-op if minMove is 0). */
|
|
133
|
-
snapToTick(price: number): number;
|
|
134
|
-
/**
|
|
135
|
-
* Override the numeric formatting used for axis tick labels, the last-price
|
|
136
|
-
* tag, and price-line labels (e.g. a currency or percent format). Pass null
|
|
137
|
-
* to restore the default tick-size-aware `toFixed`.
|
|
138
|
-
*/
|
|
139
|
-
setPriceFormatter(fn: ((price: number) => string) | null): void;
|
|
140
|
-
/** Format a price for axis/label display. */
|
|
141
|
-
format(price: number): string;
|
|
142
|
-
/** Clamp a y to the pane (used by crosshair/order dragging). */
|
|
143
|
-
clampY(y: number): number;
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
/**
|
|
147
|
-
* Internal time is always **UTC seconds** (integer). Feed adapters convert
|
|
148
|
-
* broker formats (IST strings, epoch ms) to this at the edge; see ARCHITECTURE.md §4.0.
|
|
149
|
-
*/
|
|
150
|
-
type UTCSeconds = number;
|
|
151
|
-
/** A single OHLC(V) bar. `volume` is optional (not all feeds carry it). */
|
|
152
|
-
interface Bar {
|
|
153
|
-
time: UTCSeconds;
|
|
154
|
-
open: number;
|
|
155
|
-
high: number;
|
|
156
|
-
low: number;
|
|
157
|
-
close: number;
|
|
158
|
-
volume?: number;
|
|
159
|
-
}
|
|
160
|
-
/** A single value point (for line/area/baseline series). */
|
|
161
|
-
interface LinePoint {
|
|
162
|
-
time: UTCSeconds;
|
|
163
|
-
value: number;
|
|
164
|
-
}
|
|
165
|
-
/** A whitespace point: occupies a logical index for alignment but draws nothing. */
|
|
166
|
-
interface Whitespace {
|
|
167
|
-
time: UTCSeconds;
|
|
168
|
-
}
|
|
169
|
-
/** Any item a series accepts: an OHLC bar, a value point, or a whitespace gap. */
|
|
170
|
-
type SeriesDataItem = Bar | LinePoint | Whitespace;
|
|
171
|
-
|
|
172
|
-
/**
|
|
173
|
-
* Shared data layer (ARCHITECTURE.md §4.1). One per chart. Merges all series by
|
|
174
|
-
* time onto a single logical-index space (0..N-1) so price + volume + indicator
|
|
175
|
-
* panes stay aligned, and so non-trading gaps collapse (an absent time simply
|
|
176
|
-
* has no logical index). Per-series rows are addressable by that shared index.
|
|
177
|
-
*/
|
|
178
|
-
|
|
179
|
-
type SeriesId = number;
|
|
180
|
-
interface IndexedBar {
|
|
181
|
-
index: number;
|
|
182
|
-
bar: Bar;
|
|
183
|
-
}
|
|
184
|
-
declare class DataLayer {
|
|
185
|
-
private readonly _series;
|
|
186
|
-
private _sortedTimes;
|
|
187
|
-
private readonly _indexByTime;
|
|
188
|
-
private _nextId;
|
|
189
|
-
/** Register a new series; returns its id. */
|
|
190
|
-
createSeries(): SeriesId;
|
|
191
|
-
removeSeries(id: SeriesId): void;
|
|
192
|
-
/**
|
|
193
|
-
* Bulk-load (full replace) one series' data, then re-merge the time axis.
|
|
194
|
-
* Input is sorted and de-duplicated by time (see {@link sortedUniqueByTime}).
|
|
195
|
-
*/
|
|
196
|
-
setSeriesData(id: SeriesId, bars: readonly Bar[]): void;
|
|
197
|
-
/**
|
|
198
|
-
* Upsert bars into a series by time (used for history paging / backfill /
|
|
199
|
-
* out-of-order corrections — ARCHITECTURE.md §4.2). Existing times are
|
|
200
|
-
* replaced; new times are inserted; the result stays time-sorted.
|
|
201
|
-
*
|
|
202
|
-
* Prepending older bars shifts every existing logical index up by the
|
|
203
|
-
* inserted count — callers preserve the viewport by re-reading `baseIndex`
|
|
204
|
-
* (the invariant `rightEdge − index` is unchanged, so visible bars don't move).
|
|
205
|
-
*/
|
|
206
|
-
addBars(id: SeriesId, bars: readonly Bar[]): void;
|
|
207
|
-
/**
|
|
208
|
-
* Apply a single live bar (ARCHITECTURE.md §4.2 hot path). Returns the kind of
|
|
209
|
-
* change so the chart auto-scrolls only on a genuine right-edge append:
|
|
210
|
-
* - `'append'` → newer than the last bar (advances baseIndex)
|
|
211
|
-
* - `'replace'` → same time as the last bar (intra-bar tick) or an existing time
|
|
212
|
-
* - `'insert'` → an older time inserted into history (late / out-of-order)
|
|
213
|
-
*/
|
|
214
|
-
update(id: SeriesId, bar: Bar): 'append' | 'replace' | 'insert';
|
|
215
|
-
private _appendTime;
|
|
216
|
-
/** Number of logical indices (distinct time points across all series). */
|
|
217
|
-
get length(): number;
|
|
218
|
-
/** Logical index of the latest real bar (length - 1), or -1 if empty. */
|
|
219
|
-
get baseIndex(): number;
|
|
220
|
-
indexToTime(index: number): number | undefined;
|
|
221
|
-
timeToIndex(time: number): number | undefined;
|
|
222
|
-
/**
|
|
223
|
-
* Fractional logical index → UTC seconds, interpolating between bars and
|
|
224
|
-
* extrapolating past either edge at the nearest bar spacing.
|
|
225
|
-
*
|
|
226
|
-
* `indexToTime` only answers for indices that have a bar. Anything anchored to
|
|
227
|
-
* an arbitrary x — a drawing endpoint, a cursor readout, a projection to the
|
|
228
|
-
* right of the last bar — needs a time for positions *between* bars too, which
|
|
229
|
-
* the gapless axis (§5.3) makes common: everything a weekend or a session
|
|
230
|
-
* break collapsed away lands there. Returns NaN when there is no data.
|
|
231
|
-
*/
|
|
232
|
-
indexToTimeFloat(index: number): number;
|
|
233
|
-
/** UTC seconds → fractional logical index. The inverse of `indexToTimeFloat`. */
|
|
234
|
-
timeToIndexFloat(time: number): number;
|
|
235
|
-
/**
|
|
236
|
-
* A series' bars, time-sorted, with no per-call allocation — the read path
|
|
237
|
-
* for anything that recomputes over full history (indicators, transforms).
|
|
238
|
-
* The array is live: treat it as read-only.
|
|
239
|
-
*/
|
|
240
|
-
seriesBars(id: SeriesId): readonly Bar[];
|
|
241
|
-
/** All bars of a series paired with their shared logical index. */
|
|
242
|
-
indexedBars(id: SeriesId): IndexedBar[];
|
|
243
|
-
/**
|
|
244
|
-
* Bars of a series whose logical index lies within [fromIndex, toIndex].
|
|
245
|
-
* Binary-searches the (time-sorted) series into the visible time window instead
|
|
246
|
-
* of scanning all bars, so a full repaint costs O(log n + visible) per series,
|
|
247
|
-
* not O(total bars) - the hot path called for autoscale and drawing every frame.
|
|
248
|
-
*/
|
|
249
|
-
visibleBars(id: SeriesId, fromIndex: number, toIndex: number): IndexedBar[];
|
|
250
|
-
/** The last bar of a series with its shared logical index, in O(1). */
|
|
251
|
-
lastIndexedBar(id: SeriesId): IndexedBar | null;
|
|
252
|
-
private _rebuild;
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
/**
|
|
256
|
-
* Chart theme (palette). A single object drives chart chrome (background, grid,
|
|
257
|
-
* axes, crosshair), series defaults (up/down, line, area gradient, last price),
|
|
258
|
-
* and the trade layer (buy/sell, profit/loss). Renderers read theme colors when
|
|
259
|
-
* a per-series style field is absent, so one theme restyles the whole chart.
|
|
260
|
-
*/
|
|
261
|
-
interface ChartTheme {
|
|
262
|
-
background: string;
|
|
263
|
-
grid: string;
|
|
264
|
-
axisText: string;
|
|
265
|
-
axisLine: string;
|
|
266
|
-
crosshair: string;
|
|
267
|
-
/** Axis label font size in px (default 11). */
|
|
268
|
-
axisFontSize?: number;
|
|
269
|
-
/** Grid line dash style (default 'solid'). */
|
|
270
|
-
gridStyle?: 'solid' | 'dashed' | 'dotted';
|
|
271
|
-
/** Crosshair line dash style (default 'dashed'). */
|
|
272
|
-
crosshairStyle?: 'solid' | 'dashed' | 'dotted';
|
|
273
|
-
/** Crosshair line width in device px (default 1 = hairline). */
|
|
274
|
-
crosshairWidth?: number;
|
|
275
|
-
/** Background of the crosshair value tags (defaults to `crosshair`). */
|
|
276
|
-
crosshairLabelBackground?: string;
|
|
277
|
-
/** Show the crosshair price/time value tags (default true). */
|
|
278
|
-
crosshairLabelVisible?: boolean;
|
|
279
|
-
upColor: string;
|
|
280
|
-
downColor: string;
|
|
281
|
-
wickUpColor: string;
|
|
282
|
-
wickDownColor: string;
|
|
283
|
-
lineColor: string;
|
|
284
|
-
areaTopColor: string;
|
|
285
|
-
areaBottomColor: string;
|
|
286
|
-
baselineTopLine: string;
|
|
287
|
-
baselineTopFill: string;
|
|
288
|
-
baselineBottomLine: string;
|
|
289
|
-
baselineBottomFill: string;
|
|
290
|
-
lastPriceUp: string;
|
|
291
|
-
lastPriceDown: string;
|
|
292
|
-
lastPriceText: string;
|
|
293
|
-
buy: string;
|
|
294
|
-
sell: string;
|
|
295
|
-
profit: string;
|
|
296
|
-
loss: string;
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
/**
|
|
300
|
-
* Primitive / plugin API (ARCHITECTURE.md §8). The extension point that keeps
|
|
301
|
-
* the core small and powers markers, events, indicators, and the trade layer.
|
|
302
|
-
* A primitive draws on a pane, optionally contributes to autoscale, and
|
|
303
|
-
* optionally hit-tests for hover/drag.
|
|
304
|
-
*/
|
|
305
|
-
|
|
306
|
-
type ZOrder = 'bottom' | 'normal' | 'top';
|
|
307
|
-
interface PrimitiveRenderContext {
|
|
308
|
-
timeScale: TimeScale;
|
|
309
|
-
priceScale: PriceScale;
|
|
310
|
-
dataLayer: DataLayer;
|
|
311
|
-
plotWidth: number;
|
|
312
|
-
plotHeight: number;
|
|
313
|
-
priceAxisWidth: number;
|
|
314
|
-
dpr: number;
|
|
315
|
-
theme: ChartTheme;
|
|
316
|
-
/**
|
|
317
|
-
* The pane's primary price series, for a primitive that needs what price
|
|
318
|
-
* actually did rather than just the scales — a forecast scoring itself, say.
|
|
319
|
-
* Lazy, so nothing pays for it unless asked. Absent on synthetic contexts.
|
|
320
|
-
*/
|
|
321
|
-
bars?: () => readonly Bar[];
|
|
322
|
-
/** externalId of the primitive hit under the pointer (hover state), if any. */
|
|
323
|
-
hoverId?: string | null;
|
|
324
|
-
/** externalId of the line being dragged (active state), if any. */
|
|
325
|
-
dragId?: string | null;
|
|
326
|
-
}
|
|
327
|
-
interface PrimitiveHit {
|
|
328
|
-
externalId: string;
|
|
329
|
-
zOrder: ZOrder;
|
|
330
|
-
/** Pixel distance from the cursor (smaller wins ties before z-order). */
|
|
331
|
-
distance: number;
|
|
332
|
-
cursor?: string;
|
|
333
|
-
/**
|
|
334
|
-
* Arm a drag on press. Price lines set `cursor: 'ns-resize'` and move on one
|
|
335
|
-
* axis; anything that moves on **both** (a drawing anchor, a whole shape)
|
|
336
|
-
* declares it here, and the drag callbacks receive time as well as price.
|
|
337
|
-
*/
|
|
338
|
-
draggable?: boolean;
|
|
339
|
-
}
|
|
340
|
-
/** Injected when a primitive is attached; lets it request a repaint. */
|
|
341
|
-
interface PrimitiveHost {
|
|
342
|
-
requestUpdate(): void;
|
|
343
|
-
}
|
|
344
|
-
interface IPrimitive {
|
|
345
|
-
/** Layer order vs series: 'bottom' (behind), 'normal' (over), 'top' (overlay). */
|
|
346
|
-
zOrder(): ZOrder;
|
|
347
|
-
draw(ctx: CanvasRenderingContext2D, rc: PrimitiveRenderContext): void;
|
|
348
|
-
/** Optional: expand the pane's autoscale range so this primitive isn't clipped. */
|
|
349
|
-
autoscaleInfo?(): {
|
|
350
|
-
min: number;
|
|
351
|
-
max: number;
|
|
352
|
-
} | null;
|
|
353
|
-
/** Optional: topmost hit under (x,y) in media px (relative to the pane plot). */
|
|
354
|
-
hitTest?(x: number, y: number, rc: PrimitiveRenderContext): PrimitiveHit | null;
|
|
355
|
-
attached?(host: PrimitiveHost): void;
|
|
356
|
-
detached?(): void;
|
|
357
|
-
}
|
|
1
|
+
import { PrimitiveRenderContext, IPrimitive, PrimitiveHost, ZOrder, PrimitiveHit, DataLayer } from 'openalgo-charts';
|
|
358
2
|
|
|
359
3
|
/**
|
|
360
4
|
* Drawing model (ARCHITECTURE.md §8). A drawing is **plain data** — anchors in
|
|
@@ -580,1489 +224,6 @@ declare class DrawingLayer implements IPrimitive {
|
|
|
580
224
|
hitTest(x: number, y: number, rc: PrimitiveRenderContext): PrimitiveHit | null;
|
|
581
225
|
}
|
|
582
226
|
|
|
583
|
-
/**
|
|
584
|
-
* Invalidation model (ARCHITECTURE.md §3.2).
|
|
585
|
-
*
|
|
586
|
-
* A single global level is too coarse for multi-pane indicators and trade
|
|
587
|
-
* overlays, so the mask carries a **global level + a per-pane map + a queue of
|
|
588
|
-
* time-scale operations**. Multiple invalidations within one frame coalesce via
|
|
589
|
-
* {@link InvalidateMask.merge}.
|
|
590
|
-
*/
|
|
591
|
-
/** How much of a pane (or the whole chart) must be repainted this frame. */
|
|
592
|
-
declare const InvalidationLevel: {
|
|
593
|
-
/** Nothing to do. */
|
|
594
|
-
readonly None: 0;
|
|
595
|
-
/** Repaint only the top (overlay) canvas — crosshair, hover, dragging primitives. */
|
|
596
|
-
readonly Cursor: 1;
|
|
597
|
-
/** Repaint the base canvas at the current scales — series moved/changed, no rescale. */
|
|
598
|
-
readonly Light: 2;
|
|
599
|
-
/** Recompute scales/ticks then repaint everything. */
|
|
600
|
-
readonly Full: 3;
|
|
601
|
-
};
|
|
602
|
-
type InvalidationLevel = (typeof InvalidationLevel)[keyof typeof InvalidationLevel];
|
|
603
|
-
/** Per-pane invalidation entry. `autoScale` requests a price-axis rescale. */
|
|
604
|
-
interface PaneInvalidation {
|
|
605
|
-
level: InvalidationLevel;
|
|
606
|
-
autoScale: boolean;
|
|
607
|
-
}
|
|
608
|
-
/** Discrete operations applied to the shared time scale before painting. */
|
|
609
|
-
type TimeScaleOp = {
|
|
610
|
-
type: 'fitContent';
|
|
611
|
-
} | {
|
|
612
|
-
type: 'applyBarSpacing';
|
|
613
|
-
value: number;
|
|
614
|
-
} | {
|
|
615
|
-
type: 'applyRightOffset';
|
|
616
|
-
value: number;
|
|
617
|
-
} | {
|
|
618
|
-
type: 'reset';
|
|
619
|
-
};
|
|
620
|
-
declare class InvalidateMask {
|
|
621
|
-
private _globalLevel;
|
|
622
|
-
private readonly _panes;
|
|
623
|
-
private _timeScaleOps;
|
|
624
|
-
constructor(globalLevel?: InvalidationLevel);
|
|
625
|
-
get globalLevel(): InvalidationLevel;
|
|
626
|
-
/** Raise the chart-wide level (monotonic — only ever increases). */
|
|
627
|
-
invalidateGlobal(level: InvalidationLevel): void;
|
|
628
|
-
/** Raise a single pane's level without touching the others. */
|
|
629
|
-
invalidatePane(paneIndex: number, invalidation: PaneInvalidation): void;
|
|
630
|
-
paneInvalidation(paneIndex: number): PaneInvalidation | undefined;
|
|
631
|
-
panes(): ReadonlyMap<number, PaneInvalidation>;
|
|
632
|
-
addTimeScaleOp(op: TimeScaleOp): void;
|
|
633
|
-
timeScaleOps(): readonly TimeScaleOp[];
|
|
634
|
-
isEmpty(): boolean;
|
|
635
|
-
/** Fold another mask into this one (coalescing multiple invalidations per frame). */
|
|
636
|
-
merge(other: InvalidateMask): void;
|
|
637
|
-
}
|
|
638
|
-
|
|
639
|
-
/**
|
|
640
|
-
* Frame scheduler (ARCHITECTURE.md §3.2). Coalesces many `requestFrame()` calls
|
|
641
|
-
* within a single tick into one `onFrame` invocation. The rAF function is
|
|
642
|
-
* injectable so the loop is deterministically testable without a browser.
|
|
643
|
-
*/
|
|
644
|
-
type RafScheduler = (cb: () => void) => number;
|
|
645
|
-
type RafCanceller = (handle: number) => void;
|
|
646
|
-
|
|
647
|
-
/**
|
|
648
|
-
* A single `<canvas>` element with media/bitmap sizing. Constructed only in a
|
|
649
|
-
* browser; the size math above is the part exercised by unit tests.
|
|
650
|
-
*/
|
|
651
|
-
declare class CanvasLayer {
|
|
652
|
-
readonly element: HTMLCanvasElement;
|
|
653
|
-
readonly ctx: CanvasRenderingContext2D;
|
|
654
|
-
private _mediaWidth;
|
|
655
|
-
private _mediaHeight;
|
|
656
|
-
private _dpr;
|
|
657
|
-
constructor(doc: Document, zIndex: number);
|
|
658
|
-
get mediaWidth(): number;
|
|
659
|
-
get mediaHeight(): number;
|
|
660
|
-
get pixelRatio(): number;
|
|
661
|
-
/** Resize backing buffer + CSS box. No-op if nothing changed. */
|
|
662
|
-
resize(mediaWidth: number, mediaHeight: number, dpr: number): void;
|
|
663
|
-
/** Clear the whole bitmap and reset the transform to bitmap (device-px) scope. */
|
|
664
|
-
clearBitmap(): void;
|
|
665
|
-
}
|
|
666
|
-
|
|
667
|
-
/**
|
|
668
|
-
* Unified style bag for all Family-A series types (ARCHITECTURE.md §6A). Each
|
|
669
|
-
* renderer reads the fields it needs; per-type defaults are filled by the
|
|
670
|
-
* chart-type registry. Keeping one optional-field interface avoids a sprawling
|
|
671
|
-
* discriminated union at the rendering boundary.
|
|
672
|
-
*/
|
|
673
|
-
interface SeriesStyle {
|
|
674
|
-
upColor?: string;
|
|
675
|
-
downColor?: string;
|
|
676
|
-
borderUpColor?: string;
|
|
677
|
-
borderDownColor?: string;
|
|
678
|
-
wickUpColor?: string;
|
|
679
|
-
wickDownColor?: string;
|
|
680
|
-
borderVisible?: boolean;
|
|
681
|
-
wickVisible?: boolean;
|
|
682
|
-
hollow?: boolean;
|
|
683
|
-
/** Scale candle body width by volume / maxVisibleVolume (volume candles). */
|
|
684
|
-
volumeScaled?: boolean;
|
|
685
|
-
/** Whether the series is drawn and counted in autoscale. Default true. */
|
|
686
|
-
visible?: boolean;
|
|
687
|
-
/** Optional label carried with the series (for host-drawn legends). */
|
|
688
|
-
title?: string;
|
|
689
|
-
/** Show the dashed horizontal last-price line across the plot. Default true. */
|
|
690
|
-
priceLineVisible?: boolean;
|
|
691
|
-
/** Show the last-value tag on the price axis. Default true. */
|
|
692
|
-
lastValueVisible?: boolean;
|
|
693
|
-
color?: string;
|
|
694
|
-
lineWidth?: number;
|
|
695
|
-
/** Line dash style for line/step/area/HLC series. Default 'solid'. */
|
|
696
|
-
lineStyle?: 'solid' | 'dashed' | 'dotted';
|
|
697
|
-
step?: boolean;
|
|
698
|
-
markers?: boolean;
|
|
699
|
-
/** Draw only the markers, with no connecting line (Parabolic SAR, scatter). */
|
|
700
|
-
markersOnly?: boolean;
|
|
701
|
-
markerRadius?: number;
|
|
702
|
-
areaTopColor?: string;
|
|
703
|
-
areaBottomColor?: string;
|
|
704
|
-
baseValue?: number;
|
|
705
|
-
topColor?: string;
|
|
706
|
-
bottomColor?: string;
|
|
707
|
-
highColor?: string;
|
|
708
|
-
lowColor?: string;
|
|
709
|
-
closeColor?: string;
|
|
710
|
-
base?: number;
|
|
711
|
-
/**
|
|
712
|
-
* Fallback box size for stacking P&F X/O glyphs. Columns from
|
|
713
|
-
* `PointFigureTransform` carry their own `boxSize`, which wins — set this only
|
|
714
|
-
* for hand-built column data.
|
|
715
|
-
*/
|
|
716
|
-
boxSize?: number;
|
|
717
|
-
/** Kagi thick (yang) line color. */
|
|
718
|
-
thickColor?: string;
|
|
719
|
-
/** Kagi thin (yin) line color. */
|
|
720
|
-
thinColor?: string;
|
|
721
|
-
}
|
|
722
|
-
|
|
723
|
-
/**
|
|
724
|
-
* Chart-type registry (ARCHITECTURE.md §6A). Every series type registers a
|
|
725
|
-
* descriptor: how to draw it and how it contributes to autoscale. The core
|
|
726
|
-
* iterates descriptors, so adding a style is one registration — no core change.
|
|
727
|
-
* Phase 5 fills the Family-A (time-indexed) types; Families B/C plug in later.
|
|
728
|
-
*/
|
|
729
|
-
|
|
730
|
-
type SeriesType = 'candlestick' | 'hollow-candle' | 'volume-candle' | 'bar' | 'high-low' | 'line' | 'line-markers' | 'step' | 'area' | 'hlc-area' | 'baseline' | 'column' | 'histogram' | 'point-figure' | 'kagi';
|
|
731
|
-
|
|
732
|
-
type MarkerShape = 'arrowUp' | 'arrowDown' | 'circle' | 'square' | 'triangleUp' | 'triangleDown' | 'diamond' | 'flag' | 'text';
|
|
733
|
-
type MarkerPosition = 'aboveBar' | 'belowBar' | 'inBar' | 'atPrice';
|
|
734
|
-
type MarkerSize = 'tiny' | 'small' | 'medium' | 'big';
|
|
735
|
-
interface SeriesMarker {
|
|
736
|
-
time: number;
|
|
737
|
-
position: MarkerPosition;
|
|
738
|
-
price?: number;
|
|
739
|
-
shape: MarkerShape;
|
|
740
|
-
size: MarkerSize;
|
|
741
|
-
color: string;
|
|
742
|
-
text?: string;
|
|
743
|
-
id?: string;
|
|
744
|
-
}
|
|
745
|
-
declare class SeriesMarkers implements IPrimitive {
|
|
746
|
-
private readonly _seriesId;
|
|
747
|
-
private _markers;
|
|
748
|
-
private _host;
|
|
749
|
-
private _lastPositions;
|
|
750
|
-
constructor(seriesId: SeriesId);
|
|
751
|
-
attached(host: PrimitiveHost): void;
|
|
752
|
-
detached(): void;
|
|
753
|
-
zOrder(): ZOrder;
|
|
754
|
-
setMarkers(markers: readonly SeriesMarker[]): void;
|
|
755
|
-
draw(ctx: CanvasRenderingContext2D, rc: PrimitiveRenderContext): void;
|
|
756
|
-
hitTest(x: number, y: number): PrimitiveHit | null;
|
|
757
|
-
}
|
|
758
|
-
|
|
759
|
-
/**
|
|
760
|
-
* Series records (ARCHITECTURE.md §4.3). A series references its rows in the
|
|
761
|
-
* shared DataLayer by id, names a registered chart type, and carries a style
|
|
762
|
-
* bag. The chart-type registry (§6A) supplies the renderer + autoscale extents,
|
|
763
|
-
* so the core never switches on type.
|
|
764
|
-
*/
|
|
765
|
-
|
|
766
|
-
/**
|
|
767
|
-
* Which price axis a series maps to. 'right' (default) and 'left' each draw an
|
|
768
|
-
* axis and autoscale independently; '' is a hidden overlay scale (no axis, its
|
|
769
|
-
* own autoscale) used to pin a volume histogram inside the price pane.
|
|
770
|
-
*/
|
|
771
|
-
type PriceScaleId = 'right' | 'left' | '';
|
|
772
|
-
interface SeriesRecord {
|
|
773
|
-
dataId: SeriesId;
|
|
774
|
-
type: SeriesType;
|
|
775
|
-
style: SeriesStyle;
|
|
776
|
-
scaleId: PriceScaleId;
|
|
777
|
-
}
|
|
778
|
-
/** Public handle returned by `chart.addSeries(...)`. */
|
|
779
|
-
interface SeriesApi {
|
|
780
|
-
/** Replace all data. Accepts OHLC bars, `{ time, value }` points, or `{ time }` gaps. */
|
|
781
|
-
setData(bars: readonly SeriesDataItem[]): void;
|
|
782
|
-
/** Merge older data (history paging); same item shapes as `setData`. */
|
|
783
|
-
prependData(bars: readonly SeriesDataItem[]): void;
|
|
784
|
-
/** Live update: update the last item or append. Same item shapes as `setData`. */
|
|
785
|
-
update(bar: SeriesDataItem): void;
|
|
786
|
-
/** Current bars for this series (sorted old -> new, normalized to OHLC). Handy for computing the next live update. */
|
|
787
|
-
getData(): Bar[];
|
|
788
|
-
/** Merge a partial style into the series and repaint (recolor, `{ visible:false }` to hide, ...). */
|
|
789
|
-
applyOptions(style: Partial<SeriesStyle>): void;
|
|
790
|
-
/** Remove the series from its pane and free its data rows. */
|
|
791
|
-
remove(): void;
|
|
792
|
-
/** The price scale this series maps to (call `.setOptions({ marginTop, marginBottom })` on it). */
|
|
793
|
-
priceScale(): PriceScale;
|
|
794
|
-
/** Create a markers layer (buy/sell signals, shapes) bound to this series. */
|
|
795
|
-
createMarkers(): SeriesMarkers;
|
|
796
|
-
}
|
|
797
|
-
|
|
798
|
-
/**
|
|
799
|
-
* Axis label rendering (ARCHITECTURE.md §6, §5.3). Price axis (right strip) and
|
|
800
|
-
* time axis (bottom strip). Time labels switch from clock to date at IST day
|
|
801
|
-
* boundaries; gaps are already collapsed by the logical-index time scale.
|
|
802
|
-
*/
|
|
803
|
-
|
|
804
|
-
/**
|
|
805
|
-
* Boundary class of a time-axis label, passed to a custom `timeFormatter` as a
|
|
806
|
-
* hint so a host can render adaptive labels (year at year boundaries, month at
|
|
807
|
-
* month boundaries, day otherwise, clock intraday) — parity with common
|
|
808
|
-
* `tickMarkFormatter(time, tickMarkType)` APIs.
|
|
809
|
-
*/
|
|
810
|
-
type TickMarkType = 'year' | 'month' | 'day' | 'time' | 'timeWithSeconds';
|
|
811
|
-
|
|
812
|
-
/**
|
|
813
|
-
* A pane is one vertically-stacked drawing region (price pane, volume pane,
|
|
814
|
-
* indicator pane). It owns a base + top canvas (ARCHITECTURE.md §3.1) and a
|
|
815
|
-
* price scale, and renders its series against the shared time scale + DataLayer.
|
|
816
|
-
*/
|
|
817
|
-
|
|
818
|
-
interface PaneRenderContext {
|
|
819
|
-
timeScale: TimeScale;
|
|
820
|
-
dataLayer: DataLayer;
|
|
821
|
-
dpr: number;
|
|
822
|
-
priceAxisWidth: number;
|
|
823
|
-
/** Left inset (px) reserved chart-wide for a left price axis; 0/absent when none. */
|
|
824
|
-
leftAxisWidth?: number;
|
|
825
|
-
timeAxisHeight: number;
|
|
826
|
-
/** Only the bottom pane draws the time axis. */
|
|
827
|
-
showTimeAxis: boolean;
|
|
828
|
-
/** Enable OHLC-preserving conflation when bars fall below ~0.5px (§4.4). */
|
|
829
|
-
conflate: boolean;
|
|
830
|
-
/** Conflation aggressiveness (1 = perf only; higher = more smoothing). */
|
|
831
|
-
conflationFactor: number;
|
|
832
|
-
/** Active palette — drives chrome, series defaults, and trade colors. */
|
|
833
|
-
theme: ChartTheme;
|
|
834
|
-
/** Draw the vertical (time) grid lines. */
|
|
835
|
-
showVertGrid: boolean;
|
|
836
|
-
/** Draw the horizontal (price) grid lines. */
|
|
837
|
-
showHorzGrid: boolean;
|
|
838
|
-
/** Optional custom time label formatter (UTC seconds -> string). Defaults to IST. */
|
|
839
|
-
timeFormatter?: (utcSeconds: number, tickMark?: TickMarkType) => string;
|
|
840
|
-
/** externalId of the primitive under the pointer (hover visual state). */
|
|
841
|
-
hoverId?: string | null;
|
|
842
|
-
/** externalId of the line currently being dragged (active visual state). */
|
|
843
|
-
dragId?: string | null;
|
|
844
|
-
}
|
|
845
|
-
declare class Pane {
|
|
846
|
-
readonly element: HTMLElement;
|
|
847
|
-
readonly base: CanvasLayer;
|
|
848
|
-
readonly top: CanvasLayer;
|
|
849
|
-
readonly priceScale: PriceScale;
|
|
850
|
-
/** Extra scales created on demand: left axis and a hidden overlay (volume). */
|
|
851
|
-
private _leftScale;
|
|
852
|
-
private _overlayScale;
|
|
853
|
-
/** Relative height weight within the chart (price=1, volume≈0.3). */
|
|
854
|
-
weight: number;
|
|
855
|
-
private readonly _series;
|
|
856
|
-
private readonly _primitives;
|
|
857
|
-
private _width;
|
|
858
|
-
private _height;
|
|
859
|
-
constructor(doc: Document);
|
|
860
|
-
addSeries(record: SeriesRecord): void;
|
|
861
|
-
/** The PriceScale for a scale id, creating the left/overlay scale on first use. */
|
|
862
|
-
private _scaleFor;
|
|
863
|
-
/** The price scale a series maps to (for the series handle's `priceScale()`). */
|
|
864
|
-
scaleOf(record: SeriesRecord): PriceScale;
|
|
865
|
-
/** True when a left-axis scale is active (some series maps to it). */
|
|
866
|
-
hasLeftScale(): boolean;
|
|
867
|
-
/** Remove a series record if present; returns true if it was found. */
|
|
868
|
-
removeSeries(record: SeriesRecord): boolean;
|
|
869
|
-
series(): readonly SeriesRecord[];
|
|
870
|
-
/** Primitives attached to this pane, in draw order. */
|
|
871
|
-
primitives(): readonly IPrimitive[];
|
|
872
|
-
addPrimitive(primitive: IPrimitive, host: PrimitiveHost): void;
|
|
873
|
-
/** Remove a primitive if present; returns true if it was found. */
|
|
874
|
-
removePrimitive(primitive: IPrimitive): boolean;
|
|
875
|
-
/** Detach every primitive (lifecycle cleanup) and remove the pane element. */
|
|
876
|
-
destroy(): void;
|
|
877
|
-
private _primitiveContext;
|
|
878
|
-
/** Topmost primitive hit at media-px (x,y) relative to this pane's plot. */
|
|
879
|
-
hitTestPrimitives(x: number, y: number, ctx: PaneRenderContext): PrimitiveHit | null;
|
|
880
|
-
resize(width: number, height: number, dpr: number): void;
|
|
881
|
-
/**
|
|
882
|
-
* Give every scale on this pane its plot height. Height is a *layout*
|
|
883
|
-
* property, but it used to be set only inside the autoscale pass — so any
|
|
884
|
-
* y↔price conversion before the first paint divided by zero and returned
|
|
885
|
-
* ±Infinity. Layout is when the height is actually known.
|
|
886
|
-
*/
|
|
887
|
-
setScaleHeights(plotHeight: number): void;
|
|
888
|
-
private _layout;
|
|
889
|
-
/** Autoscale each active price scale from its own series (independent axes). */
|
|
890
|
-
autoscale(ctx: PaneRenderContext): void;
|
|
891
|
-
private _autoscaleScale;
|
|
892
|
-
/** Paint background + grid + series + axes on the base canvas. */
|
|
893
|
-
paintBase(ctx: PaneRenderContext): void;
|
|
894
|
-
/**
|
|
895
|
-
* Top (overlay) canvas: top-layer primitives + crosshair. Cheap repaint on
|
|
896
|
-
* cursor moves. `cross.x` is the shared plot x (vertical line, drawn in every
|
|
897
|
-
* pane for a global crosshair); `cross.yLocal` is the price-line y for the
|
|
898
|
-
* hovered pane only (null elsewhere); `cross.showTimeTag` draws the date tag
|
|
899
|
-
* on the bottom pane's axis strip.
|
|
900
|
-
*/
|
|
901
|
-
paintTop(cross: {
|
|
902
|
-
x: number;
|
|
903
|
-
yLocal: number | null;
|
|
904
|
-
showTimeTag: boolean;
|
|
905
|
-
} | null, ctx: PaneRenderContext): void;
|
|
906
|
-
/** Price at a media-px y on this pane (for crosshair magnet). */
|
|
907
|
-
yToPrice(y: number): number;
|
|
908
|
-
}
|
|
909
|
-
|
|
910
|
-
/**
|
|
911
|
-
* Indicator registry (ARCHITECTURE.md §6A, §8). The sibling of the chart-type
|
|
912
|
-
* registry: that one answers *"how do I paint an array of bars"*, this one
|
|
913
|
-
* answers *"what do I compute, what does it plot, and what can a user tune"*.
|
|
914
|
-
*
|
|
915
|
-
* A descriptor is data, not code-in-the-core — the chart never switches on an
|
|
916
|
-
* indicator id. Each `plot` names a registered **chart type**, so indicators
|
|
917
|
-
* ride the existing Family-A renderers and add no drawing code at all.
|
|
918
|
-
*
|
|
919
|
-
* The built-in descriptors live in the lazy `openalgo-charts/indicators` tier;
|
|
920
|
-
* only the registry and the runtime ship in the base bundle, so an app that
|
|
921
|
-
* plots its own maths pays nothing for the catalog.
|
|
922
|
-
*/
|
|
923
|
-
|
|
924
|
-
type IndicatorSettings = Record<string, unknown>;
|
|
925
|
-
/** `calc` output: one array per plot key, aligned 1:1 with the input bars. */
|
|
926
|
-
type IndicatorValues = Record<string, readonly (number | null)[]>;
|
|
927
|
-
|
|
928
|
-
/**
|
|
929
|
-
* Horizontal price line primitive (ARCHITECTURE.md §8). The reusable base for
|
|
930
|
-
* order/SL/TP/alert/indicator-level lines: a line across the plot plus a fixed
|
|
931
|
-
* right-axis price tag and an optional broker-style segmented pill group on the
|
|
932
|
-
* line — [badge][qty][label][✕] — with hover / dragging states (the chart
|
|
933
|
-
* passes `hoverId`/`dragId` on the render context) and a drag ghost at the
|
|
934
|
-
* pre-drag price via `setDragGhost`. Interaction semantics are unchanged from
|
|
935
|
-
* the classic tag: the ✕ hit-tests as `${id}::close`, everything else drags.
|
|
936
|
-
*/
|
|
937
|
-
|
|
938
|
-
interface PriceLineOptions {
|
|
939
|
-
price: number;
|
|
940
|
-
color: string;
|
|
941
|
-
lineWidth: number;
|
|
942
|
-
dashed: boolean;
|
|
943
|
-
/** Right-axis tag text. Defaults to the formatted price. */
|
|
944
|
-
label?: string;
|
|
945
|
-
/** Solid colored badge segment at the start of the pill group (e.g. 'BUY', 'TP', 'SL'). */
|
|
946
|
-
badge?: string;
|
|
947
|
-
/** Quantity segment rendered as a neutral box after the badge. */
|
|
948
|
-
qty?: string | number;
|
|
949
|
-
/** Info text segment (order type, price, P&L ...) — the classic left tag text. */
|
|
950
|
-
leftLabel?: string;
|
|
951
|
-
/**
|
|
952
|
-
* Fraction of the plot width the line spans, measured from the right (price)
|
|
953
|
-
* axis. 1 = full width (default); 0.3 = only the rightmost 30%, like a
|
|
954
|
-
* partial-width order line. The right-axis tag is always drawn.
|
|
955
|
-
*/
|
|
956
|
-
extentFromRight?: number;
|
|
957
|
-
/** Draw a cancel (✕) segment at the end of the pill group; hit-tests as `${id}::close`. */
|
|
958
|
-
closeButton?: boolean;
|
|
959
|
-
/** Stable id returned by hit-test (for click/drag routing). */
|
|
960
|
-
id: string;
|
|
961
|
-
/** Cursor hint when hovered (e.g. 'ns-resize' for draggable lines). */
|
|
962
|
-
cursor?: string;
|
|
963
|
-
}
|
|
964
|
-
declare class PriceLine implements IPrimitive {
|
|
965
|
-
private _opts;
|
|
966
|
-
private _host;
|
|
967
|
-
private _ghostPrice;
|
|
968
|
-
/** Pill-group geometry from the last draw (media px) for hit-testing. */
|
|
969
|
-
private _group;
|
|
970
|
-
constructor(opts: PriceLineOptions);
|
|
971
|
-
attached(host: PrimitiveHost): void;
|
|
972
|
-
detached(): void;
|
|
973
|
-
get price(): number;
|
|
974
|
-
/** Move the line; schedules a repaint via the host. */
|
|
975
|
-
setPrice(price: number): void;
|
|
976
|
-
/** Update the info segment text (e.g. live position P&L); repaints. */
|
|
977
|
-
setLeftLabel(text: string): void;
|
|
978
|
-
/**
|
|
979
|
-
* Show a dimmed reference line at the pre-drag price while the user drags
|
|
980
|
-
* (pass the original price on drag start, null on drag end to clear).
|
|
981
|
-
*/
|
|
982
|
-
setDragGhost(price: number | null): void;
|
|
983
|
-
options(): Readonly<PriceLineOptions>;
|
|
984
|
-
zOrder(): ZOrder;
|
|
985
|
-
autoscaleInfo(): {
|
|
986
|
-
min: number;
|
|
987
|
-
max: number;
|
|
988
|
-
} | null;
|
|
989
|
-
draw(ctx: CanvasRenderingContext2D, rc: PrimitiveRenderContext): void;
|
|
990
|
-
hitTest(x: number, y: number, rc: PrimitiveRenderContext): PrimitiveHit | null;
|
|
991
|
-
}
|
|
992
|
-
|
|
993
|
-
/**
|
|
994
|
-
* Pane legend (ARCHITECTURE.md §8) — the TradingView-style row at the top-left
|
|
995
|
-
* of a pane: a color swatch, the source's name, its parameters, the value under
|
|
996
|
-
* the crosshair, and inline action buttons on the right.
|
|
997
|
-
*
|
|
998
|
-
* Drawn on the canvas rather than in the DOM, like `BuySellButtons` and
|
|
999
|
-
* `DomLadder`, so it composites into screenshots and costs no DOM per pane.
|
|
1000
|
-
* Buttons hit-test as `${id}::close`, `${id}::hide`, and `${id}::settings`, so
|
|
1001
|
-
* the host routes them through the same `subscribeClick` path as order pills.
|
|
1002
|
-
*
|
|
1003
|
-
* Rows stack: several legends on one pane offset each other vertically, which
|
|
1004
|
-
* the host does by giving each a `row` index.
|
|
1005
|
-
*/
|
|
1006
|
-
|
|
1007
|
-
type PaneLegendAction = 'hide' | 'settings' | 'up' | 'down' | 'maximize' | 'close';
|
|
1008
|
-
/**
|
|
1009
|
-
* One reading on a legend row. Multi-plot sources show one per plot, each in
|
|
1010
|
-
* that plot's own color (an MA ribbon's four averages, MACD's three lines) —
|
|
1011
|
-
* a single string in a single color cannot say which number is which.
|
|
1012
|
-
*/
|
|
1013
|
-
interface LegendValue {
|
|
1014
|
-
/** Dimmed prefix, e.g. `O` / `H` / `Vol`. */
|
|
1015
|
-
label?: string;
|
|
1016
|
-
text: string;
|
|
1017
|
-
/** Defaults to the row's `valueColor`, then `color`, then the theme text. */
|
|
1018
|
-
color?: string;
|
|
1019
|
-
}
|
|
1020
|
-
interface PaneLegendOptions {
|
|
1021
|
-
/** Stable id; buttons hit-test as `${id}::close` etc. */
|
|
1022
|
-
id: string;
|
|
1023
|
-
/** Bold source name, e.g. `RSI`. */
|
|
1024
|
-
title: string;
|
|
1025
|
-
/** Dimmed parameter summary after the title, e.g. `14 close`. */
|
|
1026
|
-
params?: string;
|
|
1027
|
-
/** Swatch color; omitted draws no swatch. */
|
|
1028
|
-
color?: string;
|
|
1029
|
-
/**
|
|
1030
|
-
* Color for the live value. Defaults to `color`, then the theme's text — so a
|
|
1031
|
-
* row can tint its reading (an up/down change) without being forced to show a
|
|
1032
|
-
* swatch in that same color.
|
|
1033
|
-
*/
|
|
1034
|
-
valueColor?: string;
|
|
1035
|
-
/** Vertical slot on the pane (0 = topmost). */
|
|
1036
|
-
row?: number;
|
|
1037
|
-
/**
|
|
1038
|
-
* Which inline action buttons to draw, left to right. Each hit-tests as
|
|
1039
|
-
* `${id}::<action>`:
|
|
1040
|
-
* - `up` / `down` — move this pane one slot (`::up` / `::down`)
|
|
1041
|
-
* - `hide` — toggle visibility (`::hide`)
|
|
1042
|
-
* - `maximize` — expand this pane to fill the chart (`::maximize`)
|
|
1043
|
-
* - `close` — remove the source, and its pane if it empties (`::close`)
|
|
1044
|
-
*
|
|
1045
|
-
* Defaults to `['up', 'down', 'hide', 'maximize', 'close']` for pane sources
|
|
1046
|
-
* and `['hide', 'close']` for overlays (pass explicitly to override).
|
|
1047
|
-
*/
|
|
1048
|
-
actions?: readonly PaneLegendAction[];
|
|
1049
|
-
/** Rendered as hidden (dimmed, eye hollow). */
|
|
1050
|
-
hidden?: boolean;
|
|
1051
|
-
/** Rendered as maximized (the maximize glyph becomes restore). */
|
|
1052
|
-
maximized?: boolean;
|
|
1053
|
-
/** Text size in media px. Default 11. */
|
|
1054
|
-
font?: number;
|
|
1055
|
-
/** Left inset from the plot edge in media px. Default 8. */
|
|
1056
|
-
left?: number;
|
|
1057
|
-
/** Top inset in media px. Default 6. */
|
|
1058
|
-
top?: number;
|
|
1059
|
-
}
|
|
1060
|
-
declare class PaneLegend implements IPrimitive {
|
|
1061
|
-
private _opts;
|
|
1062
|
-
private _host;
|
|
1063
|
-
private _values;
|
|
1064
|
-
/** Button geometry from the last draw, in media px, for hit-testing. */
|
|
1065
|
-
private _buttons;
|
|
1066
|
-
/** Right edge of the drawn row, in media px. */
|
|
1067
|
-
private _width;
|
|
1068
|
-
constructor(opts: PaneLegendOptions);
|
|
1069
|
-
attached(host: PrimitiveHost): void;
|
|
1070
|
-
detached(): void;
|
|
1071
|
-
zOrder(): ZOrder;
|
|
1072
|
-
autoscaleInfo(): null;
|
|
1073
|
-
/** A single live reading after the params (typically crosshair-driven). */
|
|
1074
|
-
setValue(text: string, color?: string): void;
|
|
1075
|
-
/** One reading per plot, each in its own color. */
|
|
1076
|
-
setValues(values: readonly LegendValue[]): void;
|
|
1077
|
-
setOptions(patch: Partial<PaneLegendOptions>): void;
|
|
1078
|
-
options(): PaneLegendOptions;
|
|
1079
|
-
draw(ctx: CanvasRenderingContext2D, rc: PrimitiveRenderContext): void;
|
|
1080
|
-
hitTest(x: number, y: number): PrimitiveHit | null;
|
|
1081
|
-
}
|
|
1082
|
-
|
|
1083
|
-
/**
|
|
1084
|
-
* Indicator runtime (ARCHITECTURE.md §8). Turns an `IndicatorDescriptor` into
|
|
1085
|
-
* live chart objects: one series per plot, optional reference levels, an
|
|
1086
|
-
* optional fixed pane range — and recomputes them when the source data or the
|
|
1087
|
-
* settings change.
|
|
1088
|
-
*
|
|
1089
|
-
* It adds **no rendering code**. Every plot names a registered chart type, so
|
|
1090
|
-
* indicators draw through the same Family-A renderers as any other series.
|
|
1091
|
-
*/
|
|
1092
|
-
|
|
1093
|
-
/** Public handle returned by `chart.addIndicator(...)`. */
|
|
1094
|
-
interface IndicatorApi {
|
|
1095
|
-
/** Unique instance id (several instances of one indicator can coexist). */
|
|
1096
|
-
readonly id: string;
|
|
1097
|
-
/** The descriptor id, e.g. `'macd'`. */
|
|
1098
|
-
readonly indicatorId: string;
|
|
1099
|
-
/** Display name. */
|
|
1100
|
-
readonly name: string;
|
|
1101
|
-
/** Pane the indicator drew into. */
|
|
1102
|
-
readonly paneIndex: number;
|
|
1103
|
-
/** Current settings (a copy). */
|
|
1104
|
-
settings(): IndicatorSettings;
|
|
1105
|
-
/** Merge a settings patch, recompute, and restyle. */
|
|
1106
|
-
setSettings(patch: Readonly<IndicatorSettings>): void;
|
|
1107
|
-
/** The series backing one plot key, for direct styling. */
|
|
1108
|
-
series(plotKey: string): SeriesApi | undefined;
|
|
1109
|
-
/** Latest computed values (a reference — do not mutate). */
|
|
1110
|
-
values(): IndicatorValues;
|
|
1111
|
-
/** Whether the plots are drawn (the legend's eye toggle). */
|
|
1112
|
-
visible(): boolean;
|
|
1113
|
-
/** Show or hide every plot without removing the instance. */
|
|
1114
|
-
setVisible(on: boolean): void;
|
|
1115
|
-
/** This indicator's legend row, or null if it has none. */
|
|
1116
|
-
legend(): PaneLegend | null;
|
|
1117
|
-
/** Refresh the legend readings for a bar index; omit for the latest bar. */
|
|
1118
|
-
updateLegendValues(index?: number): void;
|
|
1119
|
-
/** Remove every series, level, and legend row this indicator created. */
|
|
1120
|
-
remove(): void;
|
|
1121
|
-
}
|
|
1122
|
-
|
|
1123
|
-
/**
|
|
1124
|
-
* Serialisable chart state — the keystone the persistence-shaped features hang
|
|
1125
|
-
* off (saved layouts, templates, an objects panel, favourites, drawings).
|
|
1126
|
-
*
|
|
1127
|
-
* The rule that shapes this type: **the chart serialises what the chart owns.**
|
|
1128
|
-
* Series *data* is the application's — it knows the symbol, the timeframe, and
|
|
1129
|
-
* the feed — so `restoreState` never recreates series. It restores the things
|
|
1130
|
-
* the chart is the source of truth for (viewport, grid, panes, price scales,
|
|
1131
|
-
* indicators) and reports the series it saw so an app can rebuild them itself
|
|
1132
|
-
* and re-apply their styling.
|
|
1133
|
-
*/
|
|
1134
|
-
|
|
1135
|
-
interface PriceScaleState {
|
|
1136
|
-
marginTop: number;
|
|
1137
|
-
marginBottom: number;
|
|
1138
|
-
minMove: number;
|
|
1139
|
-
mode: PriceScaleMode;
|
|
1140
|
-
inverted: boolean;
|
|
1141
|
-
/** False when the user (or an indicator's fixed range) pinned the scale. */
|
|
1142
|
-
autoScale: boolean;
|
|
1143
|
-
/** The pinned range, present only when `autoScale` is false. */
|
|
1144
|
-
range?: {
|
|
1145
|
-
min: number;
|
|
1146
|
-
max: number;
|
|
1147
|
-
};
|
|
1148
|
-
}
|
|
1149
|
-
interface PaneState {
|
|
1150
|
-
/** Relative height weight among panes. */
|
|
1151
|
-
weight: number;
|
|
1152
|
-
priceScale: PriceScaleState;
|
|
1153
|
-
}
|
|
1154
|
-
/** A series descriptor — enough to rebuild the shell, never the data. */
|
|
1155
|
-
interface SeriesState {
|
|
1156
|
-
type: string;
|
|
1157
|
-
style: SeriesStyle;
|
|
1158
|
-
paneIndex: number;
|
|
1159
|
-
priceScaleId: PriceScaleId;
|
|
1160
|
-
}
|
|
1161
|
-
interface IndicatorState {
|
|
1162
|
-
indicatorId: string;
|
|
1163
|
-
settings: IndicatorSettings;
|
|
1164
|
-
paneIndex: number;
|
|
1165
|
-
}
|
|
1166
|
-
interface ChartState {
|
|
1167
|
-
version: number;
|
|
1168
|
-
/** Visible logical range at save time. */
|
|
1169
|
-
viewport?: {
|
|
1170
|
-
from: number;
|
|
1171
|
-
to: number;
|
|
1172
|
-
};
|
|
1173
|
-
barSpacing?: number;
|
|
1174
|
-
grid?: {
|
|
1175
|
-
vertLines: boolean;
|
|
1176
|
-
horzLines: boolean;
|
|
1177
|
-
};
|
|
1178
|
-
crosshairMode?: 'normal' | 'magnet';
|
|
1179
|
-
panes?: PaneState[];
|
|
1180
|
-
/** Informational: `restoreState` does not recreate these (it has no data). */
|
|
1181
|
-
series?: SeriesState[];
|
|
1182
|
-
indicators?: IndicatorState[];
|
|
1183
|
-
/**
|
|
1184
|
-
* Opaque slot the drawing tier fills. The base engine round-trips it
|
|
1185
|
-
* untouched, so an app that persists state keeps drawings for free once the
|
|
1186
|
-
* tier is loaded.
|
|
1187
|
-
*/
|
|
1188
|
-
drawings?: unknown;
|
|
1189
|
-
}
|
|
1190
|
-
/** What `restoreState` actually applied, so a caller can finish the job. */
|
|
1191
|
-
interface RestoreReport {
|
|
1192
|
-
/** True when the payload was a recognised, applicable state object. */
|
|
1193
|
-
applied: boolean;
|
|
1194
|
-
/** Series descriptors found in the state — the app rebuilds these itself. */
|
|
1195
|
-
series: SeriesState[];
|
|
1196
|
-
/** Indicator instances recreated. */
|
|
1197
|
-
indicators: number;
|
|
1198
|
-
/** Set when the payload was rejected. */
|
|
1199
|
-
reason?: string;
|
|
1200
|
-
}
|
|
1201
|
-
|
|
1202
|
-
/**
|
|
1203
|
-
* Crosshair state + magnet snapping (ARCHITECTURE.md §6). Pure helpers so the
|
|
1204
|
-
* snap logic is unit-testable; drawing lives in render/crosshair.ts.
|
|
1205
|
-
*/
|
|
1206
|
-
|
|
1207
|
-
type CrosshairMode = 'normal' | 'magnet';
|
|
1208
|
-
|
|
1209
|
-
/**
|
|
1210
|
-
* Keyboard shortcuts (ARCHITECTURE.md §7). A small, framework-free shortcut
|
|
1211
|
-
* manager for the chart: a default keymap wired to real chart actions, combos
|
|
1212
|
-
* expressed as physical key codes (layout-independent), rebinding / disabling /
|
|
1213
|
-
* custom commands, an alternate preset, hover-vs-global scope, and optional
|
|
1214
|
-
* localStorage persistence. Pure and testable - `resolve(event)` and
|
|
1215
|
-
* `handleKey(combo)` map input to a command id without needing a real DOM.
|
|
1216
|
-
*/
|
|
1217
|
-
type ShortcutScope = 'hover' | 'global';
|
|
1218
|
-
type ShortcutPreset = 'default' | 'alt';
|
|
1219
|
-
interface CustomShortcut {
|
|
1220
|
-
command: string;
|
|
1221
|
-
label?: string;
|
|
1222
|
-
combos: string | string[];
|
|
1223
|
-
onTrigger: () => void;
|
|
1224
|
-
}
|
|
1225
|
-
interface ShortcutManagerOptions {
|
|
1226
|
-
preset?: ShortcutPreset;
|
|
1227
|
-
/** Rebind (`string`/`string[]`) or unbind (`null`) a command, still listed. */
|
|
1228
|
-
overrides?: Record<string, string | string[] | null>;
|
|
1229
|
-
/** Commands to unbind entirely (still listed in `list()`). */
|
|
1230
|
-
disabledCommands?: string[];
|
|
1231
|
-
customShortcuts?: CustomShortcut[];
|
|
1232
|
-
/** `hover` fires while the pointer is over the chart (or it is focused); `global` always. */
|
|
1233
|
-
scope?: ShortcutScope;
|
|
1234
|
-
/** Persist rebinds/preset to localStorage. */
|
|
1235
|
-
persist?: boolean;
|
|
1236
|
-
storageKey?: string;
|
|
1237
|
-
/** Force platform (⌘ vs Ctrl). Auto-detected when omitted. */
|
|
1238
|
-
isMac?: boolean;
|
|
1239
|
-
}
|
|
1240
|
-
interface ShortcutTriggerEvent {
|
|
1241
|
-
command: string;
|
|
1242
|
-
combo: string;
|
|
1243
|
-
isCustom: boolean;
|
|
1244
|
-
}
|
|
1245
|
-
interface KeyLike {
|
|
1246
|
-
code?: string;
|
|
1247
|
-
key?: string;
|
|
1248
|
-
ctrlKey?: boolean;
|
|
1249
|
-
metaKey?: boolean;
|
|
1250
|
-
altKey?: boolean;
|
|
1251
|
-
shiftKey?: boolean;
|
|
1252
|
-
}
|
|
1253
|
-
interface ShortcutListItem {
|
|
1254
|
-
command: string;
|
|
1255
|
-
label: string;
|
|
1256
|
-
combos: string[];
|
|
1257
|
-
isCustom: boolean;
|
|
1258
|
-
isDisabled: boolean;
|
|
1259
|
-
}
|
|
1260
|
-
declare class ShortcutManager {
|
|
1261
|
-
scope: ShortcutScope;
|
|
1262
|
-
private readonly _isMac;
|
|
1263
|
-
private readonly _persist;
|
|
1264
|
-
private readonly _storageKey;
|
|
1265
|
-
private _preset;
|
|
1266
|
-
private _overrides;
|
|
1267
|
-
private _disabled;
|
|
1268
|
-
private readonly _custom;
|
|
1269
|
-
private _entries;
|
|
1270
|
-
private _reverse;
|
|
1271
|
-
private readonly _listeners;
|
|
1272
|
-
constructor(options?: ShortcutManagerOptions);
|
|
1273
|
-
private _presetCombos;
|
|
1274
|
-
private _effectiveCombos;
|
|
1275
|
-
private _rebuild;
|
|
1276
|
-
/** Resolve a keyboard event to a command id (or null). */
|
|
1277
|
-
resolve(event: KeyLike): string | null;
|
|
1278
|
-
/** Resolve a combo string to a command id (or null). */
|
|
1279
|
-
handleKey(combo: string): string | null;
|
|
1280
|
-
/** Run a custom command's handler (built-ins are executed by the chart). */
|
|
1281
|
-
runCustom(command: string): boolean;
|
|
1282
|
-
emitTrigger(command: string, combo?: string): void;
|
|
1283
|
-
on(cb: (e: ShortcutTriggerEvent) => void): () => void;
|
|
1284
|
-
setBinding(command: string, combo: string | string[]): boolean;
|
|
1285
|
-
disable(command: string): void;
|
|
1286
|
-
resetBinding(command: string): void;
|
|
1287
|
-
resetAll(): void;
|
|
1288
|
-
setPreset(preset: ShortcutPreset): void;
|
|
1289
|
-
addCustom(shortcut: CustomShortcut): void;
|
|
1290
|
-
list(): ShortcutListItem[];
|
|
1291
|
-
state(): {
|
|
1292
|
-
preset: ShortcutPreset;
|
|
1293
|
-
overrides: Record<string, string[]>;
|
|
1294
|
-
disabled: string[];
|
|
1295
|
-
};
|
|
1296
|
-
private _after;
|
|
1297
|
-
private _save;
|
|
1298
|
-
private _load;
|
|
1299
|
-
/** True when a key event targets a text field and should be ignored. */
|
|
1300
|
-
static shouldIgnore(target: unknown): boolean;
|
|
1301
|
-
}
|
|
1302
|
-
|
|
1303
|
-
/**
|
|
1304
|
-
* Trading visualization API (ARCHITECTURE.md §9). A data-driven layer on top of
|
|
1305
|
-
* the chart: your app pushes exchange state (positions, orders, trades) and the
|
|
1306
|
-
* chart renders labelled price-line "pills" (with a cancel/close button and
|
|
1307
|
-
* drag-to-modify) plus trade-fill markers; user interaction is relayed back as
|
|
1308
|
-
* `trading:*` events for the app to send to the exchange. Original,
|
|
1309
|
-
* framework-free API.
|
|
1310
|
-
*/
|
|
1311
|
-
|
|
1312
|
-
type PositionSide = 'long' | 'short';
|
|
1313
|
-
type TradingOrderSide = 'buy' | 'sell';
|
|
1314
|
-
type TradingOrderType = 'limit' | 'stop' | 'stop_limit';
|
|
1315
|
-
type TradeMarkerVariant = 'chevron' | 'bubble' | 'count';
|
|
1316
|
-
type TradingLineVariant = 'standard' | 'line-only';
|
|
1317
|
-
type TradingLineStyle = 'solid' | 'dashed' | 'dotted';
|
|
1318
|
-
interface TradingPosition {
|
|
1319
|
-
id: string;
|
|
1320
|
-
side: PositionSide;
|
|
1321
|
-
entryPrice: number;
|
|
1322
|
-
size: number;
|
|
1323
|
-
pnlText?: string;
|
|
1324
|
-
pnlPercent?: string;
|
|
1325
|
-
color?: string;
|
|
1326
|
-
readOnly?: boolean;
|
|
1327
|
-
variant?: TradingLineVariant;
|
|
1328
|
-
}
|
|
1329
|
-
interface TradingOrder {
|
|
1330
|
-
id: string;
|
|
1331
|
-
type: TradingOrderType;
|
|
1332
|
-
side: TradingOrderSide;
|
|
1333
|
-
price: number;
|
|
1334
|
-
size: number;
|
|
1335
|
-
parentId?: string;
|
|
1336
|
-
bracketRole?: 'tp' | 'sl';
|
|
1337
|
-
color?: string;
|
|
1338
|
-
lineStyle?: TradingLineStyle;
|
|
1339
|
-
lineWidth?: number;
|
|
1340
|
-
readOnly?: boolean;
|
|
1341
|
-
draggable?: boolean;
|
|
1342
|
-
variant?: TradingLineVariant;
|
|
1343
|
-
}
|
|
1344
|
-
interface TradingTrade {
|
|
1345
|
-
id: string;
|
|
1346
|
-
side: TradingOrderSide;
|
|
1347
|
-
price: number;
|
|
1348
|
-
size: number;
|
|
1349
|
-
/** Execution time in milliseconds. */
|
|
1350
|
-
timestamp: number;
|
|
1351
|
-
variant?: TradeMarkerVariant;
|
|
1352
|
-
color?: string;
|
|
1353
|
-
label?: string;
|
|
1354
|
-
}
|
|
1355
|
-
interface TradingSyncPayload {
|
|
1356
|
-
positions?: TradingPosition[];
|
|
1357
|
-
orders?: TradingOrder[];
|
|
1358
|
-
trades?: TradingTrade[];
|
|
1359
|
-
}
|
|
1360
|
-
interface TradingColors {
|
|
1361
|
-
long: string;
|
|
1362
|
-
short: string;
|
|
1363
|
-
order: string;
|
|
1364
|
-
tp: string;
|
|
1365
|
-
sl: string;
|
|
1366
|
-
buy: string;
|
|
1367
|
-
sell: string;
|
|
1368
|
-
}
|
|
1369
|
-
interface TradingSettings {
|
|
1370
|
-
longColor?: string;
|
|
1371
|
-
shortColor?: string;
|
|
1372
|
-
orderColor?: string;
|
|
1373
|
-
tpColor?: string;
|
|
1374
|
-
slColor?: string;
|
|
1375
|
-
buyColor?: string;
|
|
1376
|
-
sellColor?: string;
|
|
1377
|
-
}
|
|
1378
|
-
/** What the controller needs from the chart (the Chart implements this). */
|
|
1379
|
-
interface TradingHost {
|
|
1380
|
-
addPrimitive(p: IPrimitive): void;
|
|
1381
|
-
removePrimitive(p: IPrimitive): void;
|
|
1382
|
-
subscribeClick(cb: (externalId: string) => void): void;
|
|
1383
|
-
subscribeDrag(onDrag: (externalId: string, price: number) => void, onDragEnd?: (externalId: string, price: number) => void): void;
|
|
1384
|
-
/** Optional: route trading events onto the chart's unified `chart.on(...)` bus. */
|
|
1385
|
-
emit?(event: string, payload: unknown): void;
|
|
1386
|
-
}
|
|
1387
|
-
declare class TradingController {
|
|
1388
|
-
private readonly _host;
|
|
1389
|
-
private readonly _positions;
|
|
1390
|
-
private readonly _orders;
|
|
1391
|
-
private readonly _trades;
|
|
1392
|
-
private readonly _listeners;
|
|
1393
|
-
private readonly _dragPrev;
|
|
1394
|
-
private _colors;
|
|
1395
|
-
private _markers;
|
|
1396
|
-
constructor(host: TradingHost);
|
|
1397
|
-
on(event: string, cb: (payload: unknown) => void): () => void;
|
|
1398
|
-
off(event: string, cb: (payload: unknown) => void): void;
|
|
1399
|
-
private _emit;
|
|
1400
|
-
setSettings(settings: TradingSettings): void;
|
|
1401
|
-
getSettings(): TradingColors;
|
|
1402
|
-
setPositions(positions: readonly TradingPosition[]): void;
|
|
1403
|
-
setOrders(orders: readonly TradingOrder[]): void;
|
|
1404
|
-
setTrades(trades: readonly TradingTrade[]): void;
|
|
1405
|
-
addTrade(trade: TradingTrade): void;
|
|
1406
|
-
upsertOrder(order: TradingOrder): void;
|
|
1407
|
-
removeOrder(id: string): void;
|
|
1408
|
-
syncState(payload: TradingSyncPayload): void;
|
|
1409
|
-
updatePositionPnl(id: string, unrealizedPnl: number, pnlText?: string, pnlPercent?: string): void;
|
|
1410
|
-
getPositions(): TradingPosition[];
|
|
1411
|
-
getOrders(): TradingOrder[];
|
|
1412
|
-
getTrades(): TradingTrade[];
|
|
1413
|
-
clear(): void;
|
|
1414
|
-
private _renderTrades;
|
|
1415
|
-
private _sync;
|
|
1416
|
-
private _sig;
|
|
1417
|
-
/** Info segment for a position: live P&L text (side/size live in badge/qty). */
|
|
1418
|
-
private _positionPill;
|
|
1419
|
-
private _positionOpts;
|
|
1420
|
-
private _orderOpts;
|
|
1421
|
-
private _onClick;
|
|
1422
|
-
private _onDrag;
|
|
1423
|
-
private _onDragEnd;
|
|
1424
|
-
}
|
|
1425
|
-
|
|
1426
|
-
/**
|
|
1427
|
-
* Event markers (ARCHITECTURE.md §8.2): Earnings / Dividend / Split badges in a
|
|
1428
|
-
* strip near the bottom of the plot. Time-anchored only (no price). Hover/click
|
|
1429
|
-
* carry an external id for tooltip wiring. Data source is an integration concern
|
|
1430
|
-
* (OpenAlgo has no corporate-actions calendar) — the renderer ships regardless.
|
|
1431
|
-
*/
|
|
1432
|
-
|
|
1433
|
-
interface ChartEvent {
|
|
1434
|
-
time: number;
|
|
1435
|
-
type: 'earnings' | 'dividend' | 'split' | 'news' | string;
|
|
1436
|
-
label: string;
|
|
1437
|
-
color?: string;
|
|
1438
|
-
id?: string;
|
|
1439
|
-
}
|
|
1440
|
-
declare class EventMarkers implements IPrimitive {
|
|
1441
|
-
private _events;
|
|
1442
|
-
private _host;
|
|
1443
|
-
private _positions;
|
|
1444
|
-
attached(host: PrimitiveHost): void;
|
|
1445
|
-
detached(): void;
|
|
1446
|
-
zOrder(): ZOrder;
|
|
1447
|
-
setEvents(events: readonly ChartEvent[]): void;
|
|
1448
|
-
draw(ctx: CanvasRenderingContext2D, rc: PrimitiveRenderContext): void;
|
|
1449
|
-
hitTest(x: number, y: number): PrimitiveHit | null;
|
|
1450
|
-
}
|
|
1451
|
-
|
|
1452
|
-
/**
|
|
1453
|
-
* Time navigator (ARCHITECTURE.md §8) — the hover-revealed zoom / step controls
|
|
1454
|
-
* that sit just above the time axis: `−` `+` to zoom, `‹` `›` to step one bar.
|
|
1455
|
-
*
|
|
1456
|
-
* Invisible until the pointer nears the bottom of the chart, so a clean chart
|
|
1457
|
-
* stays clean. It fades in and out rather than snapping, which is what keeps it
|
|
1458
|
-
* from reading as a glitch when the cursor crosses the reveal band.
|
|
1459
|
-
*
|
|
1460
|
-
* Reveal is driven by an explicit `setPointer` from the chart, **not** by
|
|
1461
|
-
* `rc.hoverId`. Hover ids come from `bestHit`, which picks the nearest primitive
|
|
1462
|
-
* — so a drawing or an order line near the bottom of the chart would win the
|
|
1463
|
-
* hit and silently hide the controls. Pointer position is the honest input here;
|
|
1464
|
-
* hit-testing still owns the buttons themselves.
|
|
1465
|
-
*/
|
|
1466
|
-
|
|
1467
|
-
/** Command each button runs. These are `Chart` shortcut command ids. */
|
|
1468
|
-
type TimeNavigatorAction = 'zoomOut' | 'zoomIn' | 'panLeftBar' | 'panRightBar';
|
|
1469
|
-
interface TimeNavigatorOptions {
|
|
1470
|
-
/** Prefix for hit ids. Lets a host run more than one. */
|
|
1471
|
-
id: string;
|
|
1472
|
-
/** Buttons, left to right. A `null` inserts a gap between groups. */
|
|
1473
|
-
buttons: readonly (TimeNavigatorAction | null)[];
|
|
1474
|
-
/** Button box size in media px. */
|
|
1475
|
-
size: number;
|
|
1476
|
-
/** Gap between buttons, and the wider gap a `null` produces. */
|
|
1477
|
-
gap: number;
|
|
1478
|
-
groupGap: number;
|
|
1479
|
-
/** Distance from the bottom of the plot to the bottom of the buttons. */
|
|
1480
|
-
bottomMargin: number;
|
|
1481
|
-
/**
|
|
1482
|
-
* Height of the reveal band above the plot bottom. The pointer anywhere in
|
|
1483
|
-
* this band brings the controls in.
|
|
1484
|
-
*/
|
|
1485
|
-
revealHeight: number;
|
|
1486
|
-
/** Seconds the fade takes. 0 disables the animation. */
|
|
1487
|
-
fadeSeconds: number;
|
|
1488
|
-
/** Tooltip label per action. */
|
|
1489
|
-
labels: Record<TimeNavigatorAction, string>;
|
|
1490
|
-
/** Optional keyboard hint shown next to the label, e.g. `"Ctrl + −"`. */
|
|
1491
|
-
hints: Partial<Record<TimeNavigatorAction, string>>;
|
|
1492
|
-
/** Show the tooltip above the hovered button. */
|
|
1493
|
-
showTooltip: boolean;
|
|
1494
|
-
font: number;
|
|
1495
|
-
radius: number;
|
|
1496
|
-
zOrder: ZOrder;
|
|
1497
|
-
}
|
|
1498
|
-
|
|
1499
|
-
/**
|
|
1500
|
-
* Top-level chart orchestrator (ARCHITECTURE.md §3.3). Owns the shared
|
|
1501
|
-
* DataLayer + time scale, the panes, the invalidate mask, and the render loop.
|
|
1502
|
-
* Phase 2 renders static candlesticks with price/time axes; pan/zoom (Phase 3)
|
|
1503
|
-
* and live data (Phase 4) build on this.
|
|
1504
|
-
*/
|
|
1505
|
-
|
|
1506
|
-
interface ChartOptions {
|
|
1507
|
-
document?: Document;
|
|
1508
|
-
pixelRatio?: () => number;
|
|
1509
|
-
raf?: {
|
|
1510
|
-
schedule: RafScheduler;
|
|
1511
|
-
cancel?: RafCanceller;
|
|
1512
|
-
};
|
|
1513
|
-
/** Full palette; pass `darkTheme` (default), `lightTheme`, or a custom ChartTheme. */
|
|
1514
|
-
theme?: ChartTheme;
|
|
1515
|
-
priceAxisWidth?: number;
|
|
1516
|
-
timeAxisHeight?: number;
|
|
1517
|
-
/**
|
|
1518
|
-
* Crosshair behaviour. 'normal' (default) — the cross follows the pointer
|
|
1519
|
-
* exactly. 'magnet' — the horizontal line snaps to the nearest O/H/L/C of the
|
|
1520
|
-
* bar under the cursor (price pane only).
|
|
1521
|
-
*/
|
|
1522
|
-
crosshairMode?: CrosshairMode;
|
|
1523
|
-
/** Time source for kinetic animation (defaults to performance.now). */
|
|
1524
|
-
now?: () => number;
|
|
1525
|
-
/** Enable OHLC-preserving conflation when zoomed out (§4.4). Default false. */
|
|
1526
|
-
conflate?: boolean;
|
|
1527
|
-
/** Conflation aggressiveness (default 1). */
|
|
1528
|
-
conflationFactor?: number;
|
|
1529
|
-
/** Grid line visibility. Both default to true. */
|
|
1530
|
-
grid?: {
|
|
1531
|
-
vertLines?: boolean;
|
|
1532
|
-
horzLines?: boolean;
|
|
1533
|
-
};
|
|
1534
|
-
/** Accessible label for the chart container (screen readers). */
|
|
1535
|
-
ariaLabel?: string;
|
|
1536
|
-
/**
|
|
1537
|
-
* Keyboard shortcuts. Pass a configured `ShortcutManager`, options to build
|
|
1538
|
-
* one, or `false` to disable keyboard control. Defaults to the built-in keymap.
|
|
1539
|
-
*/
|
|
1540
|
-
shortcuts?: ShortcutManager | Partial<ShortcutManagerOptions> | false;
|
|
1541
|
-
/**
|
|
1542
|
-
* Custom price formatter for every pane's axis tick labels, the last-price
|
|
1543
|
-
* tag, and price-line labels. e.g. `(p) => '$' + p.toFixed(2)`. When omitted,
|
|
1544
|
-
* a tick-size-aware `toFixed` is used. Change it later via `setPriceFormatter`.
|
|
1545
|
-
*/
|
|
1546
|
-
priceFormatter?: (price: number) => string;
|
|
1547
|
-
/**
|
|
1548
|
-
* Default price-scale options applied to every pane (tick size `minMove`,
|
|
1549
|
-
* `mode: 'linear' | 'logarithmic'`, `inverted`, and top/bottom margins).
|
|
1550
|
-
* Tune a single pane later via `chart.panes()[n].priceScale.setOptions(...)`.
|
|
1551
|
-
*/
|
|
1552
|
-
priceScale?: Partial<PriceScaleOptions>;
|
|
1553
|
-
/**
|
|
1554
|
-
* Custom time-axis and crosshair label formatter (receives UTC seconds). When
|
|
1555
|
-
* omitted, labels use IST (Indian market default). e.g. for UTC:
|
|
1556
|
-
* `(s) => new Date(s * 1000).toISOString().slice(11, 16)`.
|
|
1557
|
-
*/
|
|
1558
|
-
timeFormatter?: (utcSeconds: number, tickMark?: TickMarkType) => string;
|
|
1559
|
-
/**
|
|
1560
|
-
* Hover-revealed zoom / step controls above the time axis (TradingView-style).
|
|
1561
|
-
* `true` by default — they stay invisible until the pointer nears the bottom
|
|
1562
|
-
* of the chart. Pass `false` to drop them, or an options object to restyle.
|
|
1563
|
-
*/
|
|
1564
|
-
timeNavigator?: boolean | Partial<TimeNavigatorOptions>;
|
|
1565
|
-
}
|
|
1566
|
-
interface AddSeriesOptions {
|
|
1567
|
-
/** Target pane index (0 = price). Higher panes are created on demand. */
|
|
1568
|
-
paneIndex?: number;
|
|
1569
|
-
/** Style overrides merged onto the chart type's defaults. */
|
|
1570
|
-
style?: SeriesStyle;
|
|
1571
|
-
/**
|
|
1572
|
-
* Which price axis this series maps to. 'right' (default) and 'left' each draw
|
|
1573
|
-
* an axis and autoscale independently; '' is a hidden overlay scale (no axis)
|
|
1574
|
-
* for a volume histogram inside the price pane.
|
|
1575
|
-
*/
|
|
1576
|
-
priceScaleId?: PriceScaleId;
|
|
1577
|
-
/**
|
|
1578
|
-
* Value formatting applied to this series' price scale (axis + crosshair tag):
|
|
1579
|
-
* `price` (tick-size precision), `volume` (compact 1.2K / 3.4M / 5.6B), or a
|
|
1580
|
-
* `custom` formatter (currency, percent, ...).
|
|
1581
|
-
*/
|
|
1582
|
-
priceFormat?: {
|
|
1583
|
-
type: 'price';
|
|
1584
|
-
precision?: number;
|
|
1585
|
-
minMove?: number;
|
|
1586
|
-
} | {
|
|
1587
|
-
type: 'volume';
|
|
1588
|
-
} | {
|
|
1589
|
-
type: 'custom';
|
|
1590
|
-
formatter: (value: number) => string;
|
|
1591
|
-
};
|
|
1592
|
-
}
|
|
1593
|
-
/**
|
|
1594
|
-
* Emitted on every crosshair move (and `null` fields on pointer-leave) so a host
|
|
1595
|
-
* can render an OHLC legend / tooltip. `bar` is the hovered bar of the primary
|
|
1596
|
-
* price series; `point` is container-relative media px for positioning a
|
|
1597
|
-
* floating tooltip. See `subscribeCrosshairMove`.
|
|
1598
|
-
*/
|
|
1599
|
-
interface CrosshairMoveEvent {
|
|
1600
|
-
/** UTC seconds of the hovered bar, or null when off the data / pointer left. */
|
|
1601
|
-
time: number | null;
|
|
1602
|
-
/** Logical index under the cursor, or null. */
|
|
1603
|
-
index: number | null;
|
|
1604
|
-
/** Price under the cursor on the hovered pane, or null. */
|
|
1605
|
-
price: number | null;
|
|
1606
|
-
/** Hovered bar of the primary (first) price series, or null. */
|
|
1607
|
-
bar: Bar | null;
|
|
1608
|
-
/** Cursor position in container media px, or null on leave. */
|
|
1609
|
-
point: {
|
|
1610
|
-
x: number;
|
|
1611
|
-
y: number;
|
|
1612
|
-
} | null;
|
|
1613
|
-
/** Pane under the cursor, or null on leave. */
|
|
1614
|
-
paneIndex?: number | null;
|
|
1615
|
-
}
|
|
1616
|
-
declare class Chart {
|
|
1617
|
-
private readonly _container;
|
|
1618
|
-
private readonly _doc;
|
|
1619
|
-
private readonly _pixelRatio;
|
|
1620
|
-
private _theme;
|
|
1621
|
-
private readonly _panes;
|
|
1622
|
-
private readonly _loop;
|
|
1623
|
-
private readonly _dataLayer;
|
|
1624
|
-
private readonly _timeScale;
|
|
1625
|
-
private readonly _priceAxisWidth;
|
|
1626
|
-
private readonly _timeAxisHeight;
|
|
1627
|
-
private _pending;
|
|
1628
|
-
private _resizeObserver;
|
|
1629
|
-
private _width;
|
|
1630
|
-
private _height;
|
|
1631
|
-
private _hasFitContent;
|
|
1632
|
-
private _crosshairMode;
|
|
1633
|
-
private _shortcuts;
|
|
1634
|
-
private _trading;
|
|
1635
|
-
private _pointerInside;
|
|
1636
|
-
private _keyTarget;
|
|
1637
|
-
private readonly _now;
|
|
1638
|
-
private readonly _conflate;
|
|
1639
|
-
private readonly _conflationFactor;
|
|
1640
|
-
private _gridVert;
|
|
1641
|
-
private _gridHorz;
|
|
1642
|
-
private _cursorPane;
|
|
1643
|
-
private _cursor;
|
|
1644
|
-
private _dragging;
|
|
1645
|
-
private _dragStartX;
|
|
1646
|
-
private _dragStartY;
|
|
1647
|
-
private _lastDragY;
|
|
1648
|
-
private readonly _pointers;
|
|
1649
|
-
private _pinch;
|
|
1650
|
-
private _pinchPane;
|
|
1651
|
-
private _liveRegion;
|
|
1652
|
-
private _dragStartOffset;
|
|
1653
|
-
private _lastDragX;
|
|
1654
|
-
private _lastDragT;
|
|
1655
|
-
private _dragVelocity;
|
|
1656
|
-
private _kineticHandle;
|
|
1657
|
-
private readonly _firstDataId;
|
|
1658
|
-
private readonly _indicators;
|
|
1659
|
-
/** Guards indicator recompute against re-entry via its own `series.setData`. */
|
|
1660
|
-
private _recomputing;
|
|
1661
|
-
/** Opaque drawing-tier payload, round-tripped through get/restoreState. */
|
|
1662
|
-
private _drawingState;
|
|
1663
|
-
/** Pane currently maximized, and the weights to restore when it un-maximizes. */
|
|
1664
|
-
private _maximizedPane;
|
|
1665
|
-
private _savedWeights;
|
|
1666
|
-
/** Legend rows per pane, so new ones stack below existing ones. */
|
|
1667
|
-
private readonly _legends;
|
|
1668
|
-
/** Pane holding the primary price series (only this pane gets magnet snapping). */
|
|
1669
|
-
private _firstPaneIndex;
|
|
1670
|
-
private _historyLoader;
|
|
1671
|
-
private _loadingHistory;
|
|
1672
|
-
private _clickCb;
|
|
1673
|
-
private _crosshairCb;
|
|
1674
|
-
private _pointerMoved;
|
|
1675
|
-
/** While true, pointer gestures place anchors instead of panning. */
|
|
1676
|
-
private _placementMode;
|
|
1677
|
-
private _downPane;
|
|
1678
|
-
private _downX;
|
|
1679
|
-
private _downLocalY;
|
|
1680
|
-
private _dragId;
|
|
1681
|
-
private _hoverId;
|
|
1682
|
-
private _overlayFrozen;
|
|
1683
|
-
private _dragCb;
|
|
1684
|
-
private _dragEndCb;
|
|
1685
|
-
private _axisDrag;
|
|
1686
|
-
/** Active pane-divider drag: which boundary, and the weights/heights at grab time. */
|
|
1687
|
-
/** True once a primitive drag has actually moved — see the pointerup note. */
|
|
1688
|
-
private _dragMoved;
|
|
1689
|
-
/** Where the drag was grabbed, in data space, so deltas start at the press. */
|
|
1690
|
-
private _dragFrom;
|
|
1691
|
-
private _paneResize;
|
|
1692
|
-
private _axisStartCoord;
|
|
1693
|
-
private _axisStartMin;
|
|
1694
|
-
private _axisStartMax;
|
|
1695
|
-
private _axisStartSpacing;
|
|
1696
|
-
private _priceFormatter;
|
|
1697
|
-
private _priceScaleOptions;
|
|
1698
|
-
private _timeFormatter;
|
|
1699
|
-
private _leftAxisWidth;
|
|
1700
|
-
private _timeNav;
|
|
1701
|
-
/** Pane the navigator is currently attached to, so it can follow the bottom. */
|
|
1702
|
-
private _timeNavPane;
|
|
1703
|
-
constructor(container: HTMLElement, options?: ChartOptions);
|
|
1704
|
-
/** Register a callback fired when the user pans near the left (oldest) edge. */
|
|
1705
|
-
setHistoryLoader(loader: () => void): void;
|
|
1706
|
-
/** Call after a history-paging load resolves to re-enable the trigger. */
|
|
1707
|
-
historyLoadComplete(): void;
|
|
1708
|
-
get dataLayer(): DataLayer;
|
|
1709
|
-
get timeScale(): TimeScale;
|
|
1710
|
-
/** Restore a saved logical range (e.g. preserve the user's zoom across a data reload). */
|
|
1711
|
-
setVisibleLogicalRange(range: LogicalRange): void;
|
|
1712
|
-
/** The current visible logical range. */
|
|
1713
|
-
getVisibleLogicalRange(): LogicalRange;
|
|
1714
|
-
/** Fit all bars into view (no-arg convenience; bar count from the data). */
|
|
1715
|
-
fitContent(): void;
|
|
1716
|
-
/** The keyboard shortcut manager (null when shortcuts are disabled). */
|
|
1717
|
-
get shortcuts(): ShortcutManager | null;
|
|
1718
|
-
/**
|
|
1719
|
-
* The data-driven trading layer: push positions/orders/trades and the chart
|
|
1720
|
-
* renders pills + markers, emitting `trading:*` events on interaction. Created
|
|
1721
|
-
* on first access.
|
|
1722
|
-
*/
|
|
1723
|
-
get trading(): TradingController;
|
|
1724
|
-
/** Add a series and return its data handle. */
|
|
1725
|
-
addSeries(type: SeriesType, options?: AddSeriesOptions): SeriesApi;
|
|
1726
|
-
/**
|
|
1727
|
-
* `claimPrimary` is false for series the chart creates on a caller's behalf
|
|
1728
|
-
* (indicator plots), so an indicator's line never becomes the price series
|
|
1729
|
-
* that drives the magnet crosshair and the OHLC legend.
|
|
1730
|
-
*/
|
|
1731
|
-
private _createSeries;
|
|
1732
|
-
/** Add a horizontal price line (order/SL/TP/alert/level) to a pane. */
|
|
1733
|
-
addPriceLine(opts: PriceLineOptions, paneIndex?: number): PriceLine;
|
|
1734
|
-
/** Add an earnings/dividend/split event-marker strip to a pane. */
|
|
1735
|
-
addEventMarkers(paneIndex?: number): EventMarkers;
|
|
1736
|
-
/**
|
|
1737
|
-
* Add a registered indicator. Built-in descriptors live in the lazy
|
|
1738
|
-
* `openalgo-charts/indicators` tier — import it (or register your own with
|
|
1739
|
-
* `registerIndicator`) before calling this.
|
|
1740
|
-
*
|
|
1741
|
-
* `'onchart'` indicators overlay the price pane; `'pane'` indicators get a new
|
|
1742
|
-
* pane of their own unless `paneIndex` says otherwise. The returned handle
|
|
1743
|
-
* recomputes automatically whenever the source data changes.
|
|
1744
|
-
*
|
|
1745
|
-
* ```ts
|
|
1746
|
-
* import 'openalgo-charts/indicators';
|
|
1747
|
-
* const macd = chart.addIndicator('macd', { fastPeriod: 8 });
|
|
1748
|
-
* macd.setSettings({ fastPeriod: 12 });
|
|
1749
|
-
* macd.remove();
|
|
1750
|
-
* ```
|
|
1751
|
-
*/
|
|
1752
|
-
addIndicator(indicatorId: string, settings?: Readonly<IndicatorSettings>, options?: {
|
|
1753
|
-
paneIndex?: number;
|
|
1754
|
-
}): IndicatorApi;
|
|
1755
|
-
/** Every live indicator instance, in the order they were added. */
|
|
1756
|
-
indicators(): readonly IndicatorApi[];
|
|
1757
|
-
/** Remove one indicator instance by its handle id. Returns true if it existed. */
|
|
1758
|
-
removeIndicator(instanceId: string): boolean;
|
|
1759
|
-
private _indicatorHost;
|
|
1760
|
-
/**
|
|
1761
|
-
* Recompute every indicator after a source-data change. Reentrant-guarded:
|
|
1762
|
-
* an indicator writes its plots with `series.setData`, which re-enters the
|
|
1763
|
-
* same data-mutation path that called us.
|
|
1764
|
-
*/
|
|
1765
|
-
private _recomputeIndicators;
|
|
1766
|
-
/** Subscribe to clicks on hit-testable primitives (markers, events, lines). */
|
|
1767
|
-
subscribeClick(cb: (externalId: string) => void): void;
|
|
1768
|
-
/**
|
|
1769
|
-
* Subscribe to crosshair movement for an OHLC legend / tooltip. The callback
|
|
1770
|
-
* fires with the hovered bar of the primary price series on every move, and
|
|
1771
|
-
* with all-null fields when the pointer leaves the plot.
|
|
1772
|
-
*/
|
|
1773
|
-
subscribeCrosshairMove(cb: (e: CrosshairMoveEvent) => void): void;
|
|
1774
|
-
/**
|
|
1775
|
-
* Subscribe to drags of draggable primitives (order / SL / TP lines, drawing
|
|
1776
|
-
* handles). Fires per move and on release.
|
|
1777
|
-
*
|
|
1778
|
-
* `time` is the UTC seconds under the cursor, interpolated between bars and
|
|
1779
|
-
* extrapolated past the right edge — so a two-axis drag (a trendline endpoint,
|
|
1780
|
-
* a projection) has a usable time even where the gapless axis has no bar.
|
|
1781
|
-
* Price-only consumers can simply ignore it.
|
|
1782
|
-
*/
|
|
1783
|
-
subscribeDrag(onDrag: (externalId: string, price: number, time: number) => void, onDragEnd?: (externalId: string, price: number, time: number) => void): void;
|
|
1784
|
-
/**
|
|
1785
|
-
* Guarantee a pane's price scale has a real range before converting y↔price.
|
|
1786
|
-
* Autoscaling normally happens during paint, so every coordinate API — and
|
|
1787
|
-
* the price carried by click/drag events — used to answer with the default
|
|
1788
|
-
* 0..1 (or ±Infinity) until the first frame had run. Callers cannot be asked
|
|
1789
|
-
* to wait for a paint, so scale on demand.
|
|
1790
|
-
*/
|
|
1791
|
-
private _ensureScaled;
|
|
1792
|
-
/** Container-relative x (media px) → UTC seconds on the (gapless) time axis. */
|
|
1793
|
-
private _xToTime;
|
|
1794
|
-
/** UTC seconds → container-relative x (media px). The inverse of `_xToTime`. */
|
|
1795
|
-
timeToCoordinate(time: number): number;
|
|
1796
|
-
/** Container-relative x (media px) → UTC seconds. */
|
|
1797
|
-
coordinateToTime(x: number): number;
|
|
1798
|
-
private readonly _listeners;
|
|
1799
|
-
/** Subscribe to a named chart event. Returns an unsubscribe function. */
|
|
1800
|
-
on(event: string, cb: (payload: unknown) => void): () => void;
|
|
1801
|
-
/** Subscribe to the next occurrence of an event, then auto-unsubscribe. */
|
|
1802
|
-
once(event: string, cb: (payload: unknown) => void): () => void;
|
|
1803
|
-
/** Remove one listener, or (when `cb` is omitted) every listener for an event. */
|
|
1804
|
-
off(event: string, cb?: (payload: unknown) => void): void;
|
|
1805
|
-
/** Dispatch a named event. Public so the lazy trade layer can route through it. */
|
|
1806
|
-
emit(event: string, payload: unknown): void;
|
|
1807
|
-
/** Emit a viewport event ('pan' | 'zoom') carrying the visible time + logical range. */
|
|
1808
|
-
private _emitViewport;
|
|
1809
|
-
/** Public: attach any primitive (indicators, profiles, custom overlays) to a pane. */
|
|
1810
|
-
addPrimitive(primitive: IPrimitive, paneIndex?: number): void;
|
|
1811
|
-
/**
|
|
1812
|
-
* Map a price to a container-relative Y in media (CSS) px, for positioning DOM
|
|
1813
|
-
* overlays (order panels, tooltips) over a pane. Returns null if the pane
|
|
1814
|
-
* doesn't exist. The inverse is `coordinateToPrice`.
|
|
1815
|
-
*/
|
|
1816
|
-
priceToCoordinate(price: number, paneIndex?: number): number | null;
|
|
1817
|
-
/** Map a container-relative media-px Y back to a price on a pane (inverse of priceToCoordinate). */
|
|
1818
|
-
coordinateToPrice(y: number, paneIndex?: number): number | null;
|
|
1819
|
-
/**
|
|
1820
|
-
* Toggle the vertical (time) and/or horizontal (price) grid lines at runtime.
|
|
1821
|
-
* Omitted fields keep their current visibility. Repaints every pane.
|
|
1822
|
-
*/
|
|
1823
|
-
setGridOptions(opts: {
|
|
1824
|
-
vertLines?: boolean;
|
|
1825
|
-
horzLines?: boolean;
|
|
1826
|
-
}): void;
|
|
1827
|
-
/** Current grid line visibility. */
|
|
1828
|
-
gridOptions(): {
|
|
1829
|
-
vertLines: boolean;
|
|
1830
|
-
horzLines: boolean;
|
|
1831
|
-
};
|
|
1832
|
-
/**
|
|
1833
|
-
* Flatten every pane's base + overlay canvas into one opaque canvas (device
|
|
1834
|
-
* px). The chart renders as stacked layered canvases, so the browser's native
|
|
1835
|
-
* right-click "Save image" only captures the layer under the pointer (usually
|
|
1836
|
-
* the transparent crosshair overlay) — use this to export the full chart.
|
|
1837
|
-
*/
|
|
1838
|
-
takeScreenshot(): HTMLCanvasElement;
|
|
1839
|
-
private _addPrimitive;
|
|
1840
|
-
/** Remove a primitive from whichever pane holds it. */
|
|
1841
|
-
removePrimitive(primitive: IPrimitive): void;
|
|
1842
|
-
/**
|
|
1843
|
-
* Renumber legend rows per pane in insertion order, so removing one closes
|
|
1844
|
-
* the gap instead of leaving a hole where it used to sit.
|
|
1845
|
-
*/
|
|
1846
|
-
private _restackLegends;
|
|
1847
|
-
/** A host for the (lazy-loaded) trade layer to attach/detach its primitives on a pane. */
|
|
1848
|
-
tradeHost(paneIndex?: number): {
|
|
1849
|
-
addPrimitive(p: IPrimitive): void;
|
|
1850
|
-
removePrimitive(p: IPrimitive): void;
|
|
1851
|
-
};
|
|
1852
|
-
/** Apply one live bar; auto-scroll only on a genuine right-edge append. */
|
|
1853
|
-
private _updateBar;
|
|
1854
|
-
private _ensurePane;
|
|
1855
|
-
private _setData;
|
|
1856
|
-
/** History paging: merge older bars, preserving the viewport (§4.2). */
|
|
1857
|
-
private _prependData;
|
|
1858
|
-
private _addPane;
|
|
1859
|
-
/**
|
|
1860
|
-
* Set a custom price formatter for every pane's axis labels, last-price tag,
|
|
1861
|
-
* and price-line labels at runtime (e.g. switch to a currency format). Pass
|
|
1862
|
-
* null to restore the default tick-size-aware formatting.
|
|
1863
|
-
*/
|
|
1864
|
-
setPriceFormatter(fn: ((price: number) => string) | null): void;
|
|
1865
|
-
/**
|
|
1866
|
-
* Set a custom time-axis + crosshair label formatter (UTC seconds -> string)
|
|
1867
|
-
* at runtime. Pass undefined to restore the IST default.
|
|
1868
|
-
*/
|
|
1869
|
-
setTimeFormatter(fn: ((utcSeconds: number, tickMark?: TickMarkType) => string) | undefined): void;
|
|
1870
|
-
/**
|
|
1871
|
-
* Turn pointer gestures into anchor placement instead of panning. A host arms
|
|
1872
|
-
* this while a drawing tool is active: a press no longer scrolls the chart, and
|
|
1873
|
-
* a press-drag-release is reported as two `click` events (press point, then
|
|
1874
|
-
* release point, the latter tagged `viaDrag`) so a two-point shape can be drawn
|
|
1875
|
-
* in one gesture. `DrawingController` drives this for you.
|
|
1876
|
-
*/
|
|
1877
|
-
setPlacementMode(active: boolean): void;
|
|
1878
|
-
/** Swap the palette at runtime (dark/light toggle) without recreating the chart. */
|
|
1879
|
-
setTheme(theme: ChartTheme): void;
|
|
1880
|
-
/**
|
|
1881
|
-
* Apply a subset of chart options at runtime (theme, grid, formatters,
|
|
1882
|
-
* crosshair mode) without recreating the chart.
|
|
1883
|
-
*/
|
|
1884
|
-
applyOptions(opts: {
|
|
1885
|
-
theme?: ChartTheme;
|
|
1886
|
-
grid?: {
|
|
1887
|
-
vertLines?: boolean;
|
|
1888
|
-
horzLines?: boolean;
|
|
1889
|
-
};
|
|
1890
|
-
priceFormatter?: ((price: number) => string) | null;
|
|
1891
|
-
timeFormatter?: ((utcSeconds: number, tickMark?: TickMarkType) => string) | undefined;
|
|
1892
|
-
crosshairMode?: CrosshairMode;
|
|
1893
|
-
}): void;
|
|
1894
|
-
panes(): readonly Pane[];
|
|
1895
|
-
/**
|
|
1896
|
-
* Capture the chart's serialisable state: viewport, grid, crosshair mode,
|
|
1897
|
-
* pane weights and price scales, indicator instances, and a `drawings` slot
|
|
1898
|
-
* the drawing tier fills. JSON-safe.
|
|
1899
|
-
*
|
|
1900
|
-
* Series **data** is not captured — the app owns that (it knows the symbol,
|
|
1901
|
-
* the timeframe, and the feed). Series *descriptors* are, so an app that
|
|
1902
|
-
* rebuilds its own series can re-apply their styling and placement.
|
|
1903
|
-
*/
|
|
1904
|
-
getState(): ChartState;
|
|
1905
|
-
/**
|
|
1906
|
-
* Re-apply a state captured by `getState`. Restores grid, crosshair mode,
|
|
1907
|
-
* pane weights and price scales, indicators, and the viewport — everything
|
|
1908
|
-
* the chart is the source of truth for.
|
|
1909
|
-
*
|
|
1910
|
-
* It does **not** recreate series: the chart has no way to know their data.
|
|
1911
|
-
* The returned report lists the series descriptors it saw so the caller can
|
|
1912
|
-
* rebuild them (`addSeries(s.type, { paneIndex: s.paneIndex, style: s.style })`)
|
|
1913
|
-
* and then feed them.
|
|
1914
|
-
*
|
|
1915
|
-
* Restore the viewport *after* your data lands — logical ranges index bars, so
|
|
1916
|
-
* a range applied to an empty chart means nothing. Call `restoreState` again
|
|
1917
|
-
* (or `setVisibleLogicalRange`) once the series are populated.
|
|
1918
|
-
*/
|
|
1919
|
-
restoreState(state: unknown): RestoreReport;
|
|
1920
|
-
/**
|
|
1921
|
-
* The opaque `drawings` slot in the chart state. The base engine only
|
|
1922
|
-
* round-trips it; the drawing tier reads and writes it.
|
|
1923
|
-
*/
|
|
1924
|
-
drawingState(): unknown;
|
|
1925
|
-
setDrawingState(value: unknown): void;
|
|
1926
|
-
invalidate(build: (mask: InvalidateMask) => void): void;
|
|
1927
|
-
applySize(width: number, height: number): void;
|
|
1928
|
-
/** Distribute height across panes by weight; sync the shared time-scale width. */
|
|
1929
|
-
private _relayout;
|
|
1930
|
-
/** Reserve a chart-wide left-axis column when any pane has a left price scale. */
|
|
1931
|
-
private _recomputeLeftAxis;
|
|
1932
|
-
private _weightTotal;
|
|
1933
|
-
/** Grab tolerance around a pane boundary, in media px. */
|
|
1934
|
-
private static readonly DIVIDER_GRAB;
|
|
1935
|
-
/**
|
|
1936
|
-
* Index of the pane whose *bottom* boundary is within grab range of `y`, or
|
|
1937
|
-
* null. Boundary `i` separates pane `i` from pane `i + 1`; the last pane's
|
|
1938
|
-
* bottom is the chart edge and is not draggable.
|
|
1939
|
-
*/
|
|
1940
|
-
private _dividerAt;
|
|
1941
|
-
/**
|
|
1942
|
-
* Set a pane's relative height weight. Panes share the chart height in
|
|
1943
|
-
* proportion to their weights, so only the ratio matters.
|
|
1944
|
-
*/
|
|
1945
|
-
setPaneWeight(index: number, weight: number): void;
|
|
1946
|
-
paneWeight(index: number): number;
|
|
1947
|
-
/**
|
|
1948
|
-
* Remove a pane, everything drawn in it, and any indicator that lives there.
|
|
1949
|
-
* Pane 0 (price) is never removable — removing it would leave the chart with
|
|
1950
|
-
* no time axis owner.
|
|
1951
|
-
*
|
|
1952
|
-
* Returns false when the index is out of range or is pane 0.
|
|
1953
|
-
*/
|
|
1954
|
-
removePane(index: number): boolean;
|
|
1955
|
-
/**
|
|
1956
|
-
* Move a pane up or down one slot. Pane 0 (price) is pinned — it owns the
|
|
1957
|
-
* primary series and the shared price context — so a move that would displace
|
|
1958
|
-
* it is refused.
|
|
1959
|
-
*/
|
|
1960
|
-
movePane(index: number, direction: -1 | 1): boolean;
|
|
1961
|
-
/**
|
|
1962
|
-
* Expand one pane to fill the chart, collapsing the others to a sliver.
|
|
1963
|
-
* Calling it again (or on another pane) restores the previous weights.
|
|
1964
|
-
*/
|
|
1965
|
-
maximizePane(index: number): boolean;
|
|
1966
|
-
/** The maximized pane index, or null when none is. */
|
|
1967
|
-
maximizedPane(): number | null;
|
|
1968
|
-
/**
|
|
1969
|
-
* Route a pane-legend button press. Ids look like `indicator:<instanceId>::close`.
|
|
1970
|
-
* Returns true when the id was ours and was handled.
|
|
1971
|
-
*/
|
|
1972
|
-
private _handleLegendAction;
|
|
1973
|
-
/** Cumulative top + height of each pane, by weight (the source of truth for hit-testing). */
|
|
1974
|
-
private _paneLayout;
|
|
1975
|
-
/**
|
|
1976
|
-
* Keyboard hints for the navigator tooltips, read from the live keymap so a
|
|
1977
|
-
* rebind shows up in the tooltip instead of a stale hardcoded string. The
|
|
1978
|
-
* one-bar step buttons have no default binding, so they get no hint.
|
|
1979
|
-
*/
|
|
1980
|
-
private _navHints;
|
|
1981
|
-
/**
|
|
1982
|
-
* Keep the navigator on the bottom pane — it belongs just above the time
|
|
1983
|
-
* axis, and adding or removing a pane moves which one that is.
|
|
1984
|
-
*/
|
|
1985
|
-
private _syncTimeNavPane;
|
|
1986
|
-
/**
|
|
1987
|
-
* Push the pointer to the navigator and keep painting while it fades, so the
|
|
1988
|
-
* animation runs even when nothing else on the chart is changing.
|
|
1989
|
-
*/
|
|
1990
|
-
private _feedTimeNav;
|
|
1991
|
-
private _renderContext;
|
|
1992
|
-
private _observeSize;
|
|
1993
|
-
private _onFrame;
|
|
1994
|
-
private _attachInput;
|
|
1995
|
-
private readonly _onPointerEnter;
|
|
1996
|
-
/**
|
|
1997
|
-
* The chart renders as stacked canvases, so the browser's right-click
|
|
1998
|
-
* "Save image as…" would capture only the topmost (transparent overlay)
|
|
1999
|
-
* layer — a blank image. Just before the native menu opens, composite the
|
|
2000
|
-
* clicked pane's base layer *beneath* its overlay bitmap so the saved image
|
|
2001
|
-
* is the visible chart, and freeze overlay repaints (live ticks repaint every
|
|
2002
|
-
* few hundred ms and would wipe the snapshot while the menu is open). The
|
|
2003
|
-
* freeze lifts on the next pointer/wheel/key input after the menu closes.
|
|
2004
|
-
* Apps that present their own menu (preventDefault on contextmenu) are
|
|
2005
|
-
* unaffected. Multi-pane note: the native save captures the clicked pane
|
|
2006
|
-
* only — use `downloadScreenshot()` for the full multi-pane composite.
|
|
2007
|
-
*/
|
|
2008
|
-
private readonly _onContextMenu;
|
|
2009
|
-
/** Resume overlay repaints after the native context menu closes. */
|
|
2010
|
-
private _unfreezeOverlay;
|
|
2011
|
-
private _localPoint;
|
|
2012
|
-
private readonly _onPointerDown;
|
|
2013
|
-
private readonly _onPointerMove;
|
|
2014
|
-
private readonly _onPointerUp;
|
|
2015
|
-
/**
|
|
2016
|
-
* DOM pointerup entry point. Mirrors the primary-button guard in
|
|
2017
|
-
* `_onPointerDown`: a right-click (or any non-primary mouse button) fires
|
|
2018
|
-
* pointerdown *and* pointerup, but `_onPointerDown` ignores it — so the
|
|
2019
|
-
* down state (`_downX`/`_downLocalY`/`_downPane`/`_pointerMoved`) is never
|
|
2020
|
-
* refreshed and still holds the *previous* left-click. Letting a non-primary
|
|
2021
|
-
* pointerup through would re-run the click branch against that stale position
|
|
2022
|
-
* and replay the last click (e.g. re-firing a Buy/Sell button → a phantom
|
|
2023
|
-
* order). Touch/pen are unaffected (they contact with button 0). The internal
|
|
2024
|
-
* recovery call from `_onPointerMove` invokes `_onPointerUp` directly, so it
|
|
2025
|
-
* bypasses this filter and still ends a drag when a button release is missed.
|
|
2026
|
-
*/
|
|
2027
|
-
private readonly _onPointerUpNative;
|
|
2028
|
-
private readonly _onPointerLeave;
|
|
2029
|
-
private readonly _onWheel;
|
|
2030
|
-
/**
|
|
2031
|
-
* Restore the default view: fit all bars on the time axis and re-enable
|
|
2032
|
-
* auto-scaling on every price axis (undoing any pan/zoom or manual axis drag).
|
|
2033
|
-
* Same as double-clicking the chart.
|
|
2034
|
-
*/
|
|
2035
|
-
resetScale(): void;
|
|
2036
|
-
private readonly _onDblClick;
|
|
2037
|
-
private _beginPinch;
|
|
2038
|
-
private _updatePinch;
|
|
2039
|
-
private readonly _onKeyDown;
|
|
2040
|
-
/** Scope gating: hover keeps keys chart-local; global always acts. */
|
|
2041
|
-
private _shortcutsActive;
|
|
2042
|
-
/** Execute a built-in command; returns false for unknown (custom) commands. */
|
|
2043
|
-
private _runShortcut;
|
|
2044
|
-
/**
|
|
2045
|
-
* Composite the full chart (all panes + overlays) and trigger a PNG download.
|
|
2046
|
-
* This is what the screenshot keyboard shortcut runs; call it from a toolbar
|
|
2047
|
-
* button for a reliable "save image" — the browser's native right-click
|
|
2048
|
-
* "Save image as…" captures only the topmost (transparent overlay) canvas.
|
|
2049
|
-
*/
|
|
2050
|
-
downloadScreenshot(filename?: string): void;
|
|
2051
|
-
/** Refresh the polite live-region summary screen readers announce. */
|
|
2052
|
-
private _updateAccessibleSummary;
|
|
2053
|
-
/**
|
|
2054
|
-
* Track the primitive under the pointer: apply its cursor hint to the
|
|
2055
|
-
* container and repaint on hover enter/leave so lines/pills can render
|
|
2056
|
-
* hover states (they read `hoverId` off the render context).
|
|
2057
|
-
*/
|
|
2058
|
-
private _setHover;
|
|
2059
|
-
private _updateCursor;
|
|
2060
|
-
private _maybeLoadHistory;
|
|
2061
|
-
private _startKinetic;
|
|
2062
|
-
private _stopKinetic;
|
|
2063
|
-
destroy(): void;
|
|
2064
|
-
}
|
|
2065
|
-
|
|
2066
227
|
/**
|
|
2067
228
|
* Drawing controller — the interaction and persistence layer over
|
|
2068
229
|
* `DrawingLayer`. It is **headless**: no DOM, no toolbar. A host sets the
|
|
@@ -2074,6 +235,31 @@ declare class Chart {
|
|
|
2074
235
|
* callbacks, so a host keeps using those for its own order lines.
|
|
2075
236
|
*/
|
|
2076
237
|
|
|
238
|
+
/**
|
|
239
|
+
* The slice of the chart this controller needs.
|
|
240
|
+
*
|
|
241
|
+
* Declared structurally rather than as `Chart` on purpose. Each tier ships its
|
|
242
|
+
* own bundled `.d.ts`, so naming the class here made the draw tier re-declare
|
|
243
|
+
* `Chart` — and because `Chart` has private members, TypeScript treats the two
|
|
244
|
+
* declarations as *different* types. A TS consumer passing the chart from
|
|
245
|
+
* `createChart()` got "separate declarations of a private property", which made
|
|
246
|
+
* the tier unusable from TypeScript at all. An interface with no private
|
|
247
|
+
* members is structural, so the real `Chart` satisfies it with nothing to cast.
|
|
248
|
+
*/
|
|
249
|
+
interface DrawingChartHost {
|
|
250
|
+
on(event: string, handler: (payload: unknown) => void): () => void;
|
|
251
|
+
emit(event: string, payload: unknown): void;
|
|
252
|
+
addPrimitive(primitive: IPrimitive, paneIndex?: number): void;
|
|
253
|
+
removePrimitive(primitive: IPrimitive): void;
|
|
254
|
+
readonly dataLayer: DataLayer;
|
|
255
|
+
getVisibleLogicalRange(): {
|
|
256
|
+
from: number;
|
|
257
|
+
to: number;
|
|
258
|
+
} | null;
|
|
259
|
+
drawingState(): unknown;
|
|
260
|
+
setDrawingState(state: unknown): void;
|
|
261
|
+
setPlacementMode?(active: boolean): void;
|
|
262
|
+
}
|
|
2077
263
|
interface DrawingControllerOptions {
|
|
2078
264
|
/**
|
|
2079
265
|
* Snap new anchors to the nearest O/H/L/C of the bar under the cursor.
|
|
@@ -2104,7 +290,7 @@ declare class DrawingController {
|
|
|
2104
290
|
private _lastCursor;
|
|
2105
291
|
/** Bar under the cursor, carried by the crosshair event — used by magnet. */
|
|
2106
292
|
private _lastBar;
|
|
2107
|
-
constructor(chart:
|
|
293
|
+
constructor(chart: DrawingChartHost, options?: DrawingControllerOptions);
|
|
2108
294
|
/** Arm a tool for placement, or pass null to return to the cursor. */
|
|
2109
295
|
setTool(toolId: string | null): void;
|
|
2110
296
|
/**
|