openalgo-charts 2.5.6 → 2.5.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  /** Library version string. Matches package.json (including locally prepared releases). */
2
- declare const VERSION = "2.5.6";
2
+ declare const VERSION = "2.5.7";
3
3
  /** Returns the current library version. */
4
4
  declare function version(): string;
5
5
 
@@ -63,14 +63,6 @@ declare class InvalidateMask {
63
63
  merge(other: InvalidateMask): void;
64
64
  }
65
65
 
66
- /**
67
- * Frame scheduler (ARCHITECTURE.md §3.2). Coalesces many `requestFrame()` calls
68
- * within a single tick into one `onFrame` invocation. The rAF function is
69
- * injectable so the loop is deterministically testable without a browser.
70
- */
71
- type RafScheduler = (cb: () => void) => number;
72
- type RafCanceller = (handle: number) => void;
73
-
74
66
  /**
75
67
  * HiDPI canvas handling (ARCHITECTURE.md §3.1).
76
68
  *
@@ -4448,6 +4440,14 @@ declare class Pane {
4448
4440
  yToPrice(y: number): number;
4449
4441
  }
4450
4442
 
4443
+ /**
4444
+ * Frame scheduler (ARCHITECTURE.md §3.2). Coalesces many `requestFrame()` calls
4445
+ * within a single tick into one `onFrame` invocation. The rAF function is
4446
+ * injectable so the loop is deterministically testable without a browser.
4447
+ */
4448
+ type RafScheduler = (cb: () => void) => number;
4449
+ type RafCanceller = (handle: number) => void;
4450
+
4451
4451
  /**
4452
4452
  * Crosshair state + magnet snapping (ARCHITECTURE.md §6). Pure helpers so the
4453
4453
  * snap logic is unit-testable; drawing lives in render/crosshair.ts.
@@ -4574,227 +4574,6 @@ declare class ShortcutManager {
4574
4574
  static shouldIgnore(target: unknown): boolean;
4575
4575
  }
4576
4576
 
4577
- /**
4578
- * Trading visualization API (ARCHITECTURE.md §9). A data-driven layer on top of
4579
- * the chart: your app pushes exchange state (positions, orders, trades) and the
4580
- * chart renders labelled price-line "pills" (with a cancel/close button and
4581
- * drag-to-modify) plus trade-fill markers; user interaction is relayed back as
4582
- * `trading:*` events for the app to send to the exchange. Original,
4583
- * framework-free API.
4584
- */
4585
-
4586
- type PositionSide = 'long' | 'short';
4587
- type TradingOrderSide = 'buy' | 'sell';
4588
- type TradingOrderType = 'limit' | 'stop' | 'stop_limit';
4589
- type TradeMarkerVariant = 'chevron' | 'bubble' | 'count';
4590
- type TradingLineVariant = 'standard' | 'line-only';
4591
- type TradingLineStyle = 'solid' | 'dashed' | 'dotted';
4592
- interface TradingPosition {
4593
- id: string;
4594
- side: PositionSide;
4595
- entryPrice: number;
4596
- size: number;
4597
- pnlText?: string;
4598
- pnlPercent?: string;
4599
- color?: string;
4600
- readOnly?: boolean;
4601
- variant?: TradingLineVariant;
4602
- }
4603
- interface TradingOrder {
4604
- id: string;
4605
- type: TradingOrderType;
4606
- side: TradingOrderSide;
4607
- price: number;
4608
- size: number;
4609
- parentId?: string;
4610
- bracketRole?: 'tp' | 'sl';
4611
- color?: string;
4612
- lineStyle?: TradingLineStyle;
4613
- lineWidth?: number;
4614
- readOnly?: boolean;
4615
- draggable?: boolean;
4616
- variant?: TradingLineVariant;
4617
- }
4618
- interface TradingTrade {
4619
- id: string;
4620
- side: TradingOrderSide;
4621
- price: number;
4622
- size: number;
4623
- /** Execution time in milliseconds. */
4624
- timestamp: number;
4625
- variant?: TradeMarkerVariant;
4626
- color?: string;
4627
- label?: string;
4628
- }
4629
- interface TradingSyncPayload {
4630
- positions?: TradingPosition[];
4631
- orders?: TradingOrder[];
4632
- trades?: TradingTrade[];
4633
- }
4634
- interface TradingColors {
4635
- long: string;
4636
- short: string;
4637
- order: string;
4638
- tp: string;
4639
- sl: string;
4640
- buy: string;
4641
- sell: string;
4642
- }
4643
- interface TradingSettings {
4644
- longColor?: string;
4645
- shortColor?: string;
4646
- orderColor?: string;
4647
- tpColor?: string;
4648
- slColor?: string;
4649
- buyColor?: string;
4650
- sellColor?: string;
4651
- }
4652
- /** What the controller needs from the chart (the Chart implements this). */
4653
- interface TradingHost {
4654
- addPrimitive(p: IPrimitive): void;
4655
- removePrimitive(p: IPrimitive): void;
4656
- subscribeClick(cb: (externalId: string) => void): void;
4657
- subscribeDrag(onDrag: (externalId: string, price: number) => void, onDragEnd?: (externalId: string, price: number) => void): void;
4658
- /** Optional: route trading events onto the chart's unified `chart.on(...)` bus. */
4659
- emit?(event: string, payload: unknown): void;
4660
- /**
4661
- * Optional: the instrument's tick schedule when the layer is built. The
4662
- * layer is built on first use, often after the instrument was applied, and
4663
- * applying one cannot build the layer early: its click and drag
4664
- * subscriptions would replace the host's own.
4665
- */
4666
- tickSchedule?(): TickSchedule | null;
4667
- }
4668
- declare const DEFAULT_TRADING_COLORS: TradingColors;
4669
- /** Self-contained trade-fill markers (chevron / bubble / count) over the plot. */
4670
- declare class TradeMarkersPrimitive implements IPrimitive {
4671
- private _trades;
4672
- private _colors;
4673
- private _host;
4674
- constructor(colors: TradingColors);
4675
- attached(host: PrimitiveHost): void;
4676
- detached(): void;
4677
- zOrder(): ZOrder;
4678
- autoscaleInfo(): null;
4679
- setTrades(trades: TradingTrade[]): void;
4680
- setColors(colors: TradingColors): void;
4681
- draw(ctx: CanvasRenderingContext2D, rc: PrimitiveRenderContext): void;
4682
- }
4683
- declare class TradingController {
4684
- private readonly _host;
4685
- private readonly _positions;
4686
- private readonly _orders;
4687
- private readonly _trades;
4688
- private readonly _listeners;
4689
- private readonly _dragPrev;
4690
- private _colors;
4691
- private _markers;
4692
- private _ticks;
4693
- constructor(host: TradingHost);
4694
- on(event: string, cb: (payload: unknown) => void): () => void;
4695
- off(event: string, cb: (payload: unknown) => void): void;
4696
- private _emit;
4697
- setSettings(settings: TradingSettings): void;
4698
- getSettings(): TradingColors;
4699
- /**
4700
- * Snap dragged order and bracket lines, and the price their modify events
4701
- * carry, to the instrument's ticks. Null, the default, passes the pointer's
4702
- * price through unrounded, as it always has. The host's own validation stays
4703
- * authoritative either way; this only stops a drag previewing a price the
4704
- * instrument cannot trade at. `Instrument.applyTo` and
4705
- * `chart.setTickSchedule` set it, so call this after either to override it.
4706
- */
4707
- setTickSchedule(schedule: TickSchedule | null): void;
4708
- setPositions(positions: readonly TradingPosition[]): void;
4709
- setOrders(orders: readonly TradingOrder[]): void;
4710
- setTrades(trades: readonly TradingTrade[]): void;
4711
- addTrade(trade: TradingTrade): void;
4712
- upsertOrder(order: TradingOrder): void;
4713
- removeOrder(id: string): void;
4714
- syncState(payload: TradingSyncPayload): void;
4715
- updatePositionPnl(id: string, unrealizedPnl: number, pnlText?: string, pnlPercent?: string): void;
4716
- getPositions(): TradingPosition[];
4717
- getOrders(): TradingOrder[];
4718
- getTrades(): TradingTrade[];
4719
- clear(): void;
4720
- private _renderTrades;
4721
- private _sync;
4722
- private _sig;
4723
- /** Info segment for a position: live P&L text (side/size live in badge/qty). */
4724
- private _positionPill;
4725
- private _positionOpts;
4726
- private _orderOpts;
4727
- private _onClick;
4728
- private _onDrag;
4729
- private _onDragEnd;
4730
- }
4731
-
4732
- /**
4733
- * Interactive value capture (ARCHITECTURE.md §7). A settings input that names a
4734
- * price or a time is declarative and the host renders it, but the *value* can
4735
- * come from pointing at the chart, and only the engine knows what is under the
4736
- * cursor. So the host arms a pick ("the user is now choosing a price"), the next
4737
- * click on the plot answers with one, and the pick disarms itself.
4738
- *
4739
- * Built on the `click` event the draw tier's placement mode already resolves
4740
- * anchors from, rather than a second capture path: same pane resolution, same
4741
- * on-demand autoscale, same payload.
4742
- *
4743
- * Placement mode is deliberately *not* armed while picking. A pick wants panning
4744
- * left alone (scroll back to the bar you mean, then click it), and a drag emits
4745
- * no click outside placement mode, so panning cannot answer the pick by
4746
- * accident. It also keeps a pick from cancelling an active drawing tool.
4747
- */
4748
-
4749
- type PickKind = 'price' | 'time';
4750
- /**
4751
- * What a `'point'` pick answers: the bar time and the price under one click.
4752
- * One capture rather than a time pick and a price pick in turn, so a study
4753
- * input pairing the two is never written half from one click and half from
4754
- * another.
4755
- */
4756
- interface PickPoint {
4757
- time: number;
4758
- price: number;
4759
- }
4760
- /** Cancel a capture, or inspect whether this invocation still owns it. */
4761
- interface PickHandle {
4762
- (): void;
4763
- readonly active: () => boolean;
4764
- }
4765
- /** Optional target for Chart.beginPick. Times remain absolute UTC seconds. */
4766
- interface PickOptions {
4767
- paneIndex?: number;
4768
- priceScaleId?: PriceScaleId;
4769
- }
4770
- /**
4771
- * The slice of the chart a pick needs. Structural, so `Chart` satisfies it with
4772
- * nothing to cast and this module never imports the core (which imports this).
4773
- */
4774
- interface PickHost {
4775
- on(event: string, cb: (payload: unknown) => void): () => void;
4776
- emit(event: string, payload: unknown): void;
4777
- readonly dataLayer: {
4778
- timeToIndexFloat(time: number): number;
4779
- indexToTime(index: number): number | undefined;
4780
- };
4781
- }
4782
- /**
4783
- * Arm the next plot click to resolve to a price, a bar time, or both as a
4784
- * `'point'` ({@link PickPoint}), and hand it to `cb`. Returns a cancel
4785
- * function; calling it (or arming another pick on the same chart) disarms
4786
- * without calling back. The chart emits `pick:start`
4787
- * (`{ kind }`) and `pick:end` (`{ kind, value }`, `value` null when cancelled)
4788
- * so a host can show its own cursor or hint while the pick is live.
4789
- *
4790
- * A time is snapped to the bar the click landed on, because a time between two
4791
- * bars matches no bar and anything anchored to it would never line up. Clicking
4792
- * past the last bar keeps the projected time, which is what a pick in the empty
4793
- * right-hand space means.
4794
- */
4795
- declare function beginPick(host: PickHost, kind: 'point', cb: (value: PickPoint) => void): PickHandle;
4796
- declare function beginPick(host: PickHost, kind: PickKind, cb: (value: number) => void): PickHandle;
4797
-
4798
4577
  /** Time-anchored event badges. Event feeds and detail loading belong to the host. */
4799
4578
 
