openalgo-charts 2.4.0 → 2.4.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +56 -41
- package/dist/draw/index.d.ts +18 -2
- package/dist/index.d.ts +2260 -1678
- package/dist/indicators/index.d.ts +25 -7
- package/dist/openalgo-charts.draw.mjs +1 -1
- package/dist/openalgo-charts.draw.mjs.map +1 -1
- package/dist/openalgo-charts.indicators.mjs +1 -1
- package/dist/openalgo-charts.indicators.mjs.map +1 -1
- package/dist/openalgo-charts.mjs +1 -1
- package/dist/openalgo-charts.mjs.map +1 -1
- package/dist/openalgo-charts.standalone.js +1 -1
- package/dist/openalgo-charts.standalone.js.map +1 -1
- package/dist/openalgo-charts.trade.mjs +1 -1
- package/dist/openalgo-charts.trade.mjs.map +1 -1
- package/dist/openalgo-charts.transform.mjs +1 -1
- package/dist/openalgo-charts.transform.mjs.map +1 -1
- package/dist/openalgo-charts.widget.mjs +1 -1
- package/dist/openalgo-charts.widget.mjs.map +1 -1
- package/dist/openalgo-charts.workspace.mjs +2 -0
- package/dist/openalgo-charts.workspace.mjs.map +1 -0
- package/dist/profile/index.d.ts +22 -0
- package/dist/trade/index.d.ts +15 -4
- package/dist/transform/index.d.ts +32 -2
- package/dist/webgl/index.d.ts +22 -0
- package/dist/widget/index.d.ts +96 -8
- package/dist/workspace/index.d.ts +170 -0
- package/package.json +8 -2
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
|
+
import { TradingCapabilitySource as TradingCapabilitySource$1 } from 'openalgo-charts';
|
|
2
|
+
|
|
1
3
|
/** Library version string. Matches package.json (including locally prepared releases). */
|
|
2
|
-
declare const VERSION = "2.4.
|
|
4
|
+
declare const VERSION = "2.4.5";
|
|
3
5
|
/** Returns the current library version. */
|
|
4
6
|
declare function version(): string;
|
|
5
7
|
|
|
@@ -431,6 +433,28 @@ interface Bar {
|
|
|
431
433
|
low: number;
|
|
432
434
|
close: number;
|
|
433
435
|
volume?: number;
|
|
436
|
+
/**
|
|
437
|
+
* Open interest: contracts outstanding at the end of this bar. Optional,
|
|
438
|
+
* because only a derivatives feed carries it; on a cash instrument it is
|
|
439
|
+
* absent, and absent is not zero. Zero is a real reading on a contract nobody
|
|
440
|
+
* holds.
|
|
441
|
+
*
|
|
442
|
+
* **It is a level, not a flow, and that is the whole reason it needs saying
|
|
443
|
+
* here.** Volume is a quantity traded *during* the bar, so folding five
|
|
444
|
+
* one-minute bars into a five-minute bar adds five volumes together. Open
|
|
445
|
+
* interest is a position *as at* the bar, so the same fold takes the last
|
|
446
|
+
* one and adding them would produce a number five times too large that still
|
|
447
|
+
* looks entirely plausible on a chart.
|
|
448
|
+
*
|
|
449
|
+
* Every aggregation path in this library therefore treats the two
|
|
450
|
+
* differently: `mergeBars`, the higher-timeframe fold in `securitySeries`,
|
|
451
|
+
* and the tick-to-bar builders all sum volume and carry the latest open
|
|
452
|
+
* interest. A transform that maps one source bar to one output bar passes it
|
|
453
|
+
* through; one that invents bars from price alone (Renko, Point and Figure)
|
|
454
|
+
* does not carry it at all, because a synthetic bar has no instant to be the
|
|
455
|
+
* position as at.
|
|
456
|
+
*/
|
|
457
|
+
oi?: number;
|
|
434
458
|
/**
|
|
435
459
|
* Per-bar colour override, honoured by every Family-A renderer: candles and
|
|
436
460
|
* OHLC bars take it on body, border and wick together, histogram and column
|
|
@@ -899,8 +923,10 @@ declare class SeriesMarkers implements IPrimitive {
|
|
|
899
923
|
* Which price axis a series maps to. 'right' (default) and 'left' each draw an
|
|
900
924
|
* axis and autoscale independently; '' is a hidden overlay scale (no axis, its
|
|
901
925
|
* own autoscale) used to pin a volume histogram inside the price pane.
|
|
926
|
+
* `overlay:name` creates an independent hidden scale, shared only by series
|
|
927
|
+
* using that same name on this pane.
|
|
902
928
|
*/
|
|
903
|
-
type PriceScaleId = 'right' | 'left' | ''
|
|
929
|
+
type PriceScaleId = 'right' | 'left' | '' | `overlay:${string}`;
|
|
904
930
|
/**
|
|
905
931
|
* Value formatting for a price scale (its axis labels and crosshair tag):
|
|
906
932
|
* `price` (tick-size precision), `volume` (compact 1.2K / 3.4M / 5.6B),
|
|
@@ -1338,7 +1364,7 @@ declare class Pane {
|
|
|
1338
1364
|
private _rightScale;
|
|
1339
1365
|
/** Extra scales created on demand: left axis and a hidden overlay (volume). */
|
|
1340
1366
|
private _leftScale;
|
|
1341
|
-
private
|
|
1367
|
+
private readonly _overlayScales;
|
|
1342
1368
|
/**
|
|
1343
1369
|
* Scales whose price-per-bar ratio is pinned, with the geometry the ratio was
|
|
1344
1370
|
* last held against. A lock stores that geometry rather than a number,
|
|
@@ -1548,1344 +1574,1504 @@ declare class Pane {
|
|
|
1548
1574
|
}
|
|
1549
1575
|
|
|
1550
1576
|
/**
|
|
1551
|
-
*
|
|
1552
|
-
*
|
|
1553
|
-
*
|
|
1554
|
-
*
|
|
1555
|
-
*
|
|
1556
|
-
*
|
|
1557
|
-
*
|
|
1577
|
+
* Horizontal price line primitive (ARCHITECTURE.md §8). The reusable base for
|
|
1578
|
+
* order/SL/TP/alert/indicator-level lines: a line across the plot plus a fixed
|
|
1579
|
+
* right-axis price tag and an optional broker-style segmented pill group on the
|
|
1580
|
+
* line — [badge][qty][label][✕] — with hover / dragging states (the chart
|
|
1581
|
+
* passes `hoverId`/`dragId` on the render context) and a drag ghost at the
|
|
1582
|
+
* pre-drag price via `setDragGhost`. Interaction semantics are unchanged from
|
|
1583
|
+
* the classic tag: the ✕ hit-tests as `${id}::close`, everything else drags.
|
|
1558
1584
|
*/
|
|
1559
1585
|
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
/**
|
|
1564
|
-
|
|
1565
|
-
/**
|
|
1566
|
-
|
|
1567
|
-
align?: 'left' | 'center' | 'right';
|
|
1568
|
-
/** Overrides the table's `fontSize` for this cell, for a heading row. */
|
|
1569
|
-
fontSize?: number;
|
|
1570
|
-
bold?: boolean;
|
|
1571
|
-
}
|
|
1572
|
-
interface ChartTableOptions {
|
|
1573
|
-
position: TablePosition;
|
|
1574
|
-
/** Gap from the pane edge, media px. */
|
|
1575
|
-
margin: number;
|
|
1576
|
-
/** Column width in media px. A per-column array sizes each one separately. */
|
|
1577
|
-
cellWidth: number | readonly number[];
|
|
1578
|
-
cellHeight: number;
|
|
1579
|
-
/**
|
|
1580
|
-
* Type size in media px, or `'auto'` to fit each cell: as large as its row
|
|
1581
|
-
* allows, shrunk until its text also fits its column. A stretched grid with
|
|
1582
|
-
* one long label would otherwise either clip that cell or be sized down as a
|
|
1583
|
-
* whole to suit it.
|
|
1584
|
-
*/
|
|
1585
|
-
fontSize: number | 'auto';
|
|
1586
|
-
/** Grid line colour. Omit to draw no grid. */
|
|
1587
|
-
borderColor?: string;
|
|
1588
|
-
borderWidth: number;
|
|
1586
|
+
interface PriceLineOptions {
|
|
1587
|
+
price: number;
|
|
1588
|
+
color: string;
|
|
1589
|
+
/** Line thickness in media px. Default 1. */
|
|
1590
|
+
lineWidth?: number;
|
|
1591
|
+
/** Legacy two-state dash switch, equivalent to `lineStyle: 'dashed'`. */
|
|
1592
|
+
dashed?: boolean;
|
|
1589
1593
|
/**
|
|
1590
|
-
*
|
|
1591
|
-
*
|
|
1592
|
-
*
|
|
1593
|
-
* only decides the total.
|
|
1594
|
+
* Dash style, the three-way form of `dashed`. Set, it wins over the boolean;
|
|
1595
|
+
* unset, the boolean still decides, so a line built before this existed draws
|
|
1596
|
+
* exactly as it did.
|
|
1594
1597
|
*/
|
|
1595
|
-
|
|
1596
|
-
/**
|
|
1597
|
-
|
|
1598
|
+
lineStyle?: CanvasLineStyle;
|
|
1599
|
+
/** Right-axis tag text. Defaults to the formatted price. */
|
|
1600
|
+
label?: string;
|
|
1601
|
+
/** Solid colored badge segment at the start of the pill group (e.g. 'BUY', 'TP', 'SL'). */
|
|
1602
|
+
badge?: string;
|
|
1603
|
+
/** Quantity segment rendered as a neutral box after the badge. */
|
|
1604
|
+
qty?: string | number;
|
|
1605
|
+
/** Info text segment (order type, price, P&L ...) — the classic left tag text. */
|
|
1606
|
+
leftLabel?: string;
|
|
1598
1607
|
/**
|
|
1599
|
-
*
|
|
1600
|
-
*
|
|
1601
|
-
*
|
|
1608
|
+
* Fraction of the plot width the line spans, measured from the right (price)
|
|
1609
|
+
* axis. 1 = full width (default); 0.3 = only the rightmost 30%, like a
|
|
1610
|
+
* partial-width order line. The right-axis tag is always drawn.
|
|
1602
1611
|
*/
|
|
1603
|
-
|
|
1604
|
-
/**
|
|
1605
|
-
|
|
1606
|
-
/**
|
|
1607
|
-
id
|
|
1612
|
+
extentFromRight?: number;
|
|
1613
|
+
/** Draw a cancel (✕) segment at the end of the pill group; hit-tests as `${id}::close`. */
|
|
1614
|
+
closeButton?: boolean;
|
|
1615
|
+
/** Stable id returned by hit-test (for click/drag routing). */
|
|
1616
|
+
id: string;
|
|
1617
|
+
/** Cursor hint when hovered (e.g. 'ns-resize' for draggable lines). */
|
|
1618
|
+
cursor?: string;
|
|
1608
1619
|
}
|
|
1609
|
-
declare
|
|
1610
|
-
/** Top-left corner of the grid for a position keyword, in media px. */
|
|
1611
|
-
declare function tableOrigin(position: TablePosition, margin: number, w: number, h: number, plotW: number, plotH: number): {
|
|
1612
|
-
x: number;
|
|
1613
|
-
y: number;
|
|
1614
|
-
};
|
|
1615
|
-
declare class ChartTable implements IPrimitive {
|
|
1616
|
-
private _rows;
|
|
1620
|
+
declare class PriceLine implements IPrimitive {
|
|
1617
1621
|
private _opts;
|
|
1618
1622
|
private _host;
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
|
|
1623
|
+
private _ghostPrice;
|
|
1624
|
+
/** Pill-group geometry from the last draw (media px) for hit-testing. */
|
|
1625
|
+
private _group;
|
|
1626
|
+
constructor(opts: PriceLineOptions);
|
|
1622
1627
|
attached(host: PrimitiveHost): void;
|
|
1623
1628
|
detached(): void;
|
|
1629
|
+
get price(): number;
|
|
1630
|
+
/** Move the line; schedules a repaint via the host. */
|
|
1631
|
+
setPrice(price: number): void;
|
|
1632
|
+
/** Update the info segment text (e.g. live position P&L); repaints. */
|
|
1633
|
+
setLeftLabel(text: string): void;
|
|
1634
|
+
/**
|
|
1635
|
+
* Restyle in place; repaints. `id` is the hit-test handle the chart routes
|
|
1636
|
+
* clicks and drags through, so it is not patchable — swapping it under a
|
|
1637
|
+
* live drag would strand the gesture.
|
|
1638
|
+
*
|
|
1639
|
+
* A last-price line is the case this exists for: it has to follow the tick
|
|
1640
|
+
* direction, and only `setPrice` was updatable, so the colour was stuck at
|
|
1641
|
+
* whatever it was constructed with.
|
|
1642
|
+
*/
|
|
1643
|
+
setOptions(patch: Partial<Omit<PriceLineOptions, 'id'>>): void;
|
|
1644
|
+
/**
|
|
1645
|
+
* Show a dimmed reference line at the pre-drag price while the user drags
|
|
1646
|
+
* (pass the original price on drag start, null on drag end to clear).
|
|
1647
|
+
*/
|
|
1648
|
+
setDragGhost(price: number | null): void;
|
|
1649
|
+
options(): Readonly<PriceLineOptions>;
|
|
1624
1650
|
zOrder(): ZOrder;
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
rows(): readonly (readonly TableCell[])[];
|
|
1651
|
+
autoscaleInfo(): {
|
|
1652
|
+
min: number;
|
|
1653
|
+
max: number;
|
|
1654
|
+
} | null;
|
|
1630
1655
|
draw(ctx: CanvasRenderingContext2D, rc: PrimitiveRenderContext): void;
|
|
1631
|
-
hitTest(x: number, y: number): PrimitiveHit | null;
|
|
1656
|
+
hitTest(x: number, y: number, rc: PrimitiveRenderContext): PrimitiveHit | null;
|
|
1632
1657
|
}
|
|
1633
1658
|
|
|
1634
1659
|
/**
|
|
1635
|
-
*
|
|
1636
|
-
*
|
|
1637
|
-
*
|
|
1660
|
+
* Pane legend (ARCHITECTURE.md §8) — the row at the top-left
|
|
1661
|
+
* of a pane: a color swatch, the source's name, its parameters, the value under
|
|
1662
|
+
* the crosshair, and inline action buttons on the right.
|
|
1638
1663
|
*
|
|
1639
|
-
*
|
|
1640
|
-
*
|
|
1641
|
-
*
|
|
1664
|
+
* Drawn on the canvas rather than in the DOM, like `BuySellButtons` and
|
|
1665
|
+
* `DomLadder`, so it composites into screenshots and costs no DOM per pane.
|
|
1666
|
+
* Buttons hit-test as `${id}::close`, `${id}::hide`, and `${id}::settings`, so
|
|
1667
|
+
* the host routes them through the same `subscribeClick` path as order pills.
|
|
1642
1668
|
*
|
|
1643
|
-
*
|
|
1644
|
-
*
|
|
1645
|
-
*
|
|
1669
|
+
* Rows stack: several legends on one pane offset each other vertically, which
|
|
1670
|
+
* the host does by giving each a `row` index.
|
|
1671
|
+
*
|
|
1672
|
+
* This row is also the chart's status line, so `statusLine` carries the
|
|
1673
|
+
* per-field switches a settings dialog expects (logo, title, market status,
|
|
1674
|
+
* chart values, bar change, volume, last day change, background). Every switch
|
|
1675
|
+
* defaults to the behaviour that predates it, so a caller that passes none sees
|
|
1676
|
+
* the row it always saw. Fields the primitive cannot compute (a logo bitmap,
|
|
1677
|
+
* whether the market is open, the change since yesterday's close) arrive
|
|
1678
|
+
* through `status`; with no source they draw nothing at all rather than a
|
|
1679
|
+
* placeholder.
|
|
1646
1680
|
*/
|
|
1647
1681
|
|
|
1648
|
-
|
|
1649
|
-
type IndicatorSource = 'open' | 'high' | 'low' | 'close' | 'hl2' | 'hlc3' | 'ohlc4' | 'volume';
|
|
1682
|
+
type PaneLegendAction = 'hide' | 'settings' | 'up' | 'down' | 'maximize' | 'close';
|
|
1650
1683
|
/**
|
|
1651
|
-
* One
|
|
1652
|
-
*
|
|
1653
|
-
*
|
|
1654
|
-
* `tooltip` is help text for the row. A label has to stay short enough to fit a
|
|
1655
|
-
* dense panel, which leaves nowhere to say what a parameter actually does, and a
|
|
1656
|
-
* ported study whose every input carried an explanation arrives here with that
|
|
1657
|
-
* explanation dropped. A settings UI renders it as a hover affordance beside the
|
|
1658
|
-
* label; the core ignores it.
|
|
1684
|
+
* One reading on a legend row. Multi-plot sources show one per plot, each in
|
|
1685
|
+
* that plot's own color (an MA ribbon's four averages, MACD's three lines) —
|
|
1686
|
+
* a single string in a single color cannot say which number is which.
|
|
1659
1687
|
*/
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
label: string;
|
|
1674
|
-
default: boolean;
|
|
1675
|
-
group?: string;
|
|
1676
|
-
tooltip?: string;
|
|
1677
|
-
} | {
|
|
1678
|
-
key: string;
|
|
1679
|
-
type: 'color';
|
|
1680
|
-
label: string;
|
|
1681
|
-
default: string;
|
|
1682
|
-
group?: string;
|
|
1683
|
-
tooltip?: string;
|
|
1684
|
-
} | {
|
|
1685
|
-
key: string;
|
|
1686
|
-
type: 'text';
|
|
1687
|
-
label: string;
|
|
1688
|
-
default: string;
|
|
1689
|
-
group?: string;
|
|
1690
|
-
tooltip?: string;
|
|
1691
|
-
} | {
|
|
1692
|
-
key: string;
|
|
1693
|
-
type: 'select';
|
|
1694
|
-
label: string;
|
|
1695
|
-
default: string;
|
|
1696
|
-
options: readonly {
|
|
1697
|
-
label: string;
|
|
1698
|
-
value: string;
|
|
1699
|
-
}[];
|
|
1700
|
-
group?: string;
|
|
1701
|
-
tooltip?: string;
|
|
1702
|
-
} | {
|
|
1703
|
-
key: string;
|
|
1704
|
-
type: 'source';
|
|
1705
|
-
label: string;
|
|
1706
|
-
default: IndicatorSource;
|
|
1707
|
-
group?: string;
|
|
1708
|
-
tooltip?: string;
|
|
1688
|
+
interface LegendValue {
|
|
1689
|
+
/** Dimmed prefix, e.g. `O` / `H` / `Vol`. */
|
|
1690
|
+
label?: string;
|
|
1691
|
+
text: string;
|
|
1692
|
+
/** Defaults to the row's `valueColor`, then `color`, then the theme text. */
|
|
1693
|
+
color?: string;
|
|
1694
|
+
/**
|
|
1695
|
+
* Which status-line switch owns this reading. Untagged readings are the
|
|
1696
|
+
* source's own last value, governed by `statusLine.lastValueLabel`.
|
|
1697
|
+
*/
|
|
1698
|
+
field?: LegendField;
|
|
1699
|
+
/** Higher values retain this whole reading on narrow rows. Series readings default to 1; status metadata ranks lower. */
|
|
1700
|
+
priority?: number;
|
|
1709
1701
|
}
|
|
1710
1702
|
/**
|
|
1711
|
-
*
|
|
1712
|
-
*
|
|
1713
|
-
*
|
|
1714
|
-
* a free text box would accept `'5min'` and leave the study computing on a
|
|
1715
|
-
* code it cannot resolve. An empty default means "the chart's own interval".
|
|
1703
|
+
* Status-line groups a host can feed and switch off independently. The legend
|
|
1704
|
+
* never derives these: it tags what the host hands it, so one switch hides one
|
|
1705
|
+
* group and leaves the rest of the row alone.
|
|
1716
1706
|
*/
|
|
1717
|
-
|
|
|
1718
|
-
key: string;
|
|
1719
|
-
type: 'interval';
|
|
1720
|
-
label: string;
|
|
1721
|
-
default: string;
|
|
1722
|
-
group?: string;
|
|
1723
|
-
tooltip?: string;
|
|
1724
|
-
}
|
|
1707
|
+
type LegendField = 'ohlc' | 'change' | 'volume' | 'openInterest';
|
|
1725
1708
|
/**
|
|
1726
|
-
*
|
|
1727
|
-
*
|
|
1728
|
-
* anchored VWAP, an event to measure from. It is carried as that string, not
|
|
1729
|
-
* as UTC seconds, so a layout saved in one zone restores to the same wall
|
|
1730
|
-
* clock in another, and `zonedStringToUtcSeconds` turns it into a bar time.
|
|
1709
|
+
* Which name the title shows. `description` and `ticker` come from `status`;
|
|
1710
|
+
* with neither supplied the title falls back to `title`, which always exists.
|
|
1731
1711
|
*/
|
|
1732
|
-
|
|
|
1733
|
-
key: string;
|
|
1734
|
-
type: 'time';
|
|
1735
|
-
label: string;
|
|
1736
|
-
default: string;
|
|
1737
|
-
group?: string;
|
|
1738
|
-
tooltip?: string;
|
|
1739
|
-
};
|
|
1740
|
-
/** Dash pattern for a level, a drawing, or a plot. */
|
|
1741
|
-
type IndicatorLineStyle = 'solid' | 'dashed' | 'dotted';
|
|
1742
|
-
/** Line-style options, for a settings UI's Style tab. */
|
|
1743
|
-
declare const INDICATOR_LINE_STYLES: readonly {
|
|
1744
|
-
label: string;
|
|
1745
|
-
value: string;
|
|
1746
|
-
}[];
|
|
1747
|
-
/** Settings keys the runtime derives for a plot's appearance. */
|
|
1748
|
-
declare function plotStyleKeys(plot: IndicatorPlot): {
|
|
1749
|
-
color: string;
|
|
1750
|
-
width: string;
|
|
1751
|
-
lineStyle: string;
|
|
1752
|
-
opacity: string;
|
|
1753
|
-
type: string;
|
|
1754
|
-
};
|
|
1712
|
+
type LegendTitleMode = 'symbol' | 'description' | 'ticker';
|
|
1755
1713
|
/**
|
|
1756
|
-
*
|
|
1757
|
-
*
|
|
1758
|
-
* and line style for free, and a settings UI can render them as a "Style" tab
|
|
1759
|
-
* beside the descriptor's own `inputs`.
|
|
1760
|
-
*
|
|
1761
|
-
* Defaults come from the plot's declared style (and its legacy `colorKey`), so
|
|
1762
|
-
* an indicator that already ships colours keeps them.
|
|
1714
|
+
* The parts of the status line the primitive has no way to know. The host
|
|
1715
|
+
* supplies what it has; anything missing is simply not drawn.
|
|
1763
1716
|
*/
|
|
1764
|
-
|
|
1717
|
+
interface LegendStatusData {
|
|
1718
|
+
/** Already-decoded logo (an `<img>`, an `ImageBitmap`, a canvas). */
|
|
1719
|
+
logo?: CanvasImageSource;
|
|
1720
|
+
/** Long name for `titleMode: 'description'`, e.g. `Apple Inc.`. */
|
|
1721
|
+
description?: string;
|
|
1722
|
+
/** Exchange ticker for `titleMode: 'ticker'`, e.g. `NASDAQ:AAPL`. */
|
|
1723
|
+
ticker?: string;
|
|
1724
|
+
/** Session state, e.g. `{ text: 'Market open', color: '#26a69a' }`. */
|
|
1725
|
+
marketStatus?: LegendValue;
|
|
1726
|
+
/** Change against the previous close, e.g. `{ text: '+1.20 (+0.75%)' }`. */
|
|
1727
|
+
lastDayChange?: LegendValue;
|
|
1728
|
+
}
|
|
1765
1729
|
/**
|
|
1766
|
-
*
|
|
1767
|
-
*
|
|
1768
|
-
*
|
|
1769
|
-
* which. Restricted to the types that make sense for a single value column.
|
|
1730
|
+
* A snapshot, or a getter the legend calls each frame, so live fields (market
|
|
1731
|
+
* status, day change) can change without the host patching options at tick
|
|
1732
|
+
* speed. Returning `null` means "nothing to show".
|
|
1770
1733
|
*/
|
|
1771
|
-
|
|
1772
|
-
label: string;
|
|
1773
|
-
value: string;
|
|
1774
|
-
}[];
|
|
1775
|
-
/** Canonical option list for a `type: 'source'` input, for settings UIs. */
|
|
1776
|
-
declare const INDICATOR_SOURCES: readonly {
|
|
1777
|
-
label: string;
|
|
1778
|
-
value: IndicatorSource;
|
|
1779
|
-
}[];
|
|
1780
|
-
type IndicatorSettings = Record<string, unknown>;
|
|
1781
|
-
/** One plotted line/band/histogram. `type` is any registered chart type. */
|
|
1782
|
-
/** A shaded band between two of an indicator's plots. */
|
|
1783
|
-
interface IndicatorFillSpec {
|
|
1784
|
-
/** The two plot keys to fill between. */
|
|
1785
|
-
between: readonly [string, string];
|
|
1786
|
-
/** Colour where the first plot is above the second. */
|
|
1787
|
-
colorUp?: string;
|
|
1788
|
-
/** Colour where the second is above the first. */
|
|
1789
|
-
colorDown?: string;
|
|
1790
|
-
/** Settings keys holding those colours, so the band is restyleable. */
|
|
1791
|
-
colorUpKey?: string;
|
|
1792
|
-
colorDownKey?: string;
|
|
1793
|
-
/** 0..1. Defaults to 0.12. */
|
|
1794
|
-
opacity?: number;
|
|
1795
|
-
/**
|
|
1796
|
-
* Draw the band on the price pane even though the indicator owns a pane of
|
|
1797
|
-
* its own. The pair with `IndicatorPlot.overlay`: a study can already send
|
|
1798
|
-
* one plot to the candles, and a band between two such plots belongs beside
|
|
1799
|
-
* them rather than in the study pane the fill would otherwise land in.
|
|
1800
|
-
* Ignored for an `'onchart'` descriptor, which is on the price pane already.
|
|
1801
|
-
*/
|
|
1802
|
-
overlay?: boolean;
|
|
1803
|
-
}
|
|
1734
|
+
type LegendStatusSource = LegendStatusData | (() => LegendStatusData | null);
|
|
1804
1735
|
/**
|
|
1805
|
-
*
|
|
1806
|
-
*
|
|
1807
|
-
*
|
|
1808
|
-
* part left undefined falls back to `colorBy`, then to the plot's own colour.
|
|
1736
|
+
* Per-field switches for the status line. Existing reading fields default to
|
|
1737
|
+
* on; open interest and the background plate default to off. A missing reading
|
|
1738
|
+
* draws nothing whether its switch is on or off.
|
|
1809
1739
|
*/
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
|
|
1823
|
-
|
|
1824
|
-
|
|
1825
|
-
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
-
|
|
1829
|
-
* anything else.
|
|
1830
|
-
*
|
|
1831
|
-
* Like `style.precision`, this is a property of the **price scale**, not of the
|
|
1832
|
-
* series, so it belongs to a plot that owns its pane. Setting it on an
|
|
1833
|
-
* `'onchart'` plot reformats the instrument's own axis, which is almost never
|
|
1834
|
-
* what a study wants.
|
|
1835
|
-
*
|
|
1836
|
-
* `percent` suffixes the value as it stands and does not scale it, so a study
|
|
1837
|
-
* returning a 0..1 fraction should keep returning it and read `0.62%`. Scaling
|
|
1838
|
-
* inside `calc` to make the axis read better changes the plotted value, and the
|
|
1839
|
-
* legend, the crosshair and every downstream calculation with it.
|
|
1840
|
-
*/
|
|
1841
|
-
priceFormat?: PriceFormat;
|
|
1842
|
-
/**
|
|
1843
|
-
* Draw this one plot on the price pane even though the indicator owns a pane
|
|
1844
|
-
* of its own. An oscillator that also wants a signal
|
|
1845
|
-
* band or a stop line sitting on the candles is the case: the study belongs in
|
|
1846
|
-
* its own pane, one of its columns belongs on price, and splitting it into two
|
|
1847
|
-
* indicators would make the user configure the same inputs twice.
|
|
1848
|
-
*
|
|
1849
|
-
* Ignored for an `'onchart'` descriptor, which is already on the price pane.
|
|
1850
|
-
*/
|
|
1851
|
-
overlay?: boolean;
|
|
1740
|
+
interface LegendStatusLineOptions {
|
|
1741
|
+
/** Symbol logo, when `status` supplies one. */
|
|
1742
|
+
logo?: boolean;
|
|
1743
|
+
/** The bold name. Also the "name label" switch for an indicator row. */
|
|
1744
|
+
title?: boolean;
|
|
1745
|
+
/** Which name the title shows. Default `symbol`. */
|
|
1746
|
+
titleMode?: LegendTitleMode;
|
|
1747
|
+
/** Session state from `status.marketStatus`. */
|
|
1748
|
+
marketStatus?: boolean;
|
|
1749
|
+
/** The OHLC readout: readings tagged `field: 'ohlc'`. */
|
|
1750
|
+
chartValues?: boolean;
|
|
1751
|
+
/** Change over the hovered bar: readings tagged `field: 'change'`. */
|
|
1752
|
+
barChange?: boolean;
|
|
1753
|
+
/** Readings tagged `field: 'volume'`. */
|
|
1754
|
+
volume?: boolean;
|
|
1755
|
+
/** Readings tagged `field: 'openInterest'`. Off by default. */
|
|
1756
|
+
openInterest?: boolean;
|
|
1757
|
+
/** Change since the previous close, from `status.lastDayChange`. */
|
|
1758
|
+
lastDayChange?: boolean;
|
|
1852
1759
|
/**
|
|
1853
|
-
*
|
|
1854
|
-
*
|
|
1855
|
-
*
|
|
1856
|
-
* displaced cloud or a projected channel wants: the last `offset` values land
|
|
1857
|
-
* in the right margin, past the newest candle, where no bar exists to hold
|
|
1858
|
-
* them. It shifts the drawn series only. A fill between two plots with the
|
|
1859
|
-
* same offset follows; the legend reads the value drawn under the cursor.
|
|
1760
|
+
* The source's own reading (untagged values). This is the scales-and-lines
|
|
1761
|
+
* "last value label" control, which lands here because the legend is what
|
|
1762
|
+
* draws that number on this row.
|
|
1860
1763
|
*/
|
|
1861
|
-
|
|
1764
|
+
lastValueLabel?: boolean;
|
|
1862
1765
|
/**
|
|
1863
|
-
*
|
|
1864
|
-
*
|
|
1766
|
+
* Plate behind the row's text, for legibility over candles. Off by default:
|
|
1767
|
+
* the row has never had one, and turning it on is a deliberate choice.
|
|
1865
1768
|
*/
|
|
1866
|
-
|
|
1769
|
+
background?: boolean;
|
|
1770
|
+
/** Plate opacity, 0..1. Default 0.8, matching the hover plate. */
|
|
1771
|
+
backgroundOpacity?: number;
|
|
1772
|
+
/** Plate color. Defaults to the theme background. */
|
|
1773
|
+
backgroundColor?: string;
|
|
1774
|
+
}
|
|
1775
|
+
interface PaneLegendOptions {
|
|
1776
|
+
/** Explicit false suppresses OI without discarding its saved switch. Set by an owning chart. */
|
|
1777
|
+
hasOpenInterest?: boolean;
|
|
1778
|
+
/** Stable id; buttons hit-test as `${id}::close` etc. */
|
|
1779
|
+
id: string;
|
|
1780
|
+
/** Bold source name, e.g. `RSI`. */
|
|
1781
|
+
title: string;
|
|
1782
|
+
/** Dimmed parameter summary after the title, e.g. `14 close`. */
|
|
1783
|
+
params?: string;
|
|
1784
|
+
/** Swatch color; omitted draws no swatch. */
|
|
1785
|
+
color?: string;
|
|
1867
1786
|
/**
|
|
1868
|
-
*
|
|
1869
|
-
*
|
|
1870
|
-
*
|
|
1871
|
-
* A single column cannot express those at all, and the alternative (a second
|
|
1872
|
-
* result shape for `calc`) would fork the contract every descriptor and every
|
|
1873
|
-
* helper is written against. Naming four columns inside the *same*
|
|
1874
|
-
* `IndicatorValues` keeps one shape: a smoothed Heikin-Ashi overlay, a
|
|
1875
|
-
* higher-timeframe candle, a synthetic spread instrument each return four
|
|
1876
|
-
* ordinary columns and point at them from here.
|
|
1877
|
-
*
|
|
1878
|
-
* The named columns must all exist and be bar-aligned, or `addIndicator`
|
|
1879
|
-
* throws. `key` stays the series identity and the legend reading falls back to
|
|
1880
|
-
* the `close` column.
|
|
1787
|
+
* Color for the live value. Defaults to `color`, then the theme's text — so a
|
|
1788
|
+
* row can tint its reading (an up/down change) without being forced to show a
|
|
1789
|
+
* swatch in that same color.
|
|
1881
1790
|
*/
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
low: string;
|
|
1886
|
-
close: string;
|
|
1887
|
-
};
|
|
1791
|
+
valueColor?: string;
|
|
1792
|
+
/** Vertical slot on the pane (0 = topmost). */
|
|
1793
|
+
row?: number;
|
|
1888
1794
|
/**
|
|
1889
|
-
*
|
|
1890
|
-
*
|
|
1891
|
-
*
|
|
1795
|
+
* Which inline action buttons to draw, left to right. Each hit-tests as
|
|
1796
|
+
* `${id}::<action>`:
|
|
1797
|
+
* - `up` / `down` — move this pane one slot (`::up` / `::down`)
|
|
1798
|
+
* - `hide` — toggle visibility (`::hide`)
|
|
1799
|
+
* - `maximize` — expand this pane to fill the chart (`::maximize`)
|
|
1800
|
+
* - `close` — remove the source, and its pane if it empties (`::close`)
|
|
1892
1801
|
*
|
|
1893
|
-
*
|
|
1894
|
-
*
|
|
1895
|
-
|
|
1896
|
-
colorBy?(ctx: {
|
|
1897
|
-
value: number;
|
|
1898
|
-
index: number;
|
|
1899
|
-
values: IndicatorValues;
|
|
1900
|
-
settings: IndicatorSettings;
|
|
1901
|
-
}): string | undefined;
|
|
1902
|
-
/**
|
|
1903
|
-
* Per-bar colour split three ways, for a candle plot whose wick or border
|
|
1904
|
-
* should not follow its body: a solid wick over a translucent body, a
|
|
1905
|
-
* border in the trend colour. Takes precedence over `colorBy` for the parts
|
|
1906
|
-
* it names; a part it leaves undefined falls back to `colorBy`, then to the
|
|
1907
|
-
* plot's own colour. A value plot (line, histogram, column) reads `body` only.
|
|
1802
|
+
* When only some actions fit, the end of this list stays visible.
|
|
1803
|
+
* Defaults to `['up', 'down', 'hide', 'maximize', 'close']` for pane sources
|
|
1804
|
+
* and `['hide', 'close']` for overlays (pass explicitly to override).
|
|
1908
1805
|
*/
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
|
|
1916
|
-
/**
|
|
1917
|
-
|
|
1918
|
-
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
lineStyle?: IndicatorLineStyle;
|
|
1806
|
+
actions?: readonly PaneLegendAction[];
|
|
1807
|
+
/** Rendered as hidden (dimmed, eye hollow). */
|
|
1808
|
+
hidden?: boolean;
|
|
1809
|
+
/** Rendered as maximized (the maximize glyph becomes restore). */
|
|
1810
|
+
maximized?: boolean;
|
|
1811
|
+
/** Text size in media px. Default 11. */
|
|
1812
|
+
font?: number;
|
|
1813
|
+
/** Left inset from the plot edge in media px. Default 8. */
|
|
1814
|
+
left?: number;
|
|
1815
|
+
/** Top inset in media px. Default 6. */
|
|
1816
|
+
top?: number;
|
|
1817
|
+
/** Per-field status-line switches. Patching merges field by field. */
|
|
1818
|
+
statusLine?: LegendStatusLineOptions;
|
|
1819
|
+
/** Host-supplied status-line data (logo, names, market state, day change). */
|
|
1820
|
+
status?: LegendStatusSource;
|
|
1925
1821
|
}
|
|
1926
|
-
|
|
1927
|
-
|
|
1928
|
-
|
|
1929
|
-
|
|
1822
|
+
declare class PaneLegend implements IPrimitive {
|
|
1823
|
+
private _opts;
|
|
1824
|
+
private _host;
|
|
1825
|
+
private _values;
|
|
1826
|
+
/** Button geometry from the last draw, in media px, for hit-testing. */
|
|
1827
|
+
private _buttons;
|
|
1828
|
+
/** Right edge of the drawn row, in media px. */
|
|
1829
|
+
private _width;
|
|
1830
|
+
private _plotWidth;
|
|
1831
|
+
private _plotHeight;
|
|
1832
|
+
constructor(opts: PaneLegendOptions);
|
|
1833
|
+
attached(host: PrimitiveHost): void;
|
|
1834
|
+
detached(): void;
|
|
1835
|
+
zOrder(): ZOrder;
|
|
1836
|
+
autoscaleInfo(): null;
|
|
1837
|
+
/** A single live reading after the params (typically crosshair-driven). */
|
|
1838
|
+
setValue(text: string, color?: string): void;
|
|
1839
|
+
/** One reading per plot, each in its own color. */
|
|
1840
|
+
setValues(values: readonly LegendValue[]): void;
|
|
1841
|
+
setOptions(patch: Partial<PaneLegendOptions>): void;
|
|
1842
|
+
/** Resolve the host's status data for this frame; `{}` when it has none. */
|
|
1843
|
+
private _status;
|
|
1844
|
+
options(): PaneLegendOptions;
|
|
1845
|
+
draw(ctx: CanvasRenderingContext2D, rc: PrimitiveRenderContext): void;
|
|
1846
|
+
hitTest(x: number, y: number): PrimitiveHit | null;
|
|
1930
1847
|
}
|
|
1848
|
+
|
|
1931
1849
|
/**
|
|
1932
|
-
* A
|
|
1933
|
-
* and price rather than to a bar index.
|
|
1850
|
+
* A grid overlay pinned to a corner of the pane rather than to bars.
|
|
1934
1851
|
*
|
|
1935
|
-
*
|
|
1936
|
-
*
|
|
1937
|
-
*
|
|
1938
|
-
*
|
|
1939
|
-
*
|
|
1852
|
+
* Seasonality heatmaps, performance summaries and signal scoreboards are all
|
|
1853
|
+
* the same shape: a small table of coloured cells that stays put while the
|
|
1854
|
+
* chart pans underneath. That makes this a screen-space primitive like the
|
|
1855
|
+
* watermark and the pane legend, not a series: it has no time anchor, takes no
|
|
1856
|
+
* part in autoscale, and survives a zoom untouched.
|
|
1940
1857
|
*/
|
|
1941
|
-
|
|
1942
|
-
|
|
1943
|
-
|
|
1944
|
-
to: DrawAnchor;
|
|
1945
|
-
color?: string;
|
|
1946
|
-
lineWidth?: number;
|
|
1947
|
-
lineStyle?: IndicatorLineStyle;
|
|
1948
|
-
/** Continue the line past its anchor to the pane edge. */
|
|
1949
|
-
extendLeft?: boolean;
|
|
1950
|
-
extendRight?: boolean;
|
|
1951
|
-
} | {
|
|
1952
|
-
kind: 'box';
|
|
1953
|
-
from: DrawAnchor;
|
|
1954
|
-
to: DrawAnchor;
|
|
1955
|
-
/** Border colour. Omit `fillColor` to draw an outline only. */
|
|
1956
|
-
color?: string;
|
|
1957
|
-
fillColor?: string;
|
|
1958
|
-
/** Fill alpha, 0..1. Defaults to 0.12. */
|
|
1959
|
-
opacity?: number;
|
|
1960
|
-
lineWidth?: number;
|
|
1961
|
-
/** Caption drawn on a plate at the centre of the box; `\n` splits lines. */
|
|
1962
|
-
text?: string;
|
|
1963
|
-
textColor?: string;
|
|
1964
|
-
/**
|
|
1965
|
-
* Detail shown on a plate while the pointer rests on the box, and gone
|
|
1966
|
-
* when it leaves; `\n` splits lines. A zone that carries its size, its
|
|
1967
|
-
* age and what formed it cannot print all of that on the box without
|
|
1968
|
-
* hiding the candles under it, so the caption names it and this explains
|
|
1969
|
-
* it. The box becomes hit-testable, and `id` (or the tooltip text) is
|
|
1970
|
-
* what `subscribeClick` reports for it.
|
|
1971
|
-
*/
|
|
1972
|
-
tooltip?: string;
|
|
1973
|
-
/** Hit id, for `subscribeClick`. Defaults to the tooltip text. */
|
|
1974
|
-
id?: string;
|
|
1975
|
-
} | {
|
|
1976
|
-
kind: 'label';
|
|
1977
|
-
at: DrawAnchor;
|
|
1978
|
-
/** `\n` splits lines. */
|
|
1858
|
+
|
|
1859
|
+
type TablePosition = 'top-left' | 'top-center' | 'top-right' | 'middle-left' | 'middle-center' | 'middle-right' | 'bottom-left' | 'bottom-center' | 'bottom-right';
|
|
1860
|
+
interface TableCell {
|
|
1979
1861
|
text: string;
|
|
1980
|
-
/**
|
|
1981
|
-
|
|
1862
|
+
/** Cell fill. Transparent when omitted, so the pane shows through. */
|
|
1863
|
+
bgColor?: string;
|
|
1864
|
+
/** Text colour. Derived from `bgColor` for contrast when omitted. */
|
|
1982
1865
|
textColor?: string;
|
|
1983
|
-
/** Which edge of the plate sits on the anchor. Defaults to 'center'. */
|
|
1984
1866
|
align?: 'left' | 'center' | 'right';
|
|
1985
|
-
/**
|
|
1986
|
-
|
|
1987
|
-
|
|
1988
|
-
|
|
1989
|
-
|
|
1990
|
-
|
|
1991
|
-
|
|
1992
|
-
|
|
1993
|
-
|
|
1994
|
-
|
|
1995
|
-
|
|
1996
|
-
fillColor?: string;
|
|
1997
|
-
/** Fill alpha, 0..1. Defaults to 0.12. */
|
|
1998
|
-
opacity?: number;
|
|
1999
|
-
};
|
|
2000
|
-
/** `calc` output: one array per plot key, aligned 1:1 with the input bars. */
|
|
2001
|
-
type IndicatorValues = Record<string, readonly (number | null)[]>;
|
|
2002
|
-
/** Per-instance scratch owned by the descriptor (Tier-2 data lands here). */
|
|
2003
|
-
type IndicatorStore = Record<string, unknown>;
|
|
2004
|
-
/**
|
|
2005
|
-
* The fourth, optional argument to `calc` (and the sixth to `calcTail`): what
|
|
2006
|
-
* the calculation cannot read off the bars themselves.
|
|
2007
|
-
*
|
|
2008
|
-
* It is optional so that every descriptor written against `calc(bars, settings,
|
|
2009
|
-
* store)` keeps its exact signature and its exact behaviour, which is the whole
|
|
2010
|
-
* point: a calculation that ignores the context computes what it always did.
|
|
2011
|
-
*/
|
|
2012
|
-
interface IndicatorCalcContext {
|
|
1867
|
+
/** Overrides the table's `fontSize` for this cell, for a heading row. */
|
|
1868
|
+
fontSize?: number;
|
|
1869
|
+
bold?: boolean;
|
|
1870
|
+
}
|
|
1871
|
+
interface ChartTableOptions {
|
|
1872
|
+
position: TablePosition;
|
|
1873
|
+
/** Gap from the pane edge, media px. */
|
|
1874
|
+
margin: number;
|
|
1875
|
+
/** Column width in media px. A per-column array sizes each one separately. */
|
|
1876
|
+
cellWidth: number | readonly number[];
|
|
1877
|
+
cellHeight: number;
|
|
2013
1878
|
/**
|
|
2014
|
-
*
|
|
2015
|
-
*
|
|
1879
|
+
* Type size in media px, or `'auto'` to fit each cell: as large as its row
|
|
1880
|
+
* allows, shrunk until its text also fits its column. A stretched grid with
|
|
1881
|
+
* one long label would otherwise either clip that cell or be sized down as a
|
|
1882
|
+
* whole to suit it.
|
|
2016
1883
|
*/
|
|
2017
|
-
|
|
2018
|
-
|
|
2019
|
-
|
|
2020
|
-
|
|
2021
|
-
isConfirmed: boolean;
|
|
2022
|
-
/** A live feed is driving updates, rather than a one-off history load. */
|
|
2023
|
-
isRealtime: boolean;
|
|
2024
|
-
/** Index of the last bar, `bars.length - 1` (-1 when there are none). */
|
|
2025
|
-
lastIndex: number;
|
|
2026
|
-
};
|
|
2027
|
-
/** The instrument, when the host knows one. See `IndicatorAttachContext`. */
|
|
2028
|
-
symbol?: string;
|
|
2029
|
-
/** The timeframe (`'5m'`, `'1d'`), on the same terms as `symbol`. */
|
|
2030
|
-
interval?: string;
|
|
2031
|
-
/** The chart's IANA zone, the calendar its axis is labelled in. */
|
|
2032
|
-
timezone: string;
|
|
2033
|
-
/** Chart wall clock in UTC seconds, the clock the countdown row reads. */
|
|
2034
|
-
now(): number;
|
|
1884
|
+
fontSize: number | 'auto';
|
|
1885
|
+
/** Grid line colour. Omit to draw no grid. */
|
|
1886
|
+
borderColor?: string;
|
|
1887
|
+
borderWidth: number;
|
|
2035
1888
|
/**
|
|
2036
|
-
*
|
|
2037
|
-
*
|
|
2038
|
-
*
|
|
2039
|
-
*
|
|
2040
|
-
* quoted in the instrument's tick: an RSI is a dimensionless 0..100 band, so
|
|
2041
|
-
* its scale carries no tick at all to read.
|
|
2042
|
-
*
|
|
2043
|
-
* `undefined` when the host has not told the chart what it is, which is the
|
|
2044
|
-
* honest answer rather than a guessed 0.01: an indicator sizing a range in
|
|
2045
|
-
* ticks has to tell "one paisa" apart from "nobody said".
|
|
1889
|
+
* Table width as a percentage of the plot, 0 or omitted to size from
|
|
1890
|
+
* `cellWidth` instead. Column proportions are preserved, so a per-column
|
|
1891
|
+
* `cellWidth` array still controls the relative widths, and the percentage
|
|
1892
|
+
* only decides the total.
|
|
2046
1893
|
*/
|
|
2047
|
-
|
|
2048
|
-
|
|
2049
|
-
|
|
2050
|
-
interface IndicatorAlertContext {
|
|
2051
|
-
bars: readonly Bar[];
|
|
2052
|
-
values: IndicatorValues;
|
|
2053
|
-
settings: Readonly<IndicatorSettings>;
|
|
2054
|
-
/** The bar being evaluated. */
|
|
2055
|
-
index: number;
|
|
2056
|
-
}
|
|
2057
|
-
/**
|
|
2058
|
-
* A condition the runtime watches, declared by the descriptor rather than wired
|
|
2059
|
-
* up by the host: the indicator is the only thing that knows what a crossover of
|
|
2060
|
-
* its own columns means.
|
|
2061
|
-
*
|
|
2062
|
-
* Evaluated once per bar, for bars that are new since the last evaluation, so
|
|
2063
|
-
* adding the indicator to a loaded chart fires nothing for history.
|
|
2064
|
-
*/
|
|
2065
|
-
interface IndicatorAlertSpec {
|
|
2066
|
-
/** Stable within the descriptor, e.g. `'cross-up'`. */
|
|
2067
|
-
id: string;
|
|
2068
|
-
/** Short human label, e.g. `'MACD crossed up'`. */
|
|
2069
|
-
title: string;
|
|
1894
|
+
widthPercent?: number;
|
|
1895
|
+
/** Table height as a percentage of the plot, 0 or omitted to size from `cellHeight`. */
|
|
1896
|
+
heightPercent?: number;
|
|
2070
1897
|
/**
|
|
2071
|
-
*
|
|
2072
|
-
*
|
|
2073
|
-
*
|
|
2074
|
-
* webhook. It runs only for a bar `when` accepted.
|
|
1898
|
+
* Relative row heights, one per row, defaulting to 1. A separator row is the
|
|
1899
|
+
* reason this exists: stretched to fill a pane, an equal split makes a rule
|
|
1900
|
+
* between two sections as tall as the sections themselves.
|
|
2075
1901
|
*/
|
|
2076
|
-
|
|
2077
|
-
|
|
1902
|
+
rowWeights?: readonly number[];
|
|
1903
|
+
/** Backdrop behind the whole grid, drawn before the cells. */
|
|
1904
|
+
background?: string;
|
|
1905
|
+
/** Hit-test id, so a host can route clicks the way it does for other primitives. */
|
|
1906
|
+
id?: string;
|
|
1907
|
+
}
|
|
1908
|
+
declare const DEFAULT_CHART_TABLE_OPTIONS: ChartTableOptions;
|
|
1909
|
+
/** Top-left corner of the grid for a position keyword, in media px. */
|
|
1910
|
+
declare function tableOrigin(position: TablePosition, margin: number, w: number, h: number, plotW: number, plotH: number): {
|
|
1911
|
+
x: number;
|
|
1912
|
+
y: number;
|
|
1913
|
+
};
|
|
1914
|
+
declare class ChartTable implements IPrimitive {
|
|
1915
|
+
private _rows;
|
|
1916
|
+
private _opts;
|
|
1917
|
+
private _host;
|
|
1918
|
+
/** Last drawn rect in media px, for hit-testing without recomputing layout. */
|
|
1919
|
+
private _rect;
|
|
1920
|
+
constructor(options?: Partial<ChartTableOptions>);
|
|
1921
|
+
attached(host: PrimitiveHost): void;
|
|
1922
|
+
detached(): void;
|
|
1923
|
+
zOrder(): ZOrder;
|
|
1924
|
+
options(): Readonly<ChartTableOptions>;
|
|
1925
|
+
setOptions(patch: Partial<ChartTableOptions>): void;
|
|
1926
|
+
/** Replace the grid. Rows may be ragged; each is drawn to its own length. */
|
|
1927
|
+
setRows(rows: readonly (readonly TableCell[])[]): void;
|
|
1928
|
+
rows(): readonly (readonly TableCell[])[];
|
|
1929
|
+
draw(ctx: CanvasRenderingContext2D, rc: PrimitiveRenderContext): void;
|
|
1930
|
+
hitTest(x: number, y: number): PrimitiveHit | null;
|
|
2078
1931
|
}
|
|
1932
|
+
|
|
2079
1933
|
/**
|
|
2080
|
-
*
|
|
2081
|
-
*
|
|
2082
|
-
* fast length above the slow one, a benchmark the provider cannot serve.
|
|
1934
|
+
* Vertical gradient across the band, graded between two prices rather than
|
|
1935
|
+
* two pixel rows.
|
|
2083
1936
|
*
|
|
2084
|
-
*
|
|
2085
|
-
*
|
|
2086
|
-
*
|
|
2087
|
-
*
|
|
2088
|
-
* tell a bad input, which the user can fix, from a bug, which they cannot.
|
|
1937
|
+
* The stops are anchored in PRICE, not in pixels, because that is what the
|
|
1938
|
+
* shading is claiming: a band graded from its 70 level down to its 30 means
|
|
1939
|
+
* those levels, and a viewport-relative gradient would slide off them the
|
|
1940
|
+
* moment the pane is panned or the scale re-fits.
|
|
2089
1941
|
*/
|
|
2090
|
-
|
|
2091
|
-
|
|
1942
|
+
interface FillGradient {
|
|
1943
|
+
/** Price the top stop sits at. Omitted: the band's own highest value. */
|
|
1944
|
+
topValue?: number;
|
|
1945
|
+
/** Price the bottom stop sits at. Omitted: the band's own lowest value. */
|
|
1946
|
+
bottomValue?: number;
|
|
1947
|
+
topColor: string;
|
|
1948
|
+
bottomColor: string;
|
|
2092
1949
|
}
|
|
2093
|
-
|
|
2094
|
-
|
|
2095
|
-
|
|
2096
|
-
|
|
2097
|
-
|
|
2098
|
-
|
|
2099
|
-
|
|
2100
|
-
|
|
2101
|
-
|
|
2102
|
-
|
|
2103
|
-
|
|
2104
|
-
|
|
2105
|
-
|
|
2106
|
-
interval: string;
|
|
2107
|
-
from: number;
|
|
2108
|
-
to: number;
|
|
2109
|
-
signal?: AbortSignal;
|
|
1950
|
+
interface IndicatorFillOptions {
|
|
1951
|
+
/** Fill colour where the first series is above the second. */
|
|
1952
|
+
colorUp: string;
|
|
1953
|
+
/** Fill colour where the second is above the first. */
|
|
1954
|
+
colorDown: string;
|
|
1955
|
+
/** 0..1. Defaults to 0.12 — a band must not drown the candles it sits behind. */
|
|
1956
|
+
opacity?: number;
|
|
1957
|
+
/**
|
|
1958
|
+
* Set to grade the band instead of flat-filling it, in place of
|
|
1959
|
+
* `colorUp`/`colorDown`. A point carrying its own `color` still overrides it.
|
|
1960
|
+
* Unset leaves the two-colour fill exactly as it was.
|
|
1961
|
+
*/
|
|
1962
|
+
gradient?: FillGradient;
|
|
2110
1963
|
}
|
|
2111
|
-
|
|
2112
|
-
|
|
2113
|
-
|
|
2114
|
-
/** Descriptor id, e.g. `'macd'`. */
|
|
2115
|
-
indicatorId: string;
|
|
2116
|
-
/** Instance id, so a host can tell three EMAs apart. */
|
|
2117
|
-
instanceId: string;
|
|
2118
|
-
alertId: string;
|
|
2119
|
-
title: string;
|
|
2120
|
-
message: string;
|
|
2121
|
-
/** The bar that triggered it: UTC seconds, and its index in `bars`. */
|
|
2122
|
-
time: number;
|
|
1964
|
+
/** One bar's pair of values; `null` where either plot has no value yet. */
|
|
1965
|
+
interface FillPoint {
|
|
1966
|
+
/** Logical index on the shared time axis (fractional is fine). */
|
|
2123
1967
|
index: number;
|
|
1968
|
+
a: number | null;
|
|
1969
|
+
b: number | null;
|
|
1970
|
+
/**
|
|
1971
|
+
* Paints this bar onward in one colour, for a band shaded by something other
|
|
1972
|
+
* than which line leads: trend state, a regime, a third series. The run is
|
|
1973
|
+
* split at the bar where the colour changes, so it is per-bar and not merely
|
|
1974
|
+
* per-crossing. Most specific wins: this, then the gradient, then up/down.
|
|
1975
|
+
*/
|
|
1976
|
+
color?: string;
|
|
2124
1977
|
}
|
|
2125
|
-
|
|
2126
|
-
|
|
2127
|
-
|
|
2128
|
-
|
|
2129
|
-
|
|
1978
|
+
declare class IndicatorFill implements IPrimitive {
|
|
1979
|
+
private _points;
|
|
1980
|
+
private _opts;
|
|
1981
|
+
private _host;
|
|
1982
|
+
private _visible;
|
|
1983
|
+
constructor(options: IndicatorFillOptions);
|
|
1984
|
+
attached(host: PrimitiveHost): void;
|
|
1985
|
+
detached(): void;
|
|
1986
|
+
/** Behind the series, so the lines and candles stay crisp on top of it. */
|
|
1987
|
+
zOrder(): ZOrder;
|
|
1988
|
+
/** The plots it spans already drive the scale; the fill must not widen it. */
|
|
1989
|
+
autoscaleInfo(): null;
|
|
1990
|
+
setPoints(points: readonly FillPoint[]): void;
|
|
1991
|
+
setOptions(patch: Partial<IndicatorFillOptions>): void;
|
|
1992
|
+
setVisible(on: boolean): void;
|
|
1993
|
+
draw(ctx: CanvasRenderingContext2D, rc: PrimitiveRenderContext): void;
|
|
2130
1994
|
}
|
|
2131
|
-
|
|
2132
|
-
|
|
2133
|
-
|
|
2134
|
-
|
|
2135
|
-
|
|
2136
|
-
|
|
2137
|
-
|
|
2138
|
-
|
|
2139
|
-
|
|
2140
|
-
|
|
2141
|
-
|
|
2142
|
-
|
|
1995
|
+
|
|
1996
|
+
/**
|
|
1997
|
+
* Indicator runtime (ARCHITECTURE.md §8). Turns an `IndicatorDescriptor` into
|
|
1998
|
+
* live chart objects: one series per plot, optional reference levels, an
|
|
1999
|
+
* optional fixed pane range — and recomputes them when the source data or the
|
|
2000
|
+
* settings change.
|
|
2001
|
+
*
|
|
2002
|
+
* It adds **no rendering code**. Every plot names a registered chart type, so
|
|
2003
|
+
* indicators draw through the same Family-A renderers as any other series.
|
|
2004
|
+
*/
|
|
2005
|
+
|
|
2006
|
+
/** The slice of the chart the runtime needs. Keeps this module testable alone. */
|
|
2007
|
+
interface IndicatorHost {
|
|
2008
|
+
/** Forget a disposed instance, including disposal through its public handle. */
|
|
2009
|
+
indicatorRemoved?(instanceId: string): void;
|
|
2010
|
+
/** Optional instrument identity and source-range notifications. */
|
|
2143
2011
|
dataContext?(): Readonly<ChartDataContext> | undefined;
|
|
2144
|
-
/** Read bars and identity again when the host publishes a change. */
|
|
2145
2012
|
subscribeDataChanges?(listener: (change: IndicatorDataChange) => void): () => void;
|
|
2146
|
-
/**
|
|
2147
|
-
|
|
2148
|
-
|
|
2149
|
-
|
|
2150
|
-
|
|
2151
|
-
|
|
2152
|
-
|
|
2153
|
-
|
|
2154
|
-
|
|
2155
|
-
|
|
2156
|
-
|
|
2157
|
-
|
|
2158
|
-
|
|
2013
|
+
/** Add the pane-legend row (name + inline up/down/hide/maximize/close). */
|
|
2014
|
+
addIndicatorLegend(opts: {
|
|
2015
|
+
id: string;
|
|
2016
|
+
title: string;
|
|
2017
|
+
params: string;
|
|
2018
|
+
color?: string;
|
|
2019
|
+
row: number;
|
|
2020
|
+
paneIndex: number;
|
|
2021
|
+
}): PaneLegend;
|
|
2022
|
+
removeIndicatorLegend(legend: PaneLegend): void;
|
|
2023
|
+
/** How many legends already sit on this pane, so rows stack. */
|
|
2024
|
+
legendRowsOn(paneIndex: number): number;
|
|
2025
|
+
addIndicatorSeries(type: string, paneIndex: number, style: Record<string, unknown> | undefined, priceScaleId: string | undefined,
|
|
2026
|
+
/** Axis/crosshair formatting for the scale this plot maps to. */
|
|
2027
|
+
priceFormat?: PriceFormat): SeriesApi;
|
|
2159
2028
|
/**
|
|
2160
|
-
*
|
|
2029
|
+
* Add a reference level. One options object rather than seven positional
|
|
2030
|
+
* arguments: the list grew a width and a dash style in 1.7.1, and a call site
|
|
2031
|
+
* of seven bare values is where the next one gets passed in the wrong slot.
|
|
2032
|
+
*/
|
|
2033
|
+
addIndicatorLevel(level: {
|
|
2034
|
+
price: number;
|
|
2035
|
+
color: string;
|
|
2036
|
+
/** Kept for hosts predating `lineStyle`; always `lineStyle === 'dashed'`. */
|
|
2037
|
+
dashed: boolean;
|
|
2038
|
+
lineWidth: number;
|
|
2039
|
+
lineStyle: IndicatorLineStyle;
|
|
2040
|
+
label: string;
|
|
2041
|
+
id: string;
|
|
2042
|
+
}, paneIndex: number): PriceLine;
|
|
2043
|
+
removeIndicatorLevel(line: PriceLine): void;
|
|
2044
|
+
/** Attach a band drawn behind the plots (an Ichimoku cloud). */
|
|
2045
|
+
addIndicatorFill(fill: IndicatorFill, paneIndex: number): void;
|
|
2046
|
+
removeIndicatorFill(fill: IndicatorFill): void;
|
|
2047
|
+
/**
|
|
2048
|
+
* Detach a signal-marker layer. There is no matching `add`: the layer comes
|
|
2049
|
+
* from `series.createMarkers()` on a plot's own series, so it already lands in
|
|
2050
|
+
* the right pane. Removing a series does not remove its primitives, hence this.
|
|
2051
|
+
*/
|
|
2052
|
+
removeIndicatorMarkers(markers: SeriesMarkers): void;
|
|
2053
|
+
/** Attach a corner-pinned summary grid to a pane, and detach it again. */
|
|
2054
|
+
addIndicatorTable(paneIndex: number): ChartTable;
|
|
2055
|
+
removeIndicatorTable(table: ChartTable): void;
|
|
2056
|
+
/**
|
|
2057
|
+
* Attach an arbitrary primitive to a pane, and detach it again. Carries both
|
|
2058
|
+
* the descriptor's drawing layer and whatever a Tier-2 `attach` lifecycle
|
|
2059
|
+
* wants to paint, so those two do not need a host method each.
|
|
2161
2060
|
*
|
|
2162
|
-
*
|
|
2163
|
-
*
|
|
2164
|
-
|
|
2061
|
+
* Optional, like `timezone`, so a host predating it still satisfies this
|
|
2062
|
+
* interface: an indicator that draws simply draws nothing there.
|
|
2063
|
+
*/
|
|
2064
|
+
addIndicatorPrimitive?(primitive: IPrimitive, paneIndex: number): void;
|
|
2065
|
+
removeIndicatorPrimitive?(primitive: IPrimitive): void;
|
|
2066
|
+
/**
|
|
2067
|
+
* Recompute whatever the host has marked stale, before a caller reads a value.
|
|
2068
|
+
*
|
|
2069
|
+
* Optional, like `timezone`, so a host predating it still satisfies this
|
|
2070
|
+
* interface: one that recomputes eagerly has nothing to flush.
|
|
2071
|
+
*/
|
|
2072
|
+
flushIndicators?(): void;
|
|
2073
|
+
/** Bars of the primary price series — the calculation input. */
|
|
2074
|
+
sourceBars(): readonly Bar[];
|
|
2075
|
+
/** Selected candle after native or linked hover; absent means latest. */
|
|
2076
|
+
legendIndex?(): number | undefined;
|
|
2077
|
+
/** Index of a fresh pane for an indicator that wants its own. */
|
|
2078
|
+
nextPaneIndex(): number;
|
|
2079
|
+
/**
|
|
2080
|
+
* The chart's configured IANA zone. Optional so a host predating the option
|
|
2081
|
+
* still satisfies this interface; absent means the shipped default.
|
|
2082
|
+
*
|
|
2083
|
+
* A descriptor is handed bars and settings and never the chart, so this is
|
|
2084
|
+
* how the calendar an anchor resets on (a VWAP session, a seasonality month)
|
|
2085
|
+
* reaches the calculation. See `IndicatorInstance._descriptorSettings`.
|
|
2086
|
+
*/
|
|
2087
|
+
timezone?(): string;
|
|
2088
|
+
/**
|
|
2089
|
+
* The instrument and timeframe on screen, when the host knows them. The
|
|
2090
|
+
* host can supply an explicit `dataContext` instead. Without either hook,
|
|
2091
|
+
* a descriptor sees `undefined` rather than a guessed identity.
|
|
2165
2092
|
*/
|
|
2166
2093
|
symbol?(): string | undefined;
|
|
2167
|
-
/** The chart's timeframe (`'5m'`, `'1d'`), on the same terms as `symbol`. */
|
|
2168
2094
|
interval?(): string | undefined;
|
|
2169
|
-
/**
|
|
2170
|
-
timezone?(): string;
|
|
2171
|
-
/** Chart wall clock in UTC seconds, the same clock the countdown row uses. */
|
|
2095
|
+
/** Chart wall clock in UTC seconds. Absent means the system clock. */
|
|
2172
2096
|
now?(): number;
|
|
2173
2097
|
/**
|
|
2174
|
-
*
|
|
2175
|
-
*
|
|
2176
|
-
*
|
|
2177
|
-
*
|
|
2098
|
+
* Publish an indicator's per-bar colours onto the **primary price series**,
|
|
2099
|
+
* or withdraw them with `null`. `owner` is the instance id: a host holds one
|
|
2100
|
+
* overlay at a time and only lets its current owner withdraw it, so a second
|
|
2101
|
+
* publisher taking over does not get cleared by the first one's teardown.
|
|
2102
|
+
*
|
|
2103
|
+
* Optional, like `timezone`: a host that does not implement it simply gives a
|
|
2104
|
+
* `barColors` descriptor nowhere to publish, and the indicator's own plots are
|
|
2105
|
+
* unaffected.
|
|
2106
|
+
*/
|
|
2107
|
+
setBarColors?(colors: readonly (string | null)[] | null, owner: string): void;
|
|
2108
|
+
/** Emit on the chart's event bus (indicator alerts, and `attach`'s own events). */
|
|
2109
|
+
emit?(event: string, payload: unknown): void;
|
|
2110
|
+
/**
|
|
2111
|
+
* Bars of another instrument or interval, from wherever the host keeps its
|
|
2112
|
+
* history. Optional: without it the attach context's `requestBars` rejects,
|
|
2113
|
+
* which a study reads as "not available on this chart".
|
|
2178
2114
|
*/
|
|
2179
2115
|
requestBars?(request: IndicatorBarsRequest): Promise<readonly Bar[]>;
|
|
2180
|
-
/** The pane this instance drew into. Moves when panes are reordered. */
|
|
2181
|
-
paneIndex?(): number;
|
|
2182
|
-
/** Attach a primitive to this indicator's pane, and detach it again. */
|
|
2183
|
-
addPrimitive?(p: IPrimitive): void;
|
|
2184
|
-
removePrimitive?(p: IPrimitive): void;
|
|
2185
2116
|
/**
|
|
2186
|
-
*
|
|
2117
|
+
* Tick size of the named pane's price scale, or undefined when none is set.
|
|
2118
|
+
* Optional so a host predating it still satisfies this interface.
|
|
2187
2119
|
*
|
|
2188
|
-
*
|
|
2189
|
-
*
|
|
2190
|
-
*
|
|
2120
|
+
* Per pane, and the panes genuinely differ: a pane that does not quote the
|
|
2121
|
+
* instrument has no tick to report. Pane 0 is the price pane, so it is the
|
|
2122
|
+
* one to ask for the instrument's own step.
|
|
2191
2123
|
*/
|
|
2192
|
-
|
|
2193
|
-
}
|
|
2194
|
-
/**
|
|
2195
|
-
* What `levels` is handed. It carries `bars` and `values` **and** spreads the
|
|
2196
|
-
* settings keys onto itself, so the built-ins written against the original
|
|
2197
|
-
* `levels(settings)` signature keep working unchanged: they read
|
|
2198
|
-
* `ctx.overbought` (or pass `ctx` to a `num(s, key, default)` helper) and find
|
|
2199
|
-
* exactly what they found before. A widened parameter is the only way a level
|
|
2200
|
-
* can be data-derived (yesterday's high, the session VWAP band), and that is a
|
|
2201
|
-
* whole class of level that could not be expressed at all before.
|
|
2202
|
-
*
|
|
2203
|
-
* The three data members are optional for the same backward-compatibility
|
|
2204
|
-
* reason, not because the runtime ever omits them: it always passes all three,
|
|
2205
|
-
* but a caller holding only a settings bag must still be able to invoke
|
|
2206
|
-
* `levels` directly. A descriptor that needs the data should default them
|
|
2207
|
-
* (`ctx.bars ?? []`).
|
|
2208
|
-
*
|
|
2209
|
-
* `settings`, `bars` and `values` are therefore reserved keys, the way
|
|
2210
|
-
* `timezone` already is in the settings a `calc` receives: an input declared
|
|
2211
|
-
* under one of those names is shadowed here.
|
|
2212
|
-
*/
|
|
2213
|
-
type IndicatorLevelContext = IndicatorSettings & {
|
|
2214
|
-
settings?: Readonly<IndicatorSettings>;
|
|
2215
|
-
bars?: readonly Bar[];
|
|
2216
|
-
values?: IndicatorValues;
|
|
2217
|
-
};
|
|
2218
|
-
interface IndicatorDescriptor {
|
|
2219
|
-
/** Registry key, e.g. `'macd'`. */
|
|
2220
|
-
id: string;
|
|
2221
|
-
/** Display name, e.g. `'MACD'`. */
|
|
2222
|
-
name: string;
|
|
2223
|
-
/** Grouping for a picker UI ('Trend', 'Momentum', 'Volume', 'Volatility'). */
|
|
2224
|
-
category?: string;
|
|
2225
|
-
/** `'onchart'` overlays the price pane; `'pane'` gets its own pane. */
|
|
2226
|
-
placement: 'onchart' | 'pane';
|
|
2227
|
-
inputs: readonly IndicatorInput[];
|
|
2228
|
-
plots: readonly IndicatorPlot[];
|
|
2229
|
-
/**
|
|
2230
|
-
* Shaded bands between pairs of plots — the Ichimoku cloud, a Bollinger
|
|
2231
|
-
* channel. A pair of lines is not the same picture as a filled region: the
|
|
2232
|
-
* fill is what makes "price is above the cloud" readable at a glance, and
|
|
2233
|
-
* which side leads is itself the signal, hence the two colours.
|
|
2234
|
-
*/
|
|
2235
|
-
fills?: readonly IndicatorFillSpec[];
|
|
2236
|
-
/**
|
|
2237
|
-
* Full recompute over every bar. Must return arrays the same length as
|
|
2238
|
-
* `bars` (use `null` for warmup gaps — the line renderer breaks across them
|
|
2239
|
-
* and autoscale skips them).
|
|
2240
|
-
*
|
|
2241
|
-
* Tier-1 indicators are pure functions of `(bars, settings)` and ignore
|
|
2242
|
-
* `store`. Tier-2 indicators — the ones with their own data — read the
|
|
2243
|
-
* external series their `attach` lifecycle put in `store`.
|
|
2244
|
-
*/
|
|
2245
|
-
calc(bars: readonly Bar[], settings: Readonly<IndicatorSettings>, store: IndicatorStore, ctx?: IndicatorCalcContext): IndicatorValues;
|
|
2246
|
-
/**
|
|
2247
|
-
* Optional per-instance lifecycle, for indicators whose data is not derived
|
|
2248
|
-
* from the chart's bars (open interest, CVD, an external feed). Called once
|
|
2249
|
-
* when the instance is created; return a teardown function.
|
|
2250
|
-
*
|
|
2251
|
-
* Fetch into `ctx.store`, then call `ctx.requestRecompute()` — `calc` runs
|
|
2252
|
-
* again and reads what you stored.
|
|
2253
|
-
*/
|
|
2254
|
-
attach?(ctx: IndicatorAttachContext): (() => void) | void;
|
|
2255
|
-
/**
|
|
2256
|
-
* Optional incremental path, called instead of `calc` when only the tail
|
|
2257
|
-
* changed (a live tick). Return values for indices `[fromIndex, bars.length)`
|
|
2258
|
-
* — the runtime splices them onto the previous result — or `null` to fall
|
|
2259
|
-
* back to a full `calc`.
|
|
2260
|
-
*
|
|
2261
|
-
* Without it every tick costs a full recompute. That is a few hundred
|
|
2262
|
-
* microseconds for one indicator over 50k bars, but it is O(n) per tick per
|
|
2263
|
-
* indicator, so implement this for anything meant to run in a busy live pane.
|
|
2264
|
-
*/
|
|
2265
|
-
calcTail?(bars: readonly Bar[], settings: Readonly<IndicatorSettings>, fromIndex: number, previous: IndicatorValues, store: IndicatorStore, ctx?: IndicatorCalcContext): IndicatorValues | null;
|
|
2266
|
-
/**
|
|
2267
|
-
* Optional bar-anchored signal markers — a named "Buy"/"Sell" plate, an arrow
|
|
2268
|
-
* at a crossover. Runs after every `calc`, so it reads the values it just
|
|
2269
|
-
* produced rather than recomputing anything.
|
|
2270
|
-
*
|
|
2271
|
-
* A plot cannot express this: a plot is a column of prices drawn as a line or
|
|
2272
|
-
* histogram, whereas a signal is a discrete event with a label. Returning `[]`
|
|
2273
|
-
* (when a `showLabels`-style input is off, say) clears the layer.
|
|
2274
|
-
*/
|
|
2275
|
-
markers?(ctx: {
|
|
2276
|
-
bars: readonly Bar[];
|
|
2277
|
-
values: IndicatorValues;
|
|
2278
|
-
settings: Readonly<IndicatorSettings>;
|
|
2279
|
-
}): readonly SeriesMarker[];
|
|
2280
|
-
/**
|
|
2281
|
-
* Optional summary grid pinned to a corner of the pane.
|
|
2282
|
-
*
|
|
2283
|
-
* Some studies are not a value per bar at all: a seasonality heatmap is a
|
|
2284
|
-
* matrix of monthly returns, a scoreboard is a handful of statistics. Those
|
|
2285
|
-
* have no place in `calc`, whose contract is one column per plot aligned to
|
|
2286
|
-
* the bars, so they come back through here instead. Runs after every `calc`.
|
|
2287
|
-
*
|
|
2288
|
-
* Return `null` (or a zero-row grid) to draw nothing, which is how a
|
|
2289
|
-
* `showTable`-style input should switch it off.
|
|
2290
|
-
*/
|
|
2291
|
-
table?(ctx: {
|
|
2292
|
-
bars: readonly Bar[];
|
|
2293
|
-
values: IndicatorValues;
|
|
2294
|
-
settings: Readonly<IndicatorSettings>;
|
|
2295
|
-
}): {
|
|
2296
|
-
rows: readonly (readonly TableCell[])[];
|
|
2297
|
-
options?: Partial<ChartTableOptions>;
|
|
2298
|
-
} | null;
|
|
2299
|
-
/**
|
|
2300
|
-
* Optional free-standing shapes drawn in the indicator's pane: trendlines
|
|
2301
|
-
* between pivots, supply and demand boxes, projection labels. Runs after
|
|
2302
|
-
* every `calc`, like `markers` and `table`, and the returned list replaces the
|
|
2303
|
-
* previous one wholesale, so returning `[]` clears the layer.
|
|
2304
|
-
*/
|
|
2305
|
-
draws?(ctx: {
|
|
2306
|
-
bars: readonly Bar[];
|
|
2307
|
-
values: IndicatorValues;
|
|
2308
|
-
settings: Readonly<IndicatorSettings>;
|
|
2309
|
-
}): readonly IndicatorDrawing[];
|
|
2310
|
-
/**
|
|
2311
|
-
* Optional per-bar shading behind everything else in the indicator's pane: a
|
|
2312
|
-
* full-height column per bar, `null` where nothing should be shaded.
|
|
2313
|
-
*
|
|
2314
|
-
* A regime study answers "which state is the market in right now", and that is
|
|
2315
|
-
* a property of the whole bar, not a price. Drawn as a plot it would need a
|
|
2316
|
-
* value to sit at and would fight the pane's autoscale; as a column behind the
|
|
2317
|
-
* candles it reads at a glance and costs the scale nothing.
|
|
2318
|
-
*
|
|
2319
|
-
* Runs after every `calc`. Return `[]` to clear the layer.
|
|
2320
|
-
*/
|
|
2321
|
-
background?(ctx: {
|
|
2322
|
-
bars: readonly Bar[];
|
|
2323
|
-
values: IndicatorValues;
|
|
2324
|
-
settings: Readonly<IndicatorSettings>;
|
|
2325
|
-
}): readonly (string | null)[];
|
|
2124
|
+
tickSize?(paneIndex: number): number | undefined;
|
|
2326
2125
|
/**
|
|
2327
|
-
*
|
|
2328
|
-
* `null` to leave that bar with its own colour.
|
|
2126
|
+
* Write a number the way the price axis of that pane writes it.
|
|
2329
2127
|
*
|
|
2330
|
-
*
|
|
2331
|
-
*
|
|
2332
|
-
*
|
|
2333
|
-
*
|
|
2128
|
+
* The legend sits inches from the axis and names the same quantity, so the
|
|
2129
|
+
* two disagreeing is the reading a user has to reconcile themselves. Deriving
|
|
2130
|
+
* the format here from a tick got that wrong twice over: a study pane carries
|
|
2131
|
+
* no tick at all, so a percentage read `0.618` beside an axis saying `0.62`,
|
|
2132
|
+
* and a price pane's tick alone misses the precision floor and the host's own
|
|
2133
|
+
* formatter, so a volume study read seven digits where its axis said `1.20M`.
|
|
2334
2134
|
*
|
|
2335
|
-
*
|
|
2336
|
-
*
|
|
2337
|
-
* winner is the same one from frame to frame. Removing it, or hiding it,
|
|
2338
|
-
* restores the bars' own colours.
|
|
2339
|
-
*/
|
|
2340
|
-
barColors?(ctx: {
|
|
2341
|
-
bars: readonly Bar[];
|
|
2342
|
-
values: IndicatorValues;
|
|
2343
|
-
settings: Readonly<IndicatorSettings>;
|
|
2344
|
-
}): readonly (string | null)[];
|
|
2345
|
-
/**
|
|
2346
|
-
* Optional conditions the runtime watches on the descriptor's behalf, emitted
|
|
2347
|
-
* as `'indicator:alert'` on the chart's event bus with an
|
|
2348
|
-
* {@link IndicatorAlertPayload}. See {@link IndicatorAlertSpec}.
|
|
2349
|
-
*/
|
|
2350
|
-
alerts?: readonly IndicatorAlertSpec[];
|
|
2351
|
-
/**
|
|
2352
|
-
* Optional horizontal reference levels drawn in the indicator's pane.
|
|
2353
|
-
* Recomputed after every `calc`, so a level derived from the data (the
|
|
2354
|
-
* previous day's high) tracks it. See `IndicatorLevelContext` for why the
|
|
2355
|
-
* argument still reads as a settings bag.
|
|
2356
|
-
*/
|
|
2357
|
-
levels?(ctx: IndicatorLevelContext): readonly IndicatorLevel[];
|
|
2358
|
-
/**
|
|
2359
|
-
* Optional fixed price range for the indicator's own pane (RSI 0..100).
|
|
2360
|
-
* Applied only when the indicator creates its pane — two indicators sharing a
|
|
2361
|
-
* pane would otherwise fight over it.
|
|
2135
|
+
* Asking the scale removes the second opinion. Optional so a host driving
|
|
2136
|
+
* this module alone still works, falling back to the magnitude ladder.
|
|
2362
2137
|
*/
|
|
2363
|
-
|
|
2138
|
+
formatPrice?(paneIndex: number, value: number): string | undefined;
|
|
2139
|
+
/** Pin a pane's price scale to a fixed range, or release it with `null`. */
|
|
2140
|
+
setPaneRange(paneIndex: number, range: {
|
|
2364
2141
|
min: number;
|
|
2365
2142
|
max: number;
|
|
2366
|
-
} | null;
|
|
2143
|
+
} | null): void;
|
|
2144
|
+
}
|
|
2145
|
+
/** Public handle returned by `chart.addIndicator(...)`. */
|
|
2146
|
+
interface IndicatorApi {
|
|
2147
|
+
/** External data state, or null for a study without a managed lifecycle. */
|
|
2148
|
+
dataStatus(): Readonly<IndicatorDataStatus> | null;
|
|
2149
|
+
/** Observe changes; immediately receives the current managed status, if any. */
|
|
2150
|
+
subscribeDataStatus(listener: (status: Readonly<IndicatorDataStatus>) => void): () => void;
|
|
2151
|
+
/** Retry external history when the descriptor supplies a retry action. */
|
|
2152
|
+
retryData(): void;
|
|
2153
|
+
/** Unique instance id (several instances of one indicator can coexist). */
|
|
2154
|
+
readonly id: string;
|
|
2155
|
+
/** The descriptor id, e.g. `'macd'`. */
|
|
2156
|
+
readonly indicatorId: string;
|
|
2157
|
+
/** Display name. */
|
|
2158
|
+
readonly name: string;
|
|
2159
|
+
/** Pane the indicator drew into. */
|
|
2160
|
+
readonly paneIndex: number;
|
|
2161
|
+
/** Current settings (a copy). */
|
|
2162
|
+
settings(): IndicatorSettings;
|
|
2163
|
+
/** Merge a settings patch, recompute, and restyle. */
|
|
2164
|
+
setSettings(patch: Readonly<IndicatorSettings>): void;
|
|
2165
|
+
/** The series backing one plot key, for direct styling. */
|
|
2166
|
+
series(plotKey: string): SeriesApi | undefined;
|
|
2167
|
+
/** Latest computed values (a reference — do not mutate). */
|
|
2168
|
+
values(): IndicatorValues;
|
|
2169
|
+
/** Whether the plots are drawn (the legend's eye toggle). */
|
|
2170
|
+
visible(): boolean;
|
|
2171
|
+
/** Show or hide every plot without removing the instance. */
|
|
2172
|
+
setVisible(on: boolean): void;
|
|
2173
|
+
/** This indicator's legend row, or null if it has none. */
|
|
2174
|
+
legend(): PaneLegend | null;
|
|
2175
|
+
/** Refresh the legend readings for a bar index; omit for the latest bar. */
|
|
2176
|
+
updateLegendValues(index?: number): void;
|
|
2177
|
+
/** Remove every series, level, and legend row this indicator created. */
|
|
2178
|
+
remove(): void;
|
|
2367
2179
|
}
|
|
2368
|
-
/** Register an indicator descriptor. Later registrations of the same id win. */
|
|
2369
|
-
declare function registerIndicator(descriptor: IndicatorDescriptor): void;
|
|
2370
|
-
declare function getIndicator(id: string): IndicatorDescriptor;
|
|
2371
|
-
declare function hasIndicator(id: string): boolean;
|
|
2372
|
-
declare function registeredIndicators(): IndicatorDescriptor[];
|
|
2373
|
-
/** The descriptor's declared defaults as a settings object. */
|
|
2374
|
-
declare function indicatorDefaults(descriptor: IndicatorDescriptor): IndicatorSettings;
|
|
2375
|
-
/** Read one bar's value for a price source. */
|
|
2376
|
-
declare function sourceValue(bar: Bar, source: IndicatorSource): number;
|
|
2377
|
-
/** Read a whole bar array for a price source. */
|
|
2378
|
-
declare function sourceValues(bars: readonly Bar[], source: IndicatorSource): number[];
|
|
2379
|
-
|
|
2380
|
-
/**
|
|
2381
|
-
* Horizontal price line primitive (ARCHITECTURE.md §8). The reusable base for
|
|
2382
|
-
* order/SL/TP/alert/indicator-level lines: a line across the plot plus a fixed
|
|
2383
|
-
* right-axis price tag and an optional broker-style segmented pill group on the
|
|
2384
|
-
* line — [badge][qty][label][✕] — with hover / dragging states (the chart
|
|
2385
|
-
* passes `hoverId`/`dragId` on the render context) and a drag ghost at the
|
|
2386
|
-
* pre-drag price via `setDragGhost`. Interaction semantics are unchanged from
|
|
2387
|
-
* the classic tag: the ✕ hit-tests as `${id}::close`, everything else drags.
|
|
2388
|
-
*/
|
|
2389
2180
|
|
|
2390
|
-
|
|
2181
|
+
/** A primary-source mutation, emitted after indicator invalidation. */
|
|
2182
|
+
interface ChartDataUpdate {
|
|
2183
|
+
kind: 'update' | 'reset' | 'prepend';
|
|
2184
|
+
time?: number;
|
|
2185
|
+
}
|
|
2186
|
+
/** Minimum headless chart surface needed to evaluate alerts. */
|
|
2187
|
+
interface AlertChartHost {
|
|
2188
|
+
primaryBars(): readonly Bar[];
|
|
2189
|
+
getDataContext(): Readonly<ChartDataContext> | undefined;
|
|
2190
|
+
on(event: string, callback: (payload: unknown) => void): () => void;
|
|
2191
|
+
emit(event: string, payload: unknown): void;
|
|
2192
|
+
/** Flushes computed study values. Only required by indicator-source alerts. */
|
|
2193
|
+
indicators?(): readonly (Pick<IndicatorApi, 'id' | 'paneIndex' | 'series' | 'values'> & Partial<Pick<IndicatorApi, 'indicatorId'>>)[];
|
|
2194
|
+
addPrimitive?(primitive: IPrimitive, paneIndex?: number): void;
|
|
2195
|
+
removePrimitive?(primitive: IPrimitive): void;
|
|
2196
|
+
alertState?(): AlertsDocument | undefined;
|
|
2197
|
+
setAlertState?(document: AlertsDocument | undefined): void;
|
|
2198
|
+
}
|
|
2199
|
+
type AlertCondition = 'crossing' | 'crossingUp' | 'crossingDown' | 'greaterThan' | 'lessThan' | 'enteringRange' | 'leavingRange' | 'matches';
|
|
2200
|
+
type AlertPolicy = 'onBarClose' | 'onTouch';
|
|
2201
|
+
type AlertRepeat = 'once' | 'everyTime';
|
|
2202
|
+
type AlertState = 'armed' | 'triggered' | 'expired' | 'disabled';
|
|
2203
|
+
/** Prices are in primary-series units. Range conditions require upperPrice. */
|
|
2204
|
+
interface PriceAlertSource {
|
|
2205
|
+
kind: 'price';
|
|
2391
2206
|
price: number;
|
|
2392
|
-
|
|
2393
|
-
|
|
2394
|
-
|
|
2395
|
-
|
|
2396
|
-
|
|
2397
|
-
|
|
2398
|
-
|
|
2399
|
-
|
|
2400
|
-
|
|
2401
|
-
|
|
2402
|
-
|
|
2403
|
-
|
|
2404
|
-
label?: string;
|
|
2405
|
-
/** Solid colored badge segment at the start of the pill group (e.g. 'BUY', 'TP', 'SL'). */
|
|
2406
|
-
badge?: string;
|
|
2407
|
-
/** Quantity segment rendered as a neutral box after the badge. */
|
|
2408
|
-
qty?: string | number;
|
|
2409
|
-
/** Info text segment (order type, price, P&L ...) — the classic left tag text. */
|
|
2410
|
-
leftLabel?: string;
|
|
2411
|
-
/**
|
|
2412
|
-
* Fraction of the plot width the line spans, measured from the right (price)
|
|
2413
|
-
* axis. 1 = full width (default); 0.3 = only the rightmost 30%, like a
|
|
2414
|
-
* partial-width order line. The right-axis tag is always drawn.
|
|
2415
|
-
*/
|
|
2416
|
-
extentFromRight?: number;
|
|
2417
|
-
/** Draw a cancel (✕) segment at the end of the pill group; hit-tests as `${id}::close`. */
|
|
2418
|
-
closeButton?: boolean;
|
|
2419
|
-
/** Stable id returned by hit-test (for click/drag routing). */
|
|
2207
|
+
upperPrice?: number;
|
|
2208
|
+
}
|
|
2209
|
+
/** A threshold in plot units, anchored to one specific study instance. */
|
|
2210
|
+
interface IndicatorAlertSource {
|
|
2211
|
+
kind: 'indicator';
|
|
2212
|
+
instanceId: string;
|
|
2213
|
+
plotKey: string;
|
|
2214
|
+
value: number;
|
|
2215
|
+
upperValue?: number;
|
|
2216
|
+
}
|
|
2217
|
+
interface BarConditionAlertSource {
|
|
2218
|
+
kind: 'barCondition';
|
|
2420
2219
|
id: string;
|
|
2421
|
-
/** Cursor hint when hovered (e.g. 'ns-resize' for draggable lines). */
|
|
2422
|
-
cursor?: string;
|
|
2423
2220
|
}
|
|
2424
|
-
|
|
2425
|
-
|
|
2426
|
-
|
|
2427
|
-
|
|
2428
|
-
/**
|
|
2429
|
-
|
|
2430
|
-
|
|
2431
|
-
|
|
2432
|
-
|
|
2433
|
-
|
|
2434
|
-
|
|
2435
|
-
|
|
2436
|
-
|
|
2437
|
-
|
|
2438
|
-
|
|
2439
|
-
|
|
2440
|
-
|
|
2441
|
-
|
|
2442
|
-
|
|
2443
|
-
|
|
2444
|
-
|
|
2445
|
-
|
|
2446
|
-
|
|
2447
|
-
|
|
2448
|
-
|
|
2449
|
-
|
|
2450
|
-
|
|
2451
|
-
|
|
2452
|
-
|
|
2453
|
-
|
|
2454
|
-
|
|
2455
|
-
|
|
2456
|
-
|
|
2457
|
-
|
|
2458
|
-
|
|
2459
|
-
|
|
2460
|
-
|
|
2221
|
+
interface DrawingAlertSource {
|
|
2222
|
+
kind: 'drawing';
|
|
2223
|
+
drawingId: string;
|
|
2224
|
+
level?: string;
|
|
2225
|
+
/** Required for a drawing on a study pane, so prices are not compared to different units. */
|
|
2226
|
+
input?: {
|
|
2227
|
+
instanceId: string;
|
|
2228
|
+
plotKey: string;
|
|
2229
|
+
};
|
|
2230
|
+
}
|
|
2231
|
+
type AlertSource = PriceAlertSource | IndicatorAlertSource | BarConditionAlertSource | DrawingAlertSource;
|
|
2232
|
+
/** Missing values, an absent anchor or a paused/context-mismatched chart are unavailable. */
|
|
2233
|
+
interface AlertAvailability {
|
|
2234
|
+
available: boolean;
|
|
2235
|
+
reason?: string;
|
|
2236
|
+
paneIndex?: number;
|
|
2237
|
+
}
|
|
2238
|
+
interface AlertDrawingValue {
|
|
2239
|
+
price: number;
|
|
2240
|
+
upperPrice?: number;
|
|
2241
|
+
paneIndex: number;
|
|
2242
|
+
}
|
|
2243
|
+
interface AlertDrawingLevel {
|
|
2244
|
+
id: string;
|
|
2245
|
+
title: string;
|
|
2246
|
+
}
|
|
2247
|
+
interface AlertDrawingInfo extends AlertAvailability {
|
|
2248
|
+
levels: readonly AlertDrawingLevel[];
|
|
2249
|
+
}
|
|
2250
|
+
/** Implemented by the optional drawing tier; the alert engine never imports it. */
|
|
2251
|
+
interface AlertDrawingProvider {
|
|
2252
|
+
get(id: string): unknown;
|
|
2253
|
+
valueAt(id: string, time: number, level?: string): AlertDrawingValue | undefined;
|
|
2254
|
+
alertInfo(id: string): AlertDrawingInfo;
|
|
2255
|
+
}
|
|
2256
|
+
interface BarConditionContext {
|
|
2257
|
+
/** Only the prefix through index is exposed, including for confirmed-bar checks. */
|
|
2258
|
+
bars: readonly Bar[];
|
|
2259
|
+
index: number;
|
|
2260
|
+
}
|
|
2261
|
+
interface BarCondition {
|
|
2262
|
+
id: string;
|
|
2263
|
+
title: string;
|
|
2264
|
+
/** Runs at the alert's chosen policy, never for loaded history. */
|
|
2265
|
+
when(context: BarConditionContext): boolean;
|
|
2266
|
+
}
|
|
2267
|
+
/** An alert belongs to the instrument and interval present when it was armed. */
|
|
2268
|
+
interface AlertScope {
|
|
2269
|
+
symbol?: string;
|
|
2270
|
+
exchange?: string;
|
|
2271
|
+
interval?: string;
|
|
2272
|
+
}
|
|
2273
|
+
interface AlertInput {
|
|
2274
|
+
id?: string;
|
|
2275
|
+
source: AlertSource;
|
|
2276
|
+
condition?: AlertCondition;
|
|
2277
|
+
/** Defaults to onBarClose. An intrabar touch may disappear from final history. */
|
|
2278
|
+
policy?: AlertPolicy;
|
|
2279
|
+
repeat?: AlertRepeat;
|
|
2280
|
+
state?: 'armed' | 'disabled';
|
|
2281
|
+
title?: string;
|
|
2282
|
+
message?: string;
|
|
2283
|
+
cooldownSeconds?: number;
|
|
2284
|
+
/** UTC seconds. At this instant the alert expires before it can trigger. */
|
|
2285
|
+
expiresAt?: number;
|
|
2286
|
+
/** Opaque host routing data. The controller never interprets or delivers it. */
|
|
2287
|
+
payload?: unknown;
|
|
2288
|
+
}
|
|
2289
|
+
type AlertPatch = Partial<Omit<AlertInput, 'id'>>;
|
|
2290
|
+
/** Lifecycle record. Snapshots detach mutable configuration, retaining opaque payloads. */
|
|
2291
|
+
interface Alert extends Omit<AlertInput, 'id' | 'condition' | 'policy' | 'repeat' | 'state' | 'title' | 'cooldownSeconds'> {
|
|
2292
|
+
id: string;
|
|
2293
|
+
condition: AlertCondition;
|
|
2294
|
+
policy: AlertPolicy;
|
|
2295
|
+
repeat: AlertRepeat;
|
|
2296
|
+
state: AlertState;
|
|
2297
|
+
title: string;
|
|
2298
|
+
cooldownSeconds: number;
|
|
2299
|
+
scope: AlertScope;
|
|
2300
|
+
lastTriggeredAt?: number;
|
|
2301
|
+
lastTriggeredTime?: number;
|
|
2302
|
+
/** Newest confirmed bar already judged, including a nonmatch. */
|
|
2303
|
+
lastClosedTime?: number;
|
|
2304
|
+
/** Newest intrabar match consumed, including one suppressed by cooldown. */
|
|
2305
|
+
lastTouchedTime?: number;
|
|
2306
|
+
}
|
|
2307
|
+
/** Portable trader records. JSON persistence rejects unsupported host payloads. */
|
|
2308
|
+
interface AlertsDocument {
|
|
2309
|
+
version: 1;
|
|
2310
|
+
alerts: Alert[];
|
|
2311
|
+
}
|
|
2312
|
+
/** Shared delivery fields for trader and indicator-authored alerts. */
|
|
2313
|
+
interface AlertEventPayload {
|
|
2314
|
+
alertId: string;
|
|
2315
|
+
title: string;
|
|
2316
|
+
message?: string;
|
|
2317
|
+
/** Source bar UTC seconds and source index, not delivery wall-clock time. */
|
|
2318
|
+
time: number;
|
|
2319
|
+
index: number;
|
|
2320
|
+
}
|
|
2321
|
+
interface AlertTriggeredPayload extends AlertEventPayload {
|
|
2322
|
+
price: number;
|
|
2323
|
+
alert: Alert;
|
|
2324
|
+
}
|
|
2325
|
+
interface AlertControllerOptions {
|
|
2326
|
+
/** Delivery and expiry clock in UTC seconds. Defaults to Date.now() / 1000. */
|
|
2327
|
+
now?: () => number;
|
|
2328
|
+
drawings?: AlertDrawingProvider;
|
|
2329
|
+
/** PriceLine visuals are enabled on chart hosts; disable for a model-only consumer. */
|
|
2330
|
+
visuals?: boolean;
|
|
2461
2331
|
}
|
|
2462
2332
|
|
|
2463
2333
|
/**
|
|
2464
|
-
*
|
|
2465
|
-
*
|
|
2466
|
-
*
|
|
2467
|
-
*
|
|
2468
|
-
* Drawn on the canvas rather than in the DOM, like `BuySellButtons` and
|
|
2469
|
-
* `DomLadder`, so it composites into screenshots and costs no DOM per pane.
|
|
2470
|
-
* Buttons hit-test as `${id}::close`, `${id}::hide`, and `${id}::settings`, so
|
|
2471
|
-
* the host routes them through the same `subscribeClick` path as order pills.
|
|
2334
|
+
* Indicator registry (ARCHITECTURE.md §6A, §8). The sibling of the chart-type
|
|
2335
|
+
* registry: that one answers *"how do I paint an array of bars"*, this one
|
|
2336
|
+
* answers *"what do I compute, what does it plot, and what can a user tune"*.
|
|
2472
2337
|
*
|
|
2473
|
-
*
|
|
2474
|
-
*
|
|
2338
|
+
* A descriptor is data, not code-in-the-core — the chart never switches on an
|
|
2339
|
+
* indicator id. Each `plot` names a registered **chart type**, so indicators
|
|
2340
|
+
* ride the existing Family-A renderers and add no drawing code at all.
|
|
2475
2341
|
*
|
|
2476
|
-
*
|
|
2477
|
-
*
|
|
2478
|
-
*
|
|
2479
|
-
* defaults to the behaviour that predates it, so a caller that passes none sees
|
|
2480
|
-
* the row it always saw. Fields the primitive cannot compute (a logo bitmap,
|
|
2481
|
-
* whether the market is open, the change since yesterday's close) arrive
|
|
2482
|
-
* through `status`; with no source they draw nothing at all rather than a
|
|
2483
|
-
* placeholder.
|
|
2342
|
+
* The built-in descriptors live in the lazy `openalgo-charts/indicators` tier;
|
|
2343
|
+
* only the registry and the runtime ship in the base bundle, so an app that
|
|
2344
|
+
* plots its own maths pays nothing for the catalog.
|
|
2484
2345
|
*/
|
|
2485
2346
|
|
|
2486
|
-
|
|
2347
|
+
/** Which price a calculation reads from each bar. */
|
|
2348
|
+
type IndicatorSource = 'open' | 'high' | 'low' | 'close' | 'hl2' | 'hlc3' | 'ohlc4' | 'volume';
|
|
2487
2349
|
/**
|
|
2488
|
-
* One
|
|
2489
|
-
*
|
|
2490
|
-
*
|
|
2350
|
+
* One tunable input. `type` is what a settings UI renders; the core only reads
|
|
2351
|
+
* `key`/`default`.
|
|
2352
|
+
*
|
|
2353
|
+
* `tooltip` is help text for the row. A label has to stay short enough to fit a
|
|
2354
|
+
* dense panel, which leaves nowhere to say what a parameter actually does, and a
|
|
2355
|
+
* ported study whose every input carried an explanation arrives here with that
|
|
2356
|
+
* explanation dropped. A settings UI renders it as a hover affordance beside the
|
|
2357
|
+
* label; the core ignores it.
|
|
2491
2358
|
*/
|
|
2492
|
-
|
|
2493
|
-
|
|
2494
|
-
|
|
2495
|
-
|
|
2496
|
-
|
|
2497
|
-
|
|
2498
|
-
|
|
2499
|
-
|
|
2500
|
-
|
|
2501
|
-
|
|
2502
|
-
|
|
2359
|
+
type IndicatorInput = {
|
|
2360
|
+
key: string;
|
|
2361
|
+
type: 'number';
|
|
2362
|
+
label: string;
|
|
2363
|
+
default: number;
|
|
2364
|
+
min?: number;
|
|
2365
|
+
max?: number;
|
|
2366
|
+
step?: number;
|
|
2367
|
+
group?: string;
|
|
2368
|
+
tooltip?: string;
|
|
2369
|
+
} | {
|
|
2370
|
+
key: string;
|
|
2371
|
+
type: 'boolean';
|
|
2372
|
+
label: string;
|
|
2373
|
+
default: boolean;
|
|
2374
|
+
group?: string;
|
|
2375
|
+
tooltip?: string;
|
|
2376
|
+
} | {
|
|
2377
|
+
key: string;
|
|
2378
|
+
type: 'color';
|
|
2379
|
+
label: string;
|
|
2380
|
+
default: string;
|
|
2381
|
+
group?: string;
|
|
2382
|
+
tooltip?: string;
|
|
2383
|
+
} | {
|
|
2384
|
+
key: string;
|
|
2385
|
+
type: 'text';
|
|
2386
|
+
label: string;
|
|
2387
|
+
default: string;
|
|
2388
|
+
group?: string;
|
|
2389
|
+
tooltip?: string;
|
|
2390
|
+
} | {
|
|
2391
|
+
key: string;
|
|
2392
|
+
type: 'select';
|
|
2393
|
+
label: string;
|
|
2394
|
+
default: string;
|
|
2395
|
+
options: readonly {
|
|
2396
|
+
label: string;
|
|
2397
|
+
value: string;
|
|
2398
|
+
}[];
|
|
2399
|
+
group?: string;
|
|
2400
|
+
tooltip?: string;
|
|
2401
|
+
} | {
|
|
2402
|
+
key: string;
|
|
2403
|
+
type: 'source';
|
|
2404
|
+
label: string;
|
|
2405
|
+
default: IndicatorSource;
|
|
2406
|
+
group?: string;
|
|
2407
|
+
tooltip?: string;
|
|
2503
2408
|
}
|
|
2504
2409
|
/**
|
|
2505
|
-
*
|
|
2506
|
-
*
|
|
2507
|
-
*
|
|
2410
|
+
* A timeframe code (`'5m'`, `'1d'`), for a study that folds the chart's bars
|
|
2411
|
+
* up to a coarser interval. A settings UI renders it as a select over the
|
|
2412
|
+
* registered intervals, so the value is always one the engine can bucket by;
|
|
2413
|
+
* a free text box would accept `'5min'` and leave the study computing on a
|
|
2414
|
+
* code it cannot resolve. An empty default means "the chart's own interval".
|
|
2508
2415
|
*/
|
|
2509
|
-
|
|
2416
|
+
| {
|
|
2417
|
+
key: string;
|
|
2418
|
+
type: 'interval';
|
|
2419
|
+
label: string;
|
|
2420
|
+
default: string;
|
|
2421
|
+
group?: string;
|
|
2422
|
+
tooltip?: string;
|
|
2423
|
+
}
|
|
2510
2424
|
/**
|
|
2511
|
-
*
|
|
2512
|
-
*
|
|
2425
|
+
* A wall-clock instant in the chart's zone, written `YYYY-MM-DD HH:MM` (the
|
|
2426
|
+
* time part optional), for an anchor a user picks by date: the start of an
|
|
2427
|
+
* anchored VWAP, an event to measure from. It is carried as that string, not
|
|
2428
|
+
* as UTC seconds, so a layout saved in one zone restores to the same wall
|
|
2429
|
+
* clock in another, and `zonedStringToUtcSeconds` turns it into a bar time.
|
|
2513
2430
|
*/
|
|
2514
|
-
|
|
2431
|
+
| {
|
|
2432
|
+
key: string;
|
|
2433
|
+
type: 'time';
|
|
2434
|
+
label: string;
|
|
2435
|
+
default: string;
|
|
2436
|
+
group?: string;
|
|
2437
|
+
tooltip?: string;
|
|
2438
|
+
};
|
|
2439
|
+
/** Dash pattern for a level, a drawing, or a plot. */
|
|
2440
|
+
type IndicatorLineStyle = 'solid' | 'dashed' | 'dotted';
|
|
2441
|
+
/** Line-style options, for a settings UI's Style tab. */
|
|
2442
|
+
declare const INDICATOR_LINE_STYLES: readonly {
|
|
2443
|
+
label: string;
|
|
2444
|
+
value: string;
|
|
2445
|
+
}[];
|
|
2446
|
+
/** Settings keys the runtime derives for a plot's appearance. */
|
|
2447
|
+
declare function plotStyleKeys(plot: IndicatorPlot): {
|
|
2448
|
+
color: string;
|
|
2449
|
+
width: string;
|
|
2450
|
+
lineStyle: string;
|
|
2451
|
+
opacity: string;
|
|
2452
|
+
type: string;
|
|
2453
|
+
};
|
|
2515
2454
|
/**
|
|
2516
|
-
*
|
|
2517
|
-
*
|
|
2455
|
+
* Per-plot appearance inputs, generated from the descriptor rather than
|
|
2456
|
+
* hand-written on each one — every indicator gets colour, opacity, thickness,
|
|
2457
|
+
* and line style for free, and a settings UI can render them as a "Style" tab
|
|
2458
|
+
* beside the descriptor's own `inputs`.
|
|
2459
|
+
*
|
|
2460
|
+
* Defaults come from the plot's declared style (and its legacy `colorKey`), so
|
|
2461
|
+
* an indicator that already ships colours keeps them.
|
|
2518
2462
|
*/
|
|
2519
|
-
|
|
2520
|
-
/** Already-decoded logo (an `<img>`, an `ImageBitmap`, a canvas). */
|
|
2521
|
-
logo?: CanvasImageSource;
|
|
2522
|
-
/** Long name for `titleMode: 'description'`, e.g. `Apple Inc.`. */
|
|
2523
|
-
description?: string;
|
|
2524
|
-
/** Exchange ticker for `titleMode: 'ticker'`, e.g. `NASDAQ:AAPL`. */
|
|
2525
|
-
ticker?: string;
|
|
2526
|
-
/** Session state, e.g. `{ text: 'Market open', color: '#26a69a' }`. */
|
|
2527
|
-
marketStatus?: LegendValue;
|
|
2528
|
-
/** Change against the previous close, e.g. `{ text: '+1.20 (+0.75%)' }`. */
|
|
2529
|
-
lastDayChange?: LegendValue;
|
|
2530
|
-
}
|
|
2463
|
+
declare function indicatorStyleInputs(descriptor: IndicatorDescriptor): IndicatorInput[];
|
|
2531
2464
|
/**
|
|
2532
|
-
*
|
|
2533
|
-
*
|
|
2534
|
-
*
|
|
2465
|
+
* Chart types a plot can be re-rendered as. A moving average is a line by
|
|
2466
|
+
* default, but the same column of numbers reads better as a histogram or an
|
|
2467
|
+
* area depending on what you are looking for — and a descriptor cannot know
|
|
2468
|
+
* which. Restricted to the types that make sense for a single value column.
|
|
2535
2469
|
*/
|
|
2536
|
-
|
|
2470
|
+
declare const INDICATOR_PLOT_STYLES: readonly {
|
|
2471
|
+
label: string;
|
|
2472
|
+
value: string;
|
|
2473
|
+
}[];
|
|
2474
|
+
/** Canonical option list for a `type: 'source'` input, for settings UIs. */
|
|
2475
|
+
declare const INDICATOR_SOURCES: readonly {
|
|
2476
|
+
label: string;
|
|
2477
|
+
value: IndicatorSource;
|
|
2478
|
+
}[];
|
|
2479
|
+
type IndicatorSettings = Record<string, unknown>;
|
|
2480
|
+
/** One plotted line/band/histogram. `type` is any registered chart type. */
|
|
2481
|
+
/** A shaded band between two of an indicator's plots. */
|
|
2482
|
+
interface IndicatorFillSpec {
|
|
2483
|
+
/** The two plot keys to fill between. */
|
|
2484
|
+
between: readonly [string, string];
|
|
2485
|
+
/** Colour where the first plot is above the second. */
|
|
2486
|
+
colorUp?: string;
|
|
2487
|
+
/** Colour where the second is above the first. */
|
|
2488
|
+
colorDown?: string;
|
|
2489
|
+
/** Settings keys holding those colours, so the band is restyleable. */
|
|
2490
|
+
colorUpKey?: string;
|
|
2491
|
+
colorDownKey?: string;
|
|
2492
|
+
/** 0..1. Defaults to 0.12. */
|
|
2493
|
+
opacity?: number;
|
|
2494
|
+
/**
|
|
2495
|
+
* Draw the band on the price pane even though the indicator owns a pane of
|
|
2496
|
+
* its own. The pair with `IndicatorPlot.overlay`: a study can already send
|
|
2497
|
+
* one plot to the candles, and a band between two such plots belongs beside
|
|
2498
|
+
* them rather than in the study pane the fill would otherwise land in.
|
|
2499
|
+
* Ignored for an `'onchart'` descriptor, which is on the price pane already.
|
|
2500
|
+
*/
|
|
2501
|
+
overlay?: boolean;
|
|
2502
|
+
}
|
|
2537
2503
|
/**
|
|
2538
|
-
*
|
|
2539
|
-
*
|
|
2540
|
-
*
|
|
2504
|
+
* What `colorParts` answers: a candle plot's colour split three ways, which is
|
|
2505
|
+
* how a study paints a wick in full colour over a translucent body. `body` is
|
|
2506
|
+
* the bar's colour (and the only part a line, histogram or column reads); a
|
|
2507
|
+
* part left undefined falls back to `colorBy`, then to the plot's own colour.
|
|
2541
2508
|
*/
|
|
2542
|
-
|
|
2543
|
-
|
|
2544
|
-
|
|
2545
|
-
|
|
2546
|
-
|
|
2547
|
-
|
|
2548
|
-
|
|
2549
|
-
|
|
2550
|
-
|
|
2551
|
-
|
|
2552
|
-
|
|
2553
|
-
|
|
2554
|
-
|
|
2555
|
-
|
|
2556
|
-
|
|
2557
|
-
|
|
2558
|
-
lastDayChange?: boolean;
|
|
2509
|
+
type PlotBarColor = {
|
|
2510
|
+
body?: string;
|
|
2511
|
+
wick?: string;
|
|
2512
|
+
border?: string;
|
|
2513
|
+
};
|
|
2514
|
+
interface IndicatorPlot {
|
|
2515
|
+
/** Key into the `calc` result. */
|
|
2516
|
+
key: string;
|
|
2517
|
+
/** Registered chart type used to draw it ('line', 'histogram', 'area', ...). */
|
|
2518
|
+
type: SeriesType;
|
|
2519
|
+
/** Legend title. */
|
|
2520
|
+
title: string;
|
|
2521
|
+
/** Style overrides merged onto the chart type's defaults. */
|
|
2522
|
+
style?: SeriesStyle;
|
|
2523
|
+
/** Price axis for this plot. Defaults to 'right'. */
|
|
2524
|
+
priceScaleId?: PriceScaleId;
|
|
2559
2525
|
/**
|
|
2560
|
-
*
|
|
2561
|
-
*
|
|
2562
|
-
*
|
|
2526
|
+
* Value formatting for the axis and crosshair tag of the scale this plot maps
|
|
2527
|
+
* to: `percent` for a ratio study, `volume` for a cumulative one, `custom` for
|
|
2528
|
+
* anything else.
|
|
2529
|
+
*
|
|
2530
|
+
* Like `style.precision`, this is a property of the **price scale**, not of the
|
|
2531
|
+
* series, so it belongs to a plot that owns its pane. Setting it on an
|
|
2532
|
+
* `'onchart'` plot reformats the instrument's own axis, which is almost never
|
|
2533
|
+
* what a study wants.
|
|
2534
|
+
*
|
|
2535
|
+
* `percent` suffixes the value as it stands and does not scale it, so a study
|
|
2536
|
+
* returning a 0..1 fraction should keep returning it and read `0.62%`. Scaling
|
|
2537
|
+
* inside `calc` to make the axis read better changes the plotted value, and the
|
|
2538
|
+
* legend, the crosshair and every downstream calculation with it.
|
|
2563
2539
|
*/
|
|
2564
|
-
|
|
2540
|
+
priceFormat?: PriceFormat;
|
|
2565
2541
|
/**
|
|
2566
|
-
*
|
|
2567
|
-
*
|
|
2542
|
+
* Draw this one plot on the price pane even though the indicator owns a pane
|
|
2543
|
+
* of its own. An oscillator that also wants a signal
|
|
2544
|
+
* band or a stop line sitting on the candles is the case: the study belongs in
|
|
2545
|
+
* its own pane, one of its columns belongs on price, and splitting it into two
|
|
2546
|
+
* indicators would make the user configure the same inputs twice.
|
|
2547
|
+
*
|
|
2548
|
+
* Ignored for an `'onchart'` descriptor, which is already on the price pane.
|
|
2568
2549
|
*/
|
|
2569
|
-
|
|
2570
|
-
/** Plate opacity, 0..1. Default 0.8, matching the hover plate. */
|
|
2571
|
-
backgroundOpacity?: number;
|
|
2572
|
-
/** Plate color. Defaults to the theme background. */
|
|
2573
|
-
backgroundColor?: string;
|
|
2574
|
-
}
|
|
2575
|
-
interface PaneLegendOptions {
|
|
2576
|
-
/** Stable id; buttons hit-test as `${id}::close` etc. */
|
|
2577
|
-
id: string;
|
|
2578
|
-
/** Bold source name, e.g. `RSI`. */
|
|
2579
|
-
title: string;
|
|
2580
|
-
/** Dimmed parameter summary after the title, e.g. `14 close`. */
|
|
2581
|
-
params?: string;
|
|
2582
|
-
/** Swatch color; omitted draws no swatch. */
|
|
2583
|
-
color?: string;
|
|
2550
|
+
overlay?: boolean;
|
|
2584
2551
|
/**
|
|
2585
|
-
*
|
|
2586
|
-
*
|
|
2587
|
-
*
|
|
2552
|
+
* Draw the column shifted this many bars to the right (negative: left). The
|
|
2553
|
+
* column itself stays one value per bar and `calc` returns exactly what it
|
|
2554
|
+
* always did; only where each value is painted moves. Positive is what a
|
|
2555
|
+
* displaced cloud or a projected channel wants: the last `offset` values land
|
|
2556
|
+
* in the right margin, past the newest candle, where no bar exists to hold
|
|
2557
|
+
* them. It shifts the drawn series only. A fill between two plots with the
|
|
2558
|
+
* same offset follows; the legend reads the value drawn under the cursor.
|
|
2588
2559
|
*/
|
|
2589
|
-
|
|
2590
|
-
/** Vertical slot on the pane (0 = topmost). */
|
|
2591
|
-
row?: number;
|
|
2560
|
+
offset?: number;
|
|
2592
2561
|
/**
|
|
2593
|
-
*
|
|
2594
|
-
*
|
|
2595
|
-
|
|
2596
|
-
|
|
2597
|
-
|
|
2598
|
-
*
|
|
2562
|
+
* Settings key holding this plot's color, so a settings change restyles the
|
|
2563
|
+
* series without a full rebuild.
|
|
2564
|
+
*/
|
|
2565
|
+
colorKey?: string;
|
|
2566
|
+
/**
|
|
2567
|
+
* Four `calc` keys to draw this plot as bar-shaped elements instead of one
|
|
2568
|
+
* value per bar: candles, hollow candles, OHLC bars, high-low.
|
|
2599
2569
|
*
|
|
2600
|
-
*
|
|
2601
|
-
*
|
|
2570
|
+
* A single column cannot express those at all, and the alternative (a second
|
|
2571
|
+
* result shape for `calc`) would fork the contract every descriptor and every
|
|
2572
|
+
* helper is written against. Naming four columns inside the *same*
|
|
2573
|
+
* `IndicatorValues` keeps one shape: a smoothed Heikin-Ashi overlay, a
|
|
2574
|
+
* higher-timeframe candle, a synthetic spread instrument each return four
|
|
2575
|
+
* ordinary columns and point at them from here.
|
|
2576
|
+
*
|
|
2577
|
+
* The named columns must all exist and be bar-aligned, or `addIndicator`
|
|
2578
|
+
* throws. `key` stays the series identity and the legend reading falls back to
|
|
2579
|
+
* the `close` column.
|
|
2602
2580
|
*/
|
|
2603
|
-
|
|
2604
|
-
|
|
2605
|
-
|
|
2606
|
-
|
|
2607
|
-
|
|
2608
|
-
|
|
2609
|
-
|
|
2610
|
-
|
|
2611
|
-
|
|
2612
|
-
|
|
2613
|
-
|
|
2614
|
-
|
|
2615
|
-
|
|
2616
|
-
|
|
2617
|
-
|
|
2581
|
+
ohlc?: {
|
|
2582
|
+
open: string;
|
|
2583
|
+
high: string;
|
|
2584
|
+
low: string;
|
|
2585
|
+
close: string;
|
|
2586
|
+
};
|
|
2587
|
+
/**
|
|
2588
|
+
* Per-bar colour, for plots whose meaning changes bar to bar — a MACD
|
|
2589
|
+
* histogram is four colours by sign and direction, a conditional study two.
|
|
2590
|
+
* Return `undefined` to fall back to the plot's own colour.
|
|
2591
|
+
*
|
|
2592
|
+
* Reaches the renderer as `Bar.color`, so every Family-A plot type honours
|
|
2593
|
+
* it: histogram, column, candles, OHLC bars, line, step and area.
|
|
2594
|
+
*/
|
|
2595
|
+
colorBy?(ctx: {
|
|
2596
|
+
value: number;
|
|
2597
|
+
index: number;
|
|
2598
|
+
values: IndicatorValues;
|
|
2599
|
+
settings: IndicatorSettings;
|
|
2600
|
+
}): string | undefined;
|
|
2601
|
+
/**
|
|
2602
|
+
* Per-bar colour split three ways, for a candle plot whose wick or border
|
|
2603
|
+
* should not follow its body: a solid wick over a translucent body, a
|
|
2604
|
+
* border in the trend colour. Takes precedence over `colorBy` for the parts
|
|
2605
|
+
* it names; a part it leaves undefined falls back to `colorBy`, then to the
|
|
2606
|
+
* plot's own colour. A value plot (line, histogram, column) reads `body` only.
|
|
2607
|
+
*/
|
|
2608
|
+
colorParts?(ctx: {
|
|
2609
|
+
value: number;
|
|
2610
|
+
index: number;
|
|
2611
|
+
values: IndicatorValues;
|
|
2612
|
+
settings: IndicatorSettings;
|
|
2613
|
+
}): PlotBarColor | undefined;
|
|
2618
2614
|
}
|
|
2619
|
-
|
|
2620
|
-
|
|
2621
|
-
|
|
2622
|
-
|
|
2623
|
-
|
|
2624
|
-
|
|
2625
|
-
|
|
2626
|
-
|
|
2627
|
-
|
|
2628
|
-
|
|
2629
|
-
|
|
2630
|
-
|
|
2631
|
-
|
|
2632
|
-
|
|
2633
|
-
setValue(text: string, color?: string): void;
|
|
2634
|
-
/** One reading per plot, each in its own color. */
|
|
2635
|
-
setValues(values: readonly LegendValue[]): void;
|
|
2636
|
-
setOptions(patch: Partial<PaneLegendOptions>): void;
|
|
2637
|
-
/** Resolve the host's status data for this frame; `{}` when it has none. */
|
|
2638
|
-
private _status;
|
|
2639
|
-
options(): PaneLegendOptions;
|
|
2640
|
-
draw(ctx: CanvasRenderingContext2D, rc: PrimitiveRenderContext): void;
|
|
2641
|
-
hitTest(x: number, y: number): PrimitiveHit | null;
|
|
2615
|
+
/** A horizontal reference level (RSI 70/30, Stochastic 80/20, a zero line). */
|
|
2616
|
+
interface IndicatorLevel {
|
|
2617
|
+
price: number;
|
|
2618
|
+
color?: string;
|
|
2619
|
+
title?: string;
|
|
2620
|
+
/** Legacy two-state dash switch. `lineStyle` wins when both are given. */
|
|
2621
|
+
dashed?: boolean;
|
|
2622
|
+
lineWidth?: number;
|
|
2623
|
+
lineStyle?: IndicatorLineStyle;
|
|
2624
|
+
}
|
|
2625
|
+
/** One end of an indicator drawing: a time on the shared axis, a price on the pane's scale. */
|
|
2626
|
+
interface DrawAnchor {
|
|
2627
|
+
time: number;
|
|
2628
|
+
price: number;
|
|
2642
2629
|
}
|
|
2643
|
-
|
|
2644
2630
|
/**
|
|
2645
|
-
*
|
|
2646
|
-
*
|
|
2631
|
+
* A free-standing shape an indicator paints in its own pane, anchored to time
|
|
2632
|
+
* and price rather than to a bar index.
|
|
2633
|
+
*
|
|
2634
|
+
* Plots, levels and markers each answer a different question and none of them
|
|
2635
|
+
* answers this one: a pivot-to-pivot trendline, a supply zone, an order block,
|
|
2636
|
+
* a measured-move projection are all geometry between two arbitrary points, and
|
|
2637
|
+
* a column of one value per bar cannot express any of them. Anchors are times,
|
|
2638
|
+
* so a shape stays put when history is paged in and every logical index shifts.
|
|
2639
|
+
*/
|
|
2640
|
+
type IndicatorDrawing = {
|
|
2641
|
+
kind: 'line';
|
|
2642
|
+
from: DrawAnchor;
|
|
2643
|
+
to: DrawAnchor;
|
|
2644
|
+
color?: string;
|
|
2645
|
+
lineWidth?: number;
|
|
2646
|
+
lineStyle?: IndicatorLineStyle;
|
|
2647
|
+
/** Continue the line past its anchor to the pane edge. */
|
|
2648
|
+
extendLeft?: boolean;
|
|
2649
|
+
extendRight?: boolean;
|
|
2650
|
+
} | {
|
|
2651
|
+
kind: 'box';
|
|
2652
|
+
from: DrawAnchor;
|
|
2653
|
+
to: DrawAnchor;
|
|
2654
|
+
/** Border colour. Omit `fillColor` to draw an outline only. */
|
|
2655
|
+
color?: string;
|
|
2656
|
+
fillColor?: string;
|
|
2657
|
+
/** Fill alpha, 0..1. Defaults to 0.12. */
|
|
2658
|
+
opacity?: number;
|
|
2659
|
+
lineWidth?: number;
|
|
2660
|
+
/** Caption drawn on a plate at the centre of the box; `\n` splits lines. */
|
|
2661
|
+
text?: string;
|
|
2662
|
+
textColor?: string;
|
|
2663
|
+
/**
|
|
2664
|
+
* Detail shown on a plate while the pointer rests on the box, and gone
|
|
2665
|
+
* when it leaves; `\n` splits lines. A zone that carries its size, its
|
|
2666
|
+
* age and what formed it cannot print all of that on the box without
|
|
2667
|
+
* hiding the candles under it, so the caption names it and this explains
|
|
2668
|
+
* it. The box becomes hit-testable, and `id` (or the tooltip text) is
|
|
2669
|
+
* what `subscribeClick` reports for it.
|
|
2670
|
+
*/
|
|
2671
|
+
tooltip?: string;
|
|
2672
|
+
/** Hit id, for `subscribeClick`. Defaults to the tooltip text. */
|
|
2673
|
+
id?: string;
|
|
2674
|
+
} | {
|
|
2675
|
+
kind: 'label';
|
|
2676
|
+
at: DrawAnchor;
|
|
2677
|
+
/** `\n` splits lines. */
|
|
2678
|
+
text: string;
|
|
2679
|
+
/** Plate fill. */
|
|
2680
|
+
color?: string;
|
|
2681
|
+
textColor?: string;
|
|
2682
|
+
/** Which edge of the plate sits on the anchor. Defaults to 'center'. */
|
|
2683
|
+
align?: 'left' | 'center' | 'right';
|
|
2684
|
+
/** Hover detail, as on a box. */
|
|
2685
|
+
tooltip?: string;
|
|
2686
|
+
/** Hit id, for `subscribeClick`. Defaults to the tooltip text. */
|
|
2687
|
+
id?: string;
|
|
2688
|
+
} | {
|
|
2689
|
+
kind: 'polyline';
|
|
2690
|
+
points: readonly DrawAnchor[];
|
|
2691
|
+
color?: string;
|
|
2692
|
+
lineWidth?: number;
|
|
2693
|
+
/** Close the path back to the first point (a triangle, a wedge). */
|
|
2694
|
+
closed?: boolean;
|
|
2695
|
+
fillColor?: string;
|
|
2696
|
+
/** Fill alpha, 0..1. Defaults to 0.12. */
|
|
2697
|
+
opacity?: number;
|
|
2698
|
+
};
|
|
2699
|
+
/** `calc` output: one array per plot key, aligned 1:1 with the input bars. */
|
|
2700
|
+
type IndicatorValues = Record<string, readonly (number | null)[]>;
|
|
2701
|
+
/** Per-instance scratch owned by the descriptor (Tier-2 data lands here). */
|
|
2702
|
+
type IndicatorStore = Record<string, unknown>;
|
|
2703
|
+
/**
|
|
2704
|
+
* The fourth, optional argument to `calc` (and the sixth to `calcTail`): what
|
|
2705
|
+
* the calculation cannot read off the bars themselves.
|
|
2647
2706
|
*
|
|
2648
|
-
*
|
|
2649
|
-
*
|
|
2650
|
-
*
|
|
2651
|
-
* moment the pane is panned or the scale re-fits.
|
|
2707
|
+
* It is optional so that every descriptor written against `calc(bars, settings,
|
|
2708
|
+
* store)` keeps its exact signature and its exact behaviour, which is the whole
|
|
2709
|
+
* point: a calculation that ignores the context computes what it always did.
|
|
2652
2710
|
*/
|
|
2653
|
-
interface
|
|
2654
|
-
/** Price the top stop sits at. Omitted: the band's own highest value. */
|
|
2655
|
-
topValue?: number;
|
|
2656
|
-
/** Price the bottom stop sits at. Omitted: the band's own lowest value. */
|
|
2657
|
-
bottomValue?: number;
|
|
2658
|
-
topColor: string;
|
|
2659
|
-
bottomColor: string;
|
|
2660
|
-
}
|
|
2661
|
-
interface IndicatorFillOptions {
|
|
2662
|
-
/** Fill colour where the first series is above the second. */
|
|
2663
|
-
colorUp: string;
|
|
2664
|
-
/** Fill colour where the second is above the first. */
|
|
2665
|
-
colorDown: string;
|
|
2666
|
-
/** 0..1. Defaults to 0.12 — a band must not drown the candles it sits behind. */
|
|
2667
|
-
opacity?: number;
|
|
2711
|
+
interface IndicatorCalcContext {
|
|
2668
2712
|
/**
|
|
2669
|
-
*
|
|
2670
|
-
*
|
|
2671
|
-
* Unset leaves the two-colour fill exactly as it was.
|
|
2713
|
+
* Where the last bar stands, so a study can act once per bar rather than once
|
|
2714
|
+
* per tick, or refuse to signal off a bar that is still moving.
|
|
2672
2715
|
*/
|
|
2673
|
-
|
|
2716
|
+
barState: {
|
|
2717
|
+
/** The most recent update appended a bar rather than replacing one. */
|
|
2718
|
+
isNew: boolean;
|
|
2719
|
+
/** The last bar has closed: its interval has elapsed on the chart clock. */
|
|
2720
|
+
isConfirmed: boolean;
|
|
2721
|
+
/** A live feed is driving updates, rather than a one-off history load. */
|
|
2722
|
+
isRealtime: boolean;
|
|
2723
|
+
/** Index of the last bar, `bars.length - 1` (-1 when there are none). */
|
|
2724
|
+
lastIndex: number;
|
|
2725
|
+
};
|
|
2726
|
+
/** The instrument, when the host knows one. See `IndicatorAttachContext`. */
|
|
2727
|
+
symbol?: string;
|
|
2728
|
+
/** The timeframe (`'5m'`, `'1d'`), on the same terms as `symbol`. */
|
|
2729
|
+
interval?: string;
|
|
2730
|
+
/** The chart's IANA zone, the calendar its axis is labelled in. */
|
|
2731
|
+
timezone: string;
|
|
2732
|
+
/** Chart wall clock in UTC seconds, the clock the countdown row reads. */
|
|
2733
|
+
now(): number;
|
|
2734
|
+
/**
|
|
2735
|
+
* The instrument's tick size, from the **price pane's** `minMove`.
|
|
2736
|
+
*
|
|
2737
|
+
* The price pane and not the indicator's own, because `calc` runs on the
|
|
2738
|
+
* instrument's bars whichever pane the plot lands in, and a study pane is not
|
|
2739
|
+
* quoted in the instrument's tick: an RSI is a dimensionless 0..100 band, so
|
|
2740
|
+
* its scale carries no tick at all to read.
|
|
2741
|
+
*
|
|
2742
|
+
* `undefined` when the host has not told the chart what it is, which is the
|
|
2743
|
+
* honest answer rather than a guessed 0.01: an indicator sizing a range in
|
|
2744
|
+
* ticks has to tell "one paisa" apart from "nobody said".
|
|
2745
|
+
*/
|
|
2746
|
+
tickSize?: number;
|
|
2674
2747
|
}
|
|
2675
|
-
/**
|
|
2676
|
-
interface
|
|
2677
|
-
|
|
2748
|
+
/** What an alert's `when` predicate is handed, for the bar it is judging. */
|
|
2749
|
+
interface IndicatorAlertContext {
|
|
2750
|
+
bars: readonly Bar[];
|
|
2751
|
+
values: IndicatorValues;
|
|
2752
|
+
settings: Readonly<IndicatorSettings>;
|
|
2753
|
+
/** The bar being evaluated. */
|
|
2678
2754
|
index: number;
|
|
2679
|
-
|
|
2680
|
-
|
|
2755
|
+
}
|
|
2756
|
+
/**
|
|
2757
|
+
* A condition the runtime watches, declared by the descriptor rather than wired
|
|
2758
|
+
* up by the host: the indicator is the only thing that knows what a crossover of
|
|
2759
|
+
* its own columns means.
|
|
2760
|
+
*
|
|
2761
|
+
* Evaluated once per bar, for bars that are new since the last evaluation, so
|
|
2762
|
+
* adding the indicator to a loaded chart fires nothing for history.
|
|
2763
|
+
*/
|
|
2764
|
+
interface IndicatorAlertSpec {
|
|
2765
|
+
/** Stable within the descriptor, e.g. `'cross-up'`. */
|
|
2766
|
+
id: string;
|
|
2767
|
+
/** Short human label, e.g. `'MACD crossed up'`. */
|
|
2768
|
+
title: string;
|
|
2681
2769
|
/**
|
|
2682
|
-
*
|
|
2683
|
-
*
|
|
2684
|
-
*
|
|
2685
|
-
*
|
|
2770
|
+
* Longer text for a notification; defaults to `title`. A function is handed
|
|
2771
|
+
* the same context `when` judged, so the message can carry the bar's own
|
|
2772
|
+
* numbers: the price it crossed at, the histogram reading, a JSON body for a
|
|
2773
|
+
* webhook. It runs only for a bar `when` accepted.
|
|
2686
2774
|
*/
|
|
2687
|
-
|
|
2775
|
+
message?: string | ((ctx: IndicatorAlertContext) => string);
|
|
2776
|
+
when(ctx: IndicatorAlertContext): boolean;
|
|
2688
2777
|
}
|
|
2689
|
-
|
|
2690
|
-
|
|
2691
|
-
|
|
2692
|
-
|
|
2693
|
-
|
|
2694
|
-
|
|
2695
|
-
|
|
2696
|
-
|
|
2697
|
-
|
|
2698
|
-
|
|
2699
|
-
|
|
2700
|
-
|
|
2701
|
-
|
|
2702
|
-
setOptions(patch: Partial<IndicatorFillOptions>): void;
|
|
2703
|
-
setVisible(on: boolean): void;
|
|
2704
|
-
draw(ctx: CanvasRenderingContext2D, rc: PrimitiveRenderContext): void;
|
|
2778
|
+
/**
|
|
2779
|
+
* Thrown by a `calc` (or any hook) to say its inputs cannot produce a study,
|
|
2780
|
+
* the way a script language's runtime error does: a period at or below zero, a
|
|
2781
|
+
* fast length above the slow one, a benchmark the provider cannot serve.
|
|
2782
|
+
*
|
|
2783
|
+
* Any error out of a recompute is caught by the runtime and published on the
|
|
2784
|
+
* instance's data status as `{ state: 'error' }`, so the chart keeps drawing
|
|
2785
|
+
* every other indicator and a host can show the reason beside this one. This
|
|
2786
|
+
* class exists so a descriptor can throw a **named** condition and a host can
|
|
2787
|
+
* tell a bad input, which the user can fix, from a bug, which they cannot.
|
|
2788
|
+
*/
|
|
2789
|
+
declare class IndicatorInputError extends Error {
|
|
2790
|
+
constructor(message: string);
|
|
2705
2791
|
}
|
|
2706
|
-
|
|
2707
2792
|
/**
|
|
2708
|
-
*
|
|
2709
|
-
* live chart objects: one series per plot, optional reference levels, an
|
|
2710
|
-
* optional fixed pane range — and recomputes them when the source data or the
|
|
2711
|
-
* settings change.
|
|
2793
|
+
* Bars of another instrument or interval, supplied by the host on request.
|
|
2712
2794
|
*
|
|
2713
|
-
*
|
|
2714
|
-
*
|
|
2795
|
+
* The engine is handed one symbol's bars and owns no transport, so a study
|
|
2796
|
+
* that compares against a benchmark, or a Tier-2 provider that needs a second
|
|
2797
|
+
* series, asks the host through this and the host answers from wherever it
|
|
2798
|
+
* keeps history. `from` and `to` are UTC seconds; `signal` is aborted when the
|
|
2799
|
+
* instance is removed or its settings change, so a provider can drop the
|
|
2800
|
+
* request rather than answer into the void.
|
|
2715
2801
|
*/
|
|
2716
|
-
|
|
2717
|
-
|
|
2718
|
-
|
|
2719
|
-
|
|
2720
|
-
|
|
2721
|
-
|
|
2802
|
+
interface IndicatorBarsRequest {
|
|
2803
|
+
symbol: string;
|
|
2804
|
+
exchange?: string;
|
|
2805
|
+
interval: string;
|
|
2806
|
+
from: number;
|
|
2807
|
+
to: number;
|
|
2808
|
+
signal?: AbortSignal;
|
|
2809
|
+
}
|
|
2810
|
+
type IndicatorBarsProvider = (request: IndicatorBarsRequest) => Promise<readonly Bar[]>;
|
|
2811
|
+
/** Payload of the `'indicator:alert'` event on the chart's own bus. */
|
|
2812
|
+
interface IndicatorAlertPayload extends AlertEventPayload {
|
|
2813
|
+
/** Descriptor id, e.g. `'macd'`. */
|
|
2814
|
+
indicatorId: string;
|
|
2815
|
+
/** Instance id, so a host can tell three EMAs apart. */
|
|
2816
|
+
instanceId: string;
|
|
2817
|
+
message: string;
|
|
2818
|
+
}
|
|
2819
|
+
/** Optional instrument identity and capability supplied by the host. */
|
|
2820
|
+
interface ChartDataContext {
|
|
2821
|
+
symbol?: string;
|
|
2822
|
+
exchange?: string;
|
|
2823
|
+
interval?: string;
|
|
2824
|
+
/** Instrument capability, independent of readings: false unsupported, absent unknown. */
|
|
2825
|
+
hasOpenInterest?: boolean;
|
|
2826
|
+
}
|
|
2827
|
+
/** Source identity changed, or the available source-bar range changed. */
|
|
2828
|
+
type IndicatorDataChange = 'context' | 'range';
|
|
2829
|
+
/** Observable state of an indicator's external data lifecycle. */
|
|
2830
|
+
type IndicatorDataStatus = {
|
|
2831
|
+
state: 'loading' | 'ready' | 'empty' | 'unsupported';
|
|
2832
|
+
} | {
|
|
2833
|
+
state: 'error';
|
|
2834
|
+
error: unknown;
|
|
2835
|
+
};
|
|
2836
|
+
/** What an indicator's `attach` lifecycle can reach. */
|
|
2837
|
+
interface IndicatorAttachContext {
|
|
2838
|
+
/** Optional host identity, independent of the indicator's own settings. */
|
|
2722
2839
|
dataContext?(): Readonly<ChartDataContext> | undefined;
|
|
2840
|
+
/** Read bars and identity again when the host publishes a change. */
|
|
2723
2841
|
subscribeDataChanges?(listener: (change: IndicatorDataChange) => void): () => void;
|
|
2724
|
-
/**
|
|
2725
|
-
|
|
2726
|
-
|
|
2727
|
-
|
|
2728
|
-
|
|
2729
|
-
|
|
2730
|
-
|
|
2731
|
-
|
|
2732
|
-
|
|
2733
|
-
|
|
2734
|
-
|
|
2735
|
-
|
|
2736
|
-
|
|
2737
|
-
/** Axis/crosshair formatting for the scale this plot maps to. */
|
|
2738
|
-
priceFormat?: PriceFormat): SeriesApi;
|
|
2842
|
+
/** Publish status and an explicit retry action for this instance. */
|
|
2843
|
+
setDataStatus?(status: IndicatorDataStatus): void;
|
|
2844
|
+
setDataRetry?(retry: (() => void) | null): void;
|
|
2845
|
+
/** Instance lifetime. Aborted on removal, preserved across style changes. */
|
|
2846
|
+
signal?: AbortSignal;
|
|
2847
|
+
/** Current settings (live — read at call time, not captured). */
|
|
2848
|
+
settings(): Readonly<IndicatorSettings>;
|
|
2849
|
+
/** The chart's current source bars. */
|
|
2850
|
+
bars(): readonly Bar[];
|
|
2851
|
+
/** Re-run `calc` and repaint — call when external data arrives. */
|
|
2852
|
+
requestRecompute(): void;
|
|
2853
|
+
/** Scratch this instance owns; the same object `calc` receives. */
|
|
2854
|
+
store: IndicatorStore;
|
|
2739
2855
|
/**
|
|
2740
|
-
*
|
|
2741
|
-
*
|
|
2742
|
-
*
|
|
2856
|
+
* The instrument the chart is showing, when the host knows it.
|
|
2857
|
+
*
|
|
2858
|
+
* Hosts can supply this through `IndicatorHost` or Chart's explicit data
|
|
2859
|
+
* context. Without a configured identity it stays undefined. External
|
|
2860
|
+
* studies read `dataContext` to include the exchange as well.
|
|
2743
2861
|
*/
|
|
2744
|
-
|
|
2745
|
-
|
|
2746
|
-
|
|
2747
|
-
|
|
2748
|
-
|
|
2749
|
-
|
|
2750
|
-
|
|
2751
|
-
|
|
2752
|
-
|
|
2753
|
-
|
|
2754
|
-
|
|
2755
|
-
|
|
2756
|
-
|
|
2757
|
-
|
|
2862
|
+
symbol?(): string | undefined;
|
|
2863
|
+
/** The chart's timeframe (`'5m'`, `'1d'`), on the same terms as `symbol`. */
|
|
2864
|
+
interval?(): string | undefined;
|
|
2865
|
+
/** The chart's IANA zone, the one its axis is labelled in. */
|
|
2866
|
+
timezone?(): string;
|
|
2867
|
+
/** Chart wall clock in UTC seconds, the same clock the countdown row uses. */
|
|
2868
|
+
now?(): number;
|
|
2869
|
+
/**
|
|
2870
|
+
* Ask the host for another instrument's (or interval's) bars. Always present
|
|
2871
|
+
* under `chart.addIndicator`; it rejects when the host has registered no
|
|
2872
|
+
* provider (`chart.setBarsProvider`), so a study can treat the rejection as
|
|
2873
|
+
* "unsupported here" and say so through `setDataStatus`.
|
|
2874
|
+
*/
|
|
2875
|
+
requestBars?(request: IndicatorBarsRequest): Promise<readonly Bar[]>;
|
|
2876
|
+
/** The pane this instance drew into. Moves when panes are reordered. */
|
|
2877
|
+
paneIndex?(): number;
|
|
2878
|
+
/** Attach a primitive to this indicator's pane, and detach it again. */
|
|
2879
|
+
addPrimitive?(p: IPrimitive): void;
|
|
2880
|
+
removePrimitive?(p: IPrimitive): void;
|
|
2881
|
+
/**
|
|
2882
|
+
* Emit on the chart's own event bus, the one `chart.on(name, cb)` listens to.
|
|
2883
|
+
*
|
|
2884
|
+
* The declarative `alerts` slot covers a condition read off the bars; this is
|
|
2885
|
+
* the imperative half, for an indicator whose signal arrives from outside the
|
|
2886
|
+
* calculation entirely (a subscription its `attach` opened).
|
|
2887
|
+
*/
|
|
2888
|
+
emit?(event: string, payload: unknown): void;
|
|
2889
|
+
}
|
|
2890
|
+
/**
|
|
2891
|
+
* What `levels` is handed. It carries `bars` and `values` **and** spreads the
|
|
2892
|
+
* settings keys onto itself, so the built-ins written against the original
|
|
2893
|
+
* `levels(settings)` signature keep working unchanged: they read
|
|
2894
|
+
* `ctx.overbought` (or pass `ctx` to a `num(s, key, default)` helper) and find
|
|
2895
|
+
* exactly what they found before. A widened parameter is the only way a level
|
|
2896
|
+
* can be data-derived (yesterday's high, the session VWAP band), and that is a
|
|
2897
|
+
* whole class of level that could not be expressed at all before.
|
|
2898
|
+
*
|
|
2899
|
+
* The three data members are optional for the same backward-compatibility
|
|
2900
|
+
* reason, not because the runtime ever omits them: it always passes all three,
|
|
2901
|
+
* but a caller holding only a settings bag must still be able to invoke
|
|
2902
|
+
* `levels` directly. A descriptor that needs the data should default them
|
|
2903
|
+
* (`ctx.bars ?? []`).
|
|
2904
|
+
*
|
|
2905
|
+
* `settings`, `bars` and `values` are therefore reserved keys, the way
|
|
2906
|
+
* `timezone` already is in the settings a `calc` receives: an input declared
|
|
2907
|
+
* under one of those names is shadowed here.
|
|
2908
|
+
*/
|
|
2909
|
+
type IndicatorLevelContext = IndicatorSettings & {
|
|
2910
|
+
settings?: Readonly<IndicatorSettings>;
|
|
2911
|
+
bars?: readonly Bar[];
|
|
2912
|
+
values?: IndicatorValues;
|
|
2913
|
+
};
|
|
2914
|
+
interface IndicatorDescriptor {
|
|
2915
|
+
/** Registry key, e.g. `'macd'`. */
|
|
2916
|
+
id: string;
|
|
2917
|
+
/** Display name, e.g. `'MACD'`. */
|
|
2918
|
+
name: string;
|
|
2919
|
+
/** Grouping for a picker UI ('Trend', 'Momentum', 'Volume', 'Volatility'). */
|
|
2920
|
+
category?: string;
|
|
2921
|
+
/** `'onchart'` overlays the price pane; `'pane'` gets its own pane. */
|
|
2922
|
+
placement: 'onchart' | 'pane';
|
|
2923
|
+
inputs: readonly IndicatorInput[];
|
|
2924
|
+
plots: readonly IndicatorPlot[];
|
|
2758
2925
|
/**
|
|
2759
|
-
*
|
|
2760
|
-
*
|
|
2761
|
-
*
|
|
2926
|
+
* Shaded bands between pairs of plots — the Ichimoku cloud, a Bollinger
|
|
2927
|
+
* channel. A pair of lines is not the same picture as a filled region: the
|
|
2928
|
+
* fill is what makes "price is above the cloud" readable at a glance, and
|
|
2929
|
+
* which side leads is itself the signal, hence the two colours.
|
|
2762
2930
|
*/
|
|
2763
|
-
|
|
2764
|
-
/** Attach a corner-pinned summary grid to a pane, and detach it again. */
|
|
2765
|
-
addIndicatorTable(paneIndex: number): ChartTable;
|
|
2766
|
-
removeIndicatorTable(table: ChartTable): void;
|
|
2931
|
+
fills?: readonly IndicatorFillSpec[];
|
|
2767
2932
|
/**
|
|
2768
|
-
*
|
|
2769
|
-
*
|
|
2770
|
-
*
|
|
2933
|
+
* Full recompute over every bar. Must return arrays the same length as
|
|
2934
|
+
* `bars` (use `null` for warmup gaps — the line renderer breaks across them
|
|
2935
|
+
* and autoscale skips them).
|
|
2771
2936
|
*
|
|
2772
|
-
*
|
|
2773
|
-
*
|
|
2937
|
+
* Tier-1 indicators are pure functions of `(bars, settings)` and ignore
|
|
2938
|
+
* `store`. Tier-2 indicators — the ones with their own data — read the
|
|
2939
|
+
* external series their `attach` lifecycle put in `store`.
|
|
2774
2940
|
*/
|
|
2775
|
-
|
|
2776
|
-
removeIndicatorPrimitive?(primitive: IPrimitive): void;
|
|
2941
|
+
calc(bars: readonly Bar[], settings: Readonly<IndicatorSettings>, store: IndicatorStore, ctx?: IndicatorCalcContext): IndicatorValues;
|
|
2777
2942
|
/**
|
|
2778
|
-
*
|
|
2943
|
+
* Optional per-instance lifecycle, for indicators whose data is not derived
|
|
2944
|
+
* from the chart's bars (CVD, PCR, an external feed). Called once
|
|
2945
|
+
* when the instance is created; return a teardown function.
|
|
2779
2946
|
*
|
|
2780
|
-
*
|
|
2781
|
-
*
|
|
2947
|
+
* Fetch into `ctx.store`, then call `ctx.requestRecompute()` — `calc` runs
|
|
2948
|
+
* again and reads what you stored.
|
|
2782
2949
|
*/
|
|
2783
|
-
|
|
2784
|
-
/** Bars of the primary price series — the calculation input. */
|
|
2785
|
-
sourceBars(): readonly Bar[];
|
|
2786
|
-
/** Index of a fresh pane for an indicator that wants its own. */
|
|
2787
|
-
nextPaneIndex(): number;
|
|
2950
|
+
attach?(ctx: IndicatorAttachContext): (() => void) | void;
|
|
2788
2951
|
/**
|
|
2789
|
-
*
|
|
2790
|
-
*
|
|
2952
|
+
* Optional incremental path, called instead of `calc` when only the tail
|
|
2953
|
+
* changed (a live tick). Return values for indices `[fromIndex, bars.length)`
|
|
2954
|
+
* — the runtime splices them onto the previous result — or `null` to fall
|
|
2955
|
+
* back to a full `calc`.
|
|
2791
2956
|
*
|
|
2792
|
-
*
|
|
2793
|
-
*
|
|
2794
|
-
*
|
|
2957
|
+
* Without it every tick costs a full recompute. That is a few hundred
|
|
2958
|
+
* microseconds for one indicator over 50k bars, but it is O(n) per tick per
|
|
2959
|
+
* indicator, so implement this for anything meant to run in a busy live pane.
|
|
2795
2960
|
*/
|
|
2796
|
-
|
|
2961
|
+
calcTail?(bars: readonly Bar[], settings: Readonly<IndicatorSettings>, fromIndex: number, previous: IndicatorValues, store: IndicatorStore, ctx?: IndicatorCalcContext): IndicatorValues | null;
|
|
2797
2962
|
/**
|
|
2798
|
-
*
|
|
2799
|
-
*
|
|
2800
|
-
*
|
|
2963
|
+
* Optional bar-anchored signal markers — a named "Buy"/"Sell" plate, an arrow
|
|
2964
|
+
* at a crossover. Runs after every `calc`, so it reads the values it just
|
|
2965
|
+
* produced rather than recomputing anything.
|
|
2966
|
+
*
|
|
2967
|
+
* A plot cannot express this: a plot is a column of prices drawn as a line or
|
|
2968
|
+
* histogram, whereas a signal is a discrete event with a label. Returning `[]`
|
|
2969
|
+
* (when a `showLabels`-style input is off, say) clears the layer.
|
|
2801
2970
|
*/
|
|
2802
|
-
|
|
2803
|
-
|
|
2804
|
-
|
|
2805
|
-
|
|
2971
|
+
markers?(ctx: {
|
|
2972
|
+
bars: readonly Bar[];
|
|
2973
|
+
values: IndicatorValues;
|
|
2974
|
+
settings: Readonly<IndicatorSettings>;
|
|
2975
|
+
}): readonly SeriesMarker[];
|
|
2806
2976
|
/**
|
|
2807
|
-
*
|
|
2808
|
-
* or withdraw them with `null`. `owner` is the instance id: a host holds one
|
|
2809
|
-
* overlay at a time and only lets its current owner withdraw it, so a second
|
|
2810
|
-
* publisher taking over does not get cleared by the first one's teardown.
|
|
2977
|
+
* Optional summary grid pinned to a corner of the pane.
|
|
2811
2978
|
*
|
|
2812
|
-
*
|
|
2813
|
-
*
|
|
2814
|
-
*
|
|
2979
|
+
* Some studies are not a value per bar at all: a seasonality heatmap is a
|
|
2980
|
+
* matrix of monthly returns, a scoreboard is a handful of statistics. Those
|
|
2981
|
+
* have no place in `calc`, whose contract is one column per plot aligned to
|
|
2982
|
+
* the bars, so they come back through here instead. Runs after every `calc`.
|
|
2983
|
+
*
|
|
2984
|
+
* Return `null` (or a zero-row grid) to draw nothing, which is how a
|
|
2985
|
+
* `showTable`-style input should switch it off.
|
|
2815
2986
|
*/
|
|
2816
|
-
|
|
2817
|
-
|
|
2818
|
-
|
|
2987
|
+
table?(ctx: {
|
|
2988
|
+
bars: readonly Bar[];
|
|
2989
|
+
values: IndicatorValues;
|
|
2990
|
+
settings: Readonly<IndicatorSettings>;
|
|
2991
|
+
}): {
|
|
2992
|
+
rows: readonly (readonly TableCell[])[];
|
|
2993
|
+
options?: Partial<ChartTableOptions>;
|
|
2994
|
+
} | null;
|
|
2819
2995
|
/**
|
|
2820
|
-
*
|
|
2821
|
-
*
|
|
2822
|
-
*
|
|
2996
|
+
* Optional free-standing shapes drawn in the indicator's pane: trendlines
|
|
2997
|
+
* between pivots, supply and demand boxes, projection labels. Runs after
|
|
2998
|
+
* every `calc`, like `markers` and `table`, and the returned list replaces the
|
|
2999
|
+
* previous one wholesale, so returning `[]` clears the layer.
|
|
2823
3000
|
*/
|
|
2824
|
-
|
|
3001
|
+
draws?(ctx: {
|
|
3002
|
+
bars: readonly Bar[];
|
|
3003
|
+
values: IndicatorValues;
|
|
3004
|
+
settings: Readonly<IndicatorSettings>;
|
|
3005
|
+
}): readonly IndicatorDrawing[];
|
|
2825
3006
|
/**
|
|
2826
|
-
*
|
|
2827
|
-
*
|
|
3007
|
+
* Optional per-bar shading behind everything else in the indicator's pane: a
|
|
3008
|
+
* full-height column per bar, `null` where nothing should be shaded.
|
|
2828
3009
|
*
|
|
2829
|
-
*
|
|
2830
|
-
*
|
|
2831
|
-
*
|
|
3010
|
+
* A regime study answers "which state is the market in right now", and that is
|
|
3011
|
+
* a property of the whole bar, not a price. Drawn as a plot it would need a
|
|
3012
|
+
* value to sit at and would fight the pane's autoscale; as a column behind the
|
|
3013
|
+
* candles it reads at a glance and costs the scale nothing.
|
|
3014
|
+
*
|
|
3015
|
+
* Runs after every `calc`. Return `[]` to clear the layer.
|
|
2832
3016
|
*/
|
|
2833
|
-
|
|
3017
|
+
background?(ctx: {
|
|
3018
|
+
bars: readonly Bar[];
|
|
3019
|
+
values: IndicatorValues;
|
|
3020
|
+
settings: Readonly<IndicatorSettings>;
|
|
3021
|
+
}): readonly (string | null)[];
|
|
2834
3022
|
/**
|
|
2835
|
-
*
|
|
3023
|
+
* Optional recolouring of the **main price candles**, one entry per bar,
|
|
3024
|
+
* `null` to leave that bar with its own colour.
|
|
2836
3025
|
*
|
|
2837
|
-
*
|
|
2838
|
-
*
|
|
2839
|
-
* the
|
|
2840
|
-
*
|
|
2841
|
-
* and a price pane's tick alone misses the precision floor and the host's own
|
|
2842
|
-
* formatter, so a volume study read seven digits where its axis said `1.20M`.
|
|
3026
|
+
* Distinct from a plot's `colorBy`, which paints the indicator's own series: a
|
|
3027
|
+
* trend filter, a volatility regime or a higher-timeframe bias is a statement
|
|
3028
|
+
* about the price bars themselves, and drawing it as a second series beside
|
|
3029
|
+
* them says something weaker.
|
|
2843
3030
|
*
|
|
2844
|
-
*
|
|
2845
|
-
*
|
|
3031
|
+
* Only one indicator's colours can be on the candles at a time; the most
|
|
3032
|
+
* recent publisher wins, and publishers run in `addIndicator` order, so the
|
|
3033
|
+
* winner is the same one from frame to frame. Removing it, or hiding it,
|
|
3034
|
+
* restores the bars' own colours.
|
|
2846
3035
|
*/
|
|
2847
|
-
|
|
2848
|
-
|
|
2849
|
-
|
|
3036
|
+
barColors?(ctx: {
|
|
3037
|
+
bars: readonly Bar[];
|
|
3038
|
+
values: IndicatorValues;
|
|
3039
|
+
settings: Readonly<IndicatorSettings>;
|
|
3040
|
+
}): readonly (string | null)[];
|
|
3041
|
+
/**
|
|
3042
|
+
* Optional conditions the runtime watches on the descriptor's behalf, emitted
|
|
3043
|
+
* as `'indicator:alert'` on the chart's event bus with an
|
|
3044
|
+
* {@link IndicatorAlertPayload}. See {@link IndicatorAlertSpec}.
|
|
3045
|
+
*/
|
|
3046
|
+
alerts?: readonly IndicatorAlertSpec[];
|
|
3047
|
+
/**
|
|
3048
|
+
* Optional horizontal reference levels drawn in the indicator's pane.
|
|
3049
|
+
* Recomputed after every `calc`, so a level derived from the data (the
|
|
3050
|
+
* previous day's high) tracks it. See `IndicatorLevelContext` for why the
|
|
3051
|
+
* argument still reads as a settings bag.
|
|
3052
|
+
*/
|
|
3053
|
+
levels?(ctx: IndicatorLevelContext): readonly IndicatorLevel[];
|
|
3054
|
+
/**
|
|
3055
|
+
* Optional fixed price range for the indicator's own pane (RSI 0..100).
|
|
3056
|
+
* Applied only when the indicator creates its pane — two indicators sharing a
|
|
3057
|
+
* pane would otherwise fight over it.
|
|
3058
|
+
*/
|
|
3059
|
+
range?(settings: Readonly<IndicatorSettings>): {
|
|
2850
3060
|
min: number;
|
|
2851
3061
|
max: number;
|
|
2852
|
-
} | null
|
|
2853
|
-
}
|
|
2854
|
-
/** Public handle returned by `chart.addIndicator(...)`. */
|
|
2855
|
-
interface IndicatorApi {
|
|
2856
|
-
/** External data state, or null for a study without a managed lifecycle. */
|
|
2857
|
-
dataStatus(): Readonly<IndicatorDataStatus> | null;
|
|
2858
|
-
/** Observe changes; immediately receives the current managed status, if any. */
|
|
2859
|
-
subscribeDataStatus(listener: (status: Readonly<IndicatorDataStatus>) => void): () => void;
|
|
2860
|
-
/** Retry external history when the descriptor supplies a retry action. */
|
|
2861
|
-
retryData(): void;
|
|
2862
|
-
/** Unique instance id (several instances of one indicator can coexist). */
|
|
2863
|
-
readonly id: string;
|
|
2864
|
-
/** The descriptor id, e.g. `'macd'`. */
|
|
2865
|
-
readonly indicatorId: string;
|
|
2866
|
-
/** Display name. */
|
|
2867
|
-
readonly name: string;
|
|
2868
|
-
/** Pane the indicator drew into. */
|
|
2869
|
-
readonly paneIndex: number;
|
|
2870
|
-
/** Current settings (a copy). */
|
|
2871
|
-
settings(): IndicatorSettings;
|
|
2872
|
-
/** Merge a settings patch, recompute, and restyle. */
|
|
2873
|
-
setSettings(patch: Readonly<IndicatorSettings>): void;
|
|
2874
|
-
/** The series backing one plot key, for direct styling. */
|
|
2875
|
-
series(plotKey: string): SeriesApi | undefined;
|
|
2876
|
-
/** Latest computed values (a reference — do not mutate). */
|
|
2877
|
-
values(): IndicatorValues;
|
|
2878
|
-
/** Whether the plots are drawn (the legend's eye toggle). */
|
|
2879
|
-
visible(): boolean;
|
|
2880
|
-
/** Show or hide every plot without removing the instance. */
|
|
2881
|
-
setVisible(on: boolean): void;
|
|
2882
|
-
/** This indicator's legend row, or null if it has none. */
|
|
2883
|
-
legend(): PaneLegend | null;
|
|
2884
|
-
/** Refresh the legend readings for a bar index; omit for the latest bar. */
|
|
2885
|
-
updateLegendValues(index?: number): void;
|
|
2886
|
-
/** Remove every series, level, and legend row this indicator created. */
|
|
2887
|
-
remove(): void;
|
|
3062
|
+
} | null;
|
|
2888
3063
|
}
|
|
3064
|
+
/** Register an indicator descriptor. Later registrations of the same id win. */
|
|
3065
|
+
declare function registerIndicator(descriptor: IndicatorDescriptor): void;
|
|
3066
|
+
declare function getIndicator(id: string): IndicatorDescriptor;
|
|
3067
|
+
declare function hasIndicator(id: string): boolean;
|
|
3068
|
+
declare function registeredIndicators(): IndicatorDescriptor[];
|
|
3069
|
+
/** The descriptor's declared defaults as a settings object. */
|
|
3070
|
+
declare function indicatorDefaults(descriptor: IndicatorDescriptor): IndicatorSettings;
|
|
3071
|
+
/** Read one bar's value for a price source. */
|
|
3072
|
+
declare function sourceValue(bar: Bar, source: IndicatorSource): number;
|
|
3073
|
+
/** Read a whole bar array for a price source. */
|
|
3074
|
+
declare function sourceValues(bars: readonly Bar[], source: IndicatorSource): number[];
|
|
2889
3075
|
|
|
2890
3076
|
/**
|
|
2891
3077
|
* Serialisable chart state — the keystone the persistence-shaped features hang
|
|
@@ -2929,6 +3115,8 @@ interface SeriesState {
|
|
|
2929
3115
|
}
|
|
2930
3116
|
interface IndicatorState {
|
|
2931
3117
|
indicatorId: string;
|
|
3118
|
+
/** Stable workspace identity. Omitted by legacy states and reusable templates. */
|
|
3119
|
+
instanceId?: string;
|
|
2932
3120
|
settings: IndicatorSettings;
|
|
2933
3121
|
paneIndex: number;
|
|
2934
3122
|
/** Omitted by older layouts, which restore the indicator as visible. */
|
|
@@ -2947,6 +3135,7 @@ interface ChartState {
|
|
|
2947
3135
|
horzLines: boolean;
|
|
2948
3136
|
};
|
|
2949
3137
|
crosshairMode?: 'normal' | 'magnet';
|
|
3138
|
+
crosshairSnapToBar?: boolean;
|
|
2950
3139
|
panes?: PaneState[];
|
|
2951
3140
|
/** Informational: `restoreState` does not recreate these (it has no data). */
|
|
2952
3141
|
series?: SeriesState[];
|
|
@@ -2957,6 +3146,7 @@ interface ChartState {
|
|
|
2957
3146
|
* tier is loaded.
|
|
2958
3147
|
*/
|
|
2959
3148
|
drawings?: unknown;
|
|
3149
|
+
alerts?: AlertsDocument;
|
|
2960
3150
|
}
|
|
2961
3151
|
/** What `restoreState` actually applied, so a caller can finish the job. */
|
|
2962
3152
|
interface RestoreReport {
|
|
@@ -3848,6 +4038,8 @@ interface ChartOptions {
|
|
|
3848
4038
|
* bar under the cursor (price pane only).
|
|
3849
4039
|
*/
|
|
3850
4040
|
crosshairMode?: CrosshairMode;
|
|
4041
|
+
/** Snap the vertical crosshair to the nearest primary bar's center. Default false; independent of the price magnet. */
|
|
4042
|
+
crosshairSnapToBar?: boolean;
|
|
3851
4043
|
/**
|
|
3852
4044
|
* Optional chrome on the axis strips: the corner clock and the bar-close
|
|
3853
4045
|
* countdown. Both are off unless asked for, so a chart that omits this block
|
|
@@ -4013,6 +4205,8 @@ declare function compactVolume(v: number): string;
|
|
|
4013
4205
|
* floating tooltip. See `subscribeCrosshairMove`.
|
|
4014
4206
|
*/
|
|
4015
4207
|
interface CrosshairMoveEvent {
|
|
4208
|
+
/** Linked readouts have no physical pointer position and are not pointer gestures. */
|
|
4209
|
+
source?: 'linked';
|
|
4016
4210
|
/** UTC seconds of the hovered bar, or null when off the data / pointer left. */
|
|
4017
4211
|
time: number | null;
|
|
4018
4212
|
/** Logical index under the cursor, or null. */
|
|
@@ -4150,6 +4344,8 @@ interface ContextMenuTarget {
|
|
|
4150
4344
|
id: string | null;
|
|
4151
4345
|
/** Indicator instance id, when `kind` is 'indicator'. */
|
|
4152
4346
|
instanceId?: string;
|
|
4347
|
+
/** Exact plot key when a study's plotted series was hit rather than its legend. */
|
|
4348
|
+
plotKey?: string;
|
|
4153
4349
|
/** Series type, when `kind` is 'series'. */
|
|
4154
4350
|
seriesType?: SeriesType;
|
|
4155
4351
|
/** Which axis strip was hit, when `kind` is 'price-scale'. */
|
|
@@ -4235,6 +4431,7 @@ declare class Chart {
|
|
|
4235
4431
|
private _height;
|
|
4236
4432
|
private _hasFitContent;
|
|
4237
4433
|
private _crosshairMode;
|
|
4434
|
+
private _crosshairSnapToBar;
|
|
4238
4435
|
private _shortcuts;
|
|
4239
4436
|
private _trading;
|
|
4240
4437
|
private _pointerInside;
|
|
@@ -4317,6 +4514,7 @@ declare class Chart {
|
|
|
4317
4514
|
private readonly _firstDataId;
|
|
4318
4515
|
/** Handle + record of the primary price series (see `primarySeries`). */
|
|
4319
4516
|
private _primary;
|
|
4517
|
+
private readonly _seriesRecords;
|
|
4320
4518
|
private readonly _indicators;
|
|
4321
4519
|
private _dataContext;
|
|
4322
4520
|
private _barsProvider;
|
|
@@ -4336,6 +4534,7 @@ declare class Chart {
|
|
|
4336
4534
|
private _barColorAnchor;
|
|
4337
4535
|
/** Opaque drawing-tier payload, round-tripped through get/restoreState. */
|
|
4338
4536
|
private _drawingState;
|
|
4537
|
+
private _alertState;
|
|
4339
4538
|
/** Pane currently maximized, and the weights to restore when it un-maximizes. */
|
|
4340
4539
|
private _maximizedPane;
|
|
4341
4540
|
/** Legend rows per pane, so new ones stack below existing ones. */
|
|
@@ -4346,6 +4545,7 @@ declare class Chart {
|
|
|
4346
4545
|
private _loadingHistory;
|
|
4347
4546
|
private _clickCb;
|
|
4348
4547
|
private _crosshairCb;
|
|
4548
|
+
private _readoutTime;
|
|
4349
4549
|
private _pointerMoved;
|
|
4350
4550
|
/** While true, pointer gestures place anchors instead of panning. */
|
|
4351
4551
|
private _placementMode;
|
|
@@ -4406,6 +4606,8 @@ declare class Chart {
|
|
|
4406
4606
|
/** Call after a history-paging load resolves to re-enable the trigger. */
|
|
4407
4607
|
historyLoadComplete(): void;
|
|
4408
4608
|
get dataLayer(): DataLayer;
|
|
4609
|
+
/** Readonly source bars, without allocating a history copy on each live update. */
|
|
4610
|
+
primaryBars(): readonly Bar[];
|
|
4409
4611
|
get timeScale(): TimeScale;
|
|
4410
4612
|
/** Restore a saved logical range (e.g. preserve the user's zoom across a data reload). */
|
|
4411
4613
|
setVisibleLogicalRange(range: LogicalRange): void;
|
|
@@ -4536,6 +4738,8 @@ declare class Chart {
|
|
|
4536
4738
|
private _forgetIndicator;
|
|
4537
4739
|
/** Optional instrument identity supplied by the host, never inferred from bars. */
|
|
4538
4740
|
getDataContext(): Readonly<ChartDataContext> | undefined;
|
|
4741
|
+
/** Instrument capability from the host. A missing bar reading does not change it. */
|
|
4742
|
+
get hasOpenInterest(): boolean | undefined;
|
|
4539
4743
|
/** Clear the previous source bars before changing context, then load the new source. */
|
|
4540
4744
|
setDataContext(context: ChartDataContext | undefined): void;
|
|
4541
4745
|
/**
|
|
@@ -4607,9 +4811,17 @@ declare class Chart {
|
|
|
4607
4811
|
/**
|
|
4608
4812
|
* Subscribe to crosshair movement for an OHLC legend / tooltip. The callback
|
|
4609
4813
|
* fires with the hovered bar of the primary price series on every move, and
|
|
4610
|
-
* with all-null fields when the pointer leaves the plot.
|
|
4814
|
+
* with all-null fields when the pointer leaves the plot. A linked crosshair
|
|
4815
|
+
* also updates the readout, with source 'linked' and no pointer coordinates.
|
|
4611
4816
|
*/
|
|
4612
4817
|
subscribeCrosshairMove(cb: (e: CrosshairMoveEvent) => void): void;
|
|
4818
|
+
/**
|
|
4819
|
+
* Update the readout under a link group's separately drawn crosshair. The
|
|
4820
|
+
* physical pointer takes precedence. This never emits a pointer move event,
|
|
4821
|
+
* so hosts do not interpret it as drawing input or echo it to another group.
|
|
4822
|
+
*/
|
|
4823
|
+
setLinkedCrosshairIndex(index: number | null): void;
|
|
4824
|
+
private _readoutIndex;
|
|
4613
4825
|
/**
|
|
4614
4826
|
* Subscribe to drags of draggable primitives (order / SL / TP lines, drawing
|
|
4615
4827
|
* handles). Fires per move and on release.
|
|
@@ -4809,6 +5021,8 @@ declare class Chart {
|
|
|
4809
5021
|
axisChromeOptions(): AxisChromeOptions;
|
|
4810
5022
|
/** Crosshair behaviour ('normal' or 'magnet'). Set it via `applyOptions`. */
|
|
4811
5023
|
crosshairMode(): CrosshairMode;
|
|
5024
|
+
/** Whether the vertical crosshair snaps to an existing primary bar's center. */
|
|
5025
|
+
crosshairSnapToBar(): boolean;
|
|
4812
5026
|
/** The active palette. Swap it with `setTheme`. */
|
|
4813
5027
|
theme(): ChartTheme;
|
|
4814
5028
|
/**
|
|
@@ -4942,6 +5156,7 @@ declare class Chart {
|
|
|
4942
5156
|
timeFormatter?: ((utcSeconds: number, tickMark?: TickMarkType) => string) | undefined;
|
|
4943
5157
|
timezone?: string;
|
|
4944
5158
|
crosshairMode?: CrosshairMode;
|
|
5159
|
+
crosshairSnapToBar?: boolean;
|
|
4945
5160
|
}): void;
|
|
4946
5161
|
panes(): readonly Pane[];
|
|
4947
5162
|
/**
|
|
@@ -4971,12 +5186,17 @@ declare class Chart {
|
|
|
4971
5186
|
* (or `setVisibleLogicalRange`) once the series are populated.
|
|
4972
5187
|
*/
|
|
4973
5188
|
restoreState(state: unknown): RestoreReport;
|
|
5189
|
+
private _restoreState;
|
|
4974
5190
|
/**
|
|
4975
5191
|
* The opaque `drawings` slot in the chart state. The base engine only
|
|
4976
5192
|
* round-trips it; the drawing tier reads and writes it.
|
|
4977
5193
|
*/
|
|
4978
5194
|
drawingState(): unknown;
|
|
4979
5195
|
setDrawingState(value: unknown): void;
|
|
5196
|
+
/** Detached JSON state, also available when no alert controller is attached. */
|
|
5197
|
+
alertState(): AlertsDocument | undefined;
|
|
5198
|
+
/** Runtime snapshot. JSON safety of opaque payloads is checked when state is read. */
|
|
5199
|
+
setAlertState(document: AlertsDocument | undefined): void;
|
|
4980
5200
|
invalidate(build: (mask: InvalidateMask) => void): void;
|
|
4981
5201
|
/**
|
|
4982
5202
|
* Measure the container once more, a frame after construction.
|
|
@@ -5449,6 +5669,330 @@ declare class SvgContext {
|
|
|
5449
5669
|
private _unsupported;
|
|
5450
5670
|
}
|
|
5451
5671
|
|
|
5672
|
+
/**
|
|
5673
|
+
* Aligning a second instrument onto the primary series' bars.
|
|
5674
|
+
*
|
|
5675
|
+
* The x-axis is a gapless logical index over the times the shared DataLayer
|
|
5676
|
+
* holds (ARCHITECTURE.md §4.1, §5.3), so two instruments do not share a bar
|
|
5677
|
+
* index and cannot be laid side by side by position. They are matched by
|
|
5678
|
+
* timestamp, and the two directions of mismatch get opposite answers:
|
|
5679
|
+
*
|
|
5680
|
+
* - **A comparison bar with no primary bar is dropped.** The DataLayer merges
|
|
5681
|
+
* *every* series' times into one index space, so a time only the comparison
|
|
5682
|
+
* has would mint a new logical index: a column the primary instrument has no
|
|
5683
|
+
* candle for, inserted mid-chart, shifting every bar after it. That happens
|
|
5684
|
+
* for real (a different exchange's holiday calendar, a 24/7 instrument next
|
|
5685
|
+
* to an NSE one, a feed that emits a stray print), and warping the primary's
|
|
5686
|
+
* own axis to accommodate a comparison is never the right trade. The print is
|
|
5687
|
+
* counted in `dropped` so a host can say so rather than silently losing it.
|
|
5688
|
+
*
|
|
5689
|
+
* - **A primary bar with no comparison bar becomes whitespace**, which is a NaN
|
|
5690
|
+
* bar the line renderer breaks across, so the comparison shows a *gap*. The
|
|
5691
|
+
* alternative, carrying the last known value forward, draws a flat segment
|
|
5692
|
+
* through a session the instrument never traded and, worse, in percentage
|
|
5693
|
+
* mode it anchors the move on the far side of the gap to a print that does
|
|
5694
|
+
* not exist. Omitting the bar entirely is worse still: the renderer would
|
|
5695
|
+
* join the two sides with one straight line across the holiday.
|
|
5696
|
+
*
|
|
5697
|
+
* Matching is on the exact timestamp. Bar-open times are bucketed by the candle
|
|
5698
|
+
* builder (§10.2) and stored as UTC seconds (§4.0), so two instruments on the
|
|
5699
|
+
* same interval agree to the second; anything that does not agree is a
|
|
5700
|
+
* different interval, which no tolerance window could rescue.
|
|
5701
|
+
*/
|
|
5702
|
+
|
|
5703
|
+
/** What one alignment pass did, for a host that wants to report coverage. */
|
|
5704
|
+
interface ComparisonAlignment {
|
|
5705
|
+
/** Items handed to the comparison series: one per primary bar. */
|
|
5706
|
+
bars: number;
|
|
5707
|
+
/** Primary bars the comparison also traded (a value is drawn). */
|
|
5708
|
+
matched: number;
|
|
5709
|
+
/** Primary bars with no comparison print (drawn as a gap). */
|
|
5710
|
+
gaps: number;
|
|
5711
|
+
/** Comparison prints discarded for having no primary bar at that time. */
|
|
5712
|
+
dropped: number;
|
|
5713
|
+
}
|
|
5714
|
+
/**
|
|
5715
|
+
* Project `comparison` onto `primary`'s bars: one item per primary bar, in the
|
|
5716
|
+
* primary's order, so the result occupies exactly the logical indices the chart
|
|
5717
|
+
* already has and adds none of its own.
|
|
5718
|
+
*
|
|
5719
|
+
* Neither input is mutated and neither has to be sorted: matching goes through
|
|
5720
|
+
* a time map, which also collapses a repeated timestamp to its last item, the
|
|
5721
|
+
* same rule the DataLayer applies when it merges (`sortedUniqueByTime`).
|
|
5722
|
+
*/
|
|
5723
|
+
declare function alignToPrimary(primary: readonly Bar[], comparison: readonly SeriesDataItem[]): {
|
|
5724
|
+
items: SeriesDataItem[];
|
|
5725
|
+
alignment: ComparisonAlignment;
|
|
5726
|
+
};
|
|
5727
|
+
|
|
5728
|
+
/**
|
|
5729
|
+
* Multi-symbol comparison: put a second instrument on the primary one's pane
|
|
5730
|
+
* and read them together (NIFTY against BANKNIFTY, a stock against its index).
|
|
5731
|
+
*
|
|
5732
|
+
* Headless, in the spirit of `DrawingController` (src/draw/controller.ts) and
|
|
5733
|
+
* `ReplayController`: it owns the series, the alignment and the scales, and
|
|
5734
|
+
* ships no DOM, so the host draws its own symbol chips and legend rows from
|
|
5735
|
+
* `list()`.
|
|
5736
|
+
*
|
|
5737
|
+
* Three decisions carry the design:
|
|
5738
|
+
*
|
|
5739
|
+
* 1. **Each comparison owns a scale.** A free legacy overlay or left scale
|
|
5740
|
+
* preserves the first source's placement; additional sources use named
|
|
5741
|
+
* hidden scales so their different price units cannot affect one another.
|
|
5742
|
+
*
|
|
5743
|
+
* 2. **Comparability comes from the scale, not from the data.** The bars handed
|
|
5744
|
+
* over are stored as the instrument's own prices, so the legend, the
|
|
5745
|
+
* crosshair and any live update still speak in real prices. What makes the
|
|
5746
|
+
* lines readable together is the pane mode: `percentage` and
|
|
5747
|
+
* `indexed-to-100` give every scale its own baseline (its first visible
|
|
5748
|
+
* close, or an explicit common timestamp), and `_mirror` gives it the same
|
|
5749
|
+
* band of percent the primary's axis is showing. Without that mirror each
|
|
5750
|
+
* scale would autoscale to its own data and a 1% mover would look exactly
|
|
5751
|
+
* like a 10% mover, both filling the pane.
|
|
5752
|
+
*
|
|
5753
|
+
* 3. **Alignment is by timestamp** and lives in `./align`, which documents what
|
|
5754
|
+
* happens in each direction of mismatch.
|
|
5755
|
+
*
|
|
5756
|
+
* Each comparison owns a scale and baseline. Further instruments use keyed
|
|
5757
|
+
* hidden scales so their absolute prices cannot change another source's units.
|
|
5758
|
+
*/
|
|
5759
|
+
|
|
5760
|
+
/**
|
|
5761
|
+
* How the pane quotes prices while a comparison is on it. The two rebasing
|
|
5762
|
+
* modes are the reason the lines are comparable at all; `none` leaves the
|
|
5763
|
+
* pane's own mode alone, for a host that wants the raw overlay.
|
|
5764
|
+
*/
|
|
5765
|
+
type ComparisonMode = 'percentage' | 'indexed-to-100' | 'none';
|
|
5766
|
+
/** Independent first-visible closes, or the first visible timestamp shared by all visible sources. */
|
|
5767
|
+
type ComparisonBaseline = 'first-visible' | 'common';
|
|
5768
|
+
interface ComparisonOptions {
|
|
5769
|
+
/** Instrument label, e.g. 'BANKNIFTY'. Carried on the handle for the host's UI. */
|
|
5770
|
+
symbol: string;
|
|
5771
|
+
/** The instrument's own bars. Aligned to the primary series, see `./align`. */
|
|
5772
|
+
bars: readonly SeriesDataItem[];
|
|
5773
|
+
/** Line colour shorthand; `style.color` wins if both are given. */
|
|
5774
|
+
color?: string;
|
|
5775
|
+
/** Style overrides merged onto the chart type's defaults. */
|
|
5776
|
+
style?: SeriesStyle;
|
|
5777
|
+
/** Renderer for the comparison. Default 'line'. */
|
|
5778
|
+
type?: SeriesType;
|
|
5779
|
+
/** Pane to draw on. Default 0, the price pane. */
|
|
5780
|
+
paneIndex?: number;
|
|
5781
|
+
}
|
|
5782
|
+
interface ComparisonControllerOptions {
|
|
5783
|
+
/** Pane mode applied while any comparison is on it. Default 'percentage'. */
|
|
5784
|
+
mode?: ComparisonMode;
|
|
5785
|
+
/** Baseline policy. Default 'first-visible' preserves existing integrations. */
|
|
5786
|
+
baseline?: ComparisonBaseline;
|
|
5787
|
+
}
|
|
5788
|
+
/** What `addComparison` hands back: one instrument on the chart. */
|
|
5789
|
+
interface ComparisonHandle {
|
|
5790
|
+
readonly symbol: string;
|
|
5791
|
+
/**
|
|
5792
|
+
* The series this comparison draws through, for style patches and markers.
|
|
5793
|
+
* Data set on it directly skips alignment (use `setBars`), and removing it
|
|
5794
|
+
* directly leaves the pane rebased with nothing on it (use `remove`).
|
|
5795
|
+
*/
|
|
5796
|
+
readonly series: SeriesApi;
|
|
5797
|
+
readonly paneIndex: number;
|
|
5798
|
+
/** The hidden scale it maps to. Never the pane's own price axis. */
|
|
5799
|
+
priceScale(): PriceScale;
|
|
5800
|
+
/** How the last alignment against the primary's bars went. */
|
|
5801
|
+
alignment(): ComparisonAlignment;
|
|
5802
|
+
/** Eligible aligned bar in its own price units; null for gaps, suppressed baselines or forming replay candles. */
|
|
5803
|
+
barAt(time: number): Readonly<Bar> | null;
|
|
5804
|
+
/** Replace the instrument's bars (a longer history, a refreshed fetch). */
|
|
5805
|
+
setBars(bars: readonly SeriesDataItem[]): void;
|
|
5806
|
+
/** Take this instrument off the chart. Safe to call twice. */
|
|
5807
|
+
remove(): void;
|
|
5808
|
+
/** Every comparison on this chart, in the order they were added. */
|
|
5809
|
+
list(): readonly ComparisonHandle[];
|
|
5810
|
+
}
|
|
5811
|
+
/**
|
|
5812
|
+
* The slice of a pane the controller reads. Declared structurally, like
|
|
5813
|
+
* `ReplayViewport`, so nothing here depends on `Pane` beyond the two members
|
|
5814
|
+
* that decide where a comparison can go.
|
|
5815
|
+
*/
|
|
5816
|
+
interface ComparisonPane {
|
|
5817
|
+
readonly priceScale: PriceScale;
|
|
5818
|
+
series(): readonly {
|
|
5819
|
+
readonly scaleId: string;
|
|
5820
|
+
readonly style?: SeriesStyle;
|
|
5821
|
+
}[];
|
|
5822
|
+
}
|
|
5823
|
+
/**
|
|
5824
|
+
* The slice of the chart this controller needs. `Chart` satisfies it; declaring
|
|
5825
|
+
* it structurally keeps the controller testable against a stub.
|
|
5826
|
+
*/
|
|
5827
|
+
interface ComparisonChartHost {
|
|
5828
|
+
addSeries(type: SeriesType, options: AddSeriesOptions): SeriesApi;
|
|
5829
|
+
panes(): readonly ComparisonPane[];
|
|
5830
|
+
addPrimitive(primitive: IPrimitive, paneIndex?: number): void;
|
|
5831
|
+
removePrimitive(primitive: IPrimitive): void;
|
|
5832
|
+
primarySeries(): SeriesApi | null;
|
|
5833
|
+
/** Avoids allocating a primary history copy when the host provides it. */
|
|
5834
|
+
primaryBars?(): readonly Bar[];
|
|
5835
|
+
getVisibleLogicalRange?(): {
|
|
5836
|
+
from: number;
|
|
5837
|
+
to: number;
|
|
5838
|
+
};
|
|
5839
|
+
on?(event: string, callback: (payload: unknown) => void): () => void;
|
|
5840
|
+
/** The shared logical axis locates visible primary bars even when another series adds times. */
|
|
5841
|
+
readonly dataLayer: {
|
|
5842
|
+
readonly length: number;
|
|
5843
|
+
indexToTime?(index: number): number | undefined;
|
|
5844
|
+
};
|
|
5845
|
+
}
|
|
5846
|
+
declare class ComparisonController {
|
|
5847
|
+
private readonly _chart;
|
|
5848
|
+
private _mode;
|
|
5849
|
+
private _baseline;
|
|
5850
|
+
private readonly _panes;
|
|
5851
|
+
/** Insertion-ordered, and the handle is the key so `remove` is a lookup. */
|
|
5852
|
+
private readonly _items;
|
|
5853
|
+
/** Axis length plus primary identity and boundaries avoid scanning history each frame. */
|
|
5854
|
+
private _alignedAt;
|
|
5855
|
+
/** Guards `realign` against re-entry through its own `setData` repaint. */
|
|
5856
|
+
private _realigning;
|
|
5857
|
+
private _nextScale;
|
|
5858
|
+
private _syncing;
|
|
5859
|
+
private _alignedPrimary;
|
|
5860
|
+
private _primaryLength;
|
|
5861
|
+
private _primaryFirst;
|
|
5862
|
+
private _primaryLast;
|
|
5863
|
+
private readonly _off;
|
|
5864
|
+
private _destroyed;
|
|
5865
|
+
constructor(chart: ComparisonChartHost, options?: ComparisonControllerOptions);
|
|
5866
|
+
/** Put an instrument on the chart alongside the primary series. */
|
|
5867
|
+
add(options: ComparisonOptions): ComparisonHandle;
|
|
5868
|
+
/** Take one instrument off. Returns false if it was already gone. */
|
|
5869
|
+
remove(handle: ComparisonHandle): boolean;
|
|
5870
|
+
/** Every comparison on the chart, in the order they were added. */
|
|
5871
|
+
list(): readonly ComparisonHandle[];
|
|
5872
|
+
/** Take them all off, putting every pane back the way it was found. */
|
|
5873
|
+
clear(): void;
|
|
5874
|
+
/**
|
|
5875
|
+
* Change the mode the panes are held in while comparisons are on them.
|
|
5876
|
+
* Panes that already have one switch immediately.
|
|
5877
|
+
*/
|
|
5878
|
+
setMode(mode: ComparisonMode): void;
|
|
5879
|
+
get mode(): ComparisonMode;
|
|
5880
|
+
/** Select a shared timestamp without changing the instruments' stored price units. */
|
|
5881
|
+
setBaseline(baseline: ComparisonBaseline): void;
|
|
5882
|
+
get baseline(): ComparisonBaseline;
|
|
5883
|
+
/** Shared baseline timestamp, or null for no overlap, no visible sources, or independent baselines. */
|
|
5884
|
+
baselineTime(paneIndex?: number): number | null;
|
|
5885
|
+
/**
|
|
5886
|
+
* Re-project onto the primary's current bars. Chart handles data replacement
|
|
5887
|
+
* and replay automatically. A structural host without data events or primary
|
|
5888
|
+
* history identity can call this after replacing its timestamps.
|
|
5889
|
+
*/
|
|
5890
|
+
realign(): void;
|
|
5891
|
+
/**
|
|
5892
|
+
* Bring the overlay scales in line with the primary axis, re-aligning first
|
|
5893
|
+
* if the shared time axis has moved under us (a live bar, history paged in,
|
|
5894
|
+
* a replay step). Runs once per base paint through the per-pane hook.
|
|
5895
|
+
*
|
|
5896
|
+
* Re-aligning here writes series data mid-frame, which is safe because the
|
|
5897
|
+
* hook is a `bottom` primitive: it runs after the pane has autoscaled and
|
|
5898
|
+
* before any series is drawn, so the frame that notices the change is also
|
|
5899
|
+
* the frame that draws it. The repaint that write asks for lands on the next
|
|
5900
|
+
* frame, or re-enters this one on a host that runs frames synchronously,
|
|
5901
|
+
* which is what `realign`'s guard is for.
|
|
5902
|
+
*/
|
|
5903
|
+
sync(): void;
|
|
5904
|
+
/** Remove every comparison and forget the chart. */
|
|
5905
|
+
destroy(): void;
|
|
5906
|
+
private _dispose;
|
|
5907
|
+
private _needsAlignment;
|
|
5908
|
+
private _rememberAlignment;
|
|
5909
|
+
/**
|
|
5910
|
+
* Preserve the first comparison's legacy placement when the scale is free.
|
|
5911
|
+
* Additional comparisons need their own baselines, and an occupied volume
|
|
5912
|
+
* or left scale must keep its source and units.
|
|
5913
|
+
*/
|
|
5914
|
+
private _scaleIdFor;
|
|
5915
|
+
private _openPane;
|
|
5916
|
+
private _closePane;
|
|
5917
|
+
private _applyMode;
|
|
5918
|
+
private _restoreScale;
|
|
5919
|
+
private _restoreMode;
|
|
5920
|
+
/**
|
|
5921
|
+
* Give the overlay the same band of percent the primary axis is showing, so
|
|
5922
|
+
* equal moves land on equal pixels and the divergence between two
|
|
5923
|
+
* instruments is the thing you see.
|
|
5924
|
+
*
|
|
5925
|
+
* Each scale has its own price baseline, and rebasing maps price to the
|
|
5926
|
+
* ratio `price / baseline`. So the
|
|
5927
|
+
* two scales agree exactly when their ranges hold the same ratios, which is
|
|
5928
|
+
* one multiplication: the primary's range times `baseline_overlay /
|
|
5929
|
+
* baseline_primary`. It holds for `indexed-to-100` and `percentage` alike,
|
|
5930
|
+
* since they are one ladder a hundred points apart.
|
|
5931
|
+
*
|
|
5932
|
+
* A null baseline means this scale is not rebasing (linear, logarithmic, or
|
|
5933
|
+
* a pane with nothing visible on it yet). Then there is no shared ladder to
|
|
5934
|
+
* join and the overlay keeps its own autoscale, which is what mode 'none'
|
|
5935
|
+
* asks for: two instruments each filling the pane, comparable in shape only.
|
|
5936
|
+
*
|
|
5937
|
+
* The overlay stays under autoscale throughout, even though the range it
|
|
5938
|
+
* measures is overwritten here every frame. That measurement is one pass over
|
|
5939
|
+
* bars the renderer is about to walk anyway, and paying for it buys the
|
|
5940
|
+
* failure mode we want: a chart that stops calling `sync` falls back to an
|
|
5941
|
+
* independently scaled overlay instead of freezing on a stale range.
|
|
5942
|
+
*/
|
|
5943
|
+
private _mirror;
|
|
5944
|
+
private _primaryBars;
|
|
5945
|
+
private _record;
|
|
5946
|
+
private _visible;
|
|
5947
|
+
private _visiblePrimary;
|
|
5948
|
+
private _commonAnchor;
|
|
5949
|
+
private _setSuppressed;
|
|
5950
|
+
private _write;
|
|
5951
|
+
private _align;
|
|
5952
|
+
/**
|
|
5953
|
+
* Ask for a full repaint after a mode change. The pane hands a rebasing scale
|
|
5954
|
+
* its baseline during the autoscale pass, so a `Light` repaint (all a
|
|
5955
|
+
* primitive's `requestUpdate` raises) would paint the new mode before it has
|
|
5956
|
+
* anything to quote against. `applyOptions` is the series handle's own route
|
|
5957
|
+
* to a Full invalidation, and an empty patch changes no style. Several of
|
|
5958
|
+
* them coalesce into one frame, so asking every comparison costs nothing.
|
|
5959
|
+
*/
|
|
5960
|
+
private _repaint;
|
|
5961
|
+
}
|
|
5962
|
+
/**
|
|
5963
|
+
* The controller for a chart, created on first use. Use it to change the mode
|
|
5964
|
+
* for the whole chart, to list what is on it, or to clear it.
|
|
5965
|
+
*/
|
|
5966
|
+
declare function comparisonController(chart: ComparisonChartHost, options?: ComparisonControllerOptions): ComparisonController;
|
|
5967
|
+
/**
|
|
5968
|
+
* Put an instrument on the chart next to the primary one:
|
|
5969
|
+
*
|
|
5970
|
+
* ```ts
|
|
5971
|
+
* const bn = addComparison(chart, { symbol: 'BANKNIFTY', bars, color: '#f0b90b' });
|
|
5972
|
+
* ```
|
|
5973
|
+
*
|
|
5974
|
+
* The pane switches to percentage while any comparison is on it and goes back
|
|
5975
|
+
* to the mode it had when the last one leaves.
|
|
5976
|
+
*/
|
|
5977
|
+
declare function addComparison(chart: ComparisonChartHost, options: ComparisonOptions): ComparisonHandle;
|
|
5978
|
+
|
|
5979
|
+
/** Options for a numeric snapshot of the chart's currently loaded data. */
|
|
5980
|
+
interface ChartDataCsvOptions {
|
|
5981
|
+
/** Include every configured study's declared plots, including hidden studies. Default true. */
|
|
5982
|
+
indicators?: boolean;
|
|
5983
|
+
/** Override the chart's registered comparisons, for example with an explicitly managed controller's list. */
|
|
5984
|
+
comparisons?: readonly Pick<ComparisonHandle, 'symbol' | 'barAt'>[];
|
|
5985
|
+
}
|
|
5986
|
+
/**
|
|
5987
|
+
* CSV with UTC seconds, unrounded OHLC/volume/OI, study values and aligned comparison closes.
|
|
5988
|
+
* Reads only installed primary rows, so replay exposes only its revealed prefix.
|
|
5989
|
+
* Missing or nonfinite values are blank. Study values precede visual plot offsets;
|
|
5990
|
+
* comparison values retain their own price units, regardless of axis rebasing.
|
|
5991
|
+
* Headers have fixed prefixes so custom names cannot become spreadsheet formulas.
|
|
5992
|
+
* Does not fetch data, include trading state or initiate a browser download.
|
|
5993
|
+
*/
|
|
5994
|
+
declare function exportChartDataCsv(chart: Chart, options?: ChartDataCsvOptions): string;
|
|
5995
|
+
|
|
5452
5996
|
type ChartObjectKind = 'source' | 'indicator' | 'drawing' | 'profile';
|
|
5453
5997
|
interface ChartObjectCapabilities {
|
|
5454
5998
|
readonly select: boolean;
|
|
@@ -5786,542 +6330,394 @@ declare class Canvas2dBackend implements IRenderBackend {
|
|
|
5786
6330
|
* Nothing to do: the pane's `CanvasLayer` owns the backing store and sized it
|
|
5787
6331
|
* already. Re-sizing it here would clear a bitmap that was just painted.
|
|
5788
6332
|
*/
|
|
5789
|
-
resize(_widthPx: number, _heightPx: number, _dpr: number): void;
|
|
5790
|
-
/** The same clear `CanvasLayer.clearBitmap` does, so the op stream is unchanged. */
|
|
5791
|
-
beginFrame(clear: boolean): void;
|
|
5792
|
-
drawSeries(entry: RendererEntry, items: readonly DrawItem[], priceToY: (price: number) => number, barSpacing: number, dpr: number, style: SeriesStyle, rc: SeriesRenderContext): void;
|
|
5793
|
-
/** Every call above drew straight to the canvas; there is nothing to flush. */
|
|
5794
|
-
endFrame(): void;
|
|
5795
|
-
overlay2d(): CanvasRenderingContext2D | null;
|
|
5796
|
-
destroy(): void;
|
|
5797
|
-
}
|
|
5798
|
-
|
|
5799
|
-
/**
|
|
5800
|
-
* Histogram / column renderer (ARCHITECTURE.md §6). Used for the volume pane.
|
|
5801
|
-
* Bars are drawn from a base value (0) up to each bar's close.
|
|
5802
|
-
*/
|
|
5803
|
-
|
|
5804
|
-
interface HistogramStyle {
|
|
5805
|
-
color: string;
|
|
5806
|
-
/** Optional separate colors keyed by an up/down flag set on the bar's volume sign. */
|
|
5807
|
-
base: number;
|
|
5808
|
-
}
|
|
5809
|
-
declare const DEFAULT_HISTOGRAM_STYLE: HistogramStyle;
|
|
5810
|
-
|
|
5811
|
-
/**
|
|
5812
|
-
* Market replay: walk a historical session forward bar by bar so a trader can
|
|
5813
|
-
* practise on it, and so every indicator redraws exactly as it stood at that
|
|
5814
|
-
* past moment.
|
|
5815
|
-
*
|
|
5816
|
-
* Headless, in the spirit of `DrawingController` (src/draw/controller.ts): it
|
|
5817
|
-
* owns the playhead and the transitions and ships no DOM, so the host renders
|
|
5818
|
-
* its own transport bar, scrub slider and clock from `state()` and the events.
|
|
5819
|
-
*
|
|
5820
|
-
* The mechanic is deliberately boring. Replay feeds the chart a **prefix** of
|
|
5821
|
-
* the full bar array through the ordinary `series.setData` path, and that is
|
|
5822
|
-
* what makes indicators free: `Chart._setData` calls `_recomputeIndicators` for
|
|
5823
|
-
* the primary series, and `IndicatorInstance.recompute` re-reads the whole
|
|
5824
|
-
* history from `sourceBars()`. Shorten that history and every indicator, level,
|
|
5825
|
-
* fill, marker and legend reconstructs itself as it was at that bar, with no
|
|
5826
|
-
* replay-aware code anywhere in the indicator tier.
|
|
5827
|
-
*/
|
|
5828
|
-
|
|
5829
|
-
/** Schedules a repeating callback and returns its canceller. Inject in tests. */
|
|
5830
|
-
type ReplayScheduler = (cb: () => void, intervalMs: number) => () => void;
|
|
5831
|
-
/**
|
|
5832
|
-
* The slice of the time scale replay saves and restores. Declared structurally
|
|
5833
|
-
* rather than as `TimeScale` so nothing here depends on the scale's shape
|
|
5834
|
-
* beyond the two numbers that *are* the viewport.
|
|
5835
|
-
*/
|
|
5836
|
-
interface ReplayViewport {
|
|
5837
|
-
readonly barSpacing: number;
|
|
5838
|
-
readonly rightOffset: number;
|
|
5839
|
-
setBarSpacing(value: number): void;
|
|
5840
|
-
setRightOffset(value: number): void;
|
|
5841
|
-
}
|
|
5842
|
-
/**
|
|
5843
|
-
* The slice of the chart this controller needs. `Chart` satisfies it; declaring
|
|
5844
|
-
* it structurally keeps the controller testable against a stub and free of a
|
|
5845
|
-
* circular import back into core.
|
|
5846
|
-
*/
|
|
5847
|
-
interface ReplayChartHost {
|
|
5848
|
-
emit(event: string, payload: unknown): void;
|
|
5849
|
-
readonly timeScale: ReplayViewport;
|
|
5850
|
-
/**
|
|
5851
|
-
* Optional. When the chart can name its own primary price series, `series`
|
|
5852
|
-
* may be omitted and replay drives that one.
|
|
5853
|
-
*/
|
|
5854
|
-
primarySeries?(): SeriesApi | null;
|
|
5855
|
-
}
|
|
5856
|
-
/** Everything a transport bar and a clock need, in one object. */
|
|
5857
|
-
interface ReplayState {
|
|
5858
|
-
/** 0-based index of the newest bar currently on the chart. */
|
|
5859
|
-
index: number;
|
|
5860
|
-
/** Bars in the replay set (the scrub bar's maximum is `total - 1`). */
|
|
5861
|
-
total: number;
|
|
5862
|
-
playing: boolean;
|
|
5863
|
-
/** Multiplier over `barMs`: 2 plays two bars per `barMs`. */
|
|
5864
|
-
speed: number;
|
|
5865
|
-
/**
|
|
5866
|
-
* The bar at `index`, the replay clock's "now". Null when there is no data.
|
|
5867
|
-
*
|
|
5868
|
-
* Under intra-bar replay this is the **partial** bar as it stands this step,
|
|
5869
|
-
* not the completed one, which is what makes it the right thing to drive a
|
|
5870
|
-
* host's own forming volume bar or an OHLC readout from.
|
|
5871
|
-
*/
|
|
5872
|
-
bar: Bar | null;
|
|
5873
|
-
/**
|
|
5874
|
-
* Which step of the forming bar this is, 0-based, and how many it takes. Both
|
|
5875
|
-
* are 0 and 1 without `subBars`, so a transport that shows them needs no
|
|
5876
|
-
* special case for the plain mode.
|
|
5877
|
-
*/
|
|
5878
|
-
subIndex: number;
|
|
5879
|
-
subSteps: number;
|
|
5880
|
-
}
|
|
5881
|
-
interface ReplayOptions {
|
|
5882
|
-
/**
|
|
5883
|
-
* The series replay drives. The first one owns the timeline; any others (a
|
|
5884
|
-
* volume histogram, a comparison line) are truncated to the same instant by
|
|
5885
|
-
* time, because the shared DataLayer merges *every* series onto one axis and
|
|
5886
|
-
* a series left at full length would drag future timestamps back onto it.
|
|
5887
|
-
*
|
|
5888
|
-
* Optional only if the host chart implements `primarySeries()`.
|
|
5889
|
-
*/
|
|
5890
|
-
series?: SeriesApi | readonly SeriesApi[];
|
|
5891
|
-
/**
|
|
5892
|
-
* The full session. Defaults to the primary series' current data. Never
|
|
5893
|
-
* mutated, and never handed to the chart as-is: each frame gets its own slice.
|
|
5894
|
-
*/
|
|
5895
|
-
bars?: readonly Bar[];
|
|
5896
|
-
/**
|
|
5897
|
-
* Finer-grained bars the displayed ones are built from: the 1-minute session
|
|
5898
|
-
* under a 5-minute chart. Given these, the playhead advances a **sub-bar** at
|
|
5899
|
-
* a time and the newest bar forms in front of the user the way a live one
|
|
5900
|
-
* does, instead of appearing complete. A 5-minute bar over 1-minute data
|
|
5901
|
-
* takes five steps.
|
|
5902
|
-
*
|
|
5903
|
-
* They must cover the same session as `bars` and be sorted by time; sub-bars
|
|
5904
|
-
* outside any displayed bucket are ignored. The last step of a bucket emits
|
|
5905
|
-
* the displayed bar **verbatim** rather than the aggregate, so a bucket always
|
|
5906
|
-
* closes on exactly the number the chart would have shown without this option,
|
|
5907
|
-
* whatever the two feeds disagree about in between.
|
|
5908
|
-
*
|
|
5909
|
-
* Only the first driven series forms partially. Followers are cut to completed
|
|
5910
|
-
* buckets, because the controller cannot know how to half-aggregate an
|
|
5911
|
-
* arbitrary one: a volume histogram is summed, not OHLC-merged. The partial
|
|
5912
|
-
* bar reaches the host as `ReplayState.bar` on every frame, so a host that
|
|
5913
|
-
* wants a growing volume bar writes it from there.
|
|
5914
|
-
*/
|
|
5915
|
-
subBars?: readonly Bar[];
|
|
5916
|
-
/** Bar to open at (0-based). Default 0. */
|
|
5917
|
-
startIndex?: number;
|
|
5918
|
-
/** Wall-clock milliseconds per bar at speed 1. Default 1000. */
|
|
5919
|
-
barMs?: number;
|
|
5920
|
-
/** Initial speed multiplier. Default 1. */
|
|
5921
|
-
speed?: number;
|
|
5922
|
-
/** Called on every playhead move, after the chart has been updated. */
|
|
5923
|
-
onFrame?: (state: ReplayState) => void;
|
|
5924
|
-
/** Playback clock. Default `performance.now`. */
|
|
5925
|
-
now?: () => number;
|
|
5926
|
-
/** Playback timer. Default `setInterval`. */
|
|
5927
|
-
scheduler?: ReplayScheduler;
|
|
5928
|
-
}
|
|
5929
|
-
declare class ReplayController {
|
|
5930
|
-
private readonly _chart;
|
|
5931
|
-
private readonly _series;
|
|
5932
|
-
private readonly _bars;
|
|
5933
|
-
/** What each driven series held before replay took over, for `stop()`. */
|
|
5934
|
-
private readonly _restore;
|
|
5935
|
-
private readonly _view;
|
|
5936
|
-
private readonly _onFrame;
|
|
5937
|
-
private readonly _now;
|
|
5938
|
-
private readonly _schedule;
|
|
5939
|
-
private readonly _barMs;
|
|
5940
|
-
private readonly _startIndex;
|
|
5941
|
-
private readonly _subBars;
|
|
5942
|
-
/**
|
|
5943
|
-
* For each displayed bar, where its sub-bars start in `_subBars` and how many
|
|
5944
|
-
* there are. Built once: the alternative is a binary search per step, on a
|
|
5945
|
-
* path that runs on every played frame.
|
|
5946
|
-
*
|
|
5947
|
-
* A bucket with no sub-bars takes one step and shows the displayed bar, so a
|
|
5948
|
-
* gap in the finer feed costs that bar its formation, not its existence.
|
|
5949
|
-
*/
|
|
5950
|
-
private readonly _subStart;
|
|
5951
|
-
private readonly _subCount;
|
|
5952
|
-
private readonly _intra;
|
|
5953
|
-
private _speed;
|
|
5954
|
-
private _index;
|
|
5955
|
-
/** Step within the forming bar, 0-based. Always 0 without `subBars`. */
|
|
5956
|
-
private _sub;
|
|
5957
|
-
private _playing;
|
|
5958
|
-
/** True once replay owns the chart's data; false before start and after stop. */
|
|
5959
|
-
private _active;
|
|
5960
|
-
private _cancel;
|
|
5961
|
-
private _interval;
|
|
5962
|
-
/** Clock reading the last advance was charged to; keeps playback drift-free. */
|
|
5963
|
-
private _lastAdvance;
|
|
5964
|
-
/**
|
|
5965
|
-
* Constructing the controller **enters replay**: it snapshots the chart's data
|
|
5966
|
-
* and viewport and immediately shows `startIndex`. That is the gesture a
|
|
5967
|
-
* replay button makes, and it means the snapshot is taken before anything has
|
|
5968
|
-
* moved, so `stop()` can put the user back exactly where they were.
|
|
5969
|
-
*/
|
|
5970
|
-
constructor(chart: ReplayChartHost, options?: ReplayOptions);
|
|
5971
|
-
/**
|
|
5972
|
-
* Map every sub-bar onto the displayed bar whose bucket it falls in.
|
|
5973
|
-
*
|
|
5974
|
-
* The displayed bars' own times are the bucket starts, so one forward pass
|
|
5975
|
-
* over both sorted arrays does it. A sub-bar before the first displayed bar
|
|
5976
|
-
* belongs to no bucket and is dropped rather than folded into bar 0, which
|
|
5977
|
-
* would open that bar at a price the chart never showed.
|
|
5978
|
-
*/
|
|
5979
|
-
private _buildBuckets;
|
|
5980
|
-
/** How many steps the bar at `index` takes. At least one, always. */
|
|
5981
|
-
private _steps;
|
|
5982
|
-
/**
|
|
5983
|
-
* Jump the playhead to a bar. Out-of-range values clamp to the session.
|
|
5984
|
-
*
|
|
5985
|
-
* A seek lands on a **complete** bar even under intra-bar replay: scrubbing to
|
|
5986
|
-
* a half-formed candle is not a position anyone asks for, and it would make
|
|
5987
|
-
* the same slider position mean different things on the way past.
|
|
5988
|
-
*/
|
|
5989
|
-
seek(index: number): void;
|
|
5990
|
-
/**
|
|
5991
|
-
* Move `n` steps forward. Stops dead at the end of the session.
|
|
5992
|
-
*
|
|
5993
|
-
* A step is one displayed bar normally, and one sub-bar under intra-bar
|
|
5994
|
-
* replay, so the transport button means "advance the chart by the smallest
|
|
5995
|
-
* amount it can show" in both modes.
|
|
5996
|
-
*/
|
|
5997
|
-
step(n?: number): void;
|
|
5998
|
-
/** Move `n` steps back. Stops dead at the first bar. */
|
|
5999
|
-
stepBack(n?: number): void;
|
|
6000
|
-
/**
|
|
6001
|
-
* Move the playhead `delta` steps, carrying across bar boundaries.
|
|
6002
|
-
*
|
|
6003
|
-
* Written as a walk rather than arithmetic on a flat step count because
|
|
6004
|
-
* buckets hold different numbers of sub-bars: a session with a gap, or a
|
|
6005
|
-
* partial first bucket, has no constant steps-per-bar to divide by.
|
|
6006
|
-
*/
|
|
6007
|
-
private _advance;
|
|
6008
|
-
/**
|
|
6009
|
-
* Start (or re-speed) playback. Calling it on the last bar plays nothing and
|
|
6010
|
-
* reports `replay:end` instead of arming a timer that could never advance.
|
|
6011
|
-
*/
|
|
6012
|
-
play(options?: {
|
|
6013
|
-
speed?: number;
|
|
6014
|
-
}): void;
|
|
6015
|
-
/** Halt playback, leaving the playhead (and the chart) where it is. */
|
|
6016
|
-
pause(): void;
|
|
6017
|
-
/**
|
|
6018
|
-
* Leave replay: every driven series gets its pre-replay data back and the
|
|
6019
|
-
* viewport is restored to the pixel, so a user who exits does not lose their
|
|
6020
|
-
* place. Safe to call twice; a later `seek`/`step`/`play` re-enters replay
|
|
6021
|
-
* from `startIndex`.
|
|
6022
|
-
*/
|
|
6023
|
-
stop(): void;
|
|
6024
|
-
state(): ReplayState;
|
|
6025
|
-
/**
|
|
6026
|
-
* Put the chart at `index`. Every transition goes through here (seek, step
|
|
6027
|
-
* and each played frame alike), so arriving at a bar leaves the chart in the
|
|
6028
|
-
* same state however the user got there.
|
|
6029
|
-
*/
|
|
6030
|
-
private _apply;
|
|
6031
|
-
/**
|
|
6032
|
-
* One timer tick. The number of bars owed comes from the clock, not from the
|
|
6033
|
-
* tick count, so a coarse or throttled timer still plays at the requested
|
|
6034
|
-
* speed, and a host may drive this from rAF instead with no change here.
|
|
6035
|
-
*/
|
|
6036
|
-
private readonly _tick;
|
|
6037
|
-
/** True on the last step of the last bar, which is where playback stops. */
|
|
6038
|
-
private _atEnd;
|
|
6039
|
-
/** The session is over: stop the timer and tell the host once. */
|
|
6040
|
-
private _end;
|
|
6041
|
-
private _stopTimer;
|
|
6333
|
+
resize(_widthPx: number, _heightPx: number, _dpr: number): void;
|
|
6334
|
+
/** The same clear `CanvasLayer.clearBitmap` does, so the op stream is unchanged. */
|
|
6335
|
+
beginFrame(clear: boolean): void;
|
|
6336
|
+
drawSeries(entry: RendererEntry, items: readonly DrawItem[], priceToY: (price: number) => number, barSpacing: number, dpr: number, style: SeriesStyle, rc: SeriesRenderContext): void;
|
|
6337
|
+
/** Every call above drew straight to the canvas; there is nothing to flush. */
|
|
6338
|
+
endFrame(): void;
|
|
6339
|
+
overlay2d(): CanvasRenderingContext2D | null;
|
|
6340
|
+
destroy(): void;
|
|
6042
6341
|
}
|
|
6043
6342
|
|
|
6044
6343
|
/**
|
|
6045
|
-
*
|
|
6046
|
-
*
|
|
6047
|
-
* The x-axis is a gapless logical index over the times the shared DataLayer
|
|
6048
|
-
* holds (ARCHITECTURE.md §4.1, §5.3), so two instruments do not share a bar
|
|
6049
|
-
* index and cannot be laid side by side by position. They are matched by
|
|
6050
|
-
* timestamp, and the two directions of mismatch get opposite answers:
|
|
6051
|
-
*
|
|
6052
|
-
* - **A comparison bar with no primary bar is dropped.** The DataLayer merges
|
|
6053
|
-
* *every* series' times into one index space, so a time only the comparison
|
|
6054
|
-
* has would mint a new logical index: a column the primary instrument has no
|
|
6055
|
-
* candle for, inserted mid-chart, shifting every bar after it. That happens
|
|
6056
|
-
* for real (a different exchange's holiday calendar, a 24/7 instrument next
|
|
6057
|
-
* to an NSE one, a feed that emits a stray print), and warping the primary's
|
|
6058
|
-
* own axis to accommodate a comparison is never the right trade. The print is
|
|
6059
|
-
* counted in `dropped` so a host can say so rather than silently losing it.
|
|
6060
|
-
*
|
|
6061
|
-
* - **A primary bar with no comparison bar becomes whitespace**, which is a NaN
|
|
6062
|
-
* bar the line renderer breaks across, so the comparison shows a *gap*. The
|
|
6063
|
-
* alternative, carrying the last known value forward, draws a flat segment
|
|
6064
|
-
* through a session the instrument never traded and, worse, in percentage
|
|
6065
|
-
* mode it anchors the move on the far side of the gap to a print that does
|
|
6066
|
-
* not exist. Omitting the bar entirely is worse still: the renderer would
|
|
6067
|
-
* join the two sides with one straight line across the holiday.
|
|
6068
|
-
*
|
|
6069
|
-
* Matching is on the exact timestamp. Bar-open times are bucketed by the candle
|
|
6070
|
-
* builder (§10.2) and stored as UTC seconds (§4.0), so two instruments on the
|
|
6071
|
-
* same interval agree to the second; anything that does not agree is a
|
|
6072
|
-
* different interval, which no tolerance window could rescue.
|
|
6344
|
+
* Histogram / column renderer (ARCHITECTURE.md §6). Used for the volume pane.
|
|
6345
|
+
* Bars are drawn from a base value (0) up to each bar's close.
|
|
6073
6346
|
*/
|
|
6074
6347
|
|
|
6075
|
-
|
|
6076
|
-
|
|
6077
|
-
/**
|
|
6078
|
-
|
|
6079
|
-
|
|
6080
|
-
|
|
6081
|
-
|
|
6082
|
-
|
|
6083
|
-
|
|
6084
|
-
|
|
6348
|
+
interface HistogramStyle {
|
|
6349
|
+
color: string;
|
|
6350
|
+
/** Optional separate colors keyed by an up/down flag set on the bar's volume sign. */
|
|
6351
|
+
base: number;
|
|
6352
|
+
}
|
|
6353
|
+
declare const DEFAULT_HISTOGRAM_STYLE: HistogramStyle;
|
|
6354
|
+
|
|
6355
|
+
/** UTC seconds when this recorded candle becomes complete and available. */
|
|
6356
|
+
type ReplayBarEndTime = (bar: Bar, index: number) => number;
|
|
6357
|
+
/** Explicit availability avoids treating a coarse candle's open as its close. */
|
|
6358
|
+
interface ReplayTiming {
|
|
6359
|
+
barEndTime: ReplayBarEndTime;
|
|
6360
|
+
/** Required with finer bars; their final prices also need a known availability time. */
|
|
6361
|
+
subBarEndTime?: ReplayBarEndTime;
|
|
6085
6362
|
}
|
|
6086
|
-
/**
|
|
6087
|
-
* Project `comparison` onto `primary`'s bars: one item per primary bar, in the
|
|
6088
|
-
* primary's order, so the result occupies exactly the logical indices the chart
|
|
6089
|
-
* already has and adds none of its own.
|
|
6090
|
-
*
|
|
6091
|
-
* Neither input is mutated and neither has to be sorted: matching goes through
|
|
6092
|
-
* a time map, which also collapses a repeated timestamp to its last item, the
|
|
6093
|
-
* same rule the DataLayer applies when it merges (`sortedUniqueByTime`).
|
|
6094
|
-
*/
|
|
6095
|
-
declare function alignToPrimary(primary: readonly Bar[], comparison: readonly SeriesDataItem[]): {
|
|
6096
|
-
items: SeriesDataItem[];
|
|
6097
|
-
alignment: ComparisonAlignment;
|
|
6098
|
-
};
|
|
6099
6363
|
|
|
6100
6364
|
/**
|
|
6101
|
-
*
|
|
6102
|
-
* and
|
|
6103
|
-
*
|
|
6104
|
-
* Headless, in the spirit of `DrawingController` (src/draw/controller.ts) and
|
|
6105
|
-
* `ReplayController`: it owns the series, the alignment and the scales, and
|
|
6106
|
-
* ships no DOM, so the host draws its own symbol chips and legend rows from
|
|
6107
|
-
* `list()`.
|
|
6108
|
-
*
|
|
6109
|
-
* Three decisions carry the design:
|
|
6110
|
-
*
|
|
6111
|
-
* 1. **The comparison never touches the primary's axis.** It goes on the pane's
|
|
6112
|
-
* hidden overlay scale (`priceScaleId: ''`, see `Pane._scaleFor`), which
|
|
6113
|
-
* autoscales on its own and draws no ticks, so a 46,000 instrument next to a
|
|
6114
|
-
* 22,000 one cannot compress the primary's candles or relabel its ladder.
|
|
6115
|
-
*
|
|
6116
|
-
* 2. **Comparability comes from the scale, not from the data.** The bars handed
|
|
6117
|
-
* over are stored as the instrument's own prices, so the legend, the
|
|
6118
|
-
* crosshair and any live update still speak in real prices. What makes the
|
|
6119
|
-
* lines readable together is the pane mode: `percentage` and
|
|
6120
|
-
* `indexed-to-100` give every scale its own baseline (the first *visible*
|
|
6121
|
-
* bar, so panning re-bases), and `_mirror` then gives the overlay the same
|
|
6122
|
-
* band of percent the primary's axis is showing. Without that mirror each
|
|
6123
|
-
* scale would autoscale to its own data and a 1% mover would look exactly
|
|
6124
|
-
* like a 10% mover, both filling the pane.
|
|
6365
|
+
* Market replay: walk a historical session forward bar by bar so a trader can
|
|
6366
|
+
* practise on it, and so every indicator redraws exactly as it stood at that
|
|
6367
|
+
* past moment.
|
|
6125
6368
|
*
|
|
6126
|
-
*
|
|
6127
|
-
*
|
|
6369
|
+
* Headless, in the spirit of `DrawingController` (src/draw/controller.ts): it
|
|
6370
|
+
* owns the playhead and the transitions and ships no DOM, so the host renders
|
|
6371
|
+
* its own transport bar, scrub slider and clock from `state()` and the events.
|
|
6128
6372
|
*
|
|
6129
|
-
*
|
|
6130
|
-
*
|
|
6131
|
-
*
|
|
6132
|
-
* the
|
|
6133
|
-
*
|
|
6134
|
-
*
|
|
6373
|
+
* The mechanic is deliberately boring. Replay feeds the chart a **prefix** of
|
|
6374
|
+
* the full bar array through the ordinary `series.setData` path, and that is
|
|
6375
|
+
* what makes indicators free: `Chart._setData` calls `_recomputeIndicators` for
|
|
6376
|
+
* the primary series, and `IndicatorInstance.recompute` re-reads the whole
|
|
6377
|
+
* history from `sourceBars()`. Shorten that history and every indicator, level,
|
|
6378
|
+
* fill, marker and legend reconstructs itself as it was at that bar, with no
|
|
6379
|
+
* replay-aware code anywhere in the indicator tier.
|
|
6135
6380
|
*/
|
|
6136
6381
|
|
|
6382
|
+
/** Schedules a repeating callback and returns its canceller. Inject in tests. */
|
|
6383
|
+
type ReplayScheduler = (cb: () => void, intervalMs: number) => () => void;
|
|
6137
6384
|
/**
|
|
6138
|
-
*
|
|
6139
|
-
*
|
|
6140
|
-
*
|
|
6385
|
+
* The slice of the time scale replay saves and restores. Declared structurally
|
|
6386
|
+
* rather than as `TimeScale` so nothing here depends on the scale's shape
|
|
6387
|
+
* beyond the two numbers that *are* the viewport.
|
|
6141
6388
|
*/
|
|
6142
|
-
|
|
6143
|
-
|
|
6144
|
-
|
|
6145
|
-
|
|
6146
|
-
|
|
6147
|
-
bars: readonly SeriesDataItem[];
|
|
6148
|
-
/** Line colour shorthand; `style.color` wins if both are given. */
|
|
6149
|
-
color?: string;
|
|
6150
|
-
/** Style overrides merged onto the chart type's defaults. */
|
|
6151
|
-
style?: SeriesStyle;
|
|
6152
|
-
/** Renderer for the comparison. Default 'line'. */
|
|
6153
|
-
type?: SeriesType;
|
|
6154
|
-
/** Pane to draw on. Default 0, the price pane. */
|
|
6155
|
-
paneIndex?: number;
|
|
6156
|
-
}
|
|
6157
|
-
interface ComparisonControllerOptions {
|
|
6158
|
-
/** Pane mode applied while any comparison is on it. Default 'percentage'. */
|
|
6159
|
-
mode?: ComparisonMode;
|
|
6389
|
+
interface ReplayViewport {
|
|
6390
|
+
readonly barSpacing: number;
|
|
6391
|
+
readonly rightOffset: number;
|
|
6392
|
+
setBarSpacing(value: number): void;
|
|
6393
|
+
setRightOffset(value: number): void;
|
|
6160
6394
|
}
|
|
6161
|
-
/**
|
|
6162
|
-
|
|
6163
|
-
|
|
6395
|
+
/**
|
|
6396
|
+
* The slice of the chart this controller needs. `Chart` satisfies it; declaring
|
|
6397
|
+
* it structurally keeps the controller testable against a stub and free of a
|
|
6398
|
+
* circular import back into core.
|
|
6399
|
+
*/
|
|
6400
|
+
interface ReplayChartHost {
|
|
6401
|
+
emit(event: string, payload: unknown): void;
|
|
6402
|
+
readonly timeScale: ReplayViewport;
|
|
6164
6403
|
/**
|
|
6165
|
-
*
|
|
6166
|
-
*
|
|
6167
|
-
* directly leaves the pane rebased with nothing on it (use `remove`).
|
|
6404
|
+
* Optional. When the chart can name its own primary price series, `series`
|
|
6405
|
+
* may be omitted and replay drives that one.
|
|
6168
6406
|
*/
|
|
6169
|
-
|
|
6170
|
-
readonly paneIndex: number;
|
|
6171
|
-
/** The hidden scale it maps to. Never the pane's own price axis. */
|
|
6172
|
-
priceScale(): PriceScale;
|
|
6173
|
-
/** How the last alignment against the primary's bars went. */
|
|
6174
|
-
alignment(): ComparisonAlignment;
|
|
6175
|
-
/** Replace the instrument's bars (a longer history, a refreshed fetch). */
|
|
6176
|
-
setBars(bars: readonly SeriesDataItem[]): void;
|
|
6177
|
-
/** Take this instrument off the chart. Safe to call twice. */
|
|
6178
|
-
remove(): void;
|
|
6179
|
-
/** Every comparison on this chart, in the order they were added. */
|
|
6180
|
-
list(): readonly ComparisonHandle[];
|
|
6407
|
+
primarySeries?(): SeriesApi | null;
|
|
6181
6408
|
}
|
|
6182
|
-
/**
|
|
6183
|
-
|
|
6184
|
-
|
|
6185
|
-
|
|
6186
|
-
*/
|
|
6187
|
-
|
|
6188
|
-
|
|
6189
|
-
|
|
6190
|
-
|
|
6191
|
-
|
|
6409
|
+
/** Everything a transport bar and a clock need, in one object. */
|
|
6410
|
+
interface ReplayState {
|
|
6411
|
+
/** 0-based newest bar; -1 before the first observation in timed replay. */
|
|
6412
|
+
index: number;
|
|
6413
|
+
/** Bars in the replay set (the scrub bar's maximum is `total - 1`). */
|
|
6414
|
+
total: number;
|
|
6415
|
+
playing: boolean;
|
|
6416
|
+
/** Multiplier over `barMs`: 2 plays two bars per `barMs`. */
|
|
6417
|
+
speed: number;
|
|
6418
|
+
/**
|
|
6419
|
+
* The bar at `index`, the replay clock's "now". Null when there is no data.
|
|
6420
|
+
*
|
|
6421
|
+
* Under intra-bar replay this is the **partial** bar as it stands this step,
|
|
6422
|
+
* not the completed one, which is what makes it the right thing to drive a
|
|
6423
|
+
* host's own forming volume bar or an OHLC readout from.
|
|
6424
|
+
*/
|
|
6425
|
+
bar: Bar | null;
|
|
6426
|
+
/**
|
|
6427
|
+
* Which step of the forming bar this is, 0-based, and how many it takes. Both
|
|
6428
|
+
* are 0 and 1 without `subBars`, so a transport that shows them needs no
|
|
6429
|
+
* special case for the plain mode.
|
|
6430
|
+
*/
|
|
6431
|
+
subIndex: number;
|
|
6432
|
+
subSteps: number;
|
|
6192
6433
|
}
|
|
6193
|
-
|
|
6194
|
-
|
|
6195
|
-
|
|
6196
|
-
*/
|
|
6197
|
-
|
|
6198
|
-
|
|
6199
|
-
|
|
6200
|
-
|
|
6201
|
-
|
|
6202
|
-
|
|
6203
|
-
|
|
6204
|
-
|
|
6205
|
-
|
|
6206
|
-
|
|
6434
|
+
interface ReplayOptions {
|
|
6435
|
+
/** Explicit candle availability for time-aligned replay. Omitted preserves index-based replay. */
|
|
6436
|
+
timing?: ReplayTiming;
|
|
6437
|
+
/** Initial UTC availability time. Requires timing; otherwise startIndex selects a completed candle. */
|
|
6438
|
+
startTime?: number;
|
|
6439
|
+
/** False prepares and validates the snapshot without changing the chart. Default true. */
|
|
6440
|
+
autoStart?: boolean;
|
|
6441
|
+
/**
|
|
6442
|
+
* The series replay drives. The first one owns the timeline; any others (a
|
|
6443
|
+
* volume histogram, a comparison line) are truncated to the same instant by
|
|
6444
|
+
* time, because the shared DataLayer merges *every* series onto one axis and
|
|
6445
|
+
* a series left at full length would drag future timestamps back onto it.
|
|
6446
|
+
*
|
|
6447
|
+
* Optional only if the host chart implements `primarySeries()`.
|
|
6448
|
+
*/
|
|
6449
|
+
series?: SeriesApi | readonly SeriesApi[];
|
|
6450
|
+
/**
|
|
6451
|
+
* The full session. Defaults to the primary series' current data. Never
|
|
6452
|
+
* mutated, and never handed to the chart as-is: each frame gets its own slice.
|
|
6453
|
+
*/
|
|
6454
|
+
bars?: readonly Bar[];
|
|
6455
|
+
/**
|
|
6456
|
+
* Finer-grained bars the displayed ones are built from: the 1-minute session
|
|
6457
|
+
* under a 5-minute chart. Given these, the playhead advances a **sub-bar** at
|
|
6458
|
+
* a time and the newest bar forms in front of the user the way a live one
|
|
6459
|
+
* does, instead of appearing complete. A 5-minute bar over 1-minute data
|
|
6460
|
+
* takes five steps.
|
|
6461
|
+
*
|
|
6462
|
+
* They must cover the same session as `bars` and be sorted by time; sub-bars
|
|
6463
|
+
* outside any displayed bucket are ignored. The last step of a bucket emits
|
|
6464
|
+
* the displayed bar **verbatim** rather than the aggregate, so a bucket always
|
|
6465
|
+
* closes on exactly the number the chart would have shown without this option,
|
|
6466
|
+
* whatever the two feeds disagree about in between.
|
|
6467
|
+
*
|
|
6468
|
+
* Only the first driven series forms partially. Followers are cut to completed
|
|
6469
|
+
* buckets, because the controller cannot know how to half-aggregate an
|
|
6470
|
+
* arbitrary one: a volume histogram is summed, not OHLC-merged. The partial
|
|
6471
|
+
* bar reaches the host as `ReplayState.bar` on every frame, so a host that
|
|
6472
|
+
* wants a growing volume bar writes it from there.
|
|
6473
|
+
*/
|
|
6474
|
+
subBars?: readonly Bar[];
|
|
6475
|
+
/** Bar to open at (0-based). Default 0. */
|
|
6476
|
+
startIndex?: number;
|
|
6477
|
+
/** Wall-clock milliseconds per bar at speed 1. Default 1000. */
|
|
6478
|
+
barMs?: number;
|
|
6479
|
+
/** Initial speed multiplier. Default 1. */
|
|
6480
|
+
speed?: number;
|
|
6481
|
+
/** Called on every playhead move, after the chart has been updated. */
|
|
6482
|
+
onFrame?: (state: ReplayState) => void;
|
|
6483
|
+
/** Playback clock. Default `performance.now`. */
|
|
6484
|
+
now?: () => number;
|
|
6485
|
+
/** Playback timer. Default `setInterval`. */
|
|
6486
|
+
scheduler?: ReplayScheduler;
|
|
6207
6487
|
}
|
|
6208
|
-
declare class
|
|
6488
|
+
declare class ReplayController {
|
|
6209
6489
|
private readonly _chart;
|
|
6210
|
-
private
|
|
6211
|
-
private readonly
|
|
6212
|
-
/**
|
|
6213
|
-
private readonly
|
|
6490
|
+
private readonly _series;
|
|
6491
|
+
private readonly _bars;
|
|
6492
|
+
/** What each driven series held before replay took over, for `stop()`. */
|
|
6493
|
+
private readonly _restore;
|
|
6494
|
+
private readonly _view;
|
|
6495
|
+
private readonly _onFrame;
|
|
6496
|
+
private readonly _now;
|
|
6497
|
+
private readonly _schedule;
|
|
6498
|
+
private readonly _barMs;
|
|
6499
|
+
private readonly _startIndex;
|
|
6500
|
+
private readonly _timeline;
|
|
6501
|
+
private readonly _startTime;
|
|
6502
|
+
private _time;
|
|
6503
|
+
private _pointIndex;
|
|
6504
|
+
private readonly _subBars;
|
|
6214
6505
|
/**
|
|
6215
|
-
*
|
|
6216
|
-
*
|
|
6217
|
-
*
|
|
6506
|
+
* For each displayed bar, where its sub-bars start in `_subBars` and how many
|
|
6507
|
+
* there are. Built once: the alternative is a binary search per step, on a
|
|
6508
|
+
* path that runs on every played frame.
|
|
6509
|
+
*
|
|
6510
|
+
* A bucket with no sub-bars takes one step and shows the displayed bar, so a
|
|
6511
|
+
* gap in the finer feed costs that bar its formation, not its existence.
|
|
6218
6512
|
*/
|
|
6219
|
-
private
|
|
6220
|
-
|
|
6221
|
-
private
|
|
6222
|
-
|
|
6223
|
-
|
|
6224
|
-
|
|
6225
|
-
|
|
6226
|
-
|
|
6227
|
-
/**
|
|
6228
|
-
|
|
6229
|
-
|
|
6230
|
-
|
|
6513
|
+
private readonly _subStart;
|
|
6514
|
+
private readonly _subCount;
|
|
6515
|
+
private readonly _intra;
|
|
6516
|
+
private _speed;
|
|
6517
|
+
private _index;
|
|
6518
|
+
/** Step within the forming bar, 0-based. Always 0 without `subBars`. */
|
|
6519
|
+
private _sub;
|
|
6520
|
+
private _playing;
|
|
6521
|
+
/** True once replay owns the chart's data; false before start and after stop. */
|
|
6522
|
+
private _active;
|
|
6523
|
+
private _cancel;
|
|
6524
|
+
private _interval;
|
|
6525
|
+
/** Clock reading the last advance was charged to; keeps playback drift-free. */
|
|
6526
|
+
private _lastAdvance;
|
|
6231
6527
|
/**
|
|
6232
|
-
*
|
|
6233
|
-
*
|
|
6528
|
+
* Constructing the controller **enters replay**: it snapshots the chart's data
|
|
6529
|
+
* and viewport and immediately shows `startIndex`. That is the gesture a
|
|
6530
|
+
* replay button makes, and it means the snapshot is taken before anything has
|
|
6531
|
+
* moved, so `stop()` can put the user back exactly where they were.
|
|
6234
6532
|
*/
|
|
6235
|
-
|
|
6236
|
-
get mode(): ComparisonMode;
|
|
6533
|
+
constructor(chart: ReplayChartHost, options?: ReplayOptions);
|
|
6237
6534
|
/**
|
|
6238
|
-
*
|
|
6239
|
-
*
|
|
6240
|
-
*
|
|
6241
|
-
*
|
|
6535
|
+
* Map every sub-bar onto the displayed bar whose bucket it falls in.
|
|
6536
|
+
*
|
|
6537
|
+
* The displayed bars' own times are the bucket starts, so one forward pass
|
|
6538
|
+
* over both sorted arrays does it. A sub-bar before the first displayed bar
|
|
6539
|
+
* belongs to no bucket and is dropped rather than folded into bar 0, which
|
|
6540
|
+
* would open that bar at a price the chart never showed.
|
|
6242
6541
|
*/
|
|
6243
|
-
|
|
6542
|
+
private _buildBuckets;
|
|
6543
|
+
/** How many steps the bar at `index` takes. At least one, always. */
|
|
6544
|
+
private _steps;
|
|
6244
6545
|
/**
|
|
6245
|
-
*
|
|
6246
|
-
* if the shared time axis has moved under us (a live bar, history paged in,
|
|
6247
|
-
* a replay step). Runs once per base paint through the per-pane hook.
|
|
6546
|
+
* Jump the playhead to a bar. Out-of-range values clamp to the session.
|
|
6248
6547
|
*
|
|
6249
|
-
*
|
|
6250
|
-
*
|
|
6251
|
-
*
|
|
6252
|
-
* the frame that draws it. The repaint that write asks for lands on the next
|
|
6253
|
-
* frame, or re-enters this one on a host that runs frames synchronously,
|
|
6254
|
-
* which is what `realign`'s guard is for.
|
|
6548
|
+
* A seek lands on a **complete** bar even under intra-bar replay: scrubbing to
|
|
6549
|
+
* a half-formed candle is not a position anyone asks for, and it would make
|
|
6550
|
+
* the same slider position mean different things on the way past.
|
|
6255
6551
|
*/
|
|
6256
|
-
|
|
6257
|
-
/**
|
|
6258
|
-
|
|
6552
|
+
seek(index: number): void;
|
|
6553
|
+
/** Project only observations available by these UTC seconds. Requires timing. */
|
|
6554
|
+
seekTime(time: number): void;
|
|
6555
|
+
/** Availability clock in timed mode; the displayed bar's timestamp in legacy mode. */
|
|
6556
|
+
time(): number | null;
|
|
6557
|
+
/** Observation timestamps for a shared clock. Requires timing; returns a copy. */
|
|
6558
|
+
timePoints(): readonly number[];
|
|
6259
6559
|
/**
|
|
6260
|
-
*
|
|
6261
|
-
*
|
|
6262
|
-
*
|
|
6263
|
-
*
|
|
6264
|
-
*
|
|
6265
|
-
* instead: a visible second ladder is a far smaller surprise than an
|
|
6266
|
-
* invisible line at the bottom of the pane.
|
|
6560
|
+
* Move `n` steps forward. Stops dead at the end of the session.
|
|
6561
|
+
*
|
|
6562
|
+
* A step is one displayed bar normally, and one sub-bar under intra-bar
|
|
6563
|
+
* replay, so the transport button means "advance the chart by the smallest
|
|
6564
|
+
* amount it can show" in both modes.
|
|
6267
6565
|
*/
|
|
6268
|
-
|
|
6269
|
-
|
|
6270
|
-
|
|
6271
|
-
private _applyMode;
|
|
6272
|
-
private _restoreMode;
|
|
6566
|
+
step(n?: number): void;
|
|
6567
|
+
/** Move `n` steps back. Stops dead at the first bar. */
|
|
6568
|
+
stepBack(n?: number): void;
|
|
6273
6569
|
/**
|
|
6274
|
-
*
|
|
6275
|
-
* equal moves land on equal pixels and the divergence between two
|
|
6276
|
-
* instruments is the thing you see.
|
|
6277
|
-
*
|
|
6278
|
-
* Both scales rebase against a baseline of their own (the first visible bar
|
|
6279
|
-
* on each), and a rebase maps price to the ratio `price / baseline`. So the
|
|
6280
|
-
* two scales agree exactly when their ranges hold the same ratios, which is
|
|
6281
|
-
* one multiplication: the primary's range times `baseline_overlay /
|
|
6282
|
-
* baseline_primary`. It holds for `indexed-to-100` and `percentage` alike,
|
|
6283
|
-
* since they are one ladder a hundred points apart.
|
|
6284
|
-
*
|
|
6285
|
-
* A null baseline means this scale is not rebasing (linear, logarithmic, or
|
|
6286
|
-
* a pane with nothing visible on it yet). Then there is no shared ladder to
|
|
6287
|
-
* join and the overlay keeps its own autoscale, which is what mode 'none'
|
|
6288
|
-
* asks for: two instruments each filling the pane, comparable in shape only.
|
|
6570
|
+
* Move the playhead `delta` steps, carrying across bar boundaries.
|
|
6289
6571
|
*
|
|
6290
|
-
*
|
|
6291
|
-
*
|
|
6292
|
-
*
|
|
6293
|
-
* failure mode we want: a chart that stops calling `sync` falls back to an
|
|
6294
|
-
* independently scaled overlay instead of freezing on a stale range.
|
|
6572
|
+
* Written as a walk rather than arithmetic on a flat step count because
|
|
6573
|
+
* buckets hold different numbers of sub-bars: a session with a gap, or a
|
|
6574
|
+
* partial first bucket, has no constant steps-per-bar to divide by.
|
|
6295
6575
|
*/
|
|
6296
|
-
private
|
|
6297
|
-
private _primaryBars;
|
|
6298
|
-
private _align;
|
|
6576
|
+
private _advance;
|
|
6299
6577
|
/**
|
|
6300
|
-
*
|
|
6301
|
-
*
|
|
6302
|
-
* primitive's `requestUpdate` raises) would paint the new mode before it has
|
|
6303
|
-
* anything to quote against. `applyOptions` is the series handle's own route
|
|
6304
|
-
* to a Full invalidation, and an empty patch changes no style. Several of
|
|
6305
|
-
* them coalesce into one frame, so asking every comparison costs nothing.
|
|
6578
|
+
* Start (or re-speed) playback. Calling it on the last bar plays nothing and
|
|
6579
|
+
* reports `replay:end` instead of arming a timer that could never advance.
|
|
6306
6580
|
*/
|
|
6307
|
-
|
|
6581
|
+
play(options?: {
|
|
6582
|
+
speed?: number;
|
|
6583
|
+
}): void;
|
|
6584
|
+
/** Halt playback, leaving the playhead (and the chart) where it is. */
|
|
6585
|
+
pause(): void;
|
|
6586
|
+
/**
|
|
6587
|
+
* Leave replay: every driven series gets its pre-replay data back and the
|
|
6588
|
+
* viewport is restored to the pixel, so a user who exits does not lose their
|
|
6589
|
+
* place. Safe to call twice; a later `seek`/`step`/`play` re-enters replay
|
|
6590
|
+
* from `startIndex`.
|
|
6591
|
+
*/
|
|
6592
|
+
stop(): void;
|
|
6593
|
+
state(): ReplayState;
|
|
6594
|
+
/**
|
|
6595
|
+
* Put the chart at `index`. Every transition goes through here (seek, step
|
|
6596
|
+
* and each played frame alike), so arriving at a bar leaves the chart in the
|
|
6597
|
+
* same state however the user got there.
|
|
6598
|
+
*/
|
|
6599
|
+
private _apply;
|
|
6600
|
+
private _write;
|
|
6601
|
+
/**
|
|
6602
|
+
* One timer tick. The number of bars owed comes from the clock, not from the
|
|
6603
|
+
* tick count, so a coarse or throttled timer still plays at the requested
|
|
6604
|
+
* speed, and a host may drive this from rAF instead with no change here.
|
|
6605
|
+
*/
|
|
6606
|
+
private readonly _tick;
|
|
6607
|
+
/** True on the last step of the last bar, which is where playback stops. */
|
|
6608
|
+
private _atEnd;
|
|
6609
|
+
/** The session is over: stop the timer and tell the host once. */
|
|
6610
|
+
private _end;
|
|
6611
|
+
private _stopTimer;
|
|
6612
|
+
}
|
|
6613
|
+
|
|
6614
|
+
/** True while replay owns this chart, including when its playback clock is paused. */
|
|
6615
|
+
declare function isReplaying(chart: object): boolean;
|
|
6616
|
+
|
|
6617
|
+
type ReplayScope = 'focused' | 'all';
|
|
6618
|
+
/** Chart implements this; headless hosts may supply the lifecycle hooks too. */
|
|
6619
|
+
interface ReplayGroupChartHost extends ReplayChartHost {
|
|
6620
|
+
readonly isDestroyed?: boolean;
|
|
6621
|
+
on?(event: 'destroy', callback: () => void): () => void;
|
|
6622
|
+
}
|
|
6623
|
+
interface ReplayGroupMember {
|
|
6624
|
+
id: string;
|
|
6625
|
+
chart: ReplayGroupChartHost;
|
|
6626
|
+
/** Transport and clock options belong to the group. */
|
|
6627
|
+
options: Pick<ReplayOptions, 'series' | 'bars' | 'subBars' | 'onFrame'> & {
|
|
6628
|
+
timing: ReplayTiming;
|
|
6629
|
+
};
|
|
6630
|
+
}
|
|
6631
|
+
interface ReplayGroupState {
|
|
6632
|
+
active: boolean;
|
|
6633
|
+
destroyed: boolean;
|
|
6634
|
+
scope: ReplayScope;
|
|
6635
|
+
focusedId: string;
|
|
6636
|
+
/** UTC availability time, or null when the active histories have no observations. */
|
|
6637
|
+
time: number | null;
|
|
6638
|
+
/** Index in the union of active observation times; -1 before the first. */
|
|
6639
|
+
index: number;
|
|
6640
|
+
total: number;
|
|
6641
|
+
playing: boolean;
|
|
6642
|
+
speed: number;
|
|
6643
|
+
members: readonly {
|
|
6644
|
+
id: string;
|
|
6645
|
+
active: boolean;
|
|
6646
|
+
state: ReplayState;
|
|
6647
|
+
}[];
|
|
6648
|
+
}
|
|
6649
|
+
interface ReplayGroupOptions {
|
|
6650
|
+
/** Default focused. Changing toolbar focus alone does not redirect replay. */
|
|
6651
|
+
scope?: ReplayScope;
|
|
6652
|
+
/** Default the first member. */
|
|
6653
|
+
focusedId?: string;
|
|
6654
|
+
startTime?: number;
|
|
6655
|
+
/** Wall-clock milliseconds per observation at speed 1. Default 1000. */
|
|
6656
|
+
barMs?: number;
|
|
6657
|
+
speed?: number;
|
|
6658
|
+
now?: () => number;
|
|
6659
|
+
scheduler?: ReplayScheduler;
|
|
6660
|
+
/** Runs after all active charts reach a frame or transport transition. */
|
|
6661
|
+
onChange?: (state: ReplayGroupState) => void;
|
|
6662
|
+
}
|
|
6663
|
+
/** One opt-in clock driving validated ReplayControllers by availability time. */
|
|
6664
|
+
declare class ReplayGroup {
|
|
6665
|
+
private _members;
|
|
6666
|
+
private _activeIds;
|
|
6667
|
+
private _times;
|
|
6668
|
+
private _scope;
|
|
6669
|
+
private _focusedId;
|
|
6670
|
+
private _time;
|
|
6671
|
+
private _startTime;
|
|
6672
|
+
private _active;
|
|
6673
|
+
private _destroyed;
|
|
6674
|
+
private _playing;
|
|
6675
|
+
private _busy;
|
|
6676
|
+
private _closing;
|
|
6677
|
+
private _revision;
|
|
6678
|
+
private _speed;
|
|
6679
|
+
private readonly _barMs;
|
|
6680
|
+
private readonly _now;
|
|
6681
|
+
private readonly _scheduler;
|
|
6682
|
+
private readonly _onChange?;
|
|
6683
|
+
private _cancel;
|
|
6684
|
+
private _clockRevision;
|
|
6685
|
+
private _lastAdvance;
|
|
6686
|
+
private _pending;
|
|
6687
|
+
constructor(members: readonly ReplayGroupMember[], options?: ReplayGroupOptions);
|
|
6688
|
+
state(): ReplayGroupState;
|
|
6689
|
+
seekTime(time: number): void;
|
|
6690
|
+
/** Seek an observation index, clamped to the active timeline. */
|
|
6691
|
+
seek(index: number): void;
|
|
6692
|
+
step(n?: number): void;
|
|
6693
|
+
stepBack(n?: number): void;
|
|
6694
|
+
private _move;
|
|
6695
|
+
setScope(scope: ReplayScope, focusedId?: string): void;
|
|
6696
|
+
play(options?: {
|
|
6697
|
+
speed?: number;
|
|
6698
|
+
}): void;
|
|
6699
|
+
pause(): void;
|
|
6700
|
+
/** Restore data/viewports, retaining the captured session for later re-entry. */
|
|
6701
|
+
stop(): void;
|
|
6702
|
+
/** Restore surviving charts and release snapshots, listeners and ownership. */
|
|
6703
|
+
destroy(): void;
|
|
6704
|
+
private _validateScope;
|
|
6705
|
+
private _prepare;
|
|
6706
|
+
private _prepareEntering;
|
|
6707
|
+
private _install;
|
|
6708
|
+
private _wanted;
|
|
6709
|
+
private _rebuildTimes;
|
|
6710
|
+
private _check;
|
|
6711
|
+
private _apply;
|
|
6712
|
+
private _atEnd;
|
|
6713
|
+
private _tick;
|
|
6714
|
+
private _clearClock;
|
|
6715
|
+
private _emit;
|
|
6716
|
+
private _notify;
|
|
6717
|
+
private _execute;
|
|
6718
|
+
private _chartGone;
|
|
6719
|
+
private _cleanup;
|
|
6308
6720
|
}
|
|
6309
|
-
/**
|
|
6310
|
-
* The controller for a chart, created on first use. Use it to change the mode
|
|
6311
|
-
* for the whole chart, to list what is on it, or to clear it.
|
|
6312
|
-
*/
|
|
6313
|
-
declare function comparisonController(chart: ComparisonChartHost, options?: ComparisonControllerOptions): ComparisonController;
|
|
6314
|
-
/**
|
|
6315
|
-
* Put an instrument on the chart next to the primary one:
|
|
6316
|
-
*
|
|
6317
|
-
* ```ts
|
|
6318
|
-
* const bn = addComparison(chart, { symbol: 'BANKNIFTY', bars, color: '#f0b90b' });
|
|
6319
|
-
* ```
|
|
6320
|
-
*
|
|
6321
|
-
* The pane switches to percentage while any comparison is on it and goes back
|
|
6322
|
-
* to the mode it had when the last one leaves.
|
|
6323
|
-
*/
|
|
6324
|
-
declare function addComparison(chart: ComparisonChartHost, options: ComparisonOptions): ComparisonHandle;
|
|
6325
6721
|
|
|
6326
6722
|
/**
|
|
6327
6723
|
* Time alignment for chart linking: the one thing that makes a grid of charts
|
|
@@ -6409,7 +6805,7 @@ declare function followerRange(leader: LinkDataLayer, follower: LinkDataLayer, r
|
|
|
6409
6805
|
* ships no DOM, so the host draws its own link badge / colour chips and decides
|
|
6410
6806
|
* which charts belong to which group.
|
|
6411
6807
|
*
|
|
6412
|
-
*
|
|
6808
|
+
* Four channels sync, each switchable on its own because a user routinely
|
|
6413
6809
|
* wants one without the others (mirror the cursor across four timeframes but
|
|
6414
6810
|
* keep each zoom; or slave every chart's symbol but let each keep its own
|
|
6415
6811
|
* window):
|
|
@@ -6417,6 +6813,7 @@ declare function followerRange(leader: LinkDataLayer, follower: LinkDataLayer, r
|
|
|
6417
6813
|
* - **crosshair**: hovering one chart marks the same instant on the others.
|
|
6418
6814
|
* - **viewport**: panning or zooming one moves the others to the same window.
|
|
6419
6815
|
* - **symbol**: changing the instrument on one changes it on the others.
|
|
6816
|
+
* - **interval**: changing a timeframe asks each following host to adopt it.
|
|
6420
6817
|
*
|
|
6421
6818
|
* Four decisions carry the design.
|
|
6422
6819
|
*
|
|
@@ -6476,6 +6873,8 @@ interface LinkChart {
|
|
|
6476
6873
|
panes(): readonly unknown[];
|
|
6477
6874
|
addPrimitive(primitive: IPrimitive, paneIndex?: number): void;
|
|
6478
6875
|
removePrimitive(primitive: IPrimitive): void;
|
|
6876
|
+
/** Optional readout support alongside the group's vertical marker. */
|
|
6877
|
+
setLinkedCrosshairIndex?(index: number | null): void;
|
|
6479
6878
|
}
|
|
6480
6879
|
interface LinkOptions {
|
|
6481
6880
|
/** Mirror the hovered instant onto every other member. Default true. */
|
|
@@ -6484,6 +6883,8 @@ interface LinkOptions {
|
|
|
6484
6883
|
viewport?: boolean;
|
|
6485
6884
|
/** Mirror the instrument, via each member's `onSymbol`. Default false. */
|
|
6486
6885
|
symbol?: boolean;
|
|
6886
|
+
/** Mirror the timeframe, via each member's `onInterval`. Default false. */
|
|
6887
|
+
interval?: boolean;
|
|
6487
6888
|
/** What a follower does with an instant it has no bar for. Default 'nearest'. */
|
|
6488
6889
|
whenMissing?: LinkMissingPolicy;
|
|
6489
6890
|
}
|
|
@@ -6496,6 +6897,10 @@ interface LinkMemberOptions {
|
|
|
6496
6897
|
* it still broadcasts its own changes, it just never follows anyone else's.
|
|
6497
6898
|
*/
|
|
6498
6899
|
onSymbol?: (symbol: string, chart: LinkChart) => void;
|
|
6900
|
+
/** The interval this chart is showing, if the host tracks one. */
|
|
6901
|
+
interval?: string;
|
|
6902
|
+
/** Apply the interval synchronously; return false to refuse an unsupported token. */
|
|
6903
|
+
onInterval?: (interval: string, chart: LinkChart) => boolean | void;
|
|
6499
6904
|
}
|
|
6500
6905
|
/** Every option resolved, as `options()` reports them. */
|
|
6501
6906
|
type ResolvedLinkOptions = Required<LinkOptions>;
|
|
@@ -6505,6 +6910,7 @@ declare class LinkGroup {
|
|
|
6505
6910
|
/** True while the group is applying a change to followers. See decision 3. */
|
|
6506
6911
|
private _broadcasting;
|
|
6507
6912
|
private _symbol;
|
|
6913
|
+
private _interval;
|
|
6508
6914
|
private _destroyed;
|
|
6509
6915
|
constructor(options?: LinkOptions);
|
|
6510
6916
|
options(): ResolvedLinkOptions;
|
|
@@ -6524,6 +6930,8 @@ declare class LinkGroup {
|
|
|
6524
6930
|
has(chart: LinkChart): boolean;
|
|
6525
6931
|
/** The instrument the group has agreed on, or null if nobody declared one. */
|
|
6526
6932
|
symbol(): string | null;
|
|
6933
|
+
/** Latest interval selected by a member, even while interval linking is off. */
|
|
6934
|
+
interval(): string | null;
|
|
6527
6935
|
/**
|
|
6528
6936
|
* The member's own logical index its linked crosshair is marking, or null
|
|
6529
6937
|
* when it is showing none (it is the chart being hovered, the leader's
|
|
@@ -6551,6 +6959,8 @@ declare class LinkGroup {
|
|
|
6551
6959
|
* symbol sync is on, loads it into every other member that can follow.
|
|
6552
6960
|
*/
|
|
6553
6961
|
setSymbol(chart: LinkChart, symbol: string): void;
|
|
6962
|
+
/** Report a host-owned interval selection; followers opt in through `onInterval`. */
|
|
6963
|
+
setInterval(chart: LinkChart, interval: string): void;
|
|
6554
6964
|
/** Unlink everything: no listeners, no linked crosshairs, no references. */
|
|
6555
6965
|
destroy(): void;
|
|
6556
6966
|
private _onCrosshair;
|
|
@@ -6559,6 +6969,9 @@ declare class LinkGroup {
|
|
|
6559
6969
|
private _applySymbol;
|
|
6560
6970
|
/** Push the group's agreed symbol onto everyone who is not already on it. */
|
|
6561
6971
|
private _convergeSymbol;
|
|
6972
|
+
private _applyInterval;
|
|
6973
|
+
private _followInterval;
|
|
6974
|
+
private _convergeInterval;
|
|
6562
6975
|
/**
|
|
6563
6976
|
* Run `apply` on every member except the originator, exactly once, with the
|
|
6564
6977
|
* echo guard held. `onLeader` (optional) runs on the originator itself.
|
|
@@ -6647,6 +7060,14 @@ interface Tick {
|
|
|
6647
7060
|
ltq?: number;
|
|
6648
7061
|
/** Cumulative day volume (Quote mode). */
|
|
6649
7062
|
cumDayVolume?: number;
|
|
7063
|
+
/**
|
|
7064
|
+
* Open interest as at this tick, where the feed carries it. Unlike the two
|
|
7065
|
+
* quantities above it is not accumulated into the bar: it replaces, because
|
|
7066
|
+
* it is a level and not a flow (see `Bar.oi`). A feed that does not report it
|
|
7067
|
+
* leaves the built bar without one, which is the honest result rather than a
|
|
7068
|
+
* zero that reads as "nobody is holding this".
|
|
7069
|
+
*/
|
|
7070
|
+
oi?: number;
|
|
6650
7071
|
}
|
|
6651
7072
|
interface CandleUpdate {
|
|
6652
7073
|
bar: Bar;
|
|
@@ -7270,6 +7691,86 @@ interface TradeFeed {
|
|
|
7270
7691
|
subscribePositions(cb: (positions: unknown[]) => void): UnsubscribeFn;
|
|
7271
7692
|
}
|
|
7272
7693
|
|
|
7694
|
+
interface InstrumentCalendar {
|
|
7695
|
+
/** HHMM-HHMM[:days], with opening weekdays 1 (Sunday) through 7. */
|
|
7696
|
+
readonly sessions: readonly string[];
|
|
7697
|
+
/** Local opening dates replace weekly sessions. An empty list closes that date. */
|
|
7698
|
+
readonly exceptions?: Readonly<Record<string, readonly string[]>>;
|
|
7699
|
+
}
|
|
7700
|
+
/** Host-supplied market rules, separate from observations and saved user preferences. */
|
|
7701
|
+
interface InstrumentMetadata {
|
|
7702
|
+
readonly symbol: string;
|
|
7703
|
+
readonly exchange: string;
|
|
7704
|
+
readonly timezone: string;
|
|
7705
|
+
readonly priceTick: number;
|
|
7706
|
+
readonly pricePrecision: number;
|
|
7707
|
+
/** In the order adapter's units. This is a grid, never a lot conversion factor. */
|
|
7708
|
+
readonly quantityStep: number;
|
|
7709
|
+
readonly intervals: readonly string[];
|
|
7710
|
+
readonly calendar: InstrumentCalendar;
|
|
7711
|
+
readonly hasOpenInterest?: boolean;
|
|
7712
|
+
}
|
|
7713
|
+
interface InstrumentSession {
|
|
7714
|
+
/** Local opening date, including for an overnight window. */
|
|
7715
|
+
readonly date: string;
|
|
7716
|
+
/** UTC seconds, inclusive. */
|
|
7717
|
+
readonly open: number;
|
|
7718
|
+
/** UTC seconds, exclusive. */
|
|
7719
|
+
readonly close: number;
|
|
7720
|
+
}
|
|
7721
|
+
/** Validated, detached rules. Construction does not change global intervals or chart defaults. */
|
|
7722
|
+
declare class Instrument {
|
|
7723
|
+
readonly metadata: InstrumentMetadata;
|
|
7724
|
+
private readonly _sessions;
|
|
7725
|
+
private readonly _exceptions;
|
|
7726
|
+
constructor(input: unknown);
|
|
7727
|
+
/** Provider tokens are exact: a feed may distinguish monthly M from minute m. */
|
|
7728
|
+
supportsInterval(code: string): boolean;
|
|
7729
|
+
/** Formats display only. The source bars retain their unrounded values. */
|
|
7730
|
+
formatPrice(value: number): string;
|
|
7731
|
+
/** Resolve an active window. Closed dates and breaks return null, never inferred hours. */
|
|
7732
|
+
sessionAt(utcSeconds: number): InstrumentSession | null;
|
|
7733
|
+
/** The host clears old bars and owns source loading; only metadata is applied here. */
|
|
7734
|
+
applyTo(chart: Chart, interval: string): void;
|
|
7735
|
+
}
|
|
7736
|
+
|
|
7737
|
+
type TradingOperation = 'place' | 'modify' | 'cancel';
|
|
7738
|
+
/** Optional restrictions on existing write paths; omissions preserve legacy support. */
|
|
7739
|
+
interface TradingCapabilities {
|
|
7740
|
+
readonly place?: boolean | 'unknown';
|
|
7741
|
+
readonly modify?: boolean | 'unknown';
|
|
7742
|
+
readonly cancel?: boolean | 'unknown';
|
|
7743
|
+
/** Accepted types for new orders. An empty list disables placement. */
|
|
7744
|
+
readonly orderTypes?: readonly OrderType$1[];
|
|
7745
|
+
/** Accepted modes for new orders; does not change the broker's actual mode. */
|
|
7746
|
+
readonly modes?: readonly ('live' | 'analyzer')[];
|
|
7747
|
+
}
|
|
7748
|
+
interface TradingCapabilityRequest {
|
|
7749
|
+
readonly operation: TradingOperation;
|
|
7750
|
+
readonly symbol?: string;
|
|
7751
|
+
readonly exchange?: string;
|
|
7752
|
+
readonly orderId?: string;
|
|
7753
|
+
readonly type?: OrderType$1;
|
|
7754
|
+
readonly mode?: 'live' | 'analyzer';
|
|
7755
|
+
}
|
|
7756
|
+
/** A configured provider returning undefined declares that support is unavailable. */
|
|
7757
|
+
type TradingCapabilitySource = TradingCapabilities | ((request: Readonly<TradingCapabilityRequest>) => TradingCapabilities | undefined);
|
|
7758
|
+
type TradingCapabilityResult = {
|
|
7759
|
+
supported: true;
|
|
7760
|
+
} | {
|
|
7761
|
+
supported: false;
|
|
7762
|
+
reason: string;
|
|
7763
|
+
};
|
|
7764
|
+
/** Shared by host controls and the write boundary. Never grants broker authority. */
|
|
7765
|
+
declare function checkTradingCapability(source: TradingCapabilitySource | undefined, request: TradingCapabilityRequest): TradingCapabilityResult;
|
|
7766
|
+
/** Raised only before delivery, so an unsupported write does not become ambiguous. */
|
|
7767
|
+
declare class TradingCapabilityError extends Error {
|
|
7768
|
+
readonly preflight: true;
|
|
7769
|
+
readonly operation: TradingOperation;
|
|
7770
|
+
constructor(operation: TradingOperation, reason: string);
|
|
7771
|
+
}
|
|
7772
|
+
declare function assertTradingCapability(source: TradingCapabilitySource | undefined, request: TradingCapabilityRequest): void;
|
|
7773
|
+
|
|
7273
7774
|
/** Limits apply to each pool, whose identity belongs to one data feed. */
|
|
7274
7775
|
interface HistoryRequestPoolOptions {
|
|
7275
7776
|
maxConcurrent?: number;
|
|
@@ -7443,6 +7944,12 @@ interface OpenAlgoConfig {
|
|
|
7443
7944
|
apiKey: string;
|
|
7444
7945
|
/** Injectable fetch (defaults to global fetch); lets the adapter be tested offline. */
|
|
7445
7946
|
fetchImpl?: typeof fetch;
|
|
7947
|
+
/**
|
|
7948
|
+
* Instrument capability from host metadata. Explicit false omits the API's
|
|
7949
|
+
* placeholder OI column before it can become a misleading cash reading.
|
|
7950
|
+
* Missing/unknown capability preserves finite observations, including zero.
|
|
7951
|
+
*/
|
|
7952
|
+
hasOpenInterest?(request: Readonly<BarsRequest>): boolean | undefined;
|
|
7446
7953
|
}
|
|
7447
7954
|
interface HistoryRow {
|
|
7448
7955
|
timestamp?: number | string;
|
|
@@ -7452,6 +7959,8 @@ interface HistoryRow {
|
|
|
7452
7959
|
low: number;
|
|
7453
7960
|
close: number;
|
|
7454
7961
|
volume?: number;
|
|
7962
|
+
/** Present on a derivatives response; the platform always sends the column. */
|
|
7963
|
+
oi?: number;
|
|
7455
7964
|
}
|
|
7456
7965
|
interface HistoryResponse {
|
|
7457
7966
|
status?: string;
|
|
@@ -7461,7 +7970,7 @@ interface HistoryResponse {
|
|
|
7461
7970
|
/** Pure: coerce a row timestamp (epoch s / epoch ms / IST string) to UTC seconds. */
|
|
7462
7971
|
declare function rowTimeToUtcSeconds(value: number | string): number;
|
|
7463
7972
|
/** Pure: map an OpenAlgo history response into sorted internal bars. */
|
|
7464
|
-
declare function mapHistoryResponse(json: HistoryResponse): Bar[];
|
|
7973
|
+
declare function mapHistoryResponse(json: HistoryResponse, hasOpenInterest?: boolean): Bar[];
|
|
7465
7974
|
declare class OpenAlgoDataFeed implements DataFeed {
|
|
7466
7975
|
private readonly _config;
|
|
7467
7976
|
private readonly _fetch;
|
|
@@ -7925,6 +8434,8 @@ interface ModifyPatch {
|
|
|
7925
8434
|
* implement `OrderFeed` for the engine's write path.
|
|
7926
8435
|
*/
|
|
7927
8436
|
interface OrderFeed {
|
|
8437
|
+
/** Optional support declaration; a configured provider can report unavailable metadata. */
|
|
8438
|
+
readonly capabilities?: TradingCapabilitySource$1;
|
|
7928
8439
|
place(req: PlaceRequest & {
|
|
7929
8440
|
mode: TradeMode;
|
|
7930
8441
|
}): Promise<{
|
|
@@ -7960,6 +8471,8 @@ type ModeCheck = 'off' | 'auto' | 'always';
|
|
|
7960
8471
|
interface OpenAlgoTradeConfig {
|
|
7961
8472
|
baseUrl: string;
|
|
7962
8473
|
apiKey: string;
|
|
8474
|
+
/** Optional host/broker restrictions; omitted preserves the existing OpenAlgo path. */
|
|
8475
|
+
capabilities?: TradingCapabilitySource;
|
|
7963
8476
|
/**
|
|
7964
8477
|
* Instrument constraints for the advisory pre-trade check on `place`, looked
|
|
7965
8478
|
* up per order. Return undefined when the instrument is unknown; the
|
|
@@ -8085,7 +8598,8 @@ declare class OpenAlgoTradeFeed implements OrderFeed {
|
|
|
8085
8598
|
* or a retried promise does not become two orders.
|
|
8086
8599
|
*/
|
|
8087
8600
|
private _claimToken;
|
|
8088
|
-
|
|
8601
|
+
get capabilities(): TradingCapabilitySource | undefined;
|
|
8602
|
+
place(request: PlaceRequest & {
|
|
8089
8603
|
mode: TradeMode;
|
|
8090
8604
|
}): Promise<{
|
|
8091
8605
|
orderId: string;
|
|
@@ -8106,7 +8620,7 @@ declare class OpenAlgoTradeFeed implements OrderFeed {
|
|
|
8106
8620
|
* that an ambiguous order did not reach the exchange.
|
|
8107
8621
|
*/
|
|
8108
8622
|
releaseToken(token: string): void;
|
|
8109
|
-
modify(orderId: string,
|
|
8623
|
+
modify(orderId: string, changes: {
|
|
8110
8624
|
price?: number;
|
|
8111
8625
|
triggerPrice?: number;
|
|
8112
8626
|
qty?: number;
|
|
@@ -8533,6 +9047,11 @@ interface AggTick {
|
|
|
8533
9047
|
time: number;
|
|
8534
9048
|
price: number;
|
|
8535
9049
|
qty: number;
|
|
9050
|
+
/**
|
|
9051
|
+
* Open interest as at this tick, where the feed carries it. Carried onto the
|
|
9052
|
+
* bar as the latest reading rather than accumulated: see `Bar.oi`.
|
|
9053
|
+
*/
|
|
9054
|
+
oi?: number;
|
|
8536
9055
|
}
|
|
8537
9056
|
interface BarUpdate {
|
|
8538
9057
|
bar: Bar;
|
|
@@ -8957,4 +9476,67 @@ declare function lerp(a: number, b: number, t: number): number;
|
|
|
8957
9476
|
*/
|
|
8958
9477
|
declare function roundToTick(value: number, step: number): number;
|
|
8959
9478
|
|
|
8960
|
-
|
|
9479
|
+
/** Headless, chart-owned trader alerts. Hosts subscribe to alert:triggered for delivery. */
|
|
9480
|
+
declare class AlertController {
|
|
9481
|
+
private readonly _chart;
|
|
9482
|
+
private readonly _records;
|
|
9483
|
+
private readonly _off;
|
|
9484
|
+
private readonly _now;
|
|
9485
|
+
private readonly _drawings;
|
|
9486
|
+
private readonly _visuals;
|
|
9487
|
+
private _timer;
|
|
9488
|
+
private _timerAt;
|
|
9489
|
+
private _paused;
|
|
9490
|
+
private _restoring;
|
|
9491
|
+
private _replay;
|
|
9492
|
+
private _destroyed;
|
|
9493
|
+
private _revision;
|
|
9494
|
+
constructor(_chart: AlertChartHost, options?: AlertControllerOptions);
|
|
9495
|
+
add(input: AlertInput): Alert;
|
|
9496
|
+
update(id: string, patch: AlertPatch): Alert | undefined;
|
|
9497
|
+
remove(id: string): boolean;
|
|
9498
|
+
private _remove;
|
|
9499
|
+
list(): Alert[];
|
|
9500
|
+
toJSON(): AlertsDocument;
|
|
9501
|
+
/** Validate the complete replacement before touching current alerts or their visuals. */
|
|
9502
|
+
fromJSON(input: unknown): void;
|
|
9503
|
+
private _saveState;
|
|
9504
|
+
/** Availability is independent of lifecycle state; disabled records can still have valid anchors. */
|
|
9505
|
+
availability(id: string): AlertAvailability;
|
|
9506
|
+
enable(id: string): Alert | undefined;
|
|
9507
|
+
disable(id: string): Alert | undefined;
|
|
9508
|
+
/** Explicit host pause is independent of replay and never delivers a backlog. */
|
|
9509
|
+
setPaused(paused: boolean): void;
|
|
9510
|
+
destroy(): void;
|
|
9511
|
+
private _assertAlive;
|
|
9512
|
+
private _seed;
|
|
9513
|
+
private _seedAll;
|
|
9514
|
+
private _onObjects;
|
|
9515
|
+
private _syncVisual;
|
|
9516
|
+
private _onData;
|
|
9517
|
+
private _plot;
|
|
9518
|
+
private _reading;
|
|
9519
|
+
private _closedMatch;
|
|
9520
|
+
private _touchMatch;
|
|
9521
|
+
private _barMatch;
|
|
9522
|
+
private _drawingValue;
|
|
9523
|
+
private _drawingTouch;
|
|
9524
|
+
private _trigger;
|
|
9525
|
+
private _expireDue;
|
|
9526
|
+
private _clearTimer;
|
|
9527
|
+
private _scheduleExpiry;
|
|
9528
|
+
}
|
|
9529
|
+
|
|
9530
|
+
/** Shared editor fields in source units. Drawing bands own their bounds. */
|
|
9531
|
+
declare function alertSettingsSchema(source: AlertSource, condition?: AlertCondition): readonly IndicatorInput[];
|
|
9532
|
+
|
|
9533
|
+
/** Validate and detach a version-1 document, or migrate a legacy bare list. */
|
|
9534
|
+
declare function parseAlertsDocument(input: unknown): AlertsDocument;
|
|
9535
|
+
|
|
9536
|
+
/** Register runtime code by stable id; persisted alerts store only that id. */
|
|
9537
|
+
declare function registerBarCondition(condition: BarCondition): void;
|
|
9538
|
+
declare function unregisterBarCondition(id: string): boolean;
|
|
9539
|
+
declare function getBarCondition(id: string): Readonly<BarCondition> | undefined;
|
|
9540
|
+
declare function registeredBarConditions(): readonly Readonly<BarCondition>[];
|
|
9541
|
+
|
|
9542
|
+
export { ALT_PRESET, type AddSeriesOptions, type AggTick, type Alert, type AlertAvailability, type AlertChartHost, type AlertCondition, AlertController, type AlertControllerOptions, type AlertDrawingInfo, type AlertDrawingLevel, type AlertDrawingProvider, type AlertDrawingValue, type AlertEventPayload, type AlertInput, type AlertPatch, type AlertPolicy, type AlertRepeat, type AlertScope, type AlertSource, type AlertState, type AlertTriggeredPayload, type AlertsDocument, type AxisChromeOptions, type AxisStyle, BAR_CACHE_VERSION, BUILTIN_COMMANDS, type Bar, BarCache, type BarCacheOptions, type BarCacheStats, type BarCacheStore, type BarCondition, type BarConditionAlertSource, type BarConditionContext, type BarSubscriptionOptions, type BarUpdate, type BarsPage, type BarsPageRequest, type BarsRequest, type BrandingChangedEvent, type Bucketing, BuySellButtons, type BuySellButtonsOptions, CHART_STATE_VERSION, type CachedBars, type CachedBarsRequest, type CalendarBucketing, type CalendarUnit, CandleBuilder, type CandleBuilderOptions, type CandleGeometry, type CandleStyle, type CandleTier, type CandleUpdate, Canvas2dBackend, type CanvasLineStyle, type CanvasOptions, Chart, type ChartClickEvent, type ChartDataContext, type ChartDataCsvOptions, type ChartDataUpdate, type ChartDragEndEvent, type ChartDragEvent, type ChartEvent, type ChartEventOptions, type ChartNavigationOptions, type ChartObjectCapabilities, type ChartObjectDefinition, type ChartObjectDrawing, type ChartObjectDrawingSource, type ChartObjectKind, type ChartObjectProvider, type ChartObjectSnapshot, ChartObjects, type ChartObjectsOptions, type ChartOptions, type ChartSettingsColorPairInput, type ChartSettingsInput, type ChartSettingsState, type ChartSettingsTab, type ChartSettingsTabId, type ChartSettingsValue, type ChartSettingsValues, type ChartState, ChartTable, type ChartTableOptions, type ChartTheme, type ChartWatermarkOptions, type ComparisonAlignment, type ComparisonBaseline, type ComparisonChartHost, ComparisonController, type ComparisonControllerOptions, type ComparisonHandle, type ComparisonMode, type ComparisonOptions, type ComparisonPane, type ContextMenuEvent, type ContextMenuTarget, type ContextMenuTargetKind, type CrosshairMoveEvent, type CrosshairOptions, type CrosshairStyle, type CustomShortcut, DEFAULT_CANDLE_BUILDER_OPTIONS, DEFAULT_CANDLE_STYLE, DEFAULT_CHART_TABLE_OPTIONS, DEFAULT_HISTOGRAM_STYLE, DEFAULT_KEYMAP, DEFAULT_PRICE_SCALE_OPTIONS, DEFAULT_THEME, DEFAULT_TIMEZONE, DEFAULT_TIME_NAVIGATOR_OPTIONS, DEFAULT_TIME_SCALE_OPTIONS, DEFAULT_TRADING_COLORS, DEFAULT_ZOOM_GLIDE_OPTIONS, type DataFeed, DataLayer, DataLoadingController, type DataLoadingOptions, type DataLoadingSnapshot, type DataLoadingStatus, type DataUpdateReason, type DecodedOrder, type DepthLevel, type DoubleClickAction, type DoubleClickEvent, type DrawAnchor, type DrawItem, type DrawingAlertSource, EventMarkers, type ExportSvgOptions, FakeDataFeed, type FeedScheduler, type FillGradient, type FillPoint, type GridAxisStyle, type GridOptions, type GridStyle, type HistogramStyle, type HistoryLoadingStatus, HistoryRequestPool, type HistoryRequestPoolOptions, INDICATOR_LINE_STYLES, INDICATOR_PLOT_STYLES, INDICATOR_SOURCES, type IPrimitive, type IRenderBackend, IST_OFFSET_SECONDS, type IndexedBar, type IndicatorAlertContext, type IndicatorAlertPayload, type IndicatorAlertSource, type IndicatorAlertSpec, type IndicatorApi, type IndicatorAttachContext, IndicatorBackground, type IndicatorBarsProvider, type IndicatorBarsRequest, type IndicatorCalcContext, type IndicatorDataChange, type IndicatorDataStatus, type IndicatorDescriptor, type IndicatorDrawing, IndicatorDrawings, IndicatorFill, type IndicatorFillOptions, type IndicatorFillSpec, type IndicatorHost, type IndicatorInput, IndicatorInputError, type IndicatorLevel, type IndicatorLevelContext, type IndicatorLineStyle, type IndicatorPlot, type IndicatorSettings, type IndicatorSource, type IndicatorState, type IndicatorStore, type IndicatorValues, Instrument, type InstrumentCalendar, type InstrumentMetadata, type InstrumentSession, type IntervalBucketing, type IntervalDescriptor, type IntervalParts, InvalidationLevel, type IstParts, type KeymapEntry, LINK_CROSSHAIR_ALPHA, type LateTickPolicy, type LegendField, type LegendStatusData, type LegendStatusLineOptions, type LegendStatusSource, type LegendTitleMode, type LegendValue, type LinePoint, type LinkChart, LinkCrosshair, type LinkDataLayer, LinkGroup, type LinkMemberOptions, type LinkMissingPolicy, type LinkOptions, type LiveBarMeta, type LogicalRange, LogoWatermark, type LogoWatermarkOptions, type LtpEvent, type MarkerPosition, type MarkerShape, type MarkerSize, type MarketDepth, type MarketPhase, type MarketPhaseFn, type MaybePromise, type ModeCheck, type OpenAlgoConfig, OpenAlgoDataFeed, type OpenAlgoLiveConfig, OpenAlgoLiveDataFeed, type OpenAlgoTradeConfig, OpenAlgoTradeFeed, type OpenAlgoWsConfig, OpenAlgoWsFeed, type OrderBookSnapshot, type OrderDecodeCode, type OrderDecodeIssue, type OrderDecodeResult, type OrderSide$1 as OrderSide, type OrderType$1 as OrderType, type OrderUpdateEvent, type OriginalTime, PRICE_LEVEL_KINDS, PRICE_SCALE_MODES, Pane, type PaneInvalidation, PaneLegend, type PaneLegendAction, type PaneLegendOptions, type PaneState, type PickHost, type PickKind, type PlaceOrder, type PlotBarColor, type PlotMarginOptions, type PointerInfo, type PointerKind, type PointerModifiers, type PointerSample, type PositionSide, type PriceAlertSource, type PriceAxisState, type PriceFormat, type PriceLevelInput, type PriceLevelKind, type PriceLevelQuote, type PriceLevelStyle, type PriceLevelValues, PriceLevels, type PriceLevelsOptions, PriceLine, type PriceLineOptions, type PriceRange, PriceScale, type PriceScaleId, type PriceScaleMode, type PriceScaleOptions, type PriceScaleState, type PrimitiveAnchor, type PrimitiveHit, type PrimitiveHost, type PrimitivePlacement, type PrimitiveRenderContext, type QuarantinedRow, type RawOrder, type RenderBackendFactory, type RenderBackendKind, type RenderDevice, type RendererChoice, type RendererEntry, type RendererFallbackEvent, type RendererFallbackReason, type ReplayBarEndTime, type ReplayChartHost, ReplayController, ReplayGroup, type ReplayGroupChartHost, type ReplayGroupMember, type ReplayGroupOptions, type ReplayGroupState, type ReplayOptions, type ReplayScheduler, type ReplayScope, ReplayShade, type ReplayShadeOptions, type ReplayState, type ReplayTiming, type ReplayViewport, type ResolvedLinkOptions, type RestoreReport, SCALE_FONT_MAX, SCALE_FONT_MIN, type ScaleCanvasOptions, type SeriesApi, type SeriesDataItem, type SeriesId, type SeriesMarker, SeriesMarkers, type SeriesRenderContext, type SeriesState, type SeriesStyle, type SeriesType, type SessionSpec, type ShortcutListItem, ShortcutManager, type ShortcutManagerOptions, type ShortcutPreset, type ShortcutScope, type ShortcutTriggerEvent, type Size, type SocketFactory, type SocketLike, type SupertrendPoint, SvgContext, type SvgContextOptions, SvgLinearGradient, type TableCell, type TablePosition, TextWatermark, type TextWatermarkOptions, type Tick, TickBarAggregator, type TickBarOptions, type TickCountBucketing, type TickMarkType, type TickTimeframe, TimeNavigator, type TimeNavigatorAction, type TimeNavigatorOptions, TimeScale, type TimeScaleOp, type TimeScaleOptions, type TradeFeed, type TradeMarkerVariant, TradeMarkersPrimitive, type TradingCapabilities, TradingCapabilityError, type TradingCapabilityRequest, type TradingCapabilityResult, type TradingCapabilitySource, type TradingColors, TradingController, type TradingHost, type TradingLineStyle, type TradingLineVariant, type TradingOperation, type TradingOrder, type TradingOrderSide, type TradingOrderType, type TradingPosition, type TradingSettings, type TradingSyncPayload, type TradingTrade, type UTCSeconds, UnknownIntervalError, type UnsubscribeFn, VERSION, type VolumeBucketing, type VolumeMode, type WatermarkPosition, type Whitespace, type WsClientWarning, type WsControlMessage, type WsMode, type WsState, type ZOrder, type ZonedParts, type ZonedPeriod, type ZoomAnchor, ZoomGlide, type ZoomGlideOptions, addComparison, alertSettingsSchema, alignToPrimary, applyChartSettings, assertTradingCapability, atr, autoscaleRange, backendDegradation, backoffDelayMs, barCacheKey, barCloseSec, beginPick, bestHit, bitmapSize, bucketStartOf, calendarPeriodFlags, candleGeometry, candleTier, chartSettingsSchema, checkTradingCapability, clamp, classifyAuthAck, compactVolume, comparisonController, computePriceLevels, conflateBars, conflateItems, conflationGroupSize, createChart, createLinkGroup, createRenderBackend, darkTheme, dashPattern, decodeOrder, drawLabel, drawShape, effectiveMarkerPx, ema, emaSeries, epochMsToUtcSeconds, eventToCombo, exportChartDataCsv, followerIndex, followerRange, formatCombo, formatIstCrosshairLabel, formatIstDate, formatIstTime, formatIstTimeSeconds, formatSubscribe, formatUnsubscribe, formatZonedCrosshairLabel, formatZonedDate, formatZonedTime, formatZonedTimeSeconds, fromGradient, generateBars, getBarCondition, getChartType, getIndicator, hasIndicator, inSessionAt, indicatorDefaults, indicatorStyleInputs, intervalParts, intervalToSeconds, isDailyInterval, isIntradayInterval, isKnownInterval, isNewIstDay, isNewZonedDay, isNewZonedMonth, isNewZonedPeriod, isNewZonedQuarter, isNewZonedWeek, isNewZonedYear, isRebasing, isReplaying, isReservedCombo, isSecondsInterval, isTickInterval, isTimeBucketed, isValidCombo, isValidTimezone, isWhitespace, istStringToUtcSeconds, lastPriceLevelFromSeriesStyle, lerp, lightTheme, mapHistoryResponse, mapOrder, mapOrderStatus, mapPosition, markerSizePx, mergeBars, nextBucketStart, niceTicks, normalizeCombo, optimalBarWidth, parseAlertsDocument, parseCombo, parseMessage, parseSessionSpec, parseTopic, plotStyleKeys, precisionForStep, readChartSettings, readSequence, registerBarCondition, registerChartType, registerIndicator, registerInterval, registerRenderBackend, registeredBarConditions, registeredChartTypes, registeredIndicators, registeredIntervals, registeredRenderBackends, resolveCrosshairStyle, resolveGridStyle, resolveInterval, resolvePlotMargins, resolveRenderBackend, resolveScaleStyle, roundToTick, rowTimeToUtcSeconds, rsi, rsiSeries, seriesStyleForLastPriceLevel, sessionFlags, sessionStartFlags, sessionStartIndices, sharedHistoryRequests, snapToDevicePixel, sourceValue, sourceValues, startOfZonedDay, startOfZonedMonth, startOfZonedWeek, supertrend, supertrendSeries, tableOrigin, toBar, trueRange, tryResolveInterval, unregisterBarCondition, unregisterInterval, unregisterRenderBackend, utcSecondsToIstDateString, utcSecondsToIstParts, utcSecondsToZonedDateString, utcSecondsToZonedParts, version, verticalGradient, watermarkRect, withAlpha, withBarCache, zoneOffsetSeconds, zonedDayIndex, zonedStringToUtcSeconds, zonedWallClockToUtcSeconds, zonedWeekIndex };
|