openalgo-charts 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +201 -0
- package/README.md +80 -0
- package/dist/index.d.ts +1621 -0
- package/dist/openalgo-charts.mjs +2 -0
- package/dist/openalgo-charts.mjs.map +1 -0
- package/dist/openalgo-charts.profile.mjs +2 -0
- package/dist/openalgo-charts.profile.mjs.map +1 -0
- package/dist/openalgo-charts.standalone.js +2 -0
- package/dist/openalgo-charts.standalone.js.map +1 -0
- package/dist/openalgo-charts.trade.mjs +2 -0
- package/dist/openalgo-charts.trade.mjs.map +1 -0
- package/dist/openalgo-charts.transform.mjs +2 -0
- package/dist/openalgo-charts.transform.mjs.map +1 -0
- package/dist/profile/index.d.ts +558 -0
- package/dist/trade/index.d.ts +680 -0
- package/dist/transform/index.d.ts +178 -0
- package/package.json +71 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,1621 @@
|
|
|
1
|
+
/** Library version string, e.g. `"0.0.0"`. Replaced at release time. */
|
|
2
|
+
declare const VERSION = "0.1.0";
|
|
3
|
+
/** Returns the current library version. */
|
|
4
|
+
declare function version(): string;
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Invalidation model (ARCHITECTURE.md §3.2).
|
|
8
|
+
*
|
|
9
|
+
* A single global level is too coarse for multi-pane indicators and trade
|
|
10
|
+
* overlays, so the mask carries a **global level + a per-pane map + a queue of
|
|
11
|
+
* time-scale operations**. Multiple invalidations within one frame coalesce via
|
|
12
|
+
* {@link InvalidateMask.merge}.
|
|
13
|
+
*/
|
|
14
|
+
/** How much of a pane (or the whole chart) must be repainted this frame. */
|
|
15
|
+
declare const InvalidationLevel: {
|
|
16
|
+
/** Nothing to do. */
|
|
17
|
+
readonly None: 0;
|
|
18
|
+
/** Repaint only the top (overlay) canvas — crosshair, hover, dragging primitives. */
|
|
19
|
+
readonly Cursor: 1;
|
|
20
|
+
/** Repaint the base canvas at the current scales — series moved/changed, no rescale. */
|
|
21
|
+
readonly Light: 2;
|
|
22
|
+
/** Recompute scales/ticks then repaint everything. */
|
|
23
|
+
readonly Full: 3;
|
|
24
|
+
};
|
|
25
|
+
type InvalidationLevel = (typeof InvalidationLevel)[keyof typeof InvalidationLevel];
|
|
26
|
+
/** Per-pane invalidation entry. `autoScale` requests a price-axis rescale. */
|
|
27
|
+
interface PaneInvalidation {
|
|
28
|
+
level: InvalidationLevel;
|
|
29
|
+
autoScale: boolean;
|
|
30
|
+
}
|
|
31
|
+
/** Discrete operations applied to the shared time scale before painting. */
|
|
32
|
+
type TimeScaleOp = {
|
|
33
|
+
type: 'fitContent';
|
|
34
|
+
} | {
|
|
35
|
+
type: 'applyBarSpacing';
|
|
36
|
+
value: number;
|
|
37
|
+
} | {
|
|
38
|
+
type: 'applyRightOffset';
|
|
39
|
+
value: number;
|
|
40
|
+
} | {
|
|
41
|
+
type: 'reset';
|
|
42
|
+
};
|
|
43
|
+
declare class InvalidateMask {
|
|
44
|
+
private _globalLevel;
|
|
45
|
+
private readonly _panes;
|
|
46
|
+
private _timeScaleOps;
|
|
47
|
+
constructor(globalLevel?: InvalidationLevel);
|
|
48
|
+
get globalLevel(): InvalidationLevel;
|
|
49
|
+
/** Raise the chart-wide level (monotonic — only ever increases). */
|
|
50
|
+
invalidateGlobal(level: InvalidationLevel): void;
|
|
51
|
+
/** Raise a single pane's level without touching the others. */
|
|
52
|
+
invalidatePane(paneIndex: number, invalidation: PaneInvalidation): void;
|
|
53
|
+
paneInvalidation(paneIndex: number): PaneInvalidation | undefined;
|
|
54
|
+
panes(): ReadonlyMap<number, PaneInvalidation>;
|
|
55
|
+
addTimeScaleOp(op: TimeScaleOp): void;
|
|
56
|
+
timeScaleOps(): readonly TimeScaleOp[];
|
|
57
|
+
isEmpty(): boolean;
|
|
58
|
+
/** Fold another mask into this one (coalescing multiple invalidations per frame). */
|
|
59
|
+
merge(other: InvalidateMask): void;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Frame scheduler (ARCHITECTURE.md §3.2). Coalesces many `requestFrame()` calls
|
|
64
|
+
* within a single tick into one `onFrame` invocation. The rAF function is
|
|
65
|
+
* injectable so the loop is deterministically testable without a browser.
|
|
66
|
+
*/
|
|
67
|
+
type RafScheduler = (cb: () => void) => number;
|
|
68
|
+
type RafCanceller = (handle: number) => void;
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* HiDPI canvas handling (ARCHITECTURE.md §3.1).
|
|
72
|
+
*
|
|
73
|
+
* Each canvas has two coordinate systems: **media** (CSS px, what you reason
|
|
74
|
+
* about) and **bitmap** (device px = media × devicePixelRatio, the backing
|
|
75
|
+
* buffer). Drawing 1px lines in the bitmap scope with integer snapping keeps
|
|
76
|
+
* them crisp on retina/HiDPI displays.
|
|
77
|
+
*/
|
|
78
|
+
interface Size {
|
|
79
|
+
width: number;
|
|
80
|
+
height: number;
|
|
81
|
+
}
|
|
82
|
+
/** Pure: compute the integer device-pixel backing-buffer size for a canvas. */
|
|
83
|
+
declare function bitmapSize(mediaWidth: number, mediaHeight: number, dpr: number): Size;
|
|
84
|
+
/** Pure: snap a media-space coordinate to a crisp device-pixel edge. */
|
|
85
|
+
declare function snapToDevicePixel(mediaCoord: number, dpr: number): number;
|
|
86
|
+
/**
|
|
87
|
+
* A single `<canvas>` element with media/bitmap sizing. Constructed only in a
|
|
88
|
+
* browser; the size math above is the part exercised by unit tests.
|
|
89
|
+
*/
|
|
90
|
+
declare class CanvasLayer {
|
|
91
|
+
readonly element: HTMLCanvasElement;
|
|
92
|
+
readonly ctx: CanvasRenderingContext2D;
|
|
93
|
+
private _mediaWidth;
|
|
94
|
+
private _mediaHeight;
|
|
95
|
+
private _dpr;
|
|
96
|
+
constructor(doc: Document, zIndex: number);
|
|
97
|
+
get mediaWidth(): number;
|
|
98
|
+
get mediaHeight(): number;
|
|
99
|
+
get pixelRatio(): number;
|
|
100
|
+
/** Resize backing buffer + CSS box. No-op if nothing changed. */
|
|
101
|
+
resize(mediaWidth: number, mediaHeight: number, dpr: number): void;
|
|
102
|
+
/** Clear the whole bitmap and reset the transform to bitmap (device-px) scope. */
|
|
103
|
+
clearBitmap(): void;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
interface PriceRange {
|
|
107
|
+
min: number;
|
|
108
|
+
max: number;
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Price-scale mode. `linear` and `logarithmic` are full coordinate transforms;
|
|
112
|
+
* `percentage`/`indexed-to-100` (rebase to a baseline) and overlay scales are
|
|
113
|
+
* not yet implemented — see END_TO_END_AUDIT.md / README known limitations.
|
|
114
|
+
*/
|
|
115
|
+
type PriceScaleMode = 'linear' | 'logarithmic';
|
|
116
|
+
interface PriceScaleOptions {
|
|
117
|
+
/** Fraction of pane height kept empty at top/bottom (default 0.1 each). */
|
|
118
|
+
marginTop: number;
|
|
119
|
+
marginBottom: number;
|
|
120
|
+
/** Instrument tick size (minMove), e.g. 0.05. 0 → infer from range. */
|
|
121
|
+
minMove: number;
|
|
122
|
+
/** Linear or logarithmic price↔y mapping. */
|
|
123
|
+
mode: PriceScaleMode;
|
|
124
|
+
/** Flip the axis (price increases downward) — for spread/short views. */
|
|
125
|
+
inverted: boolean;
|
|
126
|
+
}
|
|
127
|
+
declare const DEFAULT_PRICE_SCALE_OPTIONS: PriceScaleOptions;
|
|
128
|
+
/**
|
|
129
|
+
* Pure: compute a price range from data extremes plus top/bottom margins.
|
|
130
|
+
* Returns a padded [min,max]; widens a degenerate (flat) range so it's drawable.
|
|
131
|
+
*/
|
|
132
|
+
declare function autoscaleRange(low: number, high: number, marginTop: number, marginBottom: number): PriceRange;
|
|
133
|
+
declare class PriceScale {
|
|
134
|
+
private _options;
|
|
135
|
+
private _height;
|
|
136
|
+
private _min;
|
|
137
|
+
private _max;
|
|
138
|
+
private _autoScale;
|
|
139
|
+
constructor(options?: Partial<PriceScaleOptions>);
|
|
140
|
+
get options(): PriceScaleOptions;
|
|
141
|
+
setHeight(height: number): void;
|
|
142
|
+
get height(): number;
|
|
143
|
+
setPriceRange(range: PriceRange): void;
|
|
144
|
+
priceRange(): PriceRange;
|
|
145
|
+
/** Whether the range tracks the data (true) or has been set manually (false). */
|
|
146
|
+
get autoScale(): boolean;
|
|
147
|
+
setAutoScale(on: boolean): void;
|
|
148
|
+
/**
|
|
149
|
+
* Manually scale the visible range around its centre. `factor` > 1 widens the
|
|
150
|
+
* range (compress / zoom out), < 1 narrows it (expand / zoom in). Switches the
|
|
151
|
+
* scale to manual mode so autoscale stops overriding it.
|
|
152
|
+
*/
|
|
153
|
+
scaleAroundCenter(factor: number): void;
|
|
154
|
+
/**
|
|
155
|
+
* Pan the visible range vertically by `dy` media px (dragging the plot up/down).
|
|
156
|
+
* Works in transformed space so it's correct for log scales, and respects
|
|
157
|
+
* `inverted`. Switches to manual mode so autoscale stops overriding it.
|
|
158
|
+
*/
|
|
159
|
+
panByPixels(dy: number): void;
|
|
160
|
+
/** Recompute the visible range from data extremes + configured margins. */
|
|
161
|
+
autoscale(low: number, high: number): void;
|
|
162
|
+
/** Coordinate transform for the active mode (identity for linear, log10 for log). */
|
|
163
|
+
private _t;
|
|
164
|
+
private _tInv;
|
|
165
|
+
/** Price → y (media px). Higher price → smaller y (top of pane), unless inverted. */
|
|
166
|
+
priceToY(price: number): number;
|
|
167
|
+
/** y (media px) → price. */
|
|
168
|
+
yToPrice(y: number): number;
|
|
169
|
+
/** Decimal precision implied by minMove (or the visible range if unset). */
|
|
170
|
+
precision(): number;
|
|
171
|
+
/** Snap a price to the instrument tick size (no-op if minMove is 0). */
|
|
172
|
+
snapToTick(price: number): number;
|
|
173
|
+
/** Format a price for axis/label display. */
|
|
174
|
+
format(price: number): string;
|
|
175
|
+
/** Clamp a y to the pane (used by crosshair/order dragging). */
|
|
176
|
+
clampY(y: number): number;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
interface LogicalRange {
|
|
180
|
+
from: number;
|
|
181
|
+
to: number;
|
|
182
|
+
}
|
|
183
|
+
interface TimeScaleOptions {
|
|
184
|
+
barSpacing: number;
|
|
185
|
+
minBarSpacing: number;
|
|
186
|
+
maxBarSpacing: number;
|
|
187
|
+
/** Empty bars of space kept to the right of the latest bar. */
|
|
188
|
+
rightOffset: number;
|
|
189
|
+
}
|
|
190
|
+
declare const DEFAULT_TIME_SCALE_OPTIONS: TimeScaleOptions;
|
|
191
|
+
declare class TimeScale {
|
|
192
|
+
private _barSpacing;
|
|
193
|
+
private _rightOffset;
|
|
194
|
+
private readonly _minBarSpacing;
|
|
195
|
+
private readonly _maxBarSpacing;
|
|
196
|
+
private _width;
|
|
197
|
+
private _baseIndex;
|
|
198
|
+
constructor(options?: Partial<TimeScaleOptions>);
|
|
199
|
+
setWidth(width: number): void;
|
|
200
|
+
get width(): number;
|
|
201
|
+
get barSpacing(): number;
|
|
202
|
+
setBarSpacing(value: number): void;
|
|
203
|
+
get rightOffset(): number;
|
|
204
|
+
setRightOffset(value: number): void;
|
|
205
|
+
/** Logical index of the latest bar; the right edge anchors to baseIndex+rightOffset. */
|
|
206
|
+
setBaseIndex(index: number): void;
|
|
207
|
+
private _rightEdgeIndex;
|
|
208
|
+
/** Logical index → x (media px), bar center. */
|
|
209
|
+
indexToX(index: number): number;
|
|
210
|
+
/** x (media px) → fractional logical index. */
|
|
211
|
+
xToIndex(x: number): number;
|
|
212
|
+
/** Currently visible logical index range (fractional, unclamped to data). */
|
|
213
|
+
visibleRange(): LogicalRange;
|
|
214
|
+
/**
|
|
215
|
+
* Pan by a pixel delta. Positive `dx` drags chart content to the right
|
|
216
|
+
* (revealing older bars), matching a natural left-button drag.
|
|
217
|
+
*/
|
|
218
|
+
scrollByPixels(dx: number): void;
|
|
219
|
+
/**
|
|
220
|
+
* Zoom around an anchor x (the cursor): change bar spacing by `factor`
|
|
221
|
+
* while keeping whatever logical index sits under `focusX` pinned there.
|
|
222
|
+
* `factor` > 1 zooms in (wider bars).
|
|
223
|
+
*/
|
|
224
|
+
zoomAtX(focusX: number, factor: number): void;
|
|
225
|
+
/** Choose bar spacing so `barCount` bars fit the width, anchored at the right edge. */
|
|
226
|
+
fitContent(barCount: number): void;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* Internal time is always **UTC seconds** (integer). Feed adapters convert
|
|
231
|
+
* broker formats (IST strings, epoch ms) to this at the edge; see ARCHITECTURE.md §4.0.
|
|
232
|
+
*/
|
|
233
|
+
type UTCSeconds = number;
|
|
234
|
+
/** The original, caller-supplied time value, echoed back untouched in callbacks. */
|
|
235
|
+
type OriginalTime = number | string;
|
|
236
|
+
/** A single OHLC(V) bar. `volume` is optional (not all feeds carry it). */
|
|
237
|
+
interface Bar {
|
|
238
|
+
time: UTCSeconds;
|
|
239
|
+
open: number;
|
|
240
|
+
high: number;
|
|
241
|
+
low: number;
|
|
242
|
+
close: number;
|
|
243
|
+
volume?: number;
|
|
244
|
+
}
|
|
245
|
+
/** A single value point (for line/area/baseline series). */
|
|
246
|
+
interface LinePoint {
|
|
247
|
+
time: UTCSeconds;
|
|
248
|
+
value: number;
|
|
249
|
+
}
|
|
250
|
+
/** A whitespace point: occupies a logical index for alignment but draws nothing. */
|
|
251
|
+
interface Whitespace {
|
|
252
|
+
time: UTCSeconds;
|
|
253
|
+
}
|
|
254
|
+
declare function isWhitespace(p: Bar | LinePoint | Whitespace): p is Whitespace;
|
|
255
|
+
|
|
256
|
+
/**
|
|
257
|
+
* Shared data layer (ARCHITECTURE.md §4.1). One per chart. Merges all series by
|
|
258
|
+
* time onto a single logical-index space (0..N-1) so price + volume + indicator
|
|
259
|
+
* panes stay aligned, and so non-trading gaps collapse (an absent time simply
|
|
260
|
+
* has no logical index). Per-series rows are addressable by that shared index.
|
|
261
|
+
*/
|
|
262
|
+
|
|
263
|
+
type SeriesId = number;
|
|
264
|
+
interface IndexedBar {
|
|
265
|
+
index: number;
|
|
266
|
+
bar: Bar;
|
|
267
|
+
}
|
|
268
|
+
declare class DataLayer {
|
|
269
|
+
private readonly _series;
|
|
270
|
+
private _sortedTimes;
|
|
271
|
+
private readonly _indexByTime;
|
|
272
|
+
private _nextId;
|
|
273
|
+
/** Register a new series; returns its id. */
|
|
274
|
+
createSeries(): SeriesId;
|
|
275
|
+
removeSeries(id: SeriesId): void;
|
|
276
|
+
/** Bulk-load (full replace) one series' data, then re-merge the time axis. */
|
|
277
|
+
setSeriesData(id: SeriesId, bars: readonly Bar[]): void;
|
|
278
|
+
/**
|
|
279
|
+
* Upsert bars into a series by time (used for history paging / backfill /
|
|
280
|
+
* out-of-order corrections — ARCHITECTURE.md §4.2). Existing times are
|
|
281
|
+
* replaced; new times are inserted; the result stays time-sorted.
|
|
282
|
+
*
|
|
283
|
+
* Prepending older bars shifts every existing logical index up by the
|
|
284
|
+
* inserted count — callers preserve the viewport by re-reading `baseIndex`
|
|
285
|
+
* (the invariant `rightEdge − index` is unchanged, so visible bars don't move).
|
|
286
|
+
*/
|
|
287
|
+
addBars(id: SeriesId, bars: readonly Bar[]): void;
|
|
288
|
+
/**
|
|
289
|
+
* Apply a single live bar (ARCHITECTURE.md §4.2 hot path). Returns the kind of
|
|
290
|
+
* change so the chart auto-scrolls only on a genuine right-edge append:
|
|
291
|
+
* - `'append'` → newer than the last bar (advances baseIndex)
|
|
292
|
+
* - `'replace'` → same time as the last bar (intra-bar tick) or an existing time
|
|
293
|
+
* - `'insert'` → an older time inserted into history (late / out-of-order)
|
|
294
|
+
*/
|
|
295
|
+
update(id: SeriesId, bar: Bar): 'append' | 'replace' | 'insert';
|
|
296
|
+
private _appendTime;
|
|
297
|
+
/** Number of logical indices (distinct time points across all series). */
|
|
298
|
+
get length(): number;
|
|
299
|
+
/** Logical index of the latest real bar (length - 1), or -1 if empty. */
|
|
300
|
+
get baseIndex(): number;
|
|
301
|
+
indexToTime(index: number): number | undefined;
|
|
302
|
+
timeToIndex(time: number): number | undefined;
|
|
303
|
+
/** All bars of a series paired with their shared logical index. */
|
|
304
|
+
indexedBars(id: SeriesId): IndexedBar[];
|
|
305
|
+
/** Bars of a series whose logical index lies within [fromIndex, toIndex]. */
|
|
306
|
+
visibleBars(id: SeriesId, fromIndex: number, toIndex: number): IndexedBar[];
|
|
307
|
+
private _rebuild;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
/**
|
|
311
|
+
* Unified style bag for all Family-A series types (ARCHITECTURE.md §6A). Each
|
|
312
|
+
* renderer reads the fields it needs; per-type defaults are filled by the
|
|
313
|
+
* chart-type registry. Keeping one optional-field interface avoids a sprawling
|
|
314
|
+
* discriminated union at the rendering boundary.
|
|
315
|
+
*/
|
|
316
|
+
interface SeriesStyle {
|
|
317
|
+
upColor?: string;
|
|
318
|
+
downColor?: string;
|
|
319
|
+
borderUpColor?: string;
|
|
320
|
+
borderDownColor?: string;
|
|
321
|
+
wickUpColor?: string;
|
|
322
|
+
wickDownColor?: string;
|
|
323
|
+
borderVisible?: boolean;
|
|
324
|
+
wickVisible?: boolean;
|
|
325
|
+
hollow?: boolean;
|
|
326
|
+
/** Scale candle body width by volume / maxVisibleVolume (volume candles). */
|
|
327
|
+
volumeScaled?: boolean;
|
|
328
|
+
color?: string;
|
|
329
|
+
lineWidth?: number;
|
|
330
|
+
step?: boolean;
|
|
331
|
+
markers?: boolean;
|
|
332
|
+
markerRadius?: number;
|
|
333
|
+
areaTopColor?: string;
|
|
334
|
+
areaBottomColor?: string;
|
|
335
|
+
baseValue?: number;
|
|
336
|
+
topColor?: string;
|
|
337
|
+
bottomColor?: string;
|
|
338
|
+
highColor?: string;
|
|
339
|
+
lowColor?: string;
|
|
340
|
+
closeColor?: string;
|
|
341
|
+
base?: number;
|
|
342
|
+
/** Box size for stacking P&F X/O glyphs. */
|
|
343
|
+
boxSize?: number;
|
|
344
|
+
/** Kagi thick (yang) line color. */
|
|
345
|
+
thickColor?: string;
|
|
346
|
+
/** Kagi thin (yin) line color. */
|
|
347
|
+
thinColor?: string;
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
/**
|
|
351
|
+
* Chart theme (palette). A single object drives chart chrome (background, grid,
|
|
352
|
+
* axes, crosshair), series defaults (up/down, line, area gradient, last price),
|
|
353
|
+
* and the trade layer (buy/sell, profit/loss). Renderers read theme colors when
|
|
354
|
+
* a per-series style field is absent, so one theme restyles the whole chart.
|
|
355
|
+
*/
|
|
356
|
+
interface ChartTheme {
|
|
357
|
+
background: string;
|
|
358
|
+
grid: string;
|
|
359
|
+
axisText: string;
|
|
360
|
+
axisLine: string;
|
|
361
|
+
crosshair: string;
|
|
362
|
+
upColor: string;
|
|
363
|
+
downColor: string;
|
|
364
|
+
wickUpColor: string;
|
|
365
|
+
wickDownColor: string;
|
|
366
|
+
lineColor: string;
|
|
367
|
+
areaTopColor: string;
|
|
368
|
+
areaBottomColor: string;
|
|
369
|
+
baselineTopLine: string;
|
|
370
|
+
baselineTopFill: string;
|
|
371
|
+
baselineBottomLine: string;
|
|
372
|
+
baselineBottomFill: string;
|
|
373
|
+
lastPriceUp: string;
|
|
374
|
+
lastPriceDown: string;
|
|
375
|
+
lastPriceText: string;
|
|
376
|
+
buy: string;
|
|
377
|
+
sell: string;
|
|
378
|
+
profit: string;
|
|
379
|
+
loss: string;
|
|
380
|
+
}
|
|
381
|
+
declare const darkTheme: ChartTheme;
|
|
382
|
+
declare const lightTheme: ChartTheme;
|
|
383
|
+
declare const DEFAULT_THEME: ChartTheme;
|
|
384
|
+
|
|
385
|
+
/**
|
|
386
|
+
* Chart-type registry (ARCHITECTURE.md §6A). Every series type registers a
|
|
387
|
+
* descriptor: how to draw it and how it contributes to autoscale. The core
|
|
388
|
+
* iterates descriptors, so adding a style is one registration — no core change.
|
|
389
|
+
* Phase 5 fills the Family-A (time-indexed) types; Families B/C plug in later.
|
|
390
|
+
*/
|
|
391
|
+
|
|
392
|
+
type SeriesType = 'candlestick' | 'hollow-candle' | 'volume-candle' | 'bar' | 'high-low' | 'line' | 'line-markers' | 'step' | 'area' | 'hlc-area' | 'baseline' | 'column' | 'histogram' | 'point-figure' | 'kagi';
|
|
393
|
+
interface DrawItem {
|
|
394
|
+
x: number;
|
|
395
|
+
bar: Bar;
|
|
396
|
+
}
|
|
397
|
+
interface SeriesRenderContext {
|
|
398
|
+
plotHeight: number;
|
|
399
|
+
maxVolume: number;
|
|
400
|
+
theme: ChartTheme;
|
|
401
|
+
}
|
|
402
|
+
interface RendererEntry {
|
|
403
|
+
defaultStyle: SeriesStyle;
|
|
404
|
+
/** True for the price series whose last close drives the last-price line. */
|
|
405
|
+
isPriceSeries: boolean;
|
|
406
|
+
draw(ctx: CanvasRenderingContext2D, items: readonly DrawItem[], toY: (v: number) => number, barSpacing: number, dpr: number, style: SeriesStyle, rc: SeriesRenderContext): void;
|
|
407
|
+
/** Min/max price contribution of one bar to autoscale. */
|
|
408
|
+
extents(bar: Bar, style: SeriesStyle): {
|
|
409
|
+
min: number;
|
|
410
|
+
max: number;
|
|
411
|
+
};
|
|
412
|
+
}
|
|
413
|
+
/** Register a chart type. `type` accepts a built-in `SeriesType` or any custom string. */
|
|
414
|
+
declare function registerChartType(type: SeriesType | (string & {}), entry: RendererEntry): void;
|
|
415
|
+
declare function getChartType(type: SeriesType | (string & {})): RendererEntry;
|
|
416
|
+
declare function registeredChartTypes(): string[];
|
|
417
|
+
|
|
418
|
+
/**
|
|
419
|
+
* Primitive / plugin API (ARCHITECTURE.md §8). The extension point that keeps
|
|
420
|
+
* the core small and powers markers, events, indicators, and the trade layer.
|
|
421
|
+
* A primitive draws on a pane, optionally contributes to autoscale, and
|
|
422
|
+
* optionally hit-tests for hover/drag.
|
|
423
|
+
*/
|
|
424
|
+
|
|
425
|
+
type ZOrder = 'bottom' | 'normal' | 'top';
|
|
426
|
+
interface PrimitiveRenderContext {
|
|
427
|
+
timeScale: TimeScale;
|
|
428
|
+
priceScale: PriceScale;
|
|
429
|
+
dataLayer: DataLayer;
|
|
430
|
+
plotWidth: number;
|
|
431
|
+
plotHeight: number;
|
|
432
|
+
priceAxisWidth: number;
|
|
433
|
+
dpr: number;
|
|
434
|
+
theme: ChartTheme;
|
|
435
|
+
}
|
|
436
|
+
interface PrimitiveHit {
|
|
437
|
+
externalId: string;
|
|
438
|
+
zOrder: ZOrder;
|
|
439
|
+
/** Pixel distance from the cursor (smaller wins ties before z-order). */
|
|
440
|
+
distance: number;
|
|
441
|
+
cursor?: string;
|
|
442
|
+
}
|
|
443
|
+
/** Injected when a primitive is attached; lets it request a repaint. */
|
|
444
|
+
interface PrimitiveHost {
|
|
445
|
+
requestUpdate(): void;
|
|
446
|
+
}
|
|
447
|
+
interface IPrimitive {
|
|
448
|
+
/** Layer order vs series: 'bottom' (behind), 'normal' (over), 'top' (overlay). */
|
|
449
|
+
zOrder(): ZOrder;
|
|
450
|
+
draw(ctx: CanvasRenderingContext2D, rc: PrimitiveRenderContext): void;
|
|
451
|
+
/** Optional: expand the pane's autoscale range so this primitive isn't clipped. */
|
|
452
|
+
autoscaleInfo?(): {
|
|
453
|
+
min: number;
|
|
454
|
+
max: number;
|
|
455
|
+
} | null;
|
|
456
|
+
/** Optional: topmost hit under (x,y) in media px (relative to the pane plot). */
|
|
457
|
+
hitTest?(x: number, y: number, rc: PrimitiveRenderContext): PrimitiveHit | null;
|
|
458
|
+
attached?(host: PrimitiveHost): void;
|
|
459
|
+
detached?(): void;
|
|
460
|
+
}
|
|
461
|
+
/** Pick the best hit across primitives: nearest distance, then z-order priority. */
|
|
462
|
+
declare function bestHit(hits: readonly (PrimitiveHit | null)[]): PrimitiveHit | null;
|
|
463
|
+
|
|
464
|
+
type MarkerShape = 'arrowUp' | 'arrowDown' | 'circle' | 'square' | 'triangleUp' | 'triangleDown' | 'diamond' | 'flag' | 'text';
|
|
465
|
+
type MarkerPosition = 'aboveBar' | 'belowBar' | 'inBar' | 'atPrice';
|
|
466
|
+
type MarkerSize = 'tiny' | 'small' | 'medium' | 'big';
|
|
467
|
+
interface SeriesMarker {
|
|
468
|
+
time: number;
|
|
469
|
+
position: MarkerPosition;
|
|
470
|
+
price?: number;
|
|
471
|
+
shape: MarkerShape;
|
|
472
|
+
size: MarkerSize;
|
|
473
|
+
color: string;
|
|
474
|
+
text?: string;
|
|
475
|
+
id?: string;
|
|
476
|
+
}
|
|
477
|
+
/** Base glyph size in CSS px for a marker size preset. */
|
|
478
|
+
declare function markerSizePx(size: MarkerSize): number;
|
|
479
|
+
/** Effective glyph px, clamped so it never exceeds the current bar spacing. */
|
|
480
|
+
declare function effectiveMarkerPx(size: MarkerSize, barSpacing: number): number;
|
|
481
|
+
declare function drawShape(ctx: CanvasRenderingContext2D, shape: MarkerShape, cx: number, cy: number, px: number, color: string): void;
|
|
482
|
+
declare class SeriesMarkers implements IPrimitive {
|
|
483
|
+
private readonly _seriesId;
|
|
484
|
+
private _markers;
|
|
485
|
+
private _host;
|
|
486
|
+
private _lastPositions;
|
|
487
|
+
constructor(seriesId: SeriesId);
|
|
488
|
+
attached(host: PrimitiveHost): void;
|
|
489
|
+
detached(): void;
|
|
490
|
+
zOrder(): ZOrder;
|
|
491
|
+
setMarkers(markers: readonly SeriesMarker[]): void;
|
|
492
|
+
draw(ctx: CanvasRenderingContext2D, rc: PrimitiveRenderContext): void;
|
|
493
|
+
hitTest(x: number, y: number): PrimitiveHit | null;
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
/**
|
|
497
|
+
* Series records (ARCHITECTURE.md §4.3). A series references its rows in the
|
|
498
|
+
* shared DataLayer by id, names a registered chart type, and carries a style
|
|
499
|
+
* bag. The chart-type registry (§6A) supplies the renderer + autoscale extents,
|
|
500
|
+
* so the core never switches on type.
|
|
501
|
+
*/
|
|
502
|
+
|
|
503
|
+
interface SeriesRecord {
|
|
504
|
+
dataId: SeriesId;
|
|
505
|
+
type: SeriesType;
|
|
506
|
+
style: SeriesStyle;
|
|
507
|
+
}
|
|
508
|
+
/** Public handle returned by `chart.addSeries(...)`. */
|
|
509
|
+
interface SeriesApi {
|
|
510
|
+
setData(bars: readonly Bar[]): void;
|
|
511
|
+
prependData(bars: readonly Bar[]): void;
|
|
512
|
+
update(bar: Bar): void;
|
|
513
|
+
/** Create a markers layer (buy/sell signals, shapes) bound to this series. */
|
|
514
|
+
createMarkers(): SeriesMarkers;
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
/**
|
|
518
|
+
* A pane is one vertically-stacked drawing region (price pane, volume pane,
|
|
519
|
+
* indicator pane). It owns a base + top canvas (ARCHITECTURE.md §3.1) and a
|
|
520
|
+
* price scale, and renders its series against the shared time scale + DataLayer.
|
|
521
|
+
*/
|
|
522
|
+
|
|
523
|
+
interface PaneRenderContext {
|
|
524
|
+
timeScale: TimeScale;
|
|
525
|
+
dataLayer: DataLayer;
|
|
526
|
+
dpr: number;
|
|
527
|
+
priceAxisWidth: number;
|
|
528
|
+
timeAxisHeight: number;
|
|
529
|
+
/** Only the bottom pane draws the time axis. */
|
|
530
|
+
showTimeAxis: boolean;
|
|
531
|
+
/** Enable OHLC-preserving conflation when bars fall below ~0.5px (§4.4). */
|
|
532
|
+
conflate: boolean;
|
|
533
|
+
/** Conflation aggressiveness (1 = perf only; higher = more smoothing). */
|
|
534
|
+
conflationFactor: number;
|
|
535
|
+
/** Active palette — drives chrome, series defaults, and trade colors. */
|
|
536
|
+
theme: ChartTheme;
|
|
537
|
+
/** Draw the vertical (time) grid lines. */
|
|
538
|
+
showVertGrid: boolean;
|
|
539
|
+
/** Draw the horizontal (price) grid lines. */
|
|
540
|
+
showHorzGrid: boolean;
|
|
541
|
+
}
|
|
542
|
+
declare class Pane {
|
|
543
|
+
readonly element: HTMLElement;
|
|
544
|
+
readonly base: CanvasLayer;
|
|
545
|
+
readonly top: CanvasLayer;
|
|
546
|
+
readonly priceScale: PriceScale;
|
|
547
|
+
/** Relative height weight within the chart (price=1, volume≈0.3). */
|
|
548
|
+
weight: number;
|
|
549
|
+
private readonly _series;
|
|
550
|
+
private readonly _primitives;
|
|
551
|
+
private _width;
|
|
552
|
+
private _height;
|
|
553
|
+
constructor(doc: Document);
|
|
554
|
+
addSeries(record: SeriesRecord): void;
|
|
555
|
+
series(): readonly SeriesRecord[];
|
|
556
|
+
addPrimitive(primitive: IPrimitive, host: PrimitiveHost): void;
|
|
557
|
+
/** Remove a primitive if present; returns true if it was found. */
|
|
558
|
+
removePrimitive(primitive: IPrimitive): boolean;
|
|
559
|
+
/** Detach every primitive (lifecycle cleanup) and remove the pane element. */
|
|
560
|
+
destroy(): void;
|
|
561
|
+
private _primitiveContext;
|
|
562
|
+
/** Topmost primitive hit at media-px (x,y) relative to this pane's plot. */
|
|
563
|
+
hitTestPrimitives(x: number, y: number, ctx: PaneRenderContext): PrimitiveHit | null;
|
|
564
|
+
resize(width: number, height: number, dpr: number): void;
|
|
565
|
+
private _layout;
|
|
566
|
+
/** Recompute the price range from the visible bars of all series in this pane. */
|
|
567
|
+
autoscale(ctx: PaneRenderContext): void;
|
|
568
|
+
/** Paint background + grid + series + axes on the base canvas. */
|
|
569
|
+
paintBase(ctx: PaneRenderContext): void;
|
|
570
|
+
/**
|
|
571
|
+
* Top (overlay) canvas: top-layer primitives + crosshair. Cheap repaint on
|
|
572
|
+
* cursor moves. `cross.x` is the shared plot x (vertical line, drawn in every
|
|
573
|
+
* pane for a global crosshair); `cross.yLocal` is the price-line y for the
|
|
574
|
+
* hovered pane only (null elsewhere); `cross.showTimeTag` draws the date tag
|
|
575
|
+
* on the bottom pane's axis strip.
|
|
576
|
+
*/
|
|
577
|
+
paintTop(cross: {
|
|
578
|
+
x: number;
|
|
579
|
+
yLocal: number | null;
|
|
580
|
+
showTimeTag: boolean;
|
|
581
|
+
} | null, ctx: PaneRenderContext): void;
|
|
582
|
+
/** Price at a media-px y on this pane (for crosshair magnet). */
|
|
583
|
+
yToPrice(y: number): number;
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
/**
|
|
587
|
+
* Crosshair state + magnet snapping (ARCHITECTURE.md §6). Pure helpers so the
|
|
588
|
+
* snap logic is unit-testable; drawing lives in render/crosshair.ts.
|
|
589
|
+
*/
|
|
590
|
+
|
|
591
|
+
type CrosshairMode = 'normal' | 'magnet';
|
|
592
|
+
|
|
593
|
+
/**
|
|
594
|
+
* Horizontal price line primitive (ARCHITECTURE.md §8). The reusable base for
|
|
595
|
+
* order/SL/TP/alert/indicator-level lines: a line across the plot plus a fixed
|
|
596
|
+
* right-axis price tag. Drag handling is added by the trade layer in Phase 9.
|
|
597
|
+
*/
|
|
598
|
+
|
|
599
|
+
interface PriceLineOptions {
|
|
600
|
+
price: number;
|
|
601
|
+
color: string;
|
|
602
|
+
lineWidth: number;
|
|
603
|
+
dashed: boolean;
|
|
604
|
+
/** Right-axis tag text. Defaults to the formatted price. */
|
|
605
|
+
label?: string;
|
|
606
|
+
/** Optional tag drawn at the LEFT end of the line (NinjaTrader-style order tag). */
|
|
607
|
+
leftLabel?: string;
|
|
608
|
+
/**
|
|
609
|
+
* Fraction of the plot width the line spans, measured from the right (price)
|
|
610
|
+
* axis. 1 = full width (default); 0.3 = only the rightmost 30% — like a
|
|
611
|
+
* NinjaTrader order line. The right-axis tag is always drawn.
|
|
612
|
+
*/
|
|
613
|
+
extentFromRight?: number;
|
|
614
|
+
/** Draw a small cancel (cross) box at the right end; hit-tests as `${id}::close`. */
|
|
615
|
+
closeButton?: boolean;
|
|
616
|
+
/** Stable id returned by hit-test (for click/drag routing). */
|
|
617
|
+
id: string;
|
|
618
|
+
/** Cursor hint when hovered (e.g. 'ns-resize' for draggable lines). */
|
|
619
|
+
cursor?: string;
|
|
620
|
+
}
|
|
621
|
+
declare class PriceLine implements IPrimitive {
|
|
622
|
+
private _opts;
|
|
623
|
+
private _host;
|
|
624
|
+
constructor(opts: PriceLineOptions);
|
|
625
|
+
attached(host: PrimitiveHost): void;
|
|
626
|
+
detached(): void;
|
|
627
|
+
get price(): number;
|
|
628
|
+
/** Move the line; schedules a repaint via the host. */
|
|
629
|
+
setPrice(price: number): void;
|
|
630
|
+
/** Update the left-end tag text (e.g. live position P&L); repaints. */
|
|
631
|
+
setLeftLabel(text: string): void;
|
|
632
|
+
options(): Readonly<PriceLineOptions>;
|
|
633
|
+
zOrder(): ZOrder;
|
|
634
|
+
autoscaleInfo(): {
|
|
635
|
+
min: number;
|
|
636
|
+
max: number;
|
|
637
|
+
} | null;
|
|
638
|
+
draw(ctx: CanvasRenderingContext2D, rc: PrimitiveRenderContext): void;
|
|
639
|
+
hitTest(x: number, y: number, rc: PrimitiveRenderContext): PrimitiveHit | null;
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
/**
|
|
643
|
+
* Event markers (ARCHITECTURE.md §8.2): Earnings / Dividend / Split badges in a
|
|
644
|
+
* strip near the bottom of the plot. Time-anchored only (no price). Hover/click
|
|
645
|
+
* carry an external id for tooltip wiring. Data source is an integration concern
|
|
646
|
+
* (OpenAlgo has no corporate-actions calendar) — the renderer ships regardless.
|
|
647
|
+
*/
|
|
648
|
+
|
|
649
|
+
interface ChartEvent {
|
|
650
|
+
time: number;
|
|
651
|
+
type: 'earnings' | 'dividend' | 'split' | 'news' | string;
|
|
652
|
+
label: string;
|
|
653
|
+
color?: string;
|
|
654
|
+
id?: string;
|
|
655
|
+
}
|
|
656
|
+
declare class EventMarkers implements IPrimitive {
|
|
657
|
+
private _events;
|
|
658
|
+
private _host;
|
|
659
|
+
private _positions;
|
|
660
|
+
attached(host: PrimitiveHost): void;
|
|
661
|
+
detached(): void;
|
|
662
|
+
zOrder(): ZOrder;
|
|
663
|
+
setEvents(events: readonly ChartEvent[]): void;
|
|
664
|
+
draw(ctx: CanvasRenderingContext2D, rc: PrimitiveRenderContext): void;
|
|
665
|
+
hitTest(x: number, y: number): PrimitiveHit | null;
|
|
666
|
+
}
|
|
667
|
+
|
|
668
|
+
/**
|
|
669
|
+
* Top-level chart orchestrator (ARCHITECTURE.md §3.3). Owns the shared
|
|
670
|
+
* DataLayer + time scale, the panes, the invalidate mask, and the render loop.
|
|
671
|
+
* Phase 2 renders static candlesticks with price/time axes; pan/zoom (Phase 3)
|
|
672
|
+
* and live data (Phase 4) build on this.
|
|
673
|
+
*/
|
|
674
|
+
|
|
675
|
+
interface ChartOptions {
|
|
676
|
+
document?: Document;
|
|
677
|
+
pixelRatio?: () => number;
|
|
678
|
+
raf?: {
|
|
679
|
+
schedule: RafScheduler;
|
|
680
|
+
cancel?: RafCanceller;
|
|
681
|
+
};
|
|
682
|
+
/** Full palette; pass `darkTheme` (default), `lightTheme`, or a custom ChartTheme. */
|
|
683
|
+
theme?: ChartTheme;
|
|
684
|
+
priceAxisWidth?: number;
|
|
685
|
+
timeAxisHeight?: number;
|
|
686
|
+
/**
|
|
687
|
+
* Crosshair behaviour. 'normal' (default) — the cross follows the pointer
|
|
688
|
+
* exactly. 'magnet' — the horizontal line snaps to the nearest O/H/L/C of the
|
|
689
|
+
* bar under the cursor (price pane only).
|
|
690
|
+
*/
|
|
691
|
+
crosshairMode?: CrosshairMode;
|
|
692
|
+
/** Time source for kinetic animation (defaults to performance.now). */
|
|
693
|
+
now?: () => number;
|
|
694
|
+
/** Enable OHLC-preserving conflation when zoomed out (§4.4). Default false. */
|
|
695
|
+
conflate?: boolean;
|
|
696
|
+
/** Conflation aggressiveness (default 1). */
|
|
697
|
+
conflationFactor?: number;
|
|
698
|
+
/** Grid line visibility. Both default to true. */
|
|
699
|
+
grid?: {
|
|
700
|
+
vertLines?: boolean;
|
|
701
|
+
horzLines?: boolean;
|
|
702
|
+
};
|
|
703
|
+
/** Accessible label for the chart container (screen readers). */
|
|
704
|
+
ariaLabel?: string;
|
|
705
|
+
}
|
|
706
|
+
interface AddSeriesOptions {
|
|
707
|
+
/** Target pane index (0 = price). Higher panes are created on demand. */
|
|
708
|
+
paneIndex?: number;
|
|
709
|
+
/** Style overrides merged onto the chart type's defaults. */
|
|
710
|
+
style?: SeriesStyle;
|
|
711
|
+
}
|
|
712
|
+
/**
|
|
713
|
+
* Emitted on every crosshair move (and `null` fields on pointer-leave) so a host
|
|
714
|
+
* can render an OHLC legend / tooltip. `bar` is the hovered bar of the primary
|
|
715
|
+
* price series; `point` is container-relative media px for positioning a
|
|
716
|
+
* floating tooltip. See `subscribeCrosshairMove`.
|
|
717
|
+
*/
|
|
718
|
+
interface CrosshairMoveEvent {
|
|
719
|
+
/** UTC seconds of the hovered bar, or null when off the data / pointer left. */
|
|
720
|
+
time: number | null;
|
|
721
|
+
/** Logical index under the cursor, or null. */
|
|
722
|
+
index: number | null;
|
|
723
|
+
/** Price under the cursor on the hovered pane, or null. */
|
|
724
|
+
price: number | null;
|
|
725
|
+
/** Hovered bar of the primary (first) price series, or null. */
|
|
726
|
+
bar: Bar | null;
|
|
727
|
+
/** Cursor position in container media px, or null on leave. */
|
|
728
|
+
point: {
|
|
729
|
+
x: number;
|
|
730
|
+
y: number;
|
|
731
|
+
} | null;
|
|
732
|
+
}
|
|
733
|
+
declare class Chart {
|
|
734
|
+
private readonly _container;
|
|
735
|
+
private readonly _doc;
|
|
736
|
+
private readonly _pixelRatio;
|
|
737
|
+
private readonly _theme;
|
|
738
|
+
private readonly _panes;
|
|
739
|
+
private readonly _loop;
|
|
740
|
+
private readonly _dataLayer;
|
|
741
|
+
private readonly _timeScale;
|
|
742
|
+
private readonly _priceAxisWidth;
|
|
743
|
+
private readonly _timeAxisHeight;
|
|
744
|
+
private _pending;
|
|
745
|
+
private _resizeObserver;
|
|
746
|
+
private _width;
|
|
747
|
+
private _height;
|
|
748
|
+
private _hasFitContent;
|
|
749
|
+
private readonly _crosshairMode;
|
|
750
|
+
private readonly _now;
|
|
751
|
+
private readonly _conflate;
|
|
752
|
+
private readonly _conflationFactor;
|
|
753
|
+
private _gridVert;
|
|
754
|
+
private _gridHorz;
|
|
755
|
+
private _cursorPane;
|
|
756
|
+
private _cursor;
|
|
757
|
+
private _dragging;
|
|
758
|
+
private _dragStartX;
|
|
759
|
+
private _dragStartY;
|
|
760
|
+
private _lastDragY;
|
|
761
|
+
private readonly _pointers;
|
|
762
|
+
private _pinch;
|
|
763
|
+
private _pinchPane;
|
|
764
|
+
private _liveRegion;
|
|
765
|
+
private _dragStartOffset;
|
|
766
|
+
private _lastDragX;
|
|
767
|
+
private _lastDragT;
|
|
768
|
+
private _dragVelocity;
|
|
769
|
+
private _kineticHandle;
|
|
770
|
+
private readonly _firstDataId;
|
|
771
|
+
/** Pane holding the primary price series (only this pane gets magnet snapping). */
|
|
772
|
+
private _firstPaneIndex;
|
|
773
|
+
private _historyLoader;
|
|
774
|
+
private _loadingHistory;
|
|
775
|
+
private _clickCb;
|
|
776
|
+
private _crosshairCb;
|
|
777
|
+
private _pointerMoved;
|
|
778
|
+
private _downPane;
|
|
779
|
+
private _downX;
|
|
780
|
+
private _downLocalY;
|
|
781
|
+
private _dragId;
|
|
782
|
+
private _dragCb;
|
|
783
|
+
private _dragEndCb;
|
|
784
|
+
private _axisDrag;
|
|
785
|
+
private _axisStartCoord;
|
|
786
|
+
private _axisStartMin;
|
|
787
|
+
private _axisStartMax;
|
|
788
|
+
private _axisStartSpacing;
|
|
789
|
+
constructor(container: HTMLElement, options?: ChartOptions);
|
|
790
|
+
/** Register a callback fired when the user pans near the left (oldest) edge. */
|
|
791
|
+
setHistoryLoader(loader: () => void): void;
|
|
792
|
+
/** Call after a history-paging load resolves to re-enable the trigger. */
|
|
793
|
+
historyLoadComplete(): void;
|
|
794
|
+
get dataLayer(): DataLayer;
|
|
795
|
+
get timeScale(): TimeScale;
|
|
796
|
+
/** Add a series and return its data handle. */
|
|
797
|
+
addSeries(type: SeriesType, options?: AddSeriesOptions): SeriesApi;
|
|
798
|
+
/** Add a horizontal price line (order/SL/TP/alert/level) to a pane. */
|
|
799
|
+
addPriceLine(opts: PriceLineOptions, paneIndex?: number): PriceLine;
|
|
800
|
+
/** Add an earnings/dividend/split event-marker strip to a pane. */
|
|
801
|
+
addEventMarkers(paneIndex?: number): EventMarkers;
|
|
802
|
+
/** Subscribe to clicks on hit-testable primitives (markers, events, lines). */
|
|
803
|
+
subscribeClick(cb: (externalId: string) => void): void;
|
|
804
|
+
/**
|
|
805
|
+
* Subscribe to crosshair movement for an OHLC legend / tooltip. The callback
|
|
806
|
+
* fires with the hovered bar of the primary price series on every move, and
|
|
807
|
+
* with all-null fields when the pointer leaves the plot.
|
|
808
|
+
*/
|
|
809
|
+
subscribeCrosshairMove(cb: (e: CrosshairMoveEvent) => void): void;
|
|
810
|
+
/** Subscribe to drags of draggable lines (order/SL/TP). Fires per move and on release. */
|
|
811
|
+
subscribeDrag(onDrag: (externalId: string, price: number) => void, onDragEnd?: (externalId: string, price: number) => void): void;
|
|
812
|
+
/** Public: attach any primitive (indicators, profiles, custom overlays) to a pane. */
|
|
813
|
+
addPrimitive(primitive: IPrimitive, paneIndex?: number): void;
|
|
814
|
+
/**
|
|
815
|
+
* Map a price to a container-relative Y in media (CSS) px, for positioning DOM
|
|
816
|
+
* overlays (order panels, tooltips) over a pane. Returns null if the pane
|
|
817
|
+
* doesn't exist. The inverse is `coordinateToPrice`.
|
|
818
|
+
*/
|
|
819
|
+
priceToCoordinate(price: number, paneIndex?: number): number | null;
|
|
820
|
+
/** Map a container-relative media-px Y back to a price on a pane (inverse of priceToCoordinate). */
|
|
821
|
+
coordinateToPrice(y: number, paneIndex?: number): number | null;
|
|
822
|
+
/**
|
|
823
|
+
* Toggle the vertical (time) and/or horizontal (price) grid lines at runtime.
|
|
824
|
+
* Omitted fields keep their current visibility. Repaints every pane.
|
|
825
|
+
*/
|
|
826
|
+
setGridOptions(opts: {
|
|
827
|
+
vertLines?: boolean;
|
|
828
|
+
horzLines?: boolean;
|
|
829
|
+
}): void;
|
|
830
|
+
/** Current grid line visibility. */
|
|
831
|
+
gridOptions(): {
|
|
832
|
+
vertLines: boolean;
|
|
833
|
+
horzLines: boolean;
|
|
834
|
+
};
|
|
835
|
+
/**
|
|
836
|
+
* Flatten every pane's base + overlay canvas into one opaque canvas (device
|
|
837
|
+
* px). The chart renders as stacked layered canvases, so the browser's native
|
|
838
|
+
* right-click "Save image" only captures the layer under the pointer (usually
|
|
839
|
+
* the transparent crosshair overlay) — use this to export the full chart.
|
|
840
|
+
*/
|
|
841
|
+
takeScreenshot(): HTMLCanvasElement;
|
|
842
|
+
private _addPrimitive;
|
|
843
|
+
/** Remove a primitive from whichever pane holds it. */
|
|
844
|
+
removePrimitive(primitive: IPrimitive): void;
|
|
845
|
+
/** A host for the (lazy-loaded) trade layer to attach/detach its primitives on a pane. */
|
|
846
|
+
tradeHost(paneIndex?: number): {
|
|
847
|
+
addPrimitive(p: IPrimitive): void;
|
|
848
|
+
removePrimitive(p: IPrimitive): void;
|
|
849
|
+
};
|
|
850
|
+
/** Apply one live bar; auto-scroll only on a genuine right-edge append. */
|
|
851
|
+
private _updateBar;
|
|
852
|
+
private _ensurePane;
|
|
853
|
+
private _setData;
|
|
854
|
+
/** History paging: merge older bars, preserving the viewport (§4.2). */
|
|
855
|
+
private _prependData;
|
|
856
|
+
private _addPane;
|
|
857
|
+
panes(): readonly Pane[];
|
|
858
|
+
invalidate(build: (mask: InvalidateMask) => void): void;
|
|
859
|
+
applySize(width: number, height: number): void;
|
|
860
|
+
/** Distribute height across panes by weight; sync the shared time-scale width. */
|
|
861
|
+
private _relayout;
|
|
862
|
+
private _weightTotal;
|
|
863
|
+
/** Cumulative top + height of each pane, by weight (the source of truth for hit-testing). */
|
|
864
|
+
private _paneLayout;
|
|
865
|
+
private _renderContext;
|
|
866
|
+
private _observeSize;
|
|
867
|
+
private _onFrame;
|
|
868
|
+
private _attachInput;
|
|
869
|
+
private _localPoint;
|
|
870
|
+
private readonly _onPointerDown;
|
|
871
|
+
private readonly _onPointerMove;
|
|
872
|
+
private readonly _onPointerUp;
|
|
873
|
+
private readonly _onPointerLeave;
|
|
874
|
+
private readonly _onWheel;
|
|
875
|
+
/**
|
|
876
|
+
* Restore the default view: fit all bars on the time axis and re-enable
|
|
877
|
+
* auto-scaling on every price axis (undoing any pan/zoom or manual axis drag).
|
|
878
|
+
* Same as double-clicking the chart.
|
|
879
|
+
*/
|
|
880
|
+
resetScale(): void;
|
|
881
|
+
private readonly _onDblClick;
|
|
882
|
+
private _beginPinch;
|
|
883
|
+
private _updatePinch;
|
|
884
|
+
private readonly _onKeyDown;
|
|
885
|
+
/** Refresh the polite live-region summary screen readers announce. */
|
|
886
|
+
private _updateAccessibleSummary;
|
|
887
|
+
private _updateCursor;
|
|
888
|
+
private _maybeLoadHistory;
|
|
889
|
+
private _startKinetic;
|
|
890
|
+
private _stopKinetic;
|
|
891
|
+
destroy(): void;
|
|
892
|
+
}
|
|
893
|
+
/** Create a chart inside the given container element. */
|
|
894
|
+
declare function createChart(container: HTMLElement, options?: ChartOptions): Chart;
|
|
895
|
+
|
|
896
|
+
declare function verticalGradient(ctx: CanvasRenderingContext2D, heightPx: number, topColor: string, bottomColor: string): CanvasGradient;
|
|
897
|
+
|
|
898
|
+
/**
|
|
899
|
+
* Generate up to ~`maxTicks` nicely-rounded tick values spanning [min, max].
|
|
900
|
+
* Returns ascending values aligned to the chosen step (may sit slightly inside
|
|
901
|
+
* the range). Returns a single midpoint when the range is degenerate.
|
|
902
|
+
*/
|
|
903
|
+
declare function niceTicks(min: number, max: number, maxTicks?: number): number[];
|
|
904
|
+
/** Decimal places implied by a price step / tick size (for label formatting). */
|
|
905
|
+
declare function precisionForStep(step: number): number;
|
|
906
|
+
|
|
907
|
+
/**
|
|
908
|
+
* Candlestick renderer (ARCHITECTURE.md §6). Pure geometry helpers are split
|
|
909
|
+
* out for unit testing; drawing happens in the bitmap (device-px) scope.
|
|
910
|
+
*/
|
|
911
|
+
|
|
912
|
+
interface CandleStyle {
|
|
913
|
+
upColor: string;
|
|
914
|
+
downColor: string;
|
|
915
|
+
borderUpColor: string;
|
|
916
|
+
borderDownColor: string;
|
|
917
|
+
wickUpColor: string;
|
|
918
|
+
wickDownColor: string;
|
|
919
|
+
borderVisible: boolean;
|
|
920
|
+
wickVisible: boolean;
|
|
921
|
+
/** Draw up-candle bodies as outlines only (hollow candles). */
|
|
922
|
+
hollow?: boolean;
|
|
923
|
+
/** Per-bar body-width scale 0..1 (volume candles); 1 = full width. */
|
|
924
|
+
widthScale?: (bar: Bar) => number;
|
|
925
|
+
}
|
|
926
|
+
declare const DEFAULT_CANDLE_STYLE: CandleStyle;
|
|
927
|
+
/**
|
|
928
|
+
* Pure: optimal candle body width in device px for a given bar spacing. Leaves
|
|
929
|
+
* a ~1px gap between candles, keeps a minimum of 1px, and matches odd/even
|
|
930
|
+
* parity with the wick so the body stays symmetric about the (1px) wick.
|
|
931
|
+
*/
|
|
932
|
+
declare function optimalBarWidth(barSpacing: number, dpr: number): number;
|
|
933
|
+
|
|
934
|
+
/**
|
|
935
|
+
* Histogram / column renderer (ARCHITECTURE.md §6). Used for the volume pane.
|
|
936
|
+
* Bars are drawn from a base value (0) up to each bar's close.
|
|
937
|
+
*/
|
|
938
|
+
|
|
939
|
+
interface HistogramStyle {
|
|
940
|
+
color: string;
|
|
941
|
+
/** Optional separate colors keyed by an up/down flag set on the bar's volume sign. */
|
|
942
|
+
base: number;
|
|
943
|
+
}
|
|
944
|
+
declare const DEFAULT_HISTOGRAM_STYLE: HistogramStyle;
|
|
945
|
+
|
|
946
|
+
/**
|
|
947
|
+
* Live candle aggregation (ARCHITECTURE.md §10.2). The WS feed does not deliver
|
|
948
|
+
* interval candles — LTP mode gives a tick price (+ last-traded-qty), Quote mode
|
|
949
|
+
* gives a *cumulative day* volume. This builder buckets ticks into interval OHLC
|
|
950
|
+
* with explicit volume, session-reset, and late-tick policies. Pure and
|
|
951
|
+
* deterministic (no Date/rAF) so it is fully unit-testable.
|
|
952
|
+
*/
|
|
953
|
+
|
|
954
|
+
type VolumeMode = 'ltq-sum' | 'day-delta';
|
|
955
|
+
type LateTickPolicy = 'foldIntoBar' | 'dropOlderThanPrevBar';
|
|
956
|
+
interface CandleBuilderOptions {
|
|
957
|
+
intervalSec: number;
|
|
958
|
+
/** 'ltq-sum' accumulates last-traded-qty; 'day-delta' diffs cumulative day volume. */
|
|
959
|
+
volumeMode: VolumeMode;
|
|
960
|
+
lateTickPolicy: LateTickPolicy;
|
|
961
|
+
/**
|
|
962
|
+
* UTC-seconds of a known session open. Buckets align to it so e.g. 5-minute
|
|
963
|
+
* bars start at 09:15, not at an arbitrary epoch floor. Defaults to 0 (epoch).
|
|
964
|
+
*/
|
|
965
|
+
sessionAnchorSec: number;
|
|
966
|
+
}
|
|
967
|
+
declare const DEFAULT_CANDLE_BUILDER_OPTIONS: CandleBuilderOptions;
|
|
968
|
+
interface Tick {
|
|
969
|
+
time: UTCSeconds;
|
|
970
|
+
price: number;
|
|
971
|
+
/** Last-traded quantity (LTP mode). */
|
|
972
|
+
ltq?: number;
|
|
973
|
+
/** Cumulative day volume (Quote mode). */
|
|
974
|
+
cumDayVolume?: number;
|
|
975
|
+
}
|
|
976
|
+
interface CandleUpdate {
|
|
977
|
+
bar: Bar;
|
|
978
|
+
/** True when this tick started a new interval bar (append vs mutate-in-place). */
|
|
979
|
+
isNew: boolean;
|
|
980
|
+
}
|
|
981
|
+
declare class CandleBuilder {
|
|
982
|
+
private readonly _opts;
|
|
983
|
+
private _current;
|
|
984
|
+
private _cumAtBarStart;
|
|
985
|
+
private _lastCum;
|
|
986
|
+
private _hasCum;
|
|
987
|
+
constructor(options?: Partial<CandleBuilderOptions>);
|
|
988
|
+
/** Seed with the last historical bar so the first live tick continues it. */
|
|
989
|
+
seed(lastBar: Bar, cumDayVolumeSoFar?: number): void;
|
|
990
|
+
current(): Bar | null;
|
|
991
|
+
/** Bucket-start (bar-open) time for a tick, aligned to the session anchor. */
|
|
992
|
+
bucketStart(time: UTCSeconds): UTCSeconds;
|
|
993
|
+
/**
|
|
994
|
+
* Feed one tick. Returns the affected bar (mutated current or a fresh one),
|
|
995
|
+
* or `null` if the tick was dropped by the late-tick policy.
|
|
996
|
+
*/
|
|
997
|
+
onTick(tick: Tick): CandleUpdate | null;
|
|
998
|
+
private _foldInto;
|
|
999
|
+
private _volumeForNewBar;
|
|
1000
|
+
private _volumeForSameBar;
|
|
1001
|
+
}
|
|
1002
|
+
|
|
1003
|
+
/**
|
|
1004
|
+
* Logo / brand watermark (ARCHITECTURE.md §8). Draws a small image (or an
|
|
1005
|
+
* already-decoded bitmap) faintly in a corner of the plot — the way charting
|
|
1006
|
+
* apps stamp a product/brand mark. Because it draws on the canvas it is captured
|
|
1007
|
+
* by `chart.takeScreenshot()`, and an optional `tint` recolors the opaque pixels
|
|
1008
|
+
* so a single-color logo reads on both dark and light themes.
|
|
1009
|
+
*
|
|
1010
|
+
* Source-agnostic: pass a `src` (URL or data URI) or a preloaded `image`. The
|
|
1011
|
+
* library ships no logo of its own, keeping the bundle lean.
|
|
1012
|
+
*/
|
|
1013
|
+
|
|
1014
|
+
type WatermarkPosition = 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right' | 'center';
|
|
1015
|
+
interface LogoWatermarkOptions {
|
|
1016
|
+
/** Image URL or data URI. Ignored when `image` is provided. */
|
|
1017
|
+
src?: string;
|
|
1018
|
+
/** A preloaded image/bitmap to draw (skips loading). */
|
|
1019
|
+
image?: CanvasImageSource & {
|
|
1020
|
+
width: number;
|
|
1021
|
+
height: number;
|
|
1022
|
+
};
|
|
1023
|
+
/** Corner (or center) to anchor to. Default `bottom-right`. */
|
|
1024
|
+
position?: WatermarkPosition;
|
|
1025
|
+
/** Gap from the plot edges in px. Default `12`. */
|
|
1026
|
+
margin?: number;
|
|
1027
|
+
/** Rendered logo height in px; width follows the source aspect. Default `28`. */
|
|
1028
|
+
height?: number;
|
|
1029
|
+
/** 0..1. Default `0.7`. */
|
|
1030
|
+
opacity?: number;
|
|
1031
|
+
/** Recolor the opaque pixels to this color (e.g. a faint theme gray). */
|
|
1032
|
+
tint?: string;
|
|
1033
|
+
/** Layer order vs the series. Default `top`. */
|
|
1034
|
+
zOrder?: ZOrder;
|
|
1035
|
+
}
|
|
1036
|
+
/** Top-left placement (in media px) of a `w x h` logo within a `plotW x plotH` plot. */
|
|
1037
|
+
declare function watermarkRect(position: WatermarkPosition, margin: number, w: number, h: number, plotW: number, plotH: number): {
|
|
1038
|
+
x: number;
|
|
1039
|
+
y: number;
|
|
1040
|
+
w: number;
|
|
1041
|
+
h: number;
|
|
1042
|
+
};
|
|
1043
|
+
declare class LogoWatermark implements IPrimitive {
|
|
1044
|
+
private _opts;
|
|
1045
|
+
private _host;
|
|
1046
|
+
private _img;
|
|
1047
|
+
private _ready;
|
|
1048
|
+
private _tintCanvas;
|
|
1049
|
+
private _tintKey;
|
|
1050
|
+
constructor(opts?: LogoWatermarkOptions);
|
|
1051
|
+
attached(host: PrimitiveHost): void;
|
|
1052
|
+
detached(): void;
|
|
1053
|
+
zOrder(): ZOrder;
|
|
1054
|
+
autoscaleInfo(): null;
|
|
1055
|
+
/** Live restyle. Pass a new `src`/`image` to swap the logo. */
|
|
1056
|
+
setOptions(patch: Partial<LogoWatermarkOptions>): void;
|
|
1057
|
+
draw(ctx: CanvasRenderingContext2D, rc: PrimitiveRenderContext): void;
|
|
1058
|
+
/** Recolor the opaque logo pixels to `color` at (dw x dh) device px, cached. */
|
|
1059
|
+
private _tinted;
|
|
1060
|
+
}
|
|
1061
|
+
|
|
1062
|
+
/**
|
|
1063
|
+
* Exponential moving average (ARCHITECTURE.md §8 — an indicator that validates
|
|
1064
|
+
* the series/extensibility model). Pure; the result is plotted as a `line`
|
|
1065
|
+
* series, demonstrating derived data on the shared time axis.
|
|
1066
|
+
*/
|
|
1067
|
+
|
|
1068
|
+
/** EMA over a numeric series. Seeds from the first value; k = 2/(period+1). */
|
|
1069
|
+
declare function ema(values: readonly number[], period: number): number[];
|
|
1070
|
+
/**
|
|
1071
|
+
* EMA of bar closes as plottable bars (close = ema; O/H/L = ema), ready to feed
|
|
1072
|
+
* a `line` series via `series.setData(...)`.
|
|
1073
|
+
*/
|
|
1074
|
+
declare function emaSeries(bars: readonly Bar[], period: number): Bar[];
|
|
1075
|
+
|
|
1076
|
+
/**
|
|
1077
|
+
* Relative Strength Index — Wilder's RSI, matching `openalgo.ta.rsi(close, 14)`.
|
|
1078
|
+
*
|
|
1079
|
+
* Uses Wilder smoothing (RMA): the first average gain/loss is the simple mean of
|
|
1080
|
+
* the first `period` deltas, then each subsequent average carries
|
|
1081
|
+
* `(prev*(period-1) + current)/period`. Warmup bars (before enough data) are NaN.
|
|
1082
|
+
*/
|
|
1083
|
+
|
|
1084
|
+
/** Wilder RSI over a numeric series. Returns NaN for the first `period` slots. */
|
|
1085
|
+
declare function rsi(values: readonly number[], period?: number): number[];
|
|
1086
|
+
/**
|
|
1087
|
+
* RSI of bar closes as plottable bars (close = rsi). Warmup bars carry NaN so a
|
|
1088
|
+
* `line` series breaks cleanly before the first value (the renderer skips
|
|
1089
|
+
* non-finite points) instead of dropping to zero.
|
|
1090
|
+
*/
|
|
1091
|
+
declare function rsiSeries(bars: readonly Bar[], period?: number): Bar[];
|
|
1092
|
+
|
|
1093
|
+
/**
|
|
1094
|
+
* Average True Range — Wilder's ATR, matching `openalgo.ta.atr(high, low, close, 14)`.
|
|
1095
|
+
* Shared by the Supertrend indicator. True range of the first bar is high-low.
|
|
1096
|
+
*/
|
|
1097
|
+
/** True range series. tr[0] = high[0]-low[0]; thereafter the classic 3-way max. */
|
|
1098
|
+
declare function trueRange(high: readonly number[], low: readonly number[], close: readonly number[]): number[];
|
|
1099
|
+
/** Wilder ATR. First value (SMA of the first `period` TRs) lands at index period-1; earlier slots NaN. */
|
|
1100
|
+
declare function atr(high: readonly number[], low: readonly number[], close: readonly number[], period?: number): number[];
|
|
1101
|
+
|
|
1102
|
+
/**
|
|
1103
|
+
* Supertrend — matching `openalgo.ta.supertrend(high, low, close, period=10, multiplier=3.0)`,
|
|
1104
|
+
* which returns (supertrend value, direction). Direction follows the OpenAlgo
|
|
1105
|
+
* convention: -1 = uptrend (line is support below price), +1 = downtrend (line
|
|
1106
|
+
* is resistance above price). ATR uses Wilder smoothing (see ./atr).
|
|
1107
|
+
*/
|
|
1108
|
+
|
|
1109
|
+
interface SupertrendPoint {
|
|
1110
|
+
/** The Supertrend band value, or NaN during ATR warmup. */
|
|
1111
|
+
value: number;
|
|
1112
|
+
/** -1 = uptrend (bullish), +1 = downtrend (bearish). */
|
|
1113
|
+
direction: -1 | 1;
|
|
1114
|
+
}
|
|
1115
|
+
/** Supertrend value + direction per bar. Warmup bars carry value=NaN. */
|
|
1116
|
+
declare function supertrend(bars: readonly Bar[], period?: number, multiplier?: number): SupertrendPoint[];
|
|
1117
|
+
/**
|
|
1118
|
+
* Supertrend as two plottable `line` series for direction coloring: `up`
|
|
1119
|
+
* (uptrend / support, typically green) carries the value only while direction is
|
|
1120
|
+
* -1; `down` (downtrend / resistance, typically red) only while +1. The inactive
|
|
1121
|
+
* series carries NaN, so each renders as separate segments that swap at flips
|
|
1122
|
+
* (the line renderer breaks across non-finite points).
|
|
1123
|
+
*/
|
|
1124
|
+
declare function supertrendSeries(bars: readonly Bar[], period?: number, multiplier?: number): {
|
|
1125
|
+
up: Bar[];
|
|
1126
|
+
down: Bar[];
|
|
1127
|
+
};
|
|
1128
|
+
|
|
1129
|
+
/**
|
|
1130
|
+
* Optional OHLC-preserving conflation / downsampling (ARCHITECTURE.md §4.4).
|
|
1131
|
+
* When zoomed far out, many bars map to sub-pixel widths; drawing them all is
|
|
1132
|
+
* wasted work. Conflation merges groups of bars into one, preserving candle
|
|
1133
|
+
* shape — open = first, close = last, high = max, low = min, volume = sum
|
|
1134
|
+
* (never a lossy average). Off by default; enabling it changes nothing until
|
|
1135
|
+
* bars fall below the pixel threshold.
|
|
1136
|
+
*/
|
|
1137
|
+
|
|
1138
|
+
/**
|
|
1139
|
+
* How many source bars to merge per drawn bar. Returns 1 (no conflation) while
|
|
1140
|
+
* each bar is at least `minPx` wide; otherwise ceil(minPx / barWidthPx) scaled
|
|
1141
|
+
* by `factor` (higher = more aggressive smoothing).
|
|
1142
|
+
*/
|
|
1143
|
+
declare function conflationGroupSize(barSpacing: number, dpr: number, minPx?: number, factor?: number): number;
|
|
1144
|
+
/** Merge a single group of bars into one OHLC-preserving bar (uses the first bar's time). */
|
|
1145
|
+
declare function mergeBars(group: readonly Bar[]): Bar;
|
|
1146
|
+
/** Conflate a bar series into groups of `groupSize` (identity when groupSize ≤ 1). */
|
|
1147
|
+
declare function conflateBars(bars: readonly Bar[], groupSize: number): Bar[];
|
|
1148
|
+
/** Conflate already-projected draw items: merge bars and place x at the group centre. */
|
|
1149
|
+
declare function conflateItems<T extends {
|
|
1150
|
+
x: number;
|
|
1151
|
+
bar: Bar;
|
|
1152
|
+
}>(items: readonly T[], groupSize: number): {
|
|
1153
|
+
x: number;
|
|
1154
|
+
bar: Bar;
|
|
1155
|
+
}[];
|
|
1156
|
+
|
|
1157
|
+
/** Cancels a subscription. */
|
|
1158
|
+
type UnsubscribeFn = () => void;
|
|
1159
|
+
interface BarsRequest {
|
|
1160
|
+
symbol: string;
|
|
1161
|
+
exchange: string;
|
|
1162
|
+
/** Interval token, e.g. "1m", "5m", "1h", "D". */
|
|
1163
|
+
interval: string;
|
|
1164
|
+
from?: UTCSeconds;
|
|
1165
|
+
to?: UTCSeconds;
|
|
1166
|
+
}
|
|
1167
|
+
/**
|
|
1168
|
+
* Broker-agnostic market-data source. The chart depends only on this.
|
|
1169
|
+
* `subscribeBars` is optional: a history-only feed (e.g. `OpenAlgoDataFeed`) omits
|
|
1170
|
+
* it, while a live feed (`OpenAlgoLiveDataFeed`, or your own) implements it.
|
|
1171
|
+
*/
|
|
1172
|
+
interface DataFeed {
|
|
1173
|
+
getBars(req: BarsRequest): Promise<Bar[]>;
|
|
1174
|
+
subscribeBars?(req: BarsRequest, onBar: (bar: Bar) => void): UnsubscribeFn;
|
|
1175
|
+
subscribeDepth?(req: BarsRequest, onDepth: (depth: MarketDepth) => void): UnsubscribeFn;
|
|
1176
|
+
}
|
|
1177
|
+
interface DepthLevel {
|
|
1178
|
+
price: number;
|
|
1179
|
+
qty: number;
|
|
1180
|
+
orders?: number;
|
|
1181
|
+
}
|
|
1182
|
+
/** Variable-depth book; `bids`/`asks` length = whatever the broker streams (5..200). */
|
|
1183
|
+
interface MarketDepth {
|
|
1184
|
+
bids: DepthLevel[];
|
|
1185
|
+
asks: DepthLevel[];
|
|
1186
|
+
ltp: number;
|
|
1187
|
+
ltq?: number;
|
|
1188
|
+
}
|
|
1189
|
+
type OrderSide$1 = 'BUY' | 'SELL';
|
|
1190
|
+
type OrderType$1 = 'MARKET' | 'LIMIT' | 'SL' | 'SL-M';
|
|
1191
|
+
interface PlaceOrder {
|
|
1192
|
+
symbol: string;
|
|
1193
|
+
exchange: string;
|
|
1194
|
+
side: OrderSide$1;
|
|
1195
|
+
type: OrderType$1;
|
|
1196
|
+
qty: number;
|
|
1197
|
+
price?: number;
|
|
1198
|
+
triggerPrice?: number;
|
|
1199
|
+
/** Idempotency token so a retried place never double-fills. */
|
|
1200
|
+
clientToken?: string;
|
|
1201
|
+
}
|
|
1202
|
+
/** Broker-agnostic trading source. */
|
|
1203
|
+
interface TradeFeed {
|
|
1204
|
+
placeOrder(o: PlaceOrder): Promise<{
|
|
1205
|
+
orderId: string;
|
|
1206
|
+
}>;
|
|
1207
|
+
modifyOrder(orderId: string, patch: Partial<PlaceOrder>): Promise<void>;
|
|
1208
|
+
cancelOrder(orderId: string): Promise<void>;
|
|
1209
|
+
subscribeOrders(cb: (orders: unknown[]) => void): UnsubscribeFn;
|
|
1210
|
+
subscribePositions(cb: (positions: unknown[]) => void): UnsubscribeFn;
|
|
1211
|
+
}
|
|
1212
|
+
|
|
1213
|
+
/**
|
|
1214
|
+
* OpenAlgo REST adapter (ARCHITECTURE.md §10.0). The chart depends only on the
|
|
1215
|
+
* `DataFeed` interface; this is the only file that knows OpenAlgo's REST shape.
|
|
1216
|
+
*
|
|
1217
|
+
* History endpoint: POST `${baseUrl}/api/v1/history`.
|
|
1218
|
+
* NOTE: the exact request/response field names must be verified against the
|
|
1219
|
+
* running OpenAlgo build and pinned here; the mapper below is tolerant of
|
|
1220
|
+
* epoch-seconds, epoch-ms, and IST date/time string timestamps.
|
|
1221
|
+
*/
|
|
1222
|
+
|
|
1223
|
+
interface OpenAlgoConfig {
|
|
1224
|
+
baseUrl: string;
|
|
1225
|
+
apiKey: string;
|
|
1226
|
+
/** Injectable fetch (defaults to global fetch); lets the adapter be tested offline. */
|
|
1227
|
+
fetchImpl?: typeof fetch;
|
|
1228
|
+
}
|
|
1229
|
+
interface HistoryRow {
|
|
1230
|
+
timestamp?: number | string;
|
|
1231
|
+
time?: number | string;
|
|
1232
|
+
open: number;
|
|
1233
|
+
high: number;
|
|
1234
|
+
low: number;
|
|
1235
|
+
close: number;
|
|
1236
|
+
volume?: number;
|
|
1237
|
+
}
|
|
1238
|
+
interface HistoryResponse {
|
|
1239
|
+
status?: string;
|
|
1240
|
+
data?: HistoryRow[];
|
|
1241
|
+
}
|
|
1242
|
+
/** Pure: coerce a row timestamp (epoch s / epoch ms / IST string) to UTC seconds. */
|
|
1243
|
+
declare function rowTimeToUtcSeconds(value: number | string): number;
|
|
1244
|
+
/** Pure: map an OpenAlgo history response into sorted internal bars. */
|
|
1245
|
+
declare function mapHistoryResponse(json: HistoryResponse): Bar[];
|
|
1246
|
+
declare class OpenAlgoDataFeed implements DataFeed {
|
|
1247
|
+
private readonly _config;
|
|
1248
|
+
private readonly _fetch;
|
|
1249
|
+
constructor(config: OpenAlgoConfig);
|
|
1250
|
+
getBars(req: BarsRequest): Promise<Bar[]>;
|
|
1251
|
+
}
|
|
1252
|
+
|
|
1253
|
+
/**
|
|
1254
|
+
* OpenAlgo WebSocket adapter (ARCHITECTURE.md §10, C2). Speaks the documented
|
|
1255
|
+
* OpenAlgo WS proxy protocol (default port 8765, or wss://host/ws in production):
|
|
1256
|
+
*
|
|
1257
|
+
* 1. authenticate: { action:'authenticate', api_key }
|
|
1258
|
+
* 2. subscribe : { action:'subscribe', symbol, exchange, mode } mode 1=LTP 2=Quote 3=Depth
|
|
1259
|
+
* (Depth adds depth_level, e.g. 5/20/30/50)
|
|
1260
|
+
* 3. server pushes { type:'market_data', mode, topic:'SYM.EXCH', data:{...} }
|
|
1261
|
+
* 4. heartbeat : server 'ping' → client 'pong' (30s)
|
|
1262
|
+
*
|
|
1263
|
+
* Maps inbound LTP / Quote / Depth into typed callbacks the chart consumes
|
|
1264
|
+
* (candle builder, last price, DOM ladder). The socket is injectable so the
|
|
1265
|
+
* adapter is unit-testable with a fake socket and no network.
|
|
1266
|
+
*/
|
|
1267
|
+
|
|
1268
|
+
type WsMode = 'LTP' | 'Quote' | 'Depth';
|
|
1269
|
+
/** Socket lifecycle reported by `onState`. */
|
|
1270
|
+
type WsState = 'connecting' | 'open' | 'closed' | 'error';
|
|
1271
|
+
/** A non-market-data control frame (auth / subscribe ack, or a server error). */
|
|
1272
|
+
interface WsControlMessage {
|
|
1273
|
+
type?: string;
|
|
1274
|
+
status?: string;
|
|
1275
|
+
message?: string;
|
|
1276
|
+
[k: string]: unknown;
|
|
1277
|
+
}
|
|
1278
|
+
/** Minimal socket surface (the browser WebSocket satisfies this). */
|
|
1279
|
+
interface SocketLike {
|
|
1280
|
+
send(data: string): void;
|
|
1281
|
+
close(): void;
|
|
1282
|
+
onopen: (() => void) | null;
|
|
1283
|
+
onclose: (() => void) | null;
|
|
1284
|
+
onerror?: (() => void) | null;
|
|
1285
|
+
onmessage: ((ev: {
|
|
1286
|
+
data: string;
|
|
1287
|
+
}) => void) | null;
|
|
1288
|
+
/** 1 === OPEN (browser WebSocket.OPEN). Used to gate sends. */
|
|
1289
|
+
readyState?: number;
|
|
1290
|
+
}
|
|
1291
|
+
type SocketFactory = (url: string) => SocketLike;
|
|
1292
|
+
interface OpenAlgoWsConfig {
|
|
1293
|
+
url: string;
|
|
1294
|
+
apiKey: string;
|
|
1295
|
+
socketFactory?: SocketFactory;
|
|
1296
|
+
}
|
|
1297
|
+
interface LtpEvent {
|
|
1298
|
+
symbol: string;
|
|
1299
|
+
exchange: string;
|
|
1300
|
+
ltp: number;
|
|
1301
|
+
ltq?: number;
|
|
1302
|
+
/** Cumulative day volume (Quote mode) — feeds the candle builder's day-delta mode. */
|
|
1303
|
+
volume?: number;
|
|
1304
|
+
timeSec: number;
|
|
1305
|
+
}
|
|
1306
|
+
/**
|
|
1307
|
+
* Pure: build a subscribe message — `{ action, symbol, exchange, mode }`, where
|
|
1308
|
+
* `mode` is the numeric OpenAlgo data mode. Depth subscriptions may request a
|
|
1309
|
+
* `depth_level` (broker-dependent: 5/20/30/50).
|
|
1310
|
+
*/
|
|
1311
|
+
declare function formatSubscribe(mode: WsMode, symbol: string, exchange: string, depthLevel?: number): string;
|
|
1312
|
+
declare function formatUnsubscribe(mode: WsMode, symbol: string, exchange: string): string;
|
|
1313
|
+
/**
|
|
1314
|
+
* Pure: classify + normalise an inbound message into an LTP or Depth event.
|
|
1315
|
+
* Payload fields live under `data` per the protocol, but the parser also
|
|
1316
|
+
* tolerates a flat shape for resilience across broker adapters.
|
|
1317
|
+
*/
|
|
1318
|
+
declare function parseMessage(raw: unknown): {
|
|
1319
|
+
kind: 'ltp';
|
|
1320
|
+
event: LtpEvent;
|
|
1321
|
+
} | {
|
|
1322
|
+
kind: 'depth';
|
|
1323
|
+
symbol: string;
|
|
1324
|
+
exchange: string;
|
|
1325
|
+
depth: MarketDepth;
|
|
1326
|
+
} | null;
|
|
1327
|
+
declare class OpenAlgoWsFeed {
|
|
1328
|
+
private readonly _config;
|
|
1329
|
+
private readonly _factory;
|
|
1330
|
+
private _sock;
|
|
1331
|
+
private _open;
|
|
1332
|
+
private readonly _queue;
|
|
1333
|
+
private readonly _ltpCbs;
|
|
1334
|
+
private readonly _depthCbs;
|
|
1335
|
+
private readonly _stateCbs;
|
|
1336
|
+
private readonly _controlCbs;
|
|
1337
|
+
constructor(config: OpenAlgoWsConfig);
|
|
1338
|
+
connect(): void;
|
|
1339
|
+
/** Subscribe to socket lifecycle (connecting / open / closed / error). */
|
|
1340
|
+
onState(cb: (state: WsState) => void): () => void;
|
|
1341
|
+
/** Subscribe to control frames — auth / subscribe acks and server errors. */
|
|
1342
|
+
onControl(cb: (msg: WsControlMessage) => void): () => void;
|
|
1343
|
+
private _emitState;
|
|
1344
|
+
/** Authenticate first, then flush any queued subscriptions (protocol order). */
|
|
1345
|
+
private _onOpen;
|
|
1346
|
+
/** Send now if open; otherwise queue until onopen (browsers throw on send-before-open). */
|
|
1347
|
+
private _send;
|
|
1348
|
+
private _flush;
|
|
1349
|
+
onLtp(cb: (e: LtpEvent) => void): () => void;
|
|
1350
|
+
onDepth(cb: (symbol: string, exchange: string, depth: MarketDepth) => void): () => void;
|
|
1351
|
+
subscribe(mode: WsMode, symbol: string, exchange: string, depthLevel?: number): void;
|
|
1352
|
+
unsubscribe(mode: WsMode, symbol: string, exchange: string): void;
|
|
1353
|
+
close(): void;
|
|
1354
|
+
private _dispatch;
|
|
1355
|
+
}
|
|
1356
|
+
|
|
1357
|
+
/**
|
|
1358
|
+
* Trade-layer data model (ARCHITECTURE.md §9). Broker-agnostic shapes the
|
|
1359
|
+
* TradeFeed produces; the chart depends only on these, not on OpenAlgo's REST.
|
|
1360
|
+
*/
|
|
1361
|
+
type OrderSide = 'BUY' | 'SELL';
|
|
1362
|
+
type OrderType = 'MARKET' | 'LIMIT' | 'SL' | 'SL-M';
|
|
1363
|
+
/** Lifecycle states (§9.5). Phase 8 reconciles read-only; Phase 9 drives writes. */
|
|
1364
|
+
type OrderStatus = 'pending' | 'working' | 'partial' | 'filled' | 'cancelled' | 'rejected';
|
|
1365
|
+
type OrderRole = 'entry' | 'sl' | 'tp';
|
|
1366
|
+
interface Order {
|
|
1367
|
+
id: string;
|
|
1368
|
+
symbol: string;
|
|
1369
|
+
side: OrderSide;
|
|
1370
|
+
type: OrderType;
|
|
1371
|
+
qty: number;
|
|
1372
|
+
filledQty: number;
|
|
1373
|
+
price: number;
|
|
1374
|
+
triggerPrice?: number;
|
|
1375
|
+
status: OrderStatus;
|
|
1376
|
+
/** Links SL/TP child orders to their position/entry. */
|
|
1377
|
+
parentId?: string;
|
|
1378
|
+
role?: OrderRole;
|
|
1379
|
+
}
|
|
1380
|
+
interface Position {
|
|
1381
|
+
symbol: string;
|
|
1382
|
+
/** Net signed quantity: positive = long, negative = short, 0 = flat. */
|
|
1383
|
+
netQty: number;
|
|
1384
|
+
avgPrice: number;
|
|
1385
|
+
}
|
|
1386
|
+
|
|
1387
|
+
/**
|
|
1388
|
+
* Order engine (ARCHITECTURE.md §9.5) — the chart-trading write path. Drives the
|
|
1389
|
+
* order state machine with: client-token idempotency, an arm/confirm gate,
|
|
1390
|
+
* pre-trade validation, rate-limited drag-modify, OCO linking, and analyzer
|
|
1391
|
+
* (sandbox) mode. Network-agnostic: it talks to an injected OrderFeed (the
|
|
1392
|
+
* FakeBroker simulates it in tests/demos).
|
|
1393
|
+
*/
|
|
1394
|
+
|
|
1395
|
+
interface PlaceRequest {
|
|
1396
|
+
symbol: string;
|
|
1397
|
+
exchange?: string;
|
|
1398
|
+
side: OrderSide;
|
|
1399
|
+
type: OrderType;
|
|
1400
|
+
qty: number;
|
|
1401
|
+
price?: number;
|
|
1402
|
+
triggerPrice?: number;
|
|
1403
|
+
/** Product: CNC (delivery), NRML (F&O carry), MIS (intraday). Required by OpenAlgo. */
|
|
1404
|
+
product?: 'CNC' | 'NRML' | 'MIS';
|
|
1405
|
+
/** Idempotency token; a retry with the same token is never double-sent. */
|
|
1406
|
+
clientToken?: string;
|
|
1407
|
+
}
|
|
1408
|
+
interface OrderFeed {
|
|
1409
|
+
place(req: PlaceRequest & {
|
|
1410
|
+
mode: TradeMode;
|
|
1411
|
+
}): Promise<{
|
|
1412
|
+
orderId: string;
|
|
1413
|
+
}>;
|
|
1414
|
+
modify(orderId: string, patch: {
|
|
1415
|
+
price?: number;
|
|
1416
|
+
triggerPrice?: number;
|
|
1417
|
+
qty?: number;
|
|
1418
|
+
}): Promise<void>;
|
|
1419
|
+
cancel(orderId: string): Promise<void>;
|
|
1420
|
+
}
|
|
1421
|
+
type TradeMode = 'live' | 'analyzer';
|
|
1422
|
+
|
|
1423
|
+
/**
|
|
1424
|
+
* OpenAlgo trade adapter (ARCHITECTURE.md §10.0). Implements the order engine's
|
|
1425
|
+
* OrderFeed over OpenAlgo REST (`/api/v1/placeorder`, `/modifyorder`,
|
|
1426
|
+
* `/cancelorder`) plus orderbook/positionbook fetches for reconciliation.
|
|
1427
|
+
*
|
|
1428
|
+
* Payloads match the local OpenAlgo docs: `placeorder` requires
|
|
1429
|
+
* strategy/symbol/action/exchange/pricetype/product/quantity; `modifyorder`
|
|
1430
|
+
* additionally requires the full order context, so we cache each order's context
|
|
1431
|
+
* (from place + the order book) and merge the patch on modify. Book responses
|
|
1432
|
+
* return string quantities/prices, which are coerced to numbers. Fetch is
|
|
1433
|
+
* injectable for offline tests; verify field names against your OpenAlgo build.
|
|
1434
|
+
*/
|
|
1435
|
+
|
|
1436
|
+
interface OpenAlgoTradeConfig {
|
|
1437
|
+
baseUrl: string;
|
|
1438
|
+
apiKey: string;
|
|
1439
|
+
/** Strategy label sent with orders (OpenAlgo groups by strategy). */
|
|
1440
|
+
strategy?: string;
|
|
1441
|
+
/** Default product when a request doesn't specify one. */
|
|
1442
|
+
defaultProduct?: 'CNC' | 'NRML' | 'MIS';
|
|
1443
|
+
fetchImpl?: typeof fetch;
|
|
1444
|
+
}
|
|
1445
|
+
declare class OpenAlgoTradeFeed implements OrderFeed {
|
|
1446
|
+
private readonly _config;
|
|
1447
|
+
private readonly _fetch;
|
|
1448
|
+
private readonly _strategy;
|
|
1449
|
+
private readonly _defaultProduct;
|
|
1450
|
+
private readonly _ctx;
|
|
1451
|
+
constructor(config: OpenAlgoTradeConfig);
|
|
1452
|
+
private _post;
|
|
1453
|
+
place(req: PlaceRequest & {
|
|
1454
|
+
mode: TradeMode;
|
|
1455
|
+
}): Promise<{
|
|
1456
|
+
orderId: string;
|
|
1457
|
+
}>;
|
|
1458
|
+
modify(orderId: string, patch: {
|
|
1459
|
+
price?: number;
|
|
1460
|
+
triggerPrice?: number;
|
|
1461
|
+
qty?: number;
|
|
1462
|
+
}): Promise<void>;
|
|
1463
|
+
cancel(orderId: string): Promise<void>;
|
|
1464
|
+
/** Fetch the order book for reconciliation (maps to broker-agnostic Order[]). */
|
|
1465
|
+
getOrders(): Promise<Order[]>;
|
|
1466
|
+
/** Fetch the position book for reconciliation. */
|
|
1467
|
+
getPositions(): Promise<Position[]>;
|
|
1468
|
+
}
|
|
1469
|
+
interface RawOrder {
|
|
1470
|
+
orderid?: string;
|
|
1471
|
+
symbol?: string;
|
|
1472
|
+
exchange?: string;
|
|
1473
|
+
action?: string;
|
|
1474
|
+
pricetype?: string;
|
|
1475
|
+
product?: string;
|
|
1476
|
+
quantity?: number | string;
|
|
1477
|
+
filled_quantity?: number | string;
|
|
1478
|
+
price?: number | string;
|
|
1479
|
+
trigger_price?: number | string;
|
|
1480
|
+
order_status?: string;
|
|
1481
|
+
}
|
|
1482
|
+
interface RawPosition {
|
|
1483
|
+
symbol?: string;
|
|
1484
|
+
quantity?: number | string;
|
|
1485
|
+
average_price?: number | string;
|
|
1486
|
+
}
|
|
1487
|
+
declare function mapOrder(r: RawOrder): Order;
|
|
1488
|
+
declare function mapPosition(r: RawPosition): Position;
|
|
1489
|
+
|
|
1490
|
+
/**
|
|
1491
|
+
* Composed OpenAlgo live data feed (resolves audit V2-M1). Implements the full
|
|
1492
|
+
* `DataFeed` contract by combining history (REST), live ticks (WS), and a
|
|
1493
|
+
* per-subscription `CandleBuilder` — so `subscribeBars()` actually delivers live
|
|
1494
|
+
* interval bars instead of being a no-op trap.
|
|
1495
|
+
*/
|
|
1496
|
+
|
|
1497
|
+
interface OpenAlgoLiveConfig extends OpenAlgoConfig {
|
|
1498
|
+
/** WS proxy URL, e.g. ws://127.0.0.1:8765. */
|
|
1499
|
+
wsUrl: string;
|
|
1500
|
+
/** Volume accounting for the live candle builder (default 'ltq-sum'). */
|
|
1501
|
+
volumeMode?: VolumeMode;
|
|
1502
|
+
}
|
|
1503
|
+
/** Map an interval token (e.g. '1m','5m','1h','D') to seconds for bucketing. */
|
|
1504
|
+
declare function intervalToSeconds(interval: string): number;
|
|
1505
|
+
declare class OpenAlgoLiveDataFeed implements DataFeed {
|
|
1506
|
+
private readonly _rest;
|
|
1507
|
+
private readonly _ws;
|
|
1508
|
+
private readonly _volumeMode;
|
|
1509
|
+
constructor(config: OpenAlgoLiveConfig);
|
|
1510
|
+
getBars(req: BarsRequest): Promise<Bar[]>;
|
|
1511
|
+
/** Live interval bars: WS LTP → CandleBuilder → onBar (mutated/append bar). */
|
|
1512
|
+
subscribeBars(req: BarsRequest, onBar: (bar: Bar) => void): UnsubscribeFn;
|
|
1513
|
+
subscribeDepth(req: BarsRequest, onDepth: (depth: MarketDepth) => void): UnsubscribeFn;
|
|
1514
|
+
close(): void;
|
|
1515
|
+
}
|
|
1516
|
+
|
|
1517
|
+
/**
|
|
1518
|
+
* Deterministic, in-memory data feed for tests and demos. No network.
|
|
1519
|
+
* Generates a reproducible synthetic OHLC walk from a fixed seed so that
|
|
1520
|
+
* pixel-diff and unit tests are stable across runs (no Math.random / Date.now).
|
|
1521
|
+
*/
|
|
1522
|
+
declare class FakeDataFeed implements DataFeed {
|
|
1523
|
+
private readonly intervalSec;
|
|
1524
|
+
constructor(intervalSec?: number);
|
|
1525
|
+
getBars(req: BarsRequest): Promise<Bar[]>;
|
|
1526
|
+
subscribeBars(_req: BarsRequest, _onBar: (bar: Bar) => void): UnsubscribeFn;
|
|
1527
|
+
}
|
|
1528
|
+
/** Pure, seeded synthetic bar generator (deterministic — no global randomness). */
|
|
1529
|
+
declare function generateBars(startTime: number, count: number, intervalSec: number): Bar[];
|
|
1530
|
+
|
|
1531
|
+
/**
|
|
1532
|
+
* Tick aggregation (ARCHITECTURE.md §10.2). Aggregates raw trade ticks into
|
|
1533
|
+
* bars on a chosen timeframe — clock interval, tick count, or traded volume.
|
|
1534
|
+
* Incremental and deterministic, so it works live and is unit-testable.
|
|
1535
|
+
*
|
|
1536
|
+
* This is the foundation for tick / volume timeframes and (with classified
|
|
1537
|
+
* bid/ask ticks) for the footprint aggregator. Tick-count and volume bars need
|
|
1538
|
+
* real trade ticks — OHLCV alone can't produce them.
|
|
1539
|
+
*/
|
|
1540
|
+
|
|
1541
|
+
type TickTimeframe = {
|
|
1542
|
+
mode: 'interval';
|
|
1543
|
+
seconds: number;
|
|
1544
|
+
anchorSec?: number;
|
|
1545
|
+
} | {
|
|
1546
|
+
mode: 'ticks';
|
|
1547
|
+
count: number;
|
|
1548
|
+
} | {
|
|
1549
|
+
mode: 'volume';
|
|
1550
|
+
perBar: number;
|
|
1551
|
+
};
|
|
1552
|
+
interface AggTick {
|
|
1553
|
+
time: number;
|
|
1554
|
+
price: number;
|
|
1555
|
+
qty: number;
|
|
1556
|
+
}
|
|
1557
|
+
interface BarUpdate {
|
|
1558
|
+
bar: Bar;
|
|
1559
|
+
isNew: boolean;
|
|
1560
|
+
}
|
|
1561
|
+
declare class TickBarAggregator {
|
|
1562
|
+
private readonly _tf;
|
|
1563
|
+
private _cur;
|
|
1564
|
+
private _count;
|
|
1565
|
+
constructor(tf: TickTimeframe);
|
|
1566
|
+
current(): Bar | null;
|
|
1567
|
+
onTick(tick: AggTick): BarUpdate;
|
|
1568
|
+
}
|
|
1569
|
+
|
|
1570
|
+
/**
|
|
1571
|
+
* Time conversions (ARCHITECTURE.md §4.0). Internal time is always UTC seconds.
|
|
1572
|
+
* Feed adapters convert broker formats here, at the edge:
|
|
1573
|
+
* - REST history → IST date/time strings
|
|
1574
|
+
* - WS feed → epoch milliseconds
|
|
1575
|
+
* India observes no DST, so IST is a fixed UTC+5:30 offset.
|
|
1576
|
+
*/
|
|
1577
|
+
/** IST offset in seconds (UTC+5:30). */
|
|
1578
|
+
declare const IST_OFFSET_SECONDS: number;
|
|
1579
|
+
/** Epoch milliseconds → UTC seconds. */
|
|
1580
|
+
declare function epochMsToUtcSeconds(ms: number): number;
|
|
1581
|
+
/**
|
|
1582
|
+
* Parse an IST wall-clock date/time string to UTC seconds. Accepts
|
|
1583
|
+
* `YYYY-MM-DD`, `YYYY-MM-DD HH:MM[:SS]`, and the `T`-separated ISO variant.
|
|
1584
|
+
* Parsing is explicit (never relies on the host machine's locale/timezone).
|
|
1585
|
+
*/
|
|
1586
|
+
declare function istStringToUtcSeconds(input: string): number;
|
|
1587
|
+
interface IstParts {
|
|
1588
|
+
year: number;
|
|
1589
|
+
month: number;
|
|
1590
|
+
day: number;
|
|
1591
|
+
hour: number;
|
|
1592
|
+
minute: number;
|
|
1593
|
+
second: number;
|
|
1594
|
+
/** 0 = Sunday .. 6 = Saturday, in IST. */
|
|
1595
|
+
weekday: number;
|
|
1596
|
+
}
|
|
1597
|
+
/** UTC seconds → IST calendar parts (for axis labels / tick decisions). */
|
|
1598
|
+
declare function utcSecondsToIstParts(utcSeconds: number): IstParts;
|
|
1599
|
+
/** Format UTC seconds as an IST `HH:MM` clock label. */
|
|
1600
|
+
declare function formatIstTime(utcSeconds: number): string;
|
|
1601
|
+
/** Format UTC seconds as an IST `HH:MM:SS` clock label (sub-minute / tick timeframes). */
|
|
1602
|
+
declare function formatIstTimeSeconds(utcSeconds: number): string;
|
|
1603
|
+
/** Format UTC seconds as an IST `YYYY-MM-DD` date (for OpenAlgo history requests). */
|
|
1604
|
+
declare function utcSecondsToIstDateString(utcSeconds: number): string;
|
|
1605
|
+
/** Format UTC seconds as an IST `DD Mon` date label. */
|
|
1606
|
+
declare function formatIstDate(utcSeconds: number): string;
|
|
1607
|
+
/** True if the two UTC-second instants fall on different IST calendar days. */
|
|
1608
|
+
declare function isNewIstDay(prevUtcSeconds: number, utcSeconds: number): boolean;
|
|
1609
|
+
|
|
1610
|
+
/** Clamp `value` into the inclusive range [min, max]. */
|
|
1611
|
+
declare function clamp(value: number, min: number, max: number): number;
|
|
1612
|
+
/** Linear interpolation between `a` and `b` by fraction `t` (0..1). */
|
|
1613
|
+
declare function lerp(a: number, b: number, t: number): number;
|
|
1614
|
+
/**
|
|
1615
|
+
* Round `value` to the nearest multiple of `step` (the instrument tick size).
|
|
1616
|
+
* Used for snapping dragged order/SL/TP prices to a valid tick. Returns
|
|
1617
|
+
* `value` unchanged when `step <= 0`.
|
|
1618
|
+
*/
|
|
1619
|
+
declare function roundToTick(value: number, step: number): number;
|
|
1620
|
+
|
|
1621
|
+
export { type AddSeriesOptions, type AggTick, type Bar, type BarUpdate, type BarsRequest, CandleBuilder, type CandleBuilderOptions, type CandleStyle, type CandleUpdate, Chart, type ChartEvent, type ChartOptions, type ChartTheme, type CrosshairMoveEvent, DEFAULT_CANDLE_BUILDER_OPTIONS, DEFAULT_CANDLE_STYLE, DEFAULT_HISTOGRAM_STYLE, DEFAULT_PRICE_SCALE_OPTIONS, DEFAULT_THEME, DEFAULT_TIME_SCALE_OPTIONS, type DataFeed, type DepthLevel, type DrawItem, EventMarkers, FakeDataFeed, type HistogramStyle, type IPrimitive, IST_OFFSET_SECONDS, InvalidationLevel, type LateTickPolicy, type LinePoint, type LogicalRange, LogoWatermark, type LogoWatermarkOptions, type LtpEvent, type MarkerPosition, type MarkerShape, type MarkerSize, type MarketDepth, type OpenAlgoConfig, OpenAlgoDataFeed, type OpenAlgoLiveConfig, OpenAlgoLiveDataFeed, type OpenAlgoTradeConfig, OpenAlgoTradeFeed, type OpenAlgoWsConfig, OpenAlgoWsFeed, type OrderSide$1 as OrderSide, type OrderType$1 as OrderType, type OriginalTime, Pane, type PaneInvalidation, type PlaceOrder, PriceLine, type PriceLineOptions, type PriceRange, PriceScale, type PriceScaleMode, type PriceScaleOptions, type PrimitiveHit, type PrimitiveHost, type PrimitiveRenderContext, type RendererEntry, type SeriesApi, type SeriesMarker, SeriesMarkers, type SeriesRenderContext, type SeriesStyle, type SeriesType, type Size, type SocketFactory, type SocketLike, type SupertrendPoint, type Tick, TickBarAggregator, type TickTimeframe, TimeScale, type TimeScaleOp, type TimeScaleOptions, type TradeFeed, type UTCSeconds, type UnsubscribeFn, VERSION, type VolumeMode, type WatermarkPosition, type Whitespace, type WsControlMessage, type WsMode, type WsState, type ZOrder, atr, autoscaleRange, bestHit, bitmapSize, clamp, conflateBars, conflateItems, conflationGroupSize, createChart, darkTheme, drawShape, effectiveMarkerPx, ema, emaSeries, epochMsToUtcSeconds, formatIstDate, formatIstTime, formatIstTimeSeconds, formatSubscribe, formatUnsubscribe, generateBars, getChartType, intervalToSeconds, isNewIstDay, isWhitespace, istStringToUtcSeconds, lerp, lightTheme, mapHistoryResponse, mapOrder, mapPosition, markerSizePx, mergeBars, niceTicks, optimalBarWidth, parseMessage, precisionForStep, registerChartType, registeredChartTypes, roundToTick, rowTimeToUtcSeconds, rsi, rsiSeries, snapToDevicePixel, supertrend, supertrendSeries, trueRange, utcSecondsToIstDateString, utcSecondsToIstParts, version, verticalGradient, watermarkRect };
|