4800
4579
  interface EventDetailField {
@@ -4962,141 +4741,11 @@ declare class TimeNavigator implements IPrimitive {
4962
4741
  }
4963
4742
 
4964
4743
  /**
4965
- * Declarative chart-settings schema: the tabs and controls a host renders to
4966
- * build the terminal's settings dialog, without hardcoding a list.
4967
- *
4968
- * WHY it reuses `IndicatorInput` rather than inventing a widget vocabulary: a
4969
- * host that can already render the indicator settings form (built from
4970
- * `indicatorStyleInputs`) can render this one with no new widget code. It adds
4971
- * exactly one widget of its own, `colorPair`, because a bullish/bearish pair is
4972
- * one row of the dialog and expressing it as two `color` inputs forces a host
4973
- * into a section header plus two stacked rows: three times the height, for the
4974
- * property a trader changes most.
4975
- *
4976
- * WHY read/write live on the same object as the input: the schema and the
4977
- * accessors are one structure, so a control cannot drift from the option it
4978
- * drives, and there is no second table to keep in step. That is also the rule
4979
- * for what ships here: **every control maps to an option that actually changes
4980
- * what is drawn or stored.** Controls this engine has no backing for are absent
4981
- * rather than inert; a checkbox that does nothing is worse than one that is not
4982
- * there.
4983
- *
4984
- * The tabs are our own five, not a reference terminal's seven. Alerts are not
4985
- * here because the feature is not built, and corporate events are not here
4986
- * because nothing in the engine sources them: an empty tab is worse than an
4987
- * absent one.
4988
- *
4989
- * Keys are dotted paths (`symbol.upColor`, `canvas.grid.vertColor`), so a patch
4990
- * is a flat `Record<string, value>` that survives JSON. They are a wire format
4991
- * a host may have written down, so they stay put when the grouping above them
4992
- * changes: a key names the option it writes, not the tab it is shown on.
4993
- */
4994
-
4995
- /**
4996
- * Tabs of the settings dialog. Five groups, chosen so a trader finds a setting
4997
- * without hunting: what the instrument is painted with, what the header reads
4998
- * out, what the two axes do, what the surface around the data looks like, and
4999
- * what the trade layer draws.
5000
- */
5001
- type ChartSettingsTabId = 'price' | 'readout' | 'axes' | 'appearance' | 'trading';
5002
- /**
5003
- * Two colours on one labelled row, with an optional switch in front of them:
5004
- *
5005
- * [x] Borders [up] [down]
5006
- *
5007
- * `key` identifies the row and is not itself a value. The value keys are
5008
- * `up.key`, `down.key` and `enabled.key`, each an ordinary flat key of
5009
- * `ChartSettingsValues`, so a host patches this row exactly the way it patches
5010
- * a plain colour and nothing about read/apply has to know the widget exists.
5011
- *
5012
- * `enabled` is absent when the pair has no visibility flag behind it (a candle
5013
- * body is always drawn), which is the difference between a row whose checkbox
5014
- * does something and one whose checkbox would be a lie.
5015
- *
5016
- * It takes `visibleWhen` and `activeWhen`, and a condition that reads any of
5017
- * its three value keys reads the pair. It takes no `inline`: the row already
5018
- * holds a switch and two swatches, so it always stands on its own.
5019
- */
5020
- interface ChartSettingsColorPairInput extends Omit<IndicatorInputPresentation, 'inline'> {
5021
- key: string;
5022
- type: 'colorPair';
5023
- label: string;
5024
- group?: string;
5025
- /** Help text for the row, on the same terms as `IndicatorInput['tooltip']`. */
5026
- tooltip?: string;
5027
- enabled?: {
5028
- key: string;
5029
- default: boolean;
5030
- };
5031
- up: {
5032
- key: string;
5033
- label: string;
5034
- default: string;
5035
- };
5036
- down: {
5037
- key: string;
5038
- label: string;
5039
- default: string;
5040
- };
5041
- }
5042
- /** Everything a host may be handed in `ChartSettingsTab.inputs`. */
5043
- type ChartSettingsInput = IndicatorInput | ChartSettingsColorPairInput;
5044
- interface ChartSettingsTab {
5045
- id: ChartSettingsTabId;
5046
- label: string;
5047
- /** Controls in display order; `input.group` names the sub-heading. */
5048
- inputs: ChartSettingsInput[];
5049
- }
5050
- type ChartSettingsValue = string | number | boolean;
5051
- /** Flat, JSON-safe snapshot of every control, keyed by the schema's dotted key. */
5052
- type ChartSettingsValues = Record<string, ChartSettingsValue>;
5053
- /**
5054
- * The settings slice of a saved chart state. It is declared here rather than on
5055
- * `ChartState` so this module owns its own persistence: `chart.getState()`
5056
- * returns a `ChartState & ChartSettingsState`, which is still a `ChartState` to
5057
- * every existing consumer, and `restoreState` reads it back.
5058
- *
5059
- * `events` stays in the saved state although the dialog no longer offers the
5060
- * switches: the chart still owns `setEventOptions`, a host that feeds its own
5061
- * corporate actions still sets them, and dropping the field would throw that
5062
- * host's saved layout away.
5063
- */
5064
- interface ChartSettingsState {
5065
- navigation?: Partial<ChartNavigationOptions>;
5066
- canvas?: CanvasOptions;
5067
- statusLine?: LegendStatusLineOptions;
5068
- watermark?: ChartWatermarkOptions;
5069
- trading?: TradingSettings;
5070
- events?: ChartEventOptions;
5071
- /**
5072
- * The axis-strip switches. Only the switches: `AxisChromeOptions.clock` is a
5073
- * callback, which no JSON survives, and a host that supplied one supplies it
5074
- * again when it builds the chart.
5075
- */
5076
- axisChrome?: Pick<AxisChromeOptions, 'sessionClock' | 'barCountdown'>;
5077
- }
5078
- /**
5079
- * The settings dialog, described. Takes the chart because the Price tab depends
5080
- * on the primary series type (a candle has borders, a line has a dash), because
5081
- * the colour defaults come from the live theme, and because the timezone list
5082
- * has to include whatever zone the chart is already in.
5083
- */
5084
- declare function chartSettingsSchema(chart: Chart): ChartSettingsTab[];
5085
- /** Current value of every control in the schema, keyed the same way. */
5086
- declare function readChartSettings(chart: Chart): ChartSettingsValues;
5087
- /**
5088
- * Apply a patch produced by the dialog. Only the keys present are written, so a
5089
- * single changed control is a one-key object; unknown keys are ignored, which is
5090
- * what lets a state saved by a newer build restore into an older one.
5091
- */
5092
- declare function applyChartSettings(chart: Chart, patch: Readonly<Partial<ChartSettingsValues>>): void;
5093
-
5094
- /**
5095
- * Logo / brand watermark (ARCHITECTURE.md §8). Draws a small image (or an
5096
- * already-decoded bitmap) faintly in a corner of the plot, the way charting
5097
- * apps stamp a product/brand mark. Because it draws on the canvas it is captured
5098
- * by `chart.takeScreenshot()`, and an optional `tint` recolors the opaque pixels
5099
- * so a single-color logo reads on both dark and light themes.
4744
+ * Logo / brand watermark (ARCHITECTURE.md §8). Draws a small image (or an
4745
+ * already-decoded bitmap) faintly in a corner of the plot, the way charting
4746
+ * apps stamp a product/brand mark. Because it draws on the canvas it is captured
4747
+ * by `chart.takeScreenshot()`, and an optional `tint` recolors the opaque pixels
4748
+ * so a single-color logo reads on both dark and light themes.
5100
4749
  *
5101
4750
  * Pass a `src` (URL or data URI) or a preloaded `image` for custom artwork.
5102
4751
  * Without a source, the original OpenAlgo glyph draws without a network request.
@@ -5279,10 +4928,16 @@ declare class TextWatermark implements IPrimitive {
5279
4928
  }
5280
4929
 
5281
4930
  /**
5282
- * Top-level chart orchestrator (ARCHITECTURE.md §3.3). Owns the shared
5283
- * DataLayer + time scale, the panes, the invalidate mask, and the render loop.
5284
- * Phase 2 renders static candlesticks with price/time axes; pan/zoom (Phase 3)
5285
- * and live data (Phase 4) build on this.
4931
+ * The public option, event and payload types of the Chart class, with the two
4932
+ * small values published beside them (`compactVolume`, `PRICE_SCALE_MODES`).
4933
+ *
4934
+ * They sit in their own module so chart.ts can be split into internal pieces
4935
+ * without each piece importing the orchestrator for a type. chart.ts re-exports
4936
+ * every name declared here, so an import of './chart' or '../core/chart' keeps
4937
+ * the same names at the same path. `ChartClickEvent` and `PriceAxisState` are
4938
+ * declared in chart.ts instead: they carry deprecated members, and the
4939
+ * deprecation inventory (COMPATIBILITY.md and its test) names chart.ts as
4940
+ * their home.
5286
4941
  */
5287
4942
 
5288
4943
  /** What a wheel zoom holds still. */
@@ -5301,7 +4956,6 @@ interface DoubleClickEvent {
5301
4956
  y: number;
5302
4957
  handled: boolean;
5303
4958
  }
5304
-
5305
4959
  /** Optional background text. Blank text follows the chart's symbol and interval. */
5306
4960
  interface ChartWatermarkOptions extends Partial<TextWatermarkOptions> {
5307
4961
  visible?: boolean;
@@ -5414,8 +5068,8 @@ interface ChartOptions {
5414
5068
  navigation?: Partial<ChartNavigationOptions>;
5415
5069
  /**
5416
5070
  * Where indicator legend rows start inside **one** pane, in media px. A host
5417
- * that draws its own overlay in a pane's top-left corner — an OHLC readout, a
5418
- * symbol line, a trade panel — needs to push these clear of it, or the rows
5071
+ * that draws its own overlay in a pane's top-left corner (an OHLC readout, a
5072
+ * symbol line, a trade panel) needs to push these clear of it, or the rows
5419
5073
  * land underneath and their settings / close buttons become invisible and
5420
5074
  * unclickable.
5421
5075
  *
@@ -5433,8 +5087,8 @@ interface ChartOptions {
5433
5087
  left?: number;
5434
5088
  };
5435
5089
  /**
5436
- * Crosshair behaviour. 'normal' (default) — the cross follows the pointer
5437
- * exactly. 'magnet' — the horizontal line snaps to the nearest O/H/L/C of the
5090
+ * Crosshair behaviour. 'normal' (default): the cross follows the pointer
5091
+ * exactly. 'magnet': the horizontal line snaps to the nearest O/H/L/C of the
5438
5092
  * bar under the cursor (price pane only).
5439
5093
  */
5440
5094
  crosshairMode?: CrosshairMode;
@@ -5573,7 +5227,7 @@ interface ChartOptions {
5573
5227
  timezone?: string;
5574
5228
  /**
5575
5229
  * Hover-revealed zoom / step controls above the time axis, as terminals show.
5576
- * `true` by default — they stay invisible until the pointer nears the bottom
5230
+ * `true` by default: they stay invisible until the pointer nears the bottom
5577
5231
  * of the chart. Pass `false` to drop them, or an options object to restyle.
5578
5232
  */
5579
5233
  timeNavigator?: boolean | Partial<TimeNavigatorOptions>;
@@ -5683,25 +5337,505 @@ interface PointerModifiers {
5683
5337
  /** Device behind a pointer gesture. Anything the browser does not name reports as a mouse. */
5684
5338
  type PointerKind = 'mouse' | 'touch' | 'pen';
5685
5339
  /**
5686
- * One position a pointer passed through during a drag, in the same media px
5687
- * space as the payload's `point` (container x, pane-local y). `pressure` is
5688
- * the pointer events convention: 0..1 from hardware that measures it, 0.5
5689
- * while a button that cannot is held, 0 when nothing is known.
5340
+ * One position a pointer passed through during a drag, in the same media px
5341
+ * space as the payload's `point` (container x, pane-local y). `pressure` is
5342
+ * the pointer events convention: 0..1 from hardware that measures it, 0.5
5343
+ * while a button that cannot is held, 0 when nothing is known.
5344
+ */
5345
+ interface PointerSample {
5346
+ x: number;
5347
+ y: number;
5348
+ pressure: number;
5349
+ }
5350
+ /**
5351
+ * What the engine reports about the physical pointer behind a gesture.
5352
+ * `crosshair:move`, `click`, `drag:start`, `drag` and `drag:end` all carry these keys.
5353
+ */
5354
+ interface PointerInfo {
5355
+ modifiers: PointerModifiers;
5356
+ pointerType: PointerKind;
5357
+ pressure: number;
5358
+ }
5359
+ /** An event-strip click, including every member of a clustered marker. */
5360
+ interface ChartEventClick extends EventMarkerDetails {
5361
+ /** Chart-container CSS pixels, including the vertical offset of an event pane. */
5362
+ point: {
5363
+ x: number;
5364
+ y: number;
5365
+ };
5366
+ paneIndex: number;
5367
+ }
5368
+ /** Payload of the `drag` event: a draggable primitive being moved. */
5369
+ interface ChartDragEvent extends PointerInfo {
5370
+ id: string;
5371
+ price: number;
5372
+ time: number;
5373
+ paneIndex: number;
5374
+ /** Where the gesture was grabbed, so a delta starts at the press rather than the first move. */
5375
+ fromPrice: number;
5376
+ fromTime: number;
5377
+ /** Current pointer position: container media x, pane-local media y. */
5378
+ point: {
5379
+ x: number;
5380
+ y: number;
5381
+ };
5382
+ /**
5383
+ * Every position the pointer passed through since the previous `drag`,
5384
+ * oldest first, the last one at `point`. Browsers deliver moves at frame
5385
+ * rate and fold the positions between frames into the event; a freehand
5386
+ * stroke drawn from `point` alone is a polyline of frame-rate corners.
5387
+ */
5388
+ samples: PointerSample[];
5389
+ }
5390
+ /** Payload of `drag:start` (press) and `drag:end` (release) for a primitive drag. */
5391
+ interface ChartDragEndEvent extends PointerInfo {
5392
+ id: string;
5393
+ price: number;
5394
+ time: number;
5395
+ paneIndex: number;
5396
+ /** Release position: container media x, pane-local media y. */
5397
+ point: {
5398
+ x: number;
5399
+ y: number;
5400
+ };
5401
+ }
5402
+ /**
5403
+ * What the pointer was over when the context menu was raised. The chart cannot
5404
+ * know which menu items an app wants, but it does know what was hit, which is
5405
+ * the part an app cannot work out for itself: a canvas gives it a pixel, not an
5406
+ * object. `primitive` is anything hit-testable that is not one of the named
5407
+ * kinds (a price line, an order pill, a marker).
5408
+ */
5409
+ type ContextMenuTargetKind = 'drawing' | 'indicator' | 'legend' | 'primitive' | 'series' | 'price-scale' | 'time-scale' | 'empty';
5410
+ interface ContextMenuTarget {
5411
+ kind: ContextMenuTargetKind;
5412
+ /** Hit-test id of the thing under the pointer, when there was one. */
5413
+ id: string | null;
5414
+ /** Indicator instance id, when `kind` is 'indicator'. */
5415
+ instanceId?: string;
5416
+ /** Exact plot key when a study's plotted series was hit rather than its legend. */
5417
+ plotKey?: string;
5418
+ /** Series type, when `kind` is 'series'. */
5419
+ seriesType?: SeriesType;
5420
+ /** Which axis strip was hit, when `kind` is 'price-scale'. */
5421
+ side?: 'right' | 'left';
5422
+ /**
5423
+ * Which of the pane's scales that strip acts on, when `kind` is
5424
+ * 'price-scale': the side's own scale, or the hidden overlay scale ('') when
5425
+ * the side carries no series of its own and the pane's values are all on the
5426
+ * overlay. It is the argument the `priceAxis*` calls take.
5427
+ */
5428
+ scaleId?: PriceScaleId;
5429
+ }
5430
+ /** The four price-scale modes, in the order a menu lists them. */
5431
+ declare const PRICE_SCALE_MODES: readonly PriceScaleMode[];
5432
+ /**
5433
+ * The setters that change what `getState` saves without an event of their
5434
+ * own, and so announce it with `layout:change`.
5435
+ */
5436
+ type LayoutSetter = 'setPaneWeight' | 'setPriceAxisOptions' | 'setPriceAxisAutoFit' | 'setPriceAxisLockRatio' | 'setPriceScaleOptions' | 'setAutoScale' | 'setGridOptions' | 'setCanvasOptions' | 'setStatusLineOptions' | 'setWatermarkOptions' | 'setTradingSettings' | 'setAxisChromeOptions' | 'setEventOptions' | 'applyOptions';
5437
+ /**
5438
+ * Payload of the `layout:change` event (`chart.on('layout:change', ...)`):
5439
+ * a setter in {@link LayoutSetter} has run and the saved layout may differ.
5440
+ * It fires once per outermost call, after the change is applied: the canvas
5441
+ * block setting the grid on its way is one event, named `setCanvasOptions`.
5442
+ * A call that names no pane or scale the chart has changes nothing and fires
5443
+ * nothing, and neither does a restore, which announces itself with
5444
+ * `state:restore:start` and `state:restore:end`. Compare what you read back
5445
+ * if a no-op matters: setting a value to what it already was still fires.
5446
+ */
5447
+ interface LayoutChangeEvent {
5448
+ setter: LayoutSetter;
5449
+ }
5450
+ /** Payload of the `contextmenu` event (`chart.on('contextmenu', ...)`). */
5451
+ interface ContextMenuEvent {
5452
+ paneIndex: number;
5453
+ /** Cursor position in container media px, for placing the menu. */
5454
+ point: {
5455
+ x: number;
5456
+ y: number;
5457
+ };
5458
+ /** Price under the pointer on that pane, or null off the plot. */
5459
+ price: number | null;
5460
+ /** UTC seconds under the pointer, or null when there is no data. */
5461
+ time: number | null;
5462
+ /** Logical bar index under the pointer, or null off the plot. */
5463
+ index: number | null;
5464
+ target: ContextMenuTarget;
5465
+ /** Suppress the browser's own menu. Call it to show your own. */
5466
+ preventDefault(): void;
5467
+ }
5468
+ /**
5469
+ * Payload of the 'renderer:fallback' event: the chart has moved every pane
5470
+ * from a GPU backend to `canvas2d` for the rest of the session, because the
5471
+ * device's context was lost or turned out unusable. The frame that noticed
5472
+ * was already painted through 2D by the backend itself, so nothing went
5473
+ * blank; this is the host's cue to update anything that shows the renderer.
5474
+ */
5475
+ interface RendererFallbackEvent {
5476
+ from: RenderBackendKind;
5477
+ to: 'canvas2d';
5478
+ reason: RendererFallbackReason;
5479
+ }
5480
+
5481
+ /**
5482
+ * Trading visualization API (ARCHITECTURE.md §9). A data-driven layer on top of
5483
+ * the chart: your app pushes exchange state (positions, orders, trades) and the
5484
+ * chart renders labelled price-line "pills" (with a cancel/close button and
5485
+ * drag-to-modify) plus trade-fill markers; user interaction is relayed back as
5486
+ * `trading:*` events for the app to send to the exchange. Original,
5487
+ * framework-free API.
5488
+ */
5489
+
5490
+ type PositionSide = 'long' | 'short';
5491
+ type TradingOrderSide = 'buy' | 'sell';
5492
+ type TradingOrderType = 'limit' | 'stop' | 'stop_limit';
5493
+ type TradeMarkerVariant = 'chevron' | 'bubble' | 'count';
5494
+ type TradingLineVariant = 'standard' | 'line-only';
5495
+ type TradingLineStyle = 'solid' | 'dashed' | 'dotted';
5496
+ interface TradingPosition {
5497
+ id: string;
5498
+ side: PositionSide;
5499
+ entryPrice: number;
5500
+ size: number;
5501
+ pnlText?: string;
5502
+ pnlPercent?: string;
5503
+ color?: string;
5504
+ readOnly?: boolean;
5505
+ variant?: TradingLineVariant;
5506
+ }
5507
+ interface TradingOrder {
5508
+ id: string;
5509
+ type: TradingOrderType;
5510
+ side: TradingOrderSide;
5511
+ price: number;
5512
+ size: number;
5513
+ parentId?: string;
5514
+ bracketRole?: 'tp' | 'sl';
5515
+ color?: string;
5516
+ lineStyle?: TradingLineStyle;
5517
+ lineWidth?: number;
5518
+ readOnly?: boolean;
5519
+ draggable?: boolean;
5520
+ variant?: TradingLineVariant;
5521
+ }
5522
+ interface TradingTrade {
5523
+ id: string;
5524
+ side: TradingOrderSide;
5525
+ price: number;
5526
+ size: number;
5527
+ /** Execution time in milliseconds. */
5528
+ timestamp: number;
5529
+ variant?: TradeMarkerVariant;
5530
+ color?: string;
5531
+ label?: string;
5532
+ }
5533
+ interface TradingSyncPayload {
5534
+ positions?: TradingPosition[];
5535
+ orders?: TradingOrder[];
5536
+ trades?: TradingTrade[];
5537
+ }
5538
+ interface TradingColors {
5539
+ long: string;
5540
+ short: string;
5541
+ order: string;
5542
+ tp: string;
5543
+ sl: string;
5544
+ buy: string;
5545
+ sell: string;
5546
+ }
5547
+ interface TradingSettings {
5548
+ longColor?: string;
5549
+ shortColor?: string;
5550
+ orderColor?: string;
5551
+ tpColor?: string;
5552
+ slColor?: string;
5553
+ buyColor?: string;
5554
+ sellColor?: string;
5555
+ }
5556
+ /** What the controller needs from the chart (the Chart implements this). */
5557
+ interface TradingHost {
5558
+ addPrimitive(p: IPrimitive): void;
5559
+ removePrimitive(p: IPrimitive): void;
5560
+ subscribeClick(cb: (externalId: string) => void): void;
5561
+ subscribeDrag(onDrag: (externalId: string, price: number) => void, onDragEnd?: (externalId: string, price: number) => void): void;
5562
+ /** Optional: route trading events onto the chart's unified `chart.on(...)` bus. */
5563
+ emit?(event: string, payload: unknown): void;
5564
+ /**
5565
+ * Optional: the instrument's tick schedule when the layer is built. The
5566
+ * layer is built on first use, often after the instrument was applied, and
5567
+ * applying one cannot build the layer early: its click and drag
5568
+ * subscriptions would replace the host's own.
5569
+ */
5570
+ tickSchedule?(): TickSchedule | null;
5571
+ }
5572
+ declare const DEFAULT_TRADING_COLORS: TradingColors;
5573
+ /** Self-contained trade-fill markers (chevron / bubble / count) over the plot. */
5574
+ declare class TradeMarkersPrimitive implements IPrimitive {
5575
+ private _trades;
5576
+ private _colors;
5577
+ private _host;
5578
+ constructor(colors: TradingColors);
5579
+ attached(host: PrimitiveHost): void;
5580
+ detached(): void;
5581
+ zOrder(): ZOrder;
5582
+ autoscaleInfo(): null;
5583
+ setTrades(trades: TradingTrade[]): void;
5584
+ setColors(colors: TradingColors): void;
5585
+ draw(ctx: CanvasRenderingContext2D, rc: PrimitiveRenderContext): void;
5586
+ }
5587
+ declare class TradingController {
5588
+ private readonly _host;
5589
+ private readonly _positions;
5590
+ private readonly _orders;
5591
+ private readonly _trades;
5592
+ private readonly _listeners;
5593
+ private readonly _dragPrev;
5594
+ private _colors;
5595
+ private _markers;
5596
+ private _ticks;
5597
+ constructor(host: TradingHost);
5598
+ on(event: string, cb: (payload: unknown) => void): () => void;
5599
+ off(event: string, cb: (payload: unknown) => void): void;
5600
+ private _emit;
5601
+ setSettings(settings: TradingSettings): void;
5602
+ getSettings(): TradingColors;
5603
+ /**
5604
+ * Snap dragged order and bracket lines, and the price their modify events
5605
+ * carry, to the instrument's ticks. Null, the default, passes the pointer's
5606
+ * price through unrounded, as it always has. The host's own validation stays
5607
+ * authoritative either way; this only stops a drag previewing a price the
5608
+ * instrument cannot trade at. `Instrument.applyTo` and
5609
+ * `chart.setTickSchedule` set it, so call this after either to override it.
5610
+ */
5611
+ setTickSchedule(schedule: TickSchedule | null): void;
5612
+ setPositions(positions: readonly TradingPosition[]): void;
5613
+ setOrders(orders: readonly TradingOrder[]): void;
5614
+ setTrades(trades: readonly TradingTrade[]): void;
5615
+ addTrade(trade: TradingTrade): void;
5616
+ upsertOrder(order: TradingOrder): void;
5617
+ removeOrder(id: string): void;
5618
+ syncState(payload: TradingSyncPayload): void;
5619
+ updatePositionPnl(id: string, unrealizedPnl: number, pnlText?: string, pnlPercent?: string): void;
5620
+ getPositions(): TradingPosition[];
5621
+ getOrders(): TradingOrder[];
5622
+ getTrades(): TradingTrade[];
5623
+ clear(): void;
5624
+ private _renderTrades;
5625
+ private _sync;
5626
+ private _sig;
5627
+ /** Info segment for a position: live P&L text (side/size live in badge/qty). */
5628
+ private _positionPill;
5629
+ private _positionOpts;
5630
+ private _orderOpts;
5631
+ private _onClick;
5632
+ private _onDrag;
5633
+ private _onDragEnd;
5634
+ }
5635
+
5636
+ /**
5637
+ * Interactive value capture (ARCHITECTURE.md §7). A settings input that names a
5638
+ * price or a time is declarative and the host renders it, but the *value* can
5639
+ * come from pointing at the chart, and only the engine knows what is under the
5640
+ * cursor. So the host arms a pick ("the user is now choosing a price"), the next
5641
+ * click on the plot answers with one, and the pick disarms itself.
5642
+ *
5643
+ * Built on the `click` event the draw tier's placement mode already resolves
5644
+ * anchors from, rather than a second capture path: same pane resolution, same
5645
+ * on-demand autoscale, same payload.
5646
+ *
5647
+ * Placement mode is deliberately *not* armed while picking. A pick wants panning
5648
+ * left alone (scroll back to the bar you mean, then click it), and a drag emits
5649
+ * no click outside placement mode, so panning cannot answer the pick by
5650
+ * accident. It also keeps a pick from cancelling an active drawing tool.
5651
+ */
5652
+
5653
+ type PickKind = 'price' | 'time';
5654
+ /**
5655
+ * What a `'point'` pick answers: the bar time and the price under one click.
5656
+ * One capture rather than a time pick and a price pick in turn, so a study
5657
+ * input pairing the two is never written half from one click and half from
5658
+ * another.
5659
+ */
5660
+ interface PickPoint {
5661
+ time: number;
5662
+ price: number;
5663
+ }
5664
+ /** Cancel a capture, or inspect whether this invocation still owns it. */
5665
+ interface PickHandle {
5666
+ (): void;
5667
+ readonly active: () => boolean;
5668
+ }
5669
+ /** Optional target for Chart.beginPick. Times remain absolute UTC seconds. */
5670
+ interface PickOptions {
5671
+ paneIndex?: number;
5672
+ priceScaleId?: PriceScaleId;
5673
+ }
5674
+ /**
5675
+ * The slice of the chart a pick needs. Structural, so `Chart` satisfies it with
5676
+ * nothing to cast and this module never imports the core (which imports this).
5677
+ */
5678
+ interface PickHost {
5679
+ on(event: string, cb: (payload: unknown) => void): () => void;
5680
+ emit(event: string, payload: unknown): void;
5681
+ readonly dataLayer: {
5682
+ timeToIndexFloat(time: number): number;
5683
+ indexToTime(index: number): number | undefined;
5684
+ };
5685
+ }
5686
+ /**
5687
+ * Arm the next plot click to resolve to a price, a bar time, or both as a
5688
+ * `'point'` ({@link PickPoint}), and hand it to `cb`. Returns a cancel
5689
+ * function; calling it (or arming another pick on the same chart) disarms
5690
+ * without calling back. The chart emits `pick:start`
5691
+ * (`{ kind }`) and `pick:end` (`{ kind, value }`, `value` null when cancelled)
5692
+ * so a host can show its own cursor or hint while the pick is live.
5693
+ *
5694
+ * A time is snapped to the bar the click landed on, because a time between two
5695
+ * bars matches no bar and anything anchored to it would never line up. Clicking
5696
+ * past the last bar keeps the projected time, which is what a pick in the empty
5697
+ * right-hand space means.
5698
+ */
5699
+ declare function beginPick(host: PickHost, kind: 'point', cb: (value: PickPoint) => void): PickHandle;
5700
+ declare function beginPick(host: PickHost, kind: PickKind, cb: (value: number) => void): PickHandle;
5701
+
5702
+ /**
5703
+ * Declarative chart-settings schema: the tabs and controls a host renders to
5704
+ * build the terminal's settings dialog, without hardcoding a list.
5705
+ *
5706
+ * WHY it reuses `IndicatorInput` rather than inventing a widget vocabulary: a
5707
+ * host that can already render the indicator settings form (built from
5708
+ * `indicatorStyleInputs`) can render this one with no new widget code. It adds
5709
+ * exactly one widget of its own, `colorPair`, because a bullish/bearish pair is
5710
+ * one row of the dialog and expressing it as two `color` inputs forces a host
5711
+ * into a section header plus two stacked rows: three times the height, for the
5712
+ * property a trader changes most.
5713
+ *
5714
+ * WHY read/write live on the same object as the input: the schema and the
5715
+ * accessors are one structure, so a control cannot drift from the option it
5716
+ * drives, and there is no second table to keep in step. That is also the rule
5717
+ * for what ships here: **every control maps to an option that actually changes
5718
+ * what is drawn or stored.** Controls this engine has no backing for are absent
5719
+ * rather than inert; a checkbox that does nothing is worse than one that is not
5720
+ * there.
5721
+ *
5722
+ * The tabs are our own five, not a reference terminal's seven. Alerts are not
5723
+ * here because the feature is not built, and corporate events are not here
5724
+ * because nothing in the engine sources them: an empty tab is worse than an
5725
+ * absent one.
5726
+ *
5727
+ * Keys are dotted paths (`symbol.upColor`, `canvas.grid.vertColor`), so a patch
5728
+ * is a flat `Record<string, value>` that survives JSON. They are a wire format
5729
+ * a host may have written down, so they stay put when the grouping above them
5730
+ * changes: a key names the option it writes, not the tab it is shown on.
5731
+ */
5732
+
5733
+ /**
5734
+ * Tabs of the settings dialog. Five groups, chosen so a trader finds a setting
5735
+ * without hunting: what the instrument is painted with, what the header reads
5736
+ * out, what the two axes do, what the surface around the data looks like, and
5737
+ * what the trade layer draws.
5738
+ */
5739
+ type ChartSettingsTabId = 'price' | 'readout' | 'axes' | 'appearance' | 'trading';
5740
+ /**
5741
+ * Two colours on one labelled row, with an optional switch in front of them:
5742
+ *
5743
+ * [x] Borders [up] [down]
5744
+ *
5745
+ * `key` identifies the row and is not itself a value. The value keys are
5746
+ * `up.key`, `down.key` and `enabled.key`, each an ordinary flat key of
5747
+ * `ChartSettingsValues`, so a host patches this row exactly the way it patches
5748
+ * a plain colour and nothing about read/apply has to know the widget exists.
5749
+ *
5750
+ * `enabled` is absent when the pair has no visibility flag behind it (a candle
5751
+ * body is always drawn), which is the difference between a row whose checkbox
5752
+ * does something and one whose checkbox would be a lie.
5753
+ *
5754
+ * It takes `visibleWhen` and `activeWhen`, and a condition that reads any of
5755
+ * its three value keys reads the pair. It takes no `inline`: the row already
5756
+ * holds a switch and two swatches, so it always stands on its own.
5757
+ */
5758
+ interface ChartSettingsColorPairInput extends Omit<IndicatorInputPresentation, 'inline'> {
5759
+ key: string;
5760
+ type: 'colorPair';
5761
+ label: string;
5762
+ group?: string;
5763
+ /** Help text for the row, on the same terms as `IndicatorInput['tooltip']`. */
5764
+ tooltip?: string;
5765
+ enabled?: {
5766
+ key: string;
5767
+ default: boolean;
5768
+ };
5769
+ up: {
5770
+ key: string;
5771
+ label: string;
5772
+ default: string;
5773
+ };
5774
+ down: {
5775
+ key: string;
5776
+ label: string;
5777
+ default: string;
5778
+ };
5779
+ }
5780
+ /** Everything a host may be handed in `ChartSettingsTab.inputs`. */
5781
+ type ChartSettingsInput = IndicatorInput | ChartSettingsColorPairInput;
5782
+ interface ChartSettingsTab {
5783
+ id: ChartSettingsTabId;
5784
+ label: string;
5785
+ /** Controls in display order; `input.group` names the sub-heading. */
5786
+ inputs: ChartSettingsInput[];
5787
+ }
5788
+ type ChartSettingsValue = string | number | boolean;
5789
+ /** Flat, JSON-safe snapshot of every control, keyed by the schema's dotted key. */
5790
+ type ChartSettingsValues = Record<string, ChartSettingsValue>;
5791
+ /**
5792
+ * The settings slice of a saved chart state. It is declared here rather than on
5793
+ * `ChartState` so this module owns its own persistence: `chart.getState()`
5794
+ * returns a `ChartState & ChartSettingsState`, which is still a `ChartState` to
5795
+ * every existing consumer, and `restoreState` reads it back.
5796
+ *
5797
+ * `events` stays in the saved state although the dialog no longer offers the
5798
+ * switches: the chart still owns `setEventOptions`, a host that feeds its own
5799
+ * corporate actions still sets them, and dropping the field would throw that
5800
+ * host's saved layout away.
5801
+ */
5802
+ interface ChartSettingsState {
5803
+ navigation?: Partial<ChartNavigationOptions>;
5804
+ canvas?: CanvasOptions;
5805
+ statusLine?: LegendStatusLineOptions;
5806
+ watermark?: ChartWatermarkOptions;
5807
+ trading?: TradingSettings;
5808
+ events?: ChartEventOptions;
5809
+ /**
5810
+ * The axis-strip switches. Only the switches: `AxisChromeOptions.clock` is a
5811
+ * callback, which no JSON survives, and a host that supplied one supplies it
5812
+ * again when it builds the chart.
5813
+ */
5814
+ axisChrome?: Pick<AxisChromeOptions, 'sessionClock' | 'barCountdown'>;
5815
+ }
5816
+ /**
5817
+ * The settings dialog, described. Takes the chart because the Price tab depends
5818
+ * on the primary series type (a candle has borders, a line has a dash), because
5819
+ * the colour defaults come from the live theme, and because the timezone list
5820
+ * has to include whatever zone the chart is already in.
5821
+ */
5822
+ declare function chartSettingsSchema(chart: Chart): ChartSettingsTab[];
5823
+ /** Current value of every control in the schema, keyed the same way. */
5824
+ declare function readChartSettings(chart: Chart): ChartSettingsValues;
5825
+ /**
5826
+ * Apply a patch produced by the dialog. Only the keys present are written, so a
5827
+ * single changed control is a one-key object; unknown keys are ignored, which is
5828
+ * what lets a state saved by a newer build restore into an older one.
5690
5829
  */
5691
- interface PointerSample {
5692
- x: number;
5693
- y: number;
5694
- pressure: number;
5695
- }
5830
+ declare function applyChartSettings(chart: Chart, patch: Readonly<Partial<ChartSettingsValues>>): void;
5831
+
5696
5832
  /**
5697
- * What the engine reports about the physical pointer behind a gesture.
5698
- * `crosshair:move`, `click`, `drag:start`, `drag` and `drag:end` all carry these keys.
5833
+ * Top-level chart orchestrator (ARCHITECTURE.md §3.3). Owns the shared
5834
+ * DataLayer + time scale, the panes, the invalidate mask, and the render loop.
5835
+ * Phase 2 renders static candlesticks with price/time axes; pan/zoom (Phase 3)
5836
+ * and live data (Phase 4) build on this.
5699
5837
  */
5700
- interface PointerInfo {
5701
- modifiers: PointerModifiers;
5702
- pointerType: PointerKind;
5703
- pressure: number;
5704
- }
5838
+
5705
5839
  /**
5706
5840
  * Payload of the `click` event (`chart.on('click', ...)`). Its `pressure` is
5707
5841
  * the pressure at the press, not the release, which always reads 0.
@@ -5733,79 +5867,6 @@ interface ChartClickEvent extends PointerInfo {
5733
5867
  /** @deprecated Removed in 3.0.0. Read `modifiers.meta` (since 2.0.0), which carries the same state. */
5734
5868
  metaKey: boolean;
5735
5869
  }
5736
- /** An event-strip click, including every member of a clustered marker. */
5737
- interface ChartEventClick extends EventMarkerDetails {
5738
- /** Chart-container CSS pixels, including the vertical offset of an event pane. */
5739
- point: {
5740
- x: number;
5741
- y: number;
5742
- };
5743
- paneIndex: number;
5744
- }
5745
- /** Payload of the `drag` event: a draggable primitive being moved. */
5746
- interface ChartDragEvent extends PointerInfo {
5747
- id: string;
5748
- price: number;
5749
- time: number;
5750
- paneIndex: number;
5751
- /** Where the gesture was grabbed, so a delta starts at the press rather than the first move. */
5752
- fromPrice: number;
5753
- fromTime: number;
5754
- /** Current pointer position: container media x, pane-local media y. */
5755
- point: {
5756
- x: number;
5757
- y: number;
5758
- };
5759
- /**
5760
- * Every position the pointer passed through since the previous `drag`,
5761
- * oldest first, the last one at `point`. Browsers deliver moves at frame
5762
- * rate and fold the positions between frames into the event; a freehand
5763
- * stroke drawn from `point` alone is a polyline of frame-rate corners.
5764
- */
5765
- samples: PointerSample[];
5766
- }
5767
- /** Payload of `drag:start` (press) and `drag:end` (release) for a primitive drag. */
5768
- interface ChartDragEndEvent extends PointerInfo {
5769
- id: string;
5770
- price: number;
5771
- time: number;
5772
- paneIndex: number;
5773
- /** Release position: container media x, pane-local media y. */
5774
- point: {
5775
- x: number;
5776
- y: number;
5777
- };
5778
- }
5779
- /**
5780
- * What the pointer was over when the context menu was raised. The chart cannot
5781
- * know which menu items an app wants, but it does know what was hit, which is
5782
- * the part an app cannot work out for itself: a canvas gives it a pixel, not an
5783
- * object. `primitive` is anything hit-testable that is not one of the named
5784
- * kinds (a price line, an order pill, a marker).
5785
- */
5786
- type ContextMenuTargetKind = 'drawing' | 'indicator' | 'legend' | 'primitive' | 'series' | 'price-scale' | 'time-scale' | 'empty';
5787
- interface ContextMenuTarget {
5788
- kind: ContextMenuTargetKind;
5789
- /** Hit-test id of the thing under the pointer, when there was one. */
5790
- id: string | null;
5791
- /** Indicator instance id, when `kind` is 'indicator'. */
5792
- instanceId?: string;
5793
- /** Exact plot key when a study's plotted series was hit rather than its legend. */
5794
- plotKey?: string;
5795
- /** Series type, when `kind` is 'series'. */
5796
- seriesType?: SeriesType;
5797
- /** Which axis strip was hit, when `kind` is 'price-scale'. */
5798
- side?: 'right' | 'left';
5799
- /**
5800
- * Which of the pane's scales that strip acts on, when `kind` is
5801
- * 'price-scale': the side's own scale, or the hidden overlay scale ('') when
5802
- * the side carries no series of its own and the pane's values are all on the
5803
- * overlay. It is the argument the `priceAxis*` calls take.
5804
- */
5805
- scaleId?: PriceScaleId;
5806
- }
5807
- /** The four price-scale modes, in the order a menu lists them. */
5808
- declare const PRICE_SCALE_MODES: readonly PriceScaleMode[];
5809
5870
  /**
5810
5871
  * What a host needs to render a menu over one price axis: which items are on,
5811
5872
  * and which of them mean anything on this axis. See `Chart.priceAxisState`.
@@ -5832,54 +5893,6 @@ interface PriceAxisState {
5832
5893
  */
5833
5894
  movable: boolean;
5834
5895
  }
5835
- /**
5836
- * The setters that change what `getState` saves without an event of their
5837
- * own, and so announce it with `layout:change`.
5838
- */
5839
- type LayoutSetter = 'setPaneWeight' | 'setPriceAxisOptions' | 'setPriceAxisAutoFit' | 'setPriceAxisLockRatio' | 'setPriceScaleOptions' | 'setAutoScale' | 'setGridOptions' | 'setCanvasOptions' | 'setStatusLineOptions' | 'setWatermarkOptions' | 'setTradingSettings' | 'setAxisChromeOptions' | 'setEventOptions' | 'applyOptions';
5840
- /**
5841
- * Payload of the `layout:change` event (`chart.on('layout:change', ...)`):
5842
- * a setter in {@link LayoutSetter} has run and the saved layout may differ.
5843
- * It fires once per outermost call, after the change is applied: the canvas
5844
- * block setting the grid on its way is one event, named `setCanvasOptions`.
5845
- * A call that names no pane or scale the chart has changes nothing and fires
5846
- * nothing, and neither does a restore, which announces itself with
5847
- * `state:restore:start` and `state:restore:end`. Compare what you read back
5848
- * if a no-op matters: setting a value to what it already was still fires.
5849
- */
5850
- interface LayoutChangeEvent {
5851
- setter: LayoutSetter;
5852
- }
5853
- /** Payload of the `contextmenu` event (`chart.on('contextmenu', ...)`). */
5854
- interface ContextMenuEvent {
5855
- paneIndex: number;
5856
- /** Cursor position in container media px, for placing the menu. */
5857
- point: {
5858
- x: number;
5859
- y: number;
5860
- };
5861
- /** Price under the pointer on that pane, or null off the plot. */
5862
- price: number | null;
5863
- /** UTC seconds under the pointer, or null when there is no data. */
5864
- time: number | null;
5865
- /** Logical bar index under the pointer, or null off the plot. */
5866
- index: number | null;
5867
- target: ContextMenuTarget;
5868
- /** Suppress the browser's own menu. Call it to show your own. */
5869
- preventDefault(): void;
5870
- }
5871
- /**
5872
- * Payload of the 'renderer:fallback' event: the chart has moved every pane
5873
- * from a GPU backend to `canvas2d` for the rest of the session, because the
5874
- * device's context was lost or turned out unusable. The frame that noticed
5875
- * was already painted through 2D by the backend itself, so nothing went
5876
- * blank; this is the host's cue to update anything that shows the renderer.
5877
- */
5878
- interface RendererFallbackEvent {
5879
- from: RenderBackendKind;
5880
- to: 'canvas2d';
5881
- reason: RendererFallbackReason;
5882
- }
5883
5896
  declare class Chart {
5884
5897
  private readonly _container;
5885
5898
  private readonly _doc;
@@ -5906,13 +5919,8 @@ declare class Chart {
5906
5919
  private readonly _timeAxisHeight;
5907
5920
  private _pending;
5908
5921
  private _scaleMutationDepth;
5909
- private _resizeObserver;
5910
- /** Watches the canvases' device-pixel boxes, where the browser reports them. */
5911
- private _deviceObserver;
5912
- /** Matches the device pixel ratio the canvases were last sized at; made again on every change. */
5913
- private _ratioQuery;
5914
- /** The window whose `resize` also re-checks the ratio. */
5915
- private _ratioView;
5922
+ /** Size and device-pixel-ratio observation; see chart-pixels.ts. */
5923
+ private readonly _pixels;
5916
5924
  /** The device pixel ratio the canvases were last sized at. */
5917
5925
  private _layoutRatio;
5918
5926
  private _width;
@@ -5927,8 +5935,8 @@ declare class Chart {
5927
5935
  private _shortcuts;
5928
5936
  private _trading;
5929
5937
  private _tickSchedule;
5930
- private _pointerInside;
5931
- private _keyTarget;
5938
+ /** Pointer, wheel and keyboard routing, hover, and the gesture state they keep; see chart-input.ts. */
5939
+ private readonly _input;
5932
5940
  private readonly _now;
5933
5941
  private readonly _conflate;
5934
5942
  private readonly _conflationFactor;
@@ -5974,38 +5982,16 @@ declare class Chart {
5974
5982
  private _events;
5975
5983
  private _eventMarkers;
5976
5984
  private _eventPane;
5977
- private readonly _eventVisible;
5978
- private _cursorPane;
5979
- private _cursor;
5980
- private _dragging;
5985
+ /** Attaching, stacking and re-homing primitives, and the event strip's type switches; see chart-primitives.ts. */
5986
+ private readonly _primitives;
5981
5987
  private readonly _navigation;
5982
- /** A cancelled navigation sequence stays consumed until every held pointer ends. */
5983
- private _navigationCancelled;
5984
- private _dragStartX;
5985
- private _dragStartY;
5986
- private _lastDragY;
5987
- /** Pointers whose gesture the missed-release recovery already ended. */
5988
- private readonly _endedPointers;
5989
- private readonly _pointers;
5990
- private _pinch;
5991
- private _pinchPane;
5992
5988
  private _liveRegion;
5993
- private _dragStartOffset;
5994
5989
  private _lastDragX;
5995
5990
  private _lastDragT;
5996
5991
  private _dragVelocity;
5997
- private _kineticHandle;
5998
- private _kineticEpoch;
5999
- private _zoomHandle;
6000
- /** The glide in flight, so a second wheel tick folds into it (see ZoomGlide.add). */
6001
- private _zoomGlide;
6002
- private _zoomGlideStart;
6003
- private _zoomGlideApplied;
5992
+ /** Kinetic pan, the zoom glide and the autoscale easing they start; see chart-motion.ts. */
5993
+ private readonly _motion;
6004
5994
  private readonly _animZoom;
6005
- private readonly _animAutoscale;
6006
- private _autoscaleTime;
6007
- private _autoscaleFrames;
6008
- private _navigationEpoch;
6009
5995
  private readonly _zoomAnchor;
6010
5996
  private readonly _doubleClick;
6011
5997
  /** `movablePrimaryPane`: without it the price pane stays pinned at slot 0. */
@@ -6029,38 +6015,28 @@ declare class Chart {
6029
6015
  * list was set by the host since, and that list becomes its own.
6030
6016
  */
6031
6017
  private readonly _legendActions;
6032
- private _restoreGeneration;
6018
+ /** Saving and restoring the chart state; see chart-state.ts. */
6019
+ private readonly _persistence;
6033
6020
  private readonly _indicatorRanges;
6034
6021
  private readonly _ownedScaleRanges;
6035
6022
  private readonly _seriesOwners;
6023
+ /** Making series and the data paths behind their handles; see chart-series.ts. */
6024
+ private readonly _series;
6036
6025
  private _dataContext;
6037
6026
  private _barsProvider;
6038
6027
  private _barsRequests;
6039
6028
  private _barsProviderRevision;
6040
6029
  private _requestedDataRevision;
6041
- /** Guards indicator recompute against re-entry via its own `series.setData`. */
6042
- private _recomputing;
6030
+ /** Adding, moving and recomputing studies, and the host they talk to; see chart-studies.ts. */
6031
+ private readonly _studies;
6043
6032
  private _indicatorsDirty;
6044
6033
  private readonly _indicatorRefreshes;
6045
- private _indicatorWork;
6046
- private _indicatorProcessed;
6047
6034
  private readonly _indicatorReservedIds;
6048
- /** Instance id of the indicator whose colours are on the price bars, if any. */
6049
- private _barColorOwner;
6050
- private _barColors;
6051
- /**
6052
- * Each price bar's own colour, indexed like the series. The overlay overwrites
6053
- * `Bar.color`, so a bar's own value is only readable the first time we touch
6054
- * it, and removing the indicator has to put something back.
6055
- */
6056
- private readonly _barColorBase;
6057
- /** Time of bar 0 when the snapshot was taken, to catch a replaced history. */
6058
- private _barColorAnchor;
6059
6035
  /** Opaque drawing-tier payload, round-tripped through get/restoreState. */
6060
6036
  private _drawingState;
6061
6037
  private _alertState;
6062
- /** Pane currently maximized, and the weights to restore when it un-maximizes. */
6063
- private _maximizedPane;
6038
+ /** Making, removing, moving, maximizing and folding panes, and their layout; see chart-panes.ts. */
6039
+ private readonly _layout;
6064
6040
  /**
6065
6041
  * Panes folded to a header strip. Held by pane identity, like `_pricePanes`,
6066
6042
  * so the fold follows its pane through a move or a removal above it without
@@ -6070,12 +6046,8 @@ declare class Chart {
6070
6046
  /** Legend rows per pane, so new ones stack below existing ones. */
6071
6047
  private readonly _legends;
6072
6048
  private readonly _studyLegends;
6073
- private _indicatorLegendToggle;
6074
- private _indicatorLegendRow;
6075
- private _indicatorTogglePress;
6076
- /** Native double clicks can join a consumed count press to a newly empty plot row. */
6077
- private _lastPressOnIndicatorToggle;
6078
- private _previousPressOnIndicatorToggle;
6049
+ /** Legend row stacking and offsets, the study count toggle, and legend button presses; see chart-legends.ts. */
6050
+ private readonly _legendStack;
6079
6051
  /**
6080
6052
  * Pane holding the primary price series (only this pane gets magnet
6081
6053
  * snapping). By identity, for the reason `_primaryPane` is: a move changes
@@ -6084,42 +6056,6 @@ declare class Chart {
6084
6056
  private _firstPane;
6085
6057
  private _historyLoader;
6086
6058
  private _loadingHistory;
6087
- private _clickCb;
6088
- private _crosshairCb;
6089
- private _readoutTime;
6090
- private _pointerMoved;
6091
- /** While true, pointer gestures place anchors instead of panning. */
6092
- private _placementMode;
6093
- /** Where indicator legend rows start inside a pane (see `legendOffset`). */
6094
- private readonly _legendOffset;
6095
- private _downPane;
6096
- private _downX;
6097
- private _downLocalY;
6098
- /** Pressure at the press; a click reports this, since its release always reads 0. */
6099
- private _downPressure;
6100
- private _dragId;
6101
- private _dragPriceScale;
6102
- private _dragCancelOnEscape;
6103
- private _hoverId;
6104
- private _hoverKey;
6105
- /** Whether that primitive draws below the overlay, so leaving it must repaint the base. */
6106
- private _hoverOnBase;
6107
- private _overlayFrozen;
6108
- private _dragCb;
6109
- private _dragEndCb;
6110
- private _axisDrag;
6111
- /** The scale a price-axis drag is rescaling: either side's, whichever strip was grabbed. */
6112
- private _axisDragScale;
6113
- /** Active pane-divider drag: which boundary, and the weights/heights at grab time. */
6114
- /** True once a primitive drag has actually moved — see the pointerup note. */
6115
- private _dragMoved;
6116
- /** Where the drag was grabbed, in data space, so deltas start at the press. */
6117
- private _dragFrom;
6118
- private _paneResize;
6119
- private _axisStartCoord;
6120
- private _axisStartMin;
6121
- private _axisStartMax;
6122
- private _axisStartSpacing;
6123
6059
  private _priceFormatter;
6124
6060
  private _priceScaleOptions;
6125
6061
  /**
@@ -6132,6 +6068,8 @@ declare class Chart {
6132
6068
  * pane is destroyed and nothing else keeps it alive.
6133
6069
  */
6134
6070
  private readonly _pricePanes;
6071
+ /** Which scales a price-scale setting reaches, and one axis' state; see chart-scales.ts. */
6072
+ private readonly _scales;
6135
6073
  private _timeFormatter;
6136
6074
  private _timezone;
6137
6075
  private _leftAxisWidth;
@@ -6144,10 +6082,9 @@ declare class Chart {
6144
6082
  /** Pane the navigator is currently attached to, so it can follow the bottom. */
6145
6083
  private _timeNavPane;
6146
6084
  private _branding;
6147
- private _brandingOptions;
6148
- private _brandingPress;
6149
- private _watermark;
6150
- private _watermarkOptions;
6085
+ /** Branding options, the background text, the option batch and the exports; see chart-appearance.ts. */
6086
+ private readonly _appearance;
6087
+ private readonly _readByCollaborators;
6151
6088
  constructor(container: HTMLElement, options?: ChartOptions);
6152
6089
  /** Register a callback fired when the user pans near the left (oldest) edge. */
6153
6090
  setHistoryLoader(loader: () => void): void;
@@ -6240,14 +6177,6 @@ declare class Chart {
6240
6177
  * An unregistered type throws before any state changes.
6241
6178
  */
6242
6179
  setSeriesType(series: SeriesApi, type: SeriesType): boolean;
6243
- private _setSeriesType;
6244
- /**
6245
- * `claimPrimary` is false for series the chart creates on a caller's behalf
6246
- * (indicator plots), so an indicator's line never becomes the price series
6247
- * that drives the magnet crosshair and the OHLC legend.
6248
- */
6249
- private _createSeries;
6250
- private _applySeriesPriceFormat;
6251
6180
  /**
6252
6181
  * The primary price series: the first one added, and the one the magnet
6253
6182
  * crosshair, the OHLC legend, the market-replay controller and a settings
@@ -6263,16 +6192,6 @@ declare class Chart {
6263
6192
  type: SeriesType;
6264
6193
  style: Readonly<SeriesStyle>;
6265
6194
  } | null;
6266
- /**
6267
- * Push a series' `precision` override onto the price scale it maps to.
6268
- *
6269
- * It rides the scale's *formatter* rather than `minMove` because minMove also
6270
- * drives `snapToTick`: precision 0 would start snapping every price to whole
6271
- * numbers. Going through the formatter covers the axis ticks, the last-value
6272
- * tag, the crosshair label and the drawing-tool labels at once, since they all
6273
- * call `priceScale.format`. Clearing it restores the chart-wide formatter.
6274
- */
6275
- private _applyPrecision;
6276
6195
  /**
6277
6196
  * Add a horizontal price line (order/SL/TP/alert/level) to a pane. Omitting
6278
6197
  * the pane means the primary price pane, wherever it sits.
@@ -6296,8 +6215,6 @@ declare class Chart {
6296
6215
  /** Turn event types on/off. Unlisted types stay visible. */
6297
6216
  setEventOptions(patch: ChartEventOptions): void;
6298
6217
  eventOptions(): ChartEventOptions;
6299
- private _ensureEventMarkers;
6300
- private _syncEvents;
6301
6218
  /**
6302
6219
  * Add a registered indicator. Built-in descriptors live in the lazy
6303
6220
  * `openalgo-charts/indicators` tier — import it (or register your own with
@@ -6330,16 +6247,6 @@ declare class Chart {
6330
6247
  policy?: IndicatorPolicy;
6331
6248
  instanceId?: string;
6332
6249
  }): IndicatorApi;
6333
- /**
6334
- * Give a repeated indicator its own colours. Three EMAs all in the
6335
- * descriptor's default blue are indistinguishable on the chart *and* in the
6336
- * legend, so the second and later instances rotate through a palette.
6337
- *
6338
- * Only fills colour keys the caller left unset, so an explicit colour always
6339
- * wins, and the first instance is never touched — it keeps the colours the
6340
- * descriptor chose.
6341
- */
6342
- private _distinctColors;
6343
6250
  /**
6344
6251
  * Every live indicator instance, in renderer stacking order.
6345
6252
  *
@@ -6358,7 +6265,6 @@ declare class Chart {
6358
6265
  * policy is not `movable` stays unless `options.force` is set.
6359
6266
  */
6360
6267
  reorderIndicator(instanceId: string, direction: -1 | 1, options?: IndicatorEditOptions): boolean;
6361
- private _reorderIndicatorResources;
6362
6268
  /** Whether a call may make a change a study's policy reserves for its host. */
6363
6269
  private _policyAllows;
6364
6270
  /**
@@ -6387,30 +6293,12 @@ declare class Chart {
6387
6293
  * layer is the case this exists for. False for a primitive on no pane.
6388
6294
  */
6389
6295
  setPrimitiveStackAbove(primitive: IPrimitive, above: string | null): boolean;
6390
- /** Each series of a pane that belongs to one of its series-band entries, with that entry's id. */
6391
- private _stackOwners;
6392
- /** The series an entry paints last on a pane: what a primitive placed above it paints after. */
6393
- private _stackSlot;
6394
- /**
6395
- * Put the price source where it was placed: directly above its study, or
6396
- * behind every study of its pane. A source nobody placed stays where it was
6397
- * added. Host series keep their slots, so only the source record moves, and
6398
- * only when it is out of place.
6399
- */
6400
- private _placeSource;
6401
- /**
6402
- * The study directly below the source, read from the band as it stands:
6403
- * how the source keeps its place when the study it sat on leaves the pane.
6404
- */
6405
- private _reanchorSource;
6406
- private _syncLegendPanes;
6407
6296
  /**
6408
6297
  * Remove one indicator instance by its handle id. Returns true if it existed
6409
6298
  * and went; a study whose policy is not `removable` stays unless
6410
6299
  * `options.force` is set.
6411
6300
  */
6412
6301
  removeIndicator(instanceId: string, options?: IndicatorEditOptions): boolean;
6413
- private _forgetIndicator;
6414
6302
  /** Optional instrument identity supplied by the host, never inferred from bars. */
6415
6303
  getDataContext(): Readonly<ChartDataContext> | undefined;
6416
6304
  /** Instrument capability from the host. A missing bar reading does not change it. */
@@ -6438,58 +6326,12 @@ declare class Chart {
6438
6326
  setWatermarkOptions(options: boolean | ChartWatermarkOptions): void;
6439
6327
  /** JSON-safe preferences. Automatic text remains blank in this snapshot. */
6440
6328
  watermarkOptions(): Readonly<ChartWatermarkOptions>;
6441
- private _syncWatermark;
6442
- private _indicatorHost;
6443
- private _validPriceScaleId;
6444
- private _assignIndicatorScale;
6445
- private _reconcileIndicatorRanges;
6446
- /**
6447
- * Take (or withdraw) the price bars' colour overlay on behalf of one
6448
- * indicator instance.
6449
- *
6450
- * Only one overlay can be on the candles, so this is last writer wins. That is
6451
- * deterministic rather than arbitrary: publishers run inside
6452
- * `_flushIndicators`, in `addIndicator` order, so the same instance wins
6453
- * every frame. Withdrawal is gated on ownership, or the first publisher's
6454
- * teardown would wipe the second one's colours. If the *winner* is removed
6455
- * while another publisher is still live, the bars go back to their own colours
6456
- * until that publisher's next recompute.
6457
- */
6458
- private _setBarColors;
6459
- /**
6460
- * Republish the primary series with the overlay applied.
6461
- *
6462
- * The bars in the data layer are the **caller's own objects** (`setData` keeps
6463
- * the references), so painting a colour onto them in place would reach back
6464
- * into the host's array and outlive the indicator. Cloning the ones that
6465
- * change is what keeps that from happening; unchanged bars are passed through,
6466
- * and a pass where nothing changed writes nothing at all, which is the common
6467
- * case on a live tick.
6468
- */
6469
- private _applyBarColors;
6470
- /**
6471
- * Mark every indicator stale after a source-data change, to be recomputed
6472
- * once before the next paint.
6473
- *
6474
- * Recomputing straight from the data update instead costs a full pass over
6475
- * every bar, for every indicator, for every tick. A busy symbol delivers ticks
6476
- * in bursts far faster than the display refreshes, so most of those passes are
6477
- * thrown away unseen: 50 ticks between two frames cost 50 recomputes per
6478
- * indicator and blocked the main thread for over half a second on a ten
6479
- * indicator chart. Deferring to the frame makes that one recompute, because
6480
- * only the last one could ever have been shown.
6481
- *
6482
- * `flushIndicators` therefore has to run before anything that can observe a
6483
- * value, which is the frame and the public `indicators()` accessor.
6484
- */
6485
- private _invalidateIndicators;
6486
6329
  /**
6487
- * Recompute every stale indicator. Reentrant-guarded: an indicator writes its
6488
- * plots with `series.setData`, which re-enters the same data-mutation path
6489
- * that marked us dirty.
6330
+ * The `IndicatorHost` a study instance talks to; see chart-studies.ts. Kept
6331
+ * here by name because the restore and tests build a host through it.
6490
6332
  */
6491
- private _flushIndicators;
6492
- private _queueIndicatorDependents;
6333
+ private _indicatorHost;
6334
+ private _validPriceScaleId;
6493
6335
  /** Subscribe to clicks on hit-testable primitives (markers, events, lines). */
6494
6336
  subscribeClick(cb: (externalId: string) => void): void;
6495
6337
  /**
@@ -6560,27 +6402,6 @@ declare class Chart {
6560
6402
  * pane, the primary price pane when none is named, or to a chart anchor.
6561
6403
  */
6562
6404
  addPrimitive(primitive: IPrimitive, where?: number | PrimitivePlacement): void;
6563
- /** The pane a chart anchor currently resolves to. */
6564
- private _anchorTarget;
6565
- /**
6566
- * The pane that wears the price pane's furniture: the primary pane while it
6567
- * is on screen, else the pane at the top, which is the one maximized over
6568
- * it. A host's symbol line and OHLC readout describe the price, so they,
6569
- * the study count, the background text and the legend offset belong with
6570
- * the price pane wherever it sits, and the price pane is hidden only while
6571
- * another pane fills the chart in its place.
6572
- */
6573
- private _priceCornerIndex;
6574
- /**
6575
- * Move every chart-anchored primitive to the pane its anchor now names.
6576
- *
6577
- * Called after anything that changes which pane sits at an edge or holds the
6578
- * price: a pane added, removed, moved, collapsed or maximized. Maximize matters
6579
- * most and is the case a host cannot easily handle itself: it HIDES the other
6580
- * panes, so a mark pinned to the price pane vanishes with it rather than
6581
- * merely sitting in the wrong place.
6582
- */
6583
- private _rehomeAnchored;
6584
6405
  /**
6585
6406
  * Map a price to a container-relative Y in media (CSS) px, for positioning DOM
6586
6407
  * overlays (order panels, tooltips) over a pane. Returns null if the pane
@@ -6608,12 +6429,6 @@ declare class Chart {
6608
6429
  * placeholder range.
6609
6430
  */
6610
6431
  plotRect(paneIndex: number): PlotRect | null;
6611
- /**
6612
- * A pane whose prices have a place on screen, scaled. A strip has none: the
6613
- * pointer events report no price there, and a conversion that still did
6614
- * would put an overlay or a nudged drawing inside a strip nobody can read.
6615
- */
6616
- private _mappedPane;
6617
6432
  /**
6618
6433
  * Grid lines at runtime: visibility of each axis, plus its colour, dash,
6619
6434
  * width and spacing. Omitted fields keep their current value. Repaints every
@@ -6661,34 +6476,6 @@ declare class Chart {
6661
6476
  * instrument. A detached copy; empty when nothing was ever set.
6662
6477
  */
6663
6478
  priceScaleDefaults(): Partial<PriceScaleOptions>;
6664
- /**
6665
- * A chart-wide price-scale patch as one pane should receive it.
6666
- *
6667
- * Every field in it describes the axis, except `minMove`, which describes the
6668
- * **instrument**: it is the step the symbol trades in, 0.05 on an NSE equity.
6669
- * A pane that plots something else is quoted in its own units, so handing it
6670
- * that step is not a coarse answer but an answer to a different question. It
6671
- * shipped as one: a host setting the instrument's 0.10 tick chart-wide made
6672
- * `PriceScale.precision` report one decimal on *every* pane, so a William VIX
6673
- * Fix reading 0.61 was labelled "0.6" and an RSI ladder read "70.0, 50.0,
6674
- * 30.0". Withheld, those axes fall back to inferring precision from the range
6675
- * they actually cover, which is the reading their own numbers imply.
6676
- *
6677
- * Only the chart-wide setters filter. An axis named outright
6678
- * (`setPriceAxisOptions`, a series' `priceFormat`) is the caller saying what
6679
- * that one axis quotes, and is obeyed.
6680
- */
6681
- private _scalePatchFor;
6682
- /**
6683
- * Record that a pane quotes the instrument, and hand it the tick it was not
6684
- * given while it did not.
6685
- *
6686
- * The primary pane is one from birth. Any other pane starts out an
6687
- * indicator's, so a host adding a second symbol to a pane of its own has to
6688
- * be able to promote one after the fact, or the comparison would lose the
6689
- * tick-sized axis it has always had.
6690
- */
6691
- private _claimPricePane;
6692
6479
  /** The primary pane's price-scale options (what the Scales tab reads), wherever it sits. */
6693
6480
  priceScaleOptions(): PriceScaleOptions;
6694
6481
  /**
@@ -6752,9 +6539,6 @@ declare class Chart {
6752
6539
  * studies.
6753
6540
  */
6754
6541
  movePriceAxis(paneIndex: number, from: 'right' | 'left', to: 'right' | 'left'): boolean;
6755
- private _canMovePriceAxis;
6756
- /** Measure one scale on demand, the way `_ensureScaled` does for the pane's right one. */
6757
- private _ensureScaledFor;
6758
6542
  /**
6759
6543
  * Per-field status-line switches, applied to every pane legend on the chart:
6760
6544
  * the host's symbol row and the indicator rows alike, which is what makes one
@@ -6821,28 +6605,8 @@ declare class Chart {
6821
6605
  exportSVG(options?: ExportSvgOptions): string;
6822
6606
  /** Chart-anchored primitives, re-homed by `_rehomeAnchored`. */
6823
6607
  private readonly _anchored;
6824
- private _addPrimitive;
6825
6608
  /** Remove a primitive from whichever pane holds it. */
6826
6609
  removePrimitive(primitive: IPrimitive): void;
6827
- /**
6828
- * Renumber legend rows per pane in insertion order, so removing one closes
6829
- * the gap instead of leaving a hole where it used to sit.
6830
- */
6831
- private _restackLegends;
6832
- /**
6833
- * Apply `legendOffset` to the price pane wherever it sits, and to the pane
6834
- * maximized over it while it is hidden, rather than to a fixed index.
6835
- *
6836
- * The offset describes the corner a host covers with its own readout of the
6837
- * price: a symbol line, an OHLC row. That readout belongs to the price pane,
6838
- * so it moves with it when the pane is moved below its studies. Maximizing a
6839
- * study pane hides the price pane, and the maximized pane then renders in
6840
- * the corner the host overlay covers; pinning the offset to one index left
6841
- * it drawing its legend straight through the host's readout.
6842
- *
6843
- * Host-added legend rows are left alone: the host positions its own.
6844
- */
6845
- private _syncLegendOffsets;
6846
6610
  /**
6847
6611
  * A host for the (lazy-loaded) trade layer to attach/detach its primitives
6848
6612
  * on a pane. Without an index it follows the primary price pane, resolved at
@@ -6853,12 +6617,6 @@ declare class Chart {
6853
6617
  addPrimitive(p: IPrimitive): void;
6854
6618
  removePrimitive(p: IPrimitive): void;
6855
6619
  };
6856
- /** Apply one live bar; auto-scroll only on a genuine right-edge append. */
6857
- private _updateBar;
6858
- private _ensurePane;
6859
- private _setData;
6860
- /** History paging: merge older bars, preserving the viewport (§4.2). */
6861
- private _prependData;
6862
6620
  /**
6863
6621
  * The render backend the chart is painting series with right now: what the
6864
6622
  * first pane was given, which is the `renderer` option unless its factory
@@ -6882,7 +6640,6 @@ declare class Chart {
6882
6640
  * path, so nothing was blank in between).
6883
6641
  */
6884
6642
  private _fallbackToCanvas2d;
6885
- private _addPane;
6886
6643
  /**
6887
6644
  * Set a custom price formatter for every pane's axis labels, last-price tag,
6888
6645
  * and price-line labels at runtime (e.g. switch to a currency format). Pass
@@ -6970,7 +6727,6 @@ declare class Chart {
6970
6727
  * (or `setVisibleLogicalRange`) once the series are populated.
6971
6728
  */
6972
6729
  restoreState(state: unknown, options?: ChartRestoreOptions): RestoreReport;
6973
- private _restoreState;
6974
6730
  /**
6975
6731
  * The opaque `drawings` slot in the chart state. The base engine only
6976
6732
  * round-trips it; the drawing tier reads and writes it.
@@ -7019,90 +6775,9 @@ declare class Chart {
7019
6775
  setAlertState(document: AlertsDocument | undefined): void;
7020
6776
  private _reserveAlertStudyIds;
7021
6777
  invalidate(build: (mask: InvalidateMask) => void): void;
7022
- /**
7023
- * Measure the container once more, a frame after construction.
7024
- *
7025
- * The size read in the constructor is only what the browser has resolved so
7026
- * far. A chart created from a script that runs before the flex/grid layout
7027
- * settles measures a pre-layout box, lays its panes into it, and then hears
7028
- * the *same* stale contentRect from the ResizeObserver in that frame, so
7029
- * nothing corrects it until an unrelated resize: the reported symptom is a
7030
- * large empty band under the chart that a refresh makes go away.
7031
- *
7032
- * Only a real measurement is allowed to win. Zero or absent means a container
7033
- * that is hidden or not in the document yet, and overwriting a size the host
7034
- * applied by hand with that would be a worse bug than the one being fixed;
7035
- * the ResizeObserver still picks such a container up when it appears.
7036
- */
7037
- private _remeasure;
7038
6778
  applySize(width: number, height: number): void;
7039
- /**
7040
- * Distribute height across panes by weight; sync the shared time-scale width.
7041
- *
7042
- * `geometryOnly` sizes the layout arithmetic (pane boxes, scale heights, the
7043
- * time-scale width) and leaves the DOM and the canvases alone. The vector
7044
- * export uses it to paint at a size that is not the screen's and then to put
7045
- * the screen's back, without clearing a canvas or moving a flex box on the
7046
- * way through.
7047
- */
7048
- private _relayout;
7049
- /**
7050
- * A hairline between stacked panes: on every pane but the one against the
7051
- * chart's top, whole device pixels tall, in the form `Pane.setSeparator`
7052
- * picks for the ratio the panes were laid out at. It sits on the DOM box,
7053
- * so it is exactly on the boundary the user drags.
7054
- */
7055
- private _syncSeparators;
7056
- /**
7057
- * The device pixel ratio pane boundaries are rounded at: the one the panes
7058
- * were last laid out at, so hit testing, `priceToCoordinate` and the DOM
7059
- * boxes agree even when the ratio has moved with no event to say so (a
7060
- * scale-only emulation, a browser with neither signal) until the next
7061
- * relayout. Before the first layout, the ratio now.
7062
- */
7063
- private _ratioForLayout;
7064
- /**
7065
- * Reserve the chart-wide axis columns: a left one as soon as any pane has a
7066
- * left price scale in use, and the right one unless every scale in use has
7067
- * moved off it. A chart with nothing on any scale keeps its right column,
7068
- * which is where an empty chart's ladder belongs; the columns are chart-wide
7069
- * rather than per pane because the panes share one time axis and their plots
7070
- * have to start and end at the same x.
7071
- */
7072
- private _recomputeAxisColumns;
7073
- private _measureAxisColumns;
7074
- /**
7075
- * The share of the chart a pane gets. While one pane is maximized it takes
7076
- * everything and the rest take nothing, so they lay out at zero height and
7077
- * are hidden outright rather than collapsed to a sliver. A sliver still
7078
- * paints a strip of squeezed candles and a separator hairline above the very
7079
- * pane the user asked to see on its own.
7080
- *
7081
- * Stored weights are never touched, so restoring is exact and `getState`
7082
- * cannot persist a placeholder.
7083
- */
7084
- private _layoutWeight;
7085
- /** First pane with a share of the chart: the one that sits against the top edge. */
7086
- private _topPaneIndex;
7087
- /**
7088
- * Last pane with a share of the chart: the one that owns the time axis, even
7089
- * as a strip, so the axis stays at the foot of the chart. `open` asks for the
7090
- * last one with a plot instead, which is where chart furniture belongs.
7091
- */
6779
+ /** Stays on the chart by name: its callers here and tests read the bottom pane through it. */
7092
6780
  private _bottomPaneIndex;
7093
- /** Drawn as a strip right now: a maximized pane shows whole whatever it is set to. */
7094
- private _collapsedShown;
7095
- /** Grab tolerance around a pane boundary, in media px. */
7096
- private static readonly DIVIDER_GRAB;
7097
- /**
7098
- * The two panes a press at `y` resizes, or null. Boundary `i` separates pane
7099
- * `i` from pane `i + 1`; the last pane's bottom is the chart edge and is not
7100
- * draggable. A strip keeps its height, so a boundary beside one moves height
7101
- * between the nearest open panes either side of it. A pane hidden behind a
7102
- * maximized one is never a side: dragging it would rewrite a weight nobody
7103
- * can see.
7104
- */
7105
- private _dividerAt;
7106
6781
  /**
7107
6782
  * Set a pane's relative height weight. Panes share the chart height in
7108
6783
  * proportion to their weights, so only the ratio matters.
@@ -7121,16 +6796,6 @@ declare class Chart {
7121
6796
  * `options.force` is set.
7122
6797
  */
7123
6798
  removePane(index: number, options?: IndicatorEditOptions): boolean;
7124
- /**
7125
- * Keep the saved drawings' slots in step with a pane that moved or went,
7126
- * for the draw tier that has not loaded yet: it reads them from
7127
- * `drawingState()` whenever it arrives, and a stale slot would put a drawing
7128
- * on the wrong pane or recreate one that is gone. The slot is the draw
7129
- * tier's document and opaque here, so only its pane field is touched, on a
7130
- * copy, and a drawing on a removed pane goes with it, as the tier drops it.
7131
- * A tier that is listening writes its own document right after the event.
7132
- */
7133
- private _remapSavedDrawings;
7134
6799
  /**
7135
6800
  * Move a pane up or down one slot, swapping it with its neighbour.
7136
6801
  *
@@ -7168,8 +6833,6 @@ declare class Chart {
7168
6833
  setPrimaryPaneIndex(index: number): boolean;
7169
6834
  /** The primary pane's slot; 0 once the chart is torn down and there are no panes. */
7170
6835
  private _primaryIndex;
7171
- /** Slot of the pane holding the primary series, the price pane before there is one. */
7172
- private _firstPaneSlot;
7173
6836
  /**
7174
6837
  * Expand one pane to fill the chart, hiding the others. Calling it again (or
7175
6838
  * on another pane) puts the stack back exactly as it was, since the stored
@@ -7201,28 +6864,10 @@ declare class Chart {
7201
6864
  setPaneCollapsed(index: number, collapsed: boolean): boolean;
7202
6865
  /** Whether a pane is collapsed to its header strip. The primary price pane never is. */
7203
6866
  paneCollapsed(index: number): boolean;
7204
- /**
7205
- * Route a pane-legend button press. Ids look like `indicator:<instanceId>::close`.
7206
- * Returns true when the id was ours and was handled.
7207
- */
6867
+ /** Stays on the chart by name: the pointer release and tests route a legend press through it. */
7208
6868
  private _handleLegendAction;
7209
- private _indicatorLegendHit;
7210
- /**
7211
- * Cumulative top + height of each pane: the source of truth for the DOM
7212
- * boxes, the canvases and hit-testing alike. A collapsed pane is a fixed
7213
- * strip one legend row tall, with the time axis under it when it is the
7214
- * bottom pane, and the open panes share what is left by weight, so folding
7215
- * one never rewrites a stored weight.
7216
- *
7217
- * Every boundary between panes sits on a device pixel (`alignToDevicePixels`)
7218
- * of the ratio the panes are laid out at (`_ratioForLayout`), so each canvas
7219
- * covers a whole number of device pixels and the separator gets rows of its
7220
- * own. It is done here rather than where the boxes are sized, so hit testing
7221
- * reads the same boxes the DOM shows.
7222
- */
6869
+ /** Stays on the chart by name: its callers here and tests read the pane boxes through it. */
7223
6870
  private _paneLayout;
7224
- /** The layout by weight and strip height alone, before device-pixel rounding. */
7225
- private _paneShares;
7226
6871
  /**
7227
6872
  * Keyboard hints for the navigator tooltips, read from the live keymap so a
7228
6873
  * rebind shows up in the tooltip instead of a stale hardcoded string. The
@@ -7256,34 +6901,7 @@ declare class Chart {
7256
6901
  * switched timeframe mid-session has to follow within a screen of bars.
7257
6902
  */
7258
6903
  private _barCountdownOptions;
7259
- private _observeSize;
7260
- /** Start or stop reading a pane's canvases' device-pixel boxes. */
7261
- private _observeCanvases;
7262
- /**
7263
- * Give each canvas the backing store the browser says its box covers. A
7264
- * canvas that starts part way into a device pixel is snapped to one pixel
7265
- * more or fewer than `media x dpr`, and a store one pixel off is stretched
7266
- * over the box, blurring every line on it.
7267
- */
7268
- private _onDevicePixels;
7269
- private _canvasLayerOf;
7270
- /** The window the chart's document shows in, or null outside a browser. */
7271
- private _view;
7272
- /**
7273
- * Follow the device pixel ratio. It changes with no box changing size when
7274
- * the window moves to a screen of another density, and no size observer
7275
- * hears of that, so the canvases would stay at the old ratio, stretched and
7276
- * blurred. A resolution query matches the one ratio it was made for, so
7277
- * each change makes a new one for the ratio now in force.
7278
- *
7279
- * The window's `resize` is heard too: a zoom fires it, and it is the one
7280
- * signal left in a browser whose query list takes no change listener. It
7281
- * costs a comparison when the ratio has not moved.
7282
- */
7283
- private _watchPixelRatio;
7284
- private _unwatchPixelRatio;
7285
6904
  private readonly _onPixelRatio;
7286
- /** Size the canvases again if the ratio is no longer the one they were sized at. */
7287
6905
  private readonly _checkPixelRatio;
7288
6906
  /**
7289
6907
  * Run the pending frame now rather than on the next animation frame, for
@@ -7297,115 +6915,28 @@ declare class Chart {
7297
6915
  */
7298
6916
  private _paintNow;
7299
6917
  private _onFrame;
7300
- private _attachInput;
7301
6918
  private readonly _onPointerEnter;
7302
- /**
7303
- * The chart renders as stacked canvases, so the browser's right-click
7304
- * "Save image as…" would capture only the topmost (transparent overlay)
7305
- * layer — a blank image. Just before the native menu opens, composite the
7306
- * clicked pane's base layer *beneath* its overlay bitmap so the saved image
7307
- * is the visible chart, and freeze overlay repaints (live ticks repaint every
7308
- * few hundred ms and would wipe the snapshot while the menu is open). The
7309
- * freeze lifts on the next pointer/wheel/key input after the menu closes.
7310
- * Apps that present their own menu (preventDefault on contextmenu) are
7311
- * unaffected. Multi-pane note: the native save captures the clicked pane
7312
- * only — use `downloadScreenshot()` for the full multi-pane composite.
7313
- *
7314
- * A listener on the `contextmenu` **chart** event takes over entirely: it is
7315
- * told what was hit, and the snapshot is skipped, since the app is raising a
7316
- * menu of its own instead of the browser's.
7317
- */
7318
6919
  private readonly _onContextMenu;
7319
- /** Build the `contextmenu` payload: where the pointer is, and what it is over. */
7320
- private _contextMenuEvent;
7321
- /**
7322
- * Classify what the pointer is over. A canvas hands an app a pixel, not an
7323
- * object, so this is the part it cannot work out for itself, and the part
7324
- * that decides which menu items make sense.
7325
- */
7326
- private _contextTarget;
7327
- /** Vacant aligned cells have no scale target, even if a hidden scale exists. */
7328
- private _axisAt;
7329
- /**
7330
- * Which series the pointer sits on, if any. A pane is one bitmap, so "on the
7331
- * candle" has to be recomputed rather than looked up: take each series'
7332
- * autoscale extents for the bar under the cursor and test the band they span,
7333
- * with a few px of slack so a 1px line is still a target.
7334
- */
7335
- private _seriesAt;
7336
- /**
7337
- * The price under a pane-local y, for an event payload. Null on a strip: it
7338
- * plots nothing, so a price read off it would place a drawing, an alert or a
7339
- * pick somewhere nobody can see.
7340
- */
7341
- private _priceAt;
7342
- /** Resume overlay repaints after the native context menu closes. */
7343
- private _unfreezeOverlay;
7344
- private _localPoint;
7345
- /** Container media px to the pane under it and that pane's local y. */
7346
- private _project;
7347
- /**
7348
- * Every position a drag passed through since the previous move event, in
7349
- * the same space as the payload's `point`. The rect and layout are read once
7350
- * for the batch: a fast stroke coalesces several positions per frame, and
7351
- * each one going back to the DOM is layout work on the pointer path.
7352
- */
7353
- private _dragSamples;
7354
- /**
7355
- * Pointer facts for a click. Modifiers and device come from the release,
7356
- * pressure from the press: a release always reads 0, which would leave the
7357
- * field carrying nothing on any device.
7358
- */
7359
- private _clickInfo;
7360
6920
  private readonly _onPointerDown;
7361
6921
  private readonly _onPointerMove;
7362
6922
  private readonly _onPointerUp;
7363
- /**
7364
- * DOM pointerup entry point. Mirrors the primary-button guard in
7365
- * `_onPointerDown`: a right-click (or any non-primary mouse button) fires
7366
- * pointerdown *and* pointerup, but `_onPointerDown` ignores it — so the
7367
- * down state (`_downX`/`_downLocalY`/`_downPane`/`_pointerMoved`) is never
7368
- * refreshed and still holds the *previous* left-click. Letting a non-primary
7369
- * pointerup through would re-run the click branch against that stale position
7370
- * and replay the last click (e.g. re-firing a Buy/Sell button → a phantom
7371
- * order). Touch and pen tip contact use button 0. The internal
7372
- * recovery call from `_onPointerMove` invokes `_onPointerUp` directly, so it
7373
- * bypasses this filter and still ends a drag when a button release is missed.
7374
- */
7375
6923
  private readonly _onPointerUpNative;
7376
6924
  private readonly _onPointerCancel;
7377
6925
  private readonly _onLostPointerCapture;
7378
- /** The corner mark's hit at a container x and pane y, whatever else is there. */
7379
- private _brandingHit;
7380
- /**
7381
- * What the pointer is over on a pane, at a container x and pane y. The
7382
- * corner mark comes last: a note pinned over it, or anything else there,
7383
- * is what the user can see and means to grab, and the mark is only a link.
7384
- */
7385
- private _hitAt;
7386
6926
  private readonly _onPointerLeave;
7387
6927
  private readonly _onWheel;
7388
- /** One zoom step, applied now. Shared by the instant path and each glide frame. */
7389
- private _applyZoom;
7390
- private _startZoomGlide;
7391
- private _beginAutoscaleMotion;
7392
- private _stopNavigationMotion;
7393
- private _stopZoomGlide;
6928
+ private readonly _onDblClick;
6929
+ private readonly _onKeyDown;
6930
+ /** Stays on the chart by name: the navigator's buttons and tests run a command through it. */
6931
+ private _runShortcut;
6932
+ /** Stays on the chart by name, for the frame and for tests; the pointer handlers set it. */
6933
+ private get _cursor();
7394
6934
  /**
7395
6935
  * Restore the preferred visible bar count and re-enable
7396
6936
  * auto-scaling on every price axis (undoing any pan/zoom or manual axis drag).
7397
6937
  * Same as double-clicking the chart.
7398
6938
  */
7399
6939
  resetScale(): void;
7400
- private readonly _onDblClick;
7401
- private _beginPinch;
7402
- private _updatePinch;
7403
- private _cancelPrimitiveDrag;
7404
- private readonly _onKeyDown;
7405
- /** Scope gating: hover keeps keys chart-local; global always acts. */
7406
- private _shortcutsActive;
7407
- /** Execute a built-in command; returns false for unknown (custom) commands. */
7408
- private _runShortcut;
7409
6940
  /**
7410
6941
  * Composite the full chart (all panes + overlays) and trigger a PNG download.
7411
6942
  * This is what the screenshot keyboard shortcut runs; call it from a toolbar
@@ -7415,23 +6946,9 @@ declare class Chart {
7415
6946
  downloadScreenshot(filename?: string): void;
7416
6947
  /** Refresh the polite live-region summary screen readers announce. */
7417
6948
  private _updateAccessibleSummary;
7418
- /**
7419
- * Track the primitive under the pointer: apply its cursor hint to the
7420
- * container and repaint on hover enter/leave so lines/pills can render
7421
- * hover states (they read `hoverId` off the render context).
7422
- */
7423
- private _setHover;
7424
- private _updateCursor;
7425
6949
  private _maybeLoadHistory;
7426
- /**
7427
- * Coast after a flick. Runs on the INJECTED scheduler, not the global
7428
- * requestAnimationFrame: a host that supplies its own raf expects to own
7429
- * every frame this chart schedules, and reaching past it also made the
7430
- * glide untestable, which is why the missing pan event on each frame went
7431
- * unnoticed until a browser drove it.
7432
- */
6950
+ /** Stays on the chart by name: the pointer release and tests start a glide through it. */
7433
6951
  private _startKinetic;
7434
- private _stopKinetic;
7435
6952
  /**
7436
6953
  * True once `destroy()` has run. Anything holding a chart it did not create
7437
6954
  * (a link group, a controller, a host cache) needs to know the object is